diff --git a/0001-bluez5-device-use-get_profile_direction.patch b/0001-bluez5-device-use-get_profile_direction.patch new file mode 100644 index 0000000..d447c31 --- /dev/null +++ b/0001-bluez5-device-use-get_profile_direction.patch @@ -0,0 +1,74 @@ +From def5cd8f4a7e29dd52c93308bfcaf9d0a33b5232 Mon Sep 17 00:00:00 2001 +From: Wim Taymans +Date: Mon, 1 Sep 2014 10:43:46 +0200 +Subject: [PATCH 1/3] bluez5-device: use get_profile_direction + +Use the get_profile_direction() helper function to decide when to add a +source and a sink instead of enumerating profiles. +--- + src/modules/bluetooth/module-bluez5-device.c | 32 +++++++++++++--------------- + 1 file changed, 15 insertions(+), 17 deletions(-) + +diff --git a/src/modules/bluetooth/module-bluez5-device.c b/src/modules/bluetooth/module-bluez5-device.c +index 48e498b..15731d1 100644 +--- a/src/modules/bluetooth/module-bluez5-device.c ++++ b/src/modules/bluetooth/module-bluez5-device.c +@@ -1210,6 +1210,19 @@ static int setup_transport(struct userdata *u) { + } + + /* Run from main thread */ ++static pa_direction_t get_profile_direction(pa_bluetooth_profile_t p) { ++ static const pa_direction_t profile_direction[] = { ++ [PA_BLUETOOTH_PROFILE_A2DP_SINK] = PA_DIRECTION_OUTPUT, ++ [PA_BLUETOOTH_PROFILE_A2DP_SOURCE] = PA_DIRECTION_INPUT, ++ [PA_BLUETOOTH_PROFILE_HEADSET_HEAD_UNIT] = PA_DIRECTION_INPUT | PA_DIRECTION_OUTPUT, ++ [PA_BLUETOOTH_PROFILE_HEADSET_AUDIO_GATEWAY] = PA_DIRECTION_INPUT | PA_DIRECTION_OUTPUT, ++ [PA_BLUETOOTH_PROFILE_OFF] = 0 ++ }; ++ ++ return profile_direction[p]; ++} ++ ++/* Run from main thread */ + static int init_profile(struct userdata *u) { + int r = 0; + pa_assert(u); +@@ -1220,13 +1233,11 @@ static int init_profile(struct userdata *u) { + + pa_assert(u->transport); + +- if (u->profile == PA_BLUETOOTH_PROFILE_A2DP_SINK || u->profile == PA_BLUETOOTH_PROFILE_HEADSET_HEAD_UNIT || +- u->profile == PA_BLUETOOTH_PROFILE_HEADSET_AUDIO_GATEWAY) ++ if (get_profile_direction (u->profile) & PA_DIRECTION_OUTPUT) + if (add_sink(u) < 0) + r = -1; + +- if (u->profile == PA_BLUETOOTH_PROFILE_A2DP_SOURCE || u->profile == PA_BLUETOOTH_PROFILE_HEADSET_HEAD_UNIT || +- u->profile == PA_BLUETOOTH_PROFILE_HEADSET_AUDIO_GATEWAY) ++ if (get_profile_direction (u->profile) & PA_DIRECTION_INPUT) + if (add_source(u) < 0) + r = -1; + +@@ -1546,19 +1557,6 @@ static char *cleanup_name(const char *name) { + } + + /* Run from main thread */ +-static pa_direction_t get_profile_direction(pa_bluetooth_profile_t p) { +- static const pa_direction_t profile_direction[] = { +- [PA_BLUETOOTH_PROFILE_A2DP_SINK] = PA_DIRECTION_OUTPUT, +- [PA_BLUETOOTH_PROFILE_A2DP_SOURCE] = PA_DIRECTION_INPUT, +- [PA_BLUETOOTH_PROFILE_HEADSET_HEAD_UNIT] = PA_DIRECTION_INPUT | PA_DIRECTION_OUTPUT, +- [PA_BLUETOOTH_PROFILE_HEADSET_AUDIO_GATEWAY] = PA_DIRECTION_INPUT | PA_DIRECTION_OUTPUT, +- [PA_BLUETOOTH_PROFILE_OFF] = 0 +- }; +- +- return profile_direction[p]; +-} +- +-/* Run from main thread */ + static pa_available_t get_port_availability(struct userdata *u, pa_direction_t direction) { + pa_available_t result = PA_AVAILABLE_NO; + unsigned i; +-- +2.1.0 + diff --git a/0002-bluez5-util-add-dispose-function.patch b/0002-bluez5-util-add-dispose-function.patch new file mode 100644 index 0000000..70b4941 --- /dev/null +++ b/0002-bluez5-util-add-dispose-function.patch @@ -0,0 +1,48 @@ +From 91164da48032b078783defaa3cf1f1e173525af0 Mon Sep 17 00:00:00 2001 +From: Wim Taymans +Date: Mon, 1 Sep 2014 13:12:27 +0200 +Subject: [PATCH 2/3] bluez5-util: add dispose function + +Add a dispose function to the transport that is called before freeing +the transport. Useful for cleaning up extra userdata. +--- + src/modules/bluetooth/bluez5-util.c | 2 ++ + src/modules/bluetooth/bluez5-util.h | 2 ++ + 2 files changed, 4 insertions(+) + +diff --git a/src/modules/bluetooth/bluez5-util.c b/src/modules/bluetooth/bluez5-util.c +index 1ee2f33..50f977e 100644 +--- a/src/modules/bluetooth/bluez5-util.c ++++ b/src/modules/bluetooth/bluez5-util.c +@@ -205,6 +205,8 @@ void pa_bluetooth_transport_unlink(pa_bluetooth_transport *t) { + void pa_bluetooth_transport_free(pa_bluetooth_transport *t) { + pa_assert(t); + ++ if (t->dispose) ++ t->dispose (t); + pa_bluetooth_transport_unlink(t); + + pa_xfree(t->owner); +diff --git a/src/modules/bluetooth/bluez5-util.h b/src/modules/bluetooth/bluez5-util.h +index 8db4a17..fde2e78 100644 +--- a/src/modules/bluetooth/bluez5-util.h ++++ b/src/modules/bluetooth/bluez5-util.h +@@ -60,6 +60,7 @@ typedef enum pa_bluetooth_transport_state { + + typedef int (*pa_bluetooth_transport_acquire_cb)(pa_bluetooth_transport *t, bool optional, size_t *imtu, size_t *omtu); + typedef void (*pa_bluetooth_transport_release_cb)(pa_bluetooth_transport *t); ++typedef void (*pa_bluetooth_transport_dispose_cb)(pa_bluetooth_transport *t); + + struct pa_bluetooth_transport { + pa_bluetooth_device *device; +@@ -76,6 +77,7 @@ struct pa_bluetooth_transport { + + pa_bluetooth_transport_acquire_cb acquire; + pa_bluetooth_transport_release_cb release; ++ pa_bluetooth_transport_dispose_cb dispose; + void *userdata; + }; + +-- +2.1.0 + diff --git a/0003-backend-native-add-a-new-native-headset-backend.patch b/0003-backend-native-add-a-new-native-headset-backend.patch new file mode 100644 index 0000000..407d1c6 --- /dev/null +++ b/0003-backend-native-add-a-new-native-headset-backend.patch @@ -0,0 +1,490 @@ +From 682329bb2fc4dc337bf980aae86aa9fa1b6608ab Mon Sep 17 00:00:00 2001 +From: Wim Taymans +Date: Mon, 1 Sep 2014 15:18:22 +0200 +Subject: [PATCH 3/3] backend-native: add a new native headset backend + +Add a simple native headset backend that implements support for the +blutooth HSP profile. +This allows pulseaudio to output audio to a Headset using the HSP profile. + +Make the native backend the default. +--- + configure.ac | 6 +- + src/modules/bluetooth/backend-native.c | 443 +++++++++++++++++++++++++++++++++ + 2 files changed, 446 insertions(+), 3 deletions(-) + create mode 100644 src/modules/bluetooth/backend-native.c + +diff --git a/configure.ac b/configure.ac +index 74bea71..9a595cb 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -1032,14 +1032,14 @@ AM_CONDITIONAL([HAVE_BLUEZ], [test "x$HAVE_BLUEZ" = x1]) + ## Bluetooth Headset profiles backend ## + + AC_ARG_WITH(bluetooth_headset_backend, +- AS_HELP_STRING([--with-bluetooth-headset-backend=],[Backend for Bluetooth headset profiles (ofono)])) ++ AS_HELP_STRING([--with-bluetooth-headset-backend=],[Backend for Bluetooth headset profiles (native)])) + if test -z "$with_bluetooth_headset_backend" ; then +- BLUETOOTH_HEADSET_BACKEND=ofono ++ BLUETOOTH_HEADSET_BACKEND=native + else + BLUETOOTH_HEADSET_BACKEND=$with_bluetooth_headset_backend + fi + +-AS_IF([test "x$BLUETOOTH_HEADSET_BACKEND" != "xofono" && test "x$BLUETOOTH_HEADSET_BACKEND" != "xnull"], ++AS_IF([test "x$BLUETOOTH_HEADSET_BACKEND" != "xofono" && test "x$BLUETOOTH_HEADSET_BACKEND" != "xnull" && test "x$BLUETOOTH_HEADSET_BACKEND" != "xnative"], + [AC_MSG_ERROR([*** Invalid Bluetooth Headset backend])]) + + AC_SUBST(BLUETOOTH_HEADSET_BACKEND) +diff --git a/src/modules/bluetooth/backend-native.c b/src/modules/bluetooth/backend-native.c +new file mode 100644 +index 0000000..b3c4220 +--- /dev/null ++++ b/src/modules/bluetooth/backend-native.c +@@ -0,0 +1,443 @@ ++/*** ++ This file is part of PulseAudio. ++ ++ Copyright 2014 Wim Taymans ++ ++ PulseAudio is free software; you can redistribute it and/or modify ++ it under the terms of the GNU Lesser General Public License as ++ published by the Free Software Foundation; either version 2.1 of the ++ License, or (at your option) any later version. ++ ++ PulseAudio is distributed in the hope that it will be useful, but ++ WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with PulseAudio; if not, write to the Free Software ++ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 ++ USA. ++***/ ++ ++#ifdef HAVE_CONFIG_H ++#include ++#endif ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include ++#include ++ ++#include "bluez5-util.h" ++ ++struct pa_bluetooth_backend { ++ pa_core *core; ++ pa_dbus_connection *connection; ++ pa_bluetooth_discovery *discovery; ++ ++ PA_LLIST_HEAD(pa_dbus_pending, pending); ++}; ++ ++struct transport_rfcomm { ++ int rfcomm_fd; ++ pa_io_event *rfcomm_io; ++ pa_mainloop_api *mainloop; ++}; ++ ++#define BLUEZ_SERVICE "org.bluez" ++#define BLUEZ_MEDIA_TRANSPORT_INTERFACE BLUEZ_SERVICE ".MediaTransport1" ++ ++#define BLUEZ_ERROR_NOT_SUPPORTED "org.bluez.Error.NotSupported" ++ ++#define BLUEZ_PROFILE_MANAGER_INTERFACE BLUEZ_SERVICE ".ProfileManager1" ++#define BLUEZ_PROFILE_INTERFACE BLUEZ_SERVICE ".Profile1" ++ ++#define HSP_AG_PROFILE "/Profile/HSPAGProfile" ++ ++#define PROFILE_INTROSPECT_XML \ ++ DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \ ++ "" \ ++ " " \ ++ " " \ ++ " " \ ++ " " \ ++ " " \ ++ " " \ ++ " " \ ++ " " \ ++ " " \ ++ " " \ ++ " " \ ++ " " \ ++ " " \ ++ " " \ ++ " " \ ++ " " \ ++ " " \ ++ "" ++ ++static pa_dbus_pending* send_and_add_to_pending(pa_bluetooth_backend *backend, DBusMessage *m, ++ DBusPendingCallNotifyFunction func, void *call_data) { ++ pa_dbus_pending *p; ++ DBusPendingCall *call; ++ ++ pa_assert(backend); ++ pa_assert(m); ++ ++ pa_assert_se(dbus_connection_send_with_reply(pa_dbus_connection_get(backend->connection), m, &call, -1)); ++ ++ p = pa_dbus_pending_new(pa_dbus_connection_get(backend->connection), m, call, backend, call_data); ++ PA_LLIST_PREPEND(pa_dbus_pending, backend->pending, p); ++ dbus_pending_call_set_notify(call, func, p, NULL); ++ ++ return p; ++} ++ ++static int bluez5_sco_acquire_cb(pa_bluetooth_transport *t, bool optional, size_t *imtu, size_t *omtu) { ++ pa_bluetooth_device *d = t->device; ++ struct sockaddr_sco addr; ++ int err, i; ++ int sock; ++ bdaddr_t src; ++ bdaddr_t dst; ++ const char *src_addr, *dst_addr; ++ ++ src_addr = d->adapter->address; ++ dst_addr = d->address; ++ ++ for (i = 5; i >= 0; i--, src_addr += 3) ++ src.b[i] = strtol(src_addr, NULL, 16); ++ for (i = 5; i >= 0; i--, dst_addr += 3) ++ dst.b[i] = strtol(dst_addr, NULL, 16); ++ ++ sock = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO); ++ if (sock < 0) { ++ pa_log_error("socket(SEQPACKET, SCO) %s", pa_cstrerror(errno)); ++ return -1; ++ } ++ ++ memset(&addr, 0, sizeof(addr)); ++ addr.sco_family = AF_BLUETOOTH; ++ bacpy(&addr.sco_bdaddr, &src); ++ ++ if (bind(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) { ++ pa_log_error("bind(): %s", pa_cstrerror(errno)); ++ goto fail_close; ++ } ++ ++ memset(&addr, 0, sizeof(addr)); ++ addr.sco_family = AF_BLUETOOTH; ++ bacpy(&addr.sco_bdaddr, &dst); ++ ++ pa_log_info ("doing connect\n"); ++ err = connect(sock, (struct sockaddr *) &addr, sizeof(addr)); ++ if (err < 0 && !(errno == EAGAIN || errno == EINPROGRESS)) { ++ pa_log_error("connect(): %s", pa_cstrerror(errno)); ++ goto fail_close; ++ } ++ ++ if (imtu) ++ *imtu = 48; ++ ++ if (omtu) ++ *omtu = 48; ++ ++ return sock; ++ ++fail_close: ++ close(sock); ++ return -1; ++} ++ ++static void bluez5_sco_release_cb(pa_bluetooth_transport *t) { ++ pa_log_info("Transport %s released", t->path); ++ /* device will close the SCO socket for us */ ++} ++ ++static void register_profile_reply(DBusPendingCall *pending, void *userdata) { ++ DBusMessage *r; ++ pa_dbus_pending *p; ++ pa_bluetooth_backend *b; ++ char *profile; ++ ++ pa_assert(pending); ++ pa_assert_se(p = userdata); ++ pa_assert_se(b = p->context_data); ++ pa_assert_se(profile = p->call_data); ++ pa_assert_se(r = dbus_pending_call_steal_reply(pending)); ++ ++ if (dbus_message_is_error(r, BLUEZ_ERROR_NOT_SUPPORTED)) { ++ pa_log_info("Couldn't register profile %s because it is disabled in BlueZ", profile); ++ goto finish; ++ } ++ ++ if (dbus_message_get_type(r) == DBUS_MESSAGE_TYPE_ERROR) { ++ pa_log_error(BLUEZ_PROFILE_MANAGER_INTERFACE ".RegisterProfile() failed: %s: %s", dbus_message_get_error_name(r), ++ pa_dbus_get_error_message(r)); ++ goto finish; ++ } ++ ++finish: ++ dbus_message_unref(r); ++ ++ PA_LLIST_REMOVE(pa_dbus_pending, b->pending, p); ++ pa_dbus_pending_free(p); ++ ++ pa_xfree(profile); ++} ++ ++static void register_profile(pa_bluetooth_backend *b, const char *profile, const char *uuid) { ++ DBusMessage *m; ++ DBusMessageIter i, d; ++ ++ pa_log_debug("Registering Profile %s", profile); ++ ++ pa_assert_se(m = dbus_message_new_method_call(BLUEZ_SERVICE, "/org/bluez", BLUEZ_PROFILE_MANAGER_INTERFACE, "RegisterProfile")); ++ ++ dbus_message_iter_init_append(m, &i); ++ dbus_message_iter_append_basic(&i, DBUS_TYPE_OBJECT_PATH, &profile); ++ dbus_message_iter_append_basic(&i, DBUS_TYPE_STRING, &uuid); ++ dbus_message_iter_open_container(&i, DBUS_TYPE_ARRAY, DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING DBUS_TYPE_STRING_AS_STRING ++ DBUS_TYPE_VARIANT_AS_STRING DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &d); ++ dbus_message_iter_close_container(&i, &d); ++ ++ send_and_add_to_pending(b, m, register_profile_reply, pa_xstrdup(profile)); ++} ++ ++static void rfcomm_io_callback(pa_mainloop_api *io, pa_io_event *e, int fd, pa_io_event_flags_t events, void*userdata) { ++ pa_bluetooth_transport *t = userdata; ++ ++ pa_assert(io); ++ pa_assert(t); ++ ++ if (events & (PA_IO_EVENT_HANGUP|PA_IO_EVENT_ERROR)) { ++ pa_log("Lost RFCOMM connection."); ++ goto fail; ++ } ++ ++ if (events & PA_IO_EVENT_INPUT) { ++ char buf[512]; ++ ssize_t len; ++ ++ len = read (fd, buf, 511); ++ buf[len] = 0; ++ pa_log("RFCOMM << %s", buf); ++ ++ pa_log("RFCOMM >> OK"); ++ len = write (fd, "\r\nOK\r\n", 5); ++ /* we ignore any errors, it's not critical and real errors should ++ * be caught with the HANGUP and ERROR events handled above */ ++ if (len < 0) ++ pa_log_error("RFCOMM write error: %s", pa_cstrerror(errno)); ++ } ++ return; ++ ++fail: ++ pa_bluetooth_transport_unlink(t); ++ pa_bluetooth_transport_free(t); ++ return; ++} ++ ++static void transport_dispose(pa_bluetooth_transport *t) { ++ struct transport_rfcomm *trfc = t->userdata; ++ ++ trfc->mainloop->io_free(trfc->rfcomm_io); ++ shutdown (trfc->rfcomm_fd, SHUT_RDWR); ++ close (trfc->rfcomm_fd); ++ ++ pa_xfree(trfc); ++} ++ ++ ++static DBusMessage *profile_new_connection(DBusConnection *conn, DBusMessage *m, void *userdata) { ++ pa_bluetooth_backend *b = userdata; ++ pa_bluetooth_device *d; ++ pa_bluetooth_transport *t; ++ pa_bluetooth_profile_t p; ++ DBusMessage *r; ++ int fd; ++ const char *sender, *path, *handler; ++ DBusMessageIter arg_i; ++ char *pathfd; ++ struct transport_rfcomm *trfc; ++ ++ if (!dbus_message_iter_init(m, &arg_i) || !pa_streq(dbus_message_get_signature(m), "oha{sv}")) { ++ pa_log_error("Invalid signature found in NewConnection"); ++ goto fail; ++ } ++ ++ handler = dbus_message_get_path(m); ++ pa_assert (pa_streq(handler, HSP_AG_PROFILE)); ++ ++ pa_assert(dbus_message_iter_get_arg_type(&arg_i) == DBUS_TYPE_OBJECT_PATH); ++ dbus_message_iter_get_basic(&arg_i, &path); ++ ++ d = pa_bluetooth_discovery_get_device_by_path(b->discovery, path); ++ if (d == NULL) { ++ pa_log_error("Device doesnt exist for %s", path); ++ goto fail; ++ } ++ ++ pa_assert_se(dbus_message_iter_next(&arg_i)); ++ ++ pa_assert(dbus_message_iter_get_arg_type(&arg_i) == DBUS_TYPE_UNIX_FD); ++ dbus_message_iter_get_basic(&arg_i, &fd); ++ ++ pa_log_debug("dbus: NewConnection path=%s, fd=%d", path, fd); ++ ++ sender = dbus_message_get_sender(m); ++ ++ p = PA_BLUETOOTH_PROFILE_HEADSET_HEAD_UNIT; ++ pathfd = pa_sprintf_malloc ("%s/fd%d", path, fd); ++ d->transports[p] = t = pa_bluetooth_transport_new(d, sender, pathfd, p, NULL, 0); ++ pa_xfree(pathfd); ++ ++ t->acquire = bluez5_sco_acquire_cb; ++ t->release = bluez5_sco_release_cb; ++ t->dispose = transport_dispose; ++ ++ trfc = pa_xnew0(struct transport_rfcomm, 1); ++ trfc->rfcomm_fd = fd; ++ trfc->mainloop = b->core->mainloop; ++ trfc->rfcomm_io = trfc->mainloop->io_new(b->core->mainloop, fd, PA_IO_EVENT_INPUT|PA_IO_EVENT_HANGUP, ++ rfcomm_io_callback, t); ++ t->userdata = trfc; ++ ++ pa_bluetooth_transport_put(t); ++ ++ pa_log_debug("Transport %s available for profile %s", t->path, pa_bluetooth_profile_to_string(t->profile)); ++ ++ pa_assert_se(r = dbus_message_new_method_return(m)); ++ ++ return r; ++ ++fail: ++ pa_assert_se(r = dbus_message_new_error(m, "org.bluez.Error.InvalidArguments", "Unable to handle new connection")); ++ return r; ++} ++ ++static DBusMessage *profile_request_disconnection(DBusConnection *conn, DBusMessage *m, void *userdata) { ++ DBusMessage *r; ++ ++ pa_assert_se(r = dbus_message_new_method_return(m)); ++ ++ return r; ++} ++ ++static DBusHandlerResult profile_handler(DBusConnection *c, DBusMessage *m, void *userdata) { ++ pa_bluetooth_backend *b = userdata; ++ DBusMessage *r = NULL; ++ const char *path, *interface, *member; ++ ++ pa_assert(b); ++ ++ path = dbus_message_get_path(m); ++ interface = dbus_message_get_interface(m); ++ member = dbus_message_get_member(m); ++ ++ pa_log_debug("dbus: path=%s, interface=%s, member=%s", path, interface, member); ++ ++ if (!pa_streq(path, HSP_AG_PROFILE)) ++ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; ++ ++ if (dbus_message_is_method_call(m, "org.freedesktop.DBus.Introspectable", "Introspect")) { ++ const char *xml = PROFILE_INTROSPECT_XML; ++ ++ pa_assert_se(r = dbus_message_new_method_return(m)); ++ pa_assert_se(dbus_message_append_args(r, DBUS_TYPE_STRING, &xml, DBUS_TYPE_INVALID)); ++ ++ } else if (dbus_message_is_method_call(m, BLUEZ_PROFILE_INTERFACE, "Release")) { ++ } else if (dbus_message_is_method_call(m, BLUEZ_PROFILE_INTERFACE, "RequestDisconnection")) { ++ r = profile_request_disconnection(c, m, userdata); ++ } else if (dbus_message_is_method_call(m, BLUEZ_PROFILE_INTERFACE, "NewConnection")) ++ r = profile_new_connection(c, m, userdata); ++ else ++ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; ++ ++ if (r) { ++ pa_assert_se(dbus_connection_send(pa_dbus_connection_get(b->connection), r, NULL)); ++ dbus_message_unref(r); ++ } ++ ++ return DBUS_HANDLER_RESULT_HANDLED; ++} ++ ++static void profile_init(pa_bluetooth_backend *b, pa_bluetooth_profile_t profile) { ++ static const DBusObjectPathVTable vtable_profile = { ++ .message_function = profile_handler, ++ }; ++ const char *object_name; ++ const char *uuid; ++ ++ pa_assert(b); ++ ++ switch(profile) { ++ case PA_BLUETOOTH_PROFILE_HEADSET_HEAD_UNIT: ++ object_name = HSP_AG_PROFILE; ++ uuid = PA_BLUETOOTH_UUID_HSP_AG; ++ break; ++ default: ++ pa_assert_not_reached(); ++ break; ++ } ++ pa_assert_se(dbus_connection_register_object_path(pa_dbus_connection_get(b->connection), ++ object_name, &vtable_profile, b)); ++ register_profile (b, object_name, uuid); ++} ++ ++static void profile_done(pa_bluetooth_backend *b, pa_bluetooth_profile_t profile) { ++ pa_assert(b); ++ ++ switch(profile) { ++ case PA_BLUETOOTH_PROFILE_HEADSET_HEAD_UNIT: ++ dbus_connection_unregister_object_path(pa_dbus_connection_get(b->connection), HSP_AG_PROFILE); ++ break; ++ default: ++ pa_assert_not_reached(); ++ break; ++ } ++} ++ ++pa_bluetooth_backend *pa_bluetooth_backend_new(pa_core *c, pa_bluetooth_discovery *y) { ++ pa_bluetooth_backend *backend; ++ DBusError err; ++ ++ pa_log_debug("Bluetooth Headset Backend API support using the NULL backend"); ++ ++ backend = pa_xnew0(pa_bluetooth_backend, 1); ++ backend->core = c; ++ ++ dbus_error_init(&err); ++ if (!(backend->connection = pa_dbus_bus_get(c, DBUS_BUS_SYSTEM, &err))) { ++ pa_log("Failed to get D-Bus connection: %s", err.message); ++ dbus_error_free(&err); ++ pa_xfree(backend); ++ return NULL; ++ } ++ ++ backend->discovery = y; ++ ++ profile_init(backend, PA_BLUETOOTH_PROFILE_HEADSET_HEAD_UNIT); ++ ++ return backend; ++} ++ ++void pa_bluetooth_backend_free(pa_bluetooth_backend *backend) { ++ pa_assert(backend); ++ ++ pa_dbus_free_pending_list(&backend->pending); ++ ++ profile_done(backend, PA_BLUETOOTH_PROFILE_HEADSET_HEAD_UNIT); ++ ++ pa_dbus_connection_unref(backend->connection); ++ ++ pa_xfree(backend); ++} +-- +2.1.0 + diff --git a/0036-module-switch-on-port-available-Don-t-switch-profile.patch b/0036-module-switch-on-port-available-Don-t-switch-profile.patch deleted file mode 100644 index e8ff6e0..0000000 --- a/0036-module-switch-on-port-available-Don-t-switch-profile.patch +++ /dev/null @@ -1,35 +0,0 @@ -From ef4a41e8b0ef81a53769d853dbc7679b25252327 Mon Sep 17 00:00:00 2001 -From: David Henningsson -Date: Fri, 28 Mar 2014 11:59:09 +0100 -Subject: [PATCH 36/38] module-switch-on-port-available: Don't switch profiles - on uninitialized cards - -This could cause the HDMI port to become the default on some systems -where analog output was available. - -BugLink: https://bugs.launchpad.net/ubuntu/+source/pulseaudio/+bug/1256511 -BugLink: https://bugs.freedesktop.org/show_bug.cgi?id=73375 -Signed-off-by: David Henningsson ---- - src/modules/module-switch-on-port-available.c | 5 +++++ - 1 file changed, 5 insertions(+) - -diff --git a/src/modules/module-switch-on-port-available.c b/src/modules/module-switch-on-port-available.c -index 2c7ad17..c560306 100644 ---- a/src/modules/module-switch-on-port-available.c -+++ b/src/modules/module-switch-on-port-available.c -@@ -173,6 +173,11 @@ static pa_hook_result_t port_available_hook_callback(pa_core *c, pa_device_port - return PA_HOOK_OK; - } - -+ if (pa_idxset_size(card->sinks) == 0 && pa_idxset_size(card->sources) == 0) -+ /* This card is not initialized yet. We'll handle it in -+ sink_new / source_new callbacks later. */ -+ return PA_HOOK_OK; -+ - find_sink_and_source(card, port, &sink, &source); - - is_active_profile = card->active_profile == pa_hashmap_get(port->profiles, card->active_profile->name); --- -1.9.0 - diff --git a/0039-Name-HDMI-outputs-uniquely.patch b/0039-Name-HDMI-outputs-uniquely.patch deleted file mode 100644 index ab8f05f..0000000 --- a/0039-Name-HDMI-outputs-uniquely.patch +++ /dev/null @@ -1,77 +0,0 @@ -From a5ba31bf9627b6c7d7f5e03cdccff2d52fa3299d Mon Sep 17 00:00:00 2001 -From: "Alexander E. Patrakov" -Date: Thu, 10 Apr 2014 21:13:43 +0600 -Subject: [PATCH 039/156] Name HDMI outputs uniquely - -On Haswell hardware, there are multiple HDMI outputs capable of -digital sound output. As they were identically named, KDE's control -center was unable to distinguish them, restored the wrong profile and -thus routed sound to the wrong HDMI monitor. - -Also, having identically-named menu items in other mixer applications -looks like a bug. ---- - src/modules/alsa/mixer/profile-sets/extra-hdmi.conf | 12 ++++++------ - 1 file changed, 6 insertions(+), 6 deletions(-) - -diff --git a/src/modules/alsa/mixer/profile-sets/extra-hdmi.conf b/src/modules/alsa/mixer/profile-sets/extra-hdmi.conf -index 96652f8..191a652 100644 ---- a/src/modules/alsa/mixer/profile-sets/extra-hdmi.conf -+++ b/src/modules/alsa/mixer/profile-sets/extra-hdmi.conf -@@ -116,7 +116,7 @@ priority = 3 - direction = output - - [Mapping hdmi-stereo-extra1] --description = Digital Stereo (HDMI) -+description = Digital Stereo (HDMI 2) - device-strings = hdmi:%f,1 - paths-output = hdmi-output-1 - channel-map = left,right -@@ -124,7 +124,7 @@ priority = 2 - direction = output - - [Mapping hdmi-surround-extra1] --description = Digital Surround 5.1 (HDMI) -+description = Digital Surround 5.1 (HDMI 2) - device-strings = hdmi:%f,1 - paths-output = hdmi-output-1 - channel-map = front-left,front-right,rear-left,rear-right,front-center,lfe -@@ -132,7 +132,7 @@ priority = 1 - direction = output - - [Mapping hdmi-stereo-extra2] --description = Digital Stereo (HDMI) -+description = Digital Stereo (HDMI 3) - device-strings = hdmi:%f,2 - paths-output = hdmi-output-2 - channel-map = left,right -@@ -140,7 +140,7 @@ priority = 2 - direction = output - - [Mapping hdmi-surround-extra2] --description = Digital Surround 5.1 (HDMI) -+description = Digital Surround 5.1 (HDMI 3) - device-strings = hdmi:%f,2 - paths-output = hdmi-output-2 - channel-map = front-left,front-right,rear-left,rear-right,front-center,lfe -@@ -148,7 +148,7 @@ priority = 1 - direction = output - - [Mapping hdmi-stereo-extra3] --description = Digital Stereo (HDMI) -+description = Digital Stereo (HDMI 4) - device-strings = hdmi:%f,3 - paths-output = hdmi-output-3 - channel-map = left,right -@@ -156,7 +156,7 @@ priority = 2 - direction = output - - [Mapping hdmi-surround-extra3] --description = Digital Surround 5.1 (HDMI) -+description = Digital Surround 5.1 (HDMI 4) - device-strings = hdmi:%f,3 - paths-output = hdmi-output-3 - channel-map = front-left,front-right,rear-left,rear-right,front-center,lfe --- -1.9.3 - diff --git a/0112-rtp-recv-fix-crash-on-empty-UDP-packets-CVE-2014-397.patch b/0112-rtp-recv-fix-crash-on-empty-UDP-packets-CVE-2014-397.patch deleted file mode 100644 index 7d26bdf..0000000 --- a/0112-rtp-recv-fix-crash-on-empty-UDP-packets-CVE-2014-397.patch +++ /dev/null @@ -1,58 +0,0 @@ -From 26b9d22dd24c17eb118d0205bf7b02b75d435e3c Mon Sep 17 00:00:00 2001 -From: "Alexander E. Patrakov" -Date: Thu, 5 Jun 2014 22:29:25 +0600 -Subject: [PATCH 112/156] rtp-recv: fix crash on empty UDP packets - (CVE-2014-3970) - -On FIONREAD returning 0 bytes, we cannot return success, as the caller -(rtpoll_work_cb in module-rtp-recv.c) would then try to -pa_memblock_unref(chunk.memblock) and, because memblock is NULL, trigger -an assertion. - -Also we have to read out the possible empty packet from the socket, so -that the kernel doesn't tell us again and again about it. - -Signed-off-by: Alexander E. Patrakov ---- - src/modules/rtp/rtp.c | 25 +++++++++++++++++++++++-- - 1 file changed, 23 insertions(+), 2 deletions(-) - -diff --git a/src/modules/rtp/rtp.c b/src/modules/rtp/rtp.c -index 570737e..7b75e0e 100644 ---- a/src/modules/rtp/rtp.c -+++ b/src/modules/rtp/rtp.c -@@ -182,8 +182,29 @@ int pa_rtp_recv(pa_rtp_context *c, pa_memchunk *chunk, pa_mempool *pool, struct - goto fail; - } - -- if (size <= 0) -- return 0; -+ if (size <= 0) { -+ /* size can be 0 due to any of the following reasons: -+ * -+ * 1. Somebody sent us a perfectly valid zero-length UDP packet. -+ * 2. Somebody sent us a UDP packet with a bad CRC. -+ * -+ * It is unknown whether size can actually be less than zero. -+ * -+ * In the first case, the packet has to be read out, otherwise the -+ * kernel will tell us again and again about it, thus preventing -+ * reception of any further packets. So let's just read it out -+ * now and discard it later, when comparing the number of bytes -+ * received (0) with the number of bytes wanted (1, see below). -+ * -+ * In the second case, recvmsg() will fail, thus allowing us to -+ * return the error. -+ * -+ * Just to avoid passing zero-sized memchunks and NULL pointers to -+ * recvmsg(), let's force allocation of at least one byte by setting -+ * size to 1. -+ */ -+ size = 1; -+ } - - if (c->memchunk.length < (unsigned) size) { - size_t l; --- -1.9.3 - diff --git a/pulseaudio-4.0-kde_autostart_phase.patch b/pulseaudio-4.0-kde_autostart_phase.patch deleted file mode 100644 index 853f665..0000000 --- a/pulseaudio-4.0-kde_autostart_phase.patch +++ /dev/null @@ -1,16 +0,0 @@ -diff -up pulseaudio-4.0-266-gf81e3/src/daemon/pulseaudio-kde.desktop.in.kde_autostart_phase pulseaudio-4.0-266-gf81e3/src/daemon/pulseaudio-kde.desktop.in ---- pulseaudio-4.0-266-gf81e3/src/daemon/pulseaudio-kde.desktop.in.kde_autostart_phase 2013-10-10 17:02:01.000000000 -0500 -+++ pulseaudio-4.0-266-gf81e3/src/daemon/pulseaudio-kde.desktop.in 2013-12-07 13:15:24.034110082 -0600 -@@ -9,3 +9,4 @@ Type=Application - Categories= - GenericName= - OnlyShowIn=KDE; -+X-KDE-autostart-phase=1 -diff -up pulseaudio-4.0-266-gf81e3/src/daemon/pulseaudio.desktop.in.kde_autostart_phase pulseaudio-4.0-266-gf81e3/src/daemon/pulseaudio.desktop.in ---- pulseaudio-4.0-266-gf81e3/src/daemon/pulseaudio.desktop.in.kde_autostart_phase 2013-10-10 17:02:01.000000000 -0500 -+++ pulseaudio-4.0-266-gf81e3/src/daemon/pulseaudio.desktop.in 2013-12-07 13:15:17.579180709 -0600 -@@ -9,3 +9,4 @@ Type=Application - Categories= - GenericName= - X-GNOME-Autostart-Phase=Initialization -+X-KDE-autostart-phase=1 diff --git a/pulseaudio-x11_device_manager.patch b/pulseaudio-x11_device_manager.patch deleted file mode 100644 index f8e4cdf..0000000 --- a/pulseaudio-x11_device_manager.patch +++ /dev/null @@ -1,14 +0,0 @@ -diff -up pulseaudio-4.0-266-gf81e3/src/daemon/start-pulseaudio-x11.in.x11_device_manager pulseaudio-4.0-266-gf81e3/src/daemon/start-pulseaudio-x11.in ---- pulseaudio-4.0-266-gf81e3/src/daemon/start-pulseaudio-x11.in.x11_device_manager 2013-10-10 17:02:01.000000000 -0500 -+++ pulseaudio-4.0-266-gf81e3/src/daemon/start-pulseaudio-x11.in 2013-10-14 09:44:04.375542726 -0500 -@@ -26,6 +26,10 @@ if [ x"$DISPLAY" != x ] ; then - @PACTL_BINARY@ load-module module-x11-publish "display=$DISPLAY" > /dev/null - @PACTL_BINARY@ load-module module-x11-cork-request "display=$DISPLAY" > /dev/null - -+ if [ x"$KDE_FULL_SESSION" = x"true" ]; then -+ @PACTL_BINARY@ load-module module-device-manager "do_routing=1" > /dev/null -+ fi -+ - if [ x"$SESSION_MANAGER" != x ] ; then - @PACTL_BINARY@ load-module module-x11-xsmp "display=$DISPLAY session_manager=$SESSION_MANAGER" > /dev/null - fi diff --git a/pulseaudio.spec b/pulseaudio.spec index bb56447..5057abe 100644 --- a/pulseaudio.spec +++ b/pulseaudio.spec @@ -1,9 +1,10 @@ %global pa_major 5.0 #global pa_minor 0 -#global gitrel 266 -#global gitcommit f81e3e1d7852c05b4b737ac7dac4db95798f0117 -#global shortcommit %(c=%{gitcommit}; echo ${c:0:5}) +%global snap 20141019 +%global gitrel 287 +%global gitcommit 4971dc9ed695256cfb179c5ef4d7bf43d3826ba2 +%global shortcommit %(c=%{gitcommit}; echo ${c:0:5}) %ifarch %{ix86} x86_64 %{arm} %global with_webrtc 1 @@ -18,7 +19,7 @@ Name: pulseaudio Summary: Improved Linux Sound Server Version: %{pa_major}%{?pa_minor:.%{pa_minor}} -Release: 10%{?gitcommit:.git%{shortcommit}}%{?dist} +Release: 20%{?snap:.%{snap}git%{shortcommit}}%{?dist} License: LGPLv2+ URL: http://www.freedesktop.org/wiki/Software/PulseAudio %if 0%{?gitrel} @@ -31,17 +32,12 @@ Source0: http://freedesktop.org/software/pulseaudio/releases/pulseaudio-% Source1: default.pa-for-gdm ## upstream patches -# https://bugzilla.redhat.com/show_bug.cgi?id=1035025 -# https://bugs.freedesktop.org/show_bug.cgi?id=73375 -Patch036: 0036-module-switch-on-port-available-Don-t-switch-profile.patch -Patch039: 0039-Name-HDMI-outputs-uniquely.patch -Patch112: 0112-rtp-recv-fix-crash-on-empty-UDP-packets-CVE-2014-397.patch ## upstreamable patches -# simplify and ship only 1 autostart file -Patch501: pulseaudio-x11_device_manager.patch -# set X-KDE-autostart-phase=1 -Patch502: pulseaudio-4.0-kde_autostart_phase.patch +# WIP bluetooth headset work from http://cgit.freedesktop.org/~wtay/pulseaudio/log/?h=headset2 +Patch1: 0001-bluez5-device-use-get_profile_direction.patch +Patch2: 0002-bluez5-util-add-dispose-function.patch +Patch3: 0003-backend-native-add-a-new-native-headset-backend.patch BuildRequires: m4 BuildRequires: libtool-ltdl-devel @@ -220,15 +216,16 @@ Requires(pre): gdm %description gdm-hooks This package contains GDM integration hooks for the PulseAudio sound server. + %prep %setup -q -T -b0 -n %{name}-%{version}%{?gitrel:-%{gitrel}-g%{shortcommit}} -%patch036 -p1 -b .0036 -%patch039 -p1 -b .0039 -%patch112 -p1 -b .0112 +%patch1 -p1 -b .0001 +%patch2 -p1 -b .0002 +%patch3 -p1 -b .0003 -%patch501 -p1 -b .x11_device_manager -%patch502 -p1 -b .kde_autostart_phase +# needed by patch3 +./bootstrap.sh sed -i.no_consolekit -e \ 's/^load-module module-console-kit/#load-module module-console-kit/' \ @@ -244,9 +241,10 @@ sed -i -e 's|"/lib /usr/lib|"/%{_lib} %{_libdir}|' configure %endif %endif -%build +%build %configure \ + --disable-silent-rules \ --disable-static \ --disable-rpath \ --with-system-user=pulse \ @@ -270,6 +268,7 @@ sed -i -e 's|"/lib /usr/lib|"/%{_lib} %{_libdir}|' configure make %{?_smp_mflags} V=1 make doxygen + %install make install DESTDIR=$RPM_BUILD_ROOT @@ -300,9 +299,6 @@ install -p -m644 -D %{SOURCE1} $RPM_BUILD_ROOT%{_localstatedir}/lib/gdm/.pulse/d rm -fv $RPM_BUILD_ROOT%{_libdir}/*.la $RPM_BUILD_ROOT%{_libdir}/pulse-%{pa_major}/modules/*.la # PA_MODULE_DEPRECATED("Please use module-udev-detect instead of module-detect!"); rm -fv $RPM_BUILD_ROOT%{_libdir}/pulse-%{pa_major}/modules/module-detect.so -# x11_device_manager folds -kde functionality into single -x11 autostart, so this -# one is no longer needed -rm -fv $RPM_BUILD_ROOT%{_sysconfdir}/xdg/autostart/pulseaudio-kde.desktop %find_lang %{name} @@ -442,6 +438,9 @@ exit 0 %{_prefix}/lib/udev/rules.d/90-pulseaudio.rules %dir %{_libexecdir}/pulse %attr(0700, pulse, pulse) %dir %{_localstatedir}/lib/pulse +%dir %{_datadir}/zsh/ +%dir %{_datadir}/zsh/site-functions/ +%{_datadir}/zsh/site-functions/_pulseaudio %files qpaeq %{_bindir}/qpaeq @@ -458,15 +457,12 @@ exit 0 %files module-x11 %{_sysconfdir}/xdg/autostart/pulseaudio.desktop -## no longer included per x11_device_manager.patch -#config %{_sysconfdir}/xdg/autostart/pulseaudio-kde.desktop -%{_bindir}/start-pulseaudio-kde +#{_bindir}/start-pulseaudio-kde %{_bindir}/start-pulseaudio-x11 %{_libdir}/pulse-%{pa_major}/modules/module-x11-bell.so %{_libdir}/pulse-%{pa_major}/modules/module-x11-publish.so %{_libdir}/pulse-%{pa_major}/modules/module-x11-xsmp.so %{_libdir}/pulse-%{pa_major}/modules/module-x11-cork-request.so -%{_mandir}/man1/start-pulseaudio-kde.1.gz %{_mandir}/man1/start-pulseaudio-x11.1.gz %files module-zeroconf @@ -529,6 +525,9 @@ exit 0 %{_datadir}/vala/vapi/libpulse.deps %{_datadir}/vala/vapi/libpulse-mainloop-glib.vapi %{_datadir}/vala/vapi/libpulse-mainloop-glib.deps +%{_datadir}/vala/vapi/libpulse-simple.deps +%{_datadir}/vala/vapi/libpulse-simple.vapi + %dir %{_libdir}/cmake %{_libdir}/cmake/PulseAudio/ @@ -558,7 +557,11 @@ exit 0 %attr(0700, gdm, gdm) %dir %{_localstatedir}/lib/gdm/.pulse %attr(0600, gdm, gdm) %{_localstatedir}/lib/gdm/.pulse/default.pa + %changelog +* Wed Oct 22 2014 Rex Dieter 5.0-20.20141007git4971d +- snapshot, with wip bt headset2 patches (#1045548,#1067470) + * Sun Aug 17 2014 Fedora Release Engineering - 5.0-10 - Rebuilt for https://fedoraproject.org/wiki/Fedora_21_22_Mass_Rebuild diff --git a/sources b/sources index d75a87f..f54d595 100644 --- a/sources +++ b/sources @@ -1 +1 @@ -c43749838612f4860465e83ed62ca38e pulseaudio-5.0.tar.xz +8872ddac114237c314887dafb526a928 pulseaudio-5.0-287-g4971d.tar.xz