Sends a message from IO thread to main thread using pa_msgobject when POLLERR or POLLHUP is received on SCO socket. --- src/modules/bluetooth/module-bluetooth-device.c | 136 ++++++++++++++--------- 1 files changed, 84 insertions(+), 52 deletions(-) diff --git a/src/modules/bluetooth/module-bluetooth-device.c b/src/modules/bluetooth/module-bluetooth-device.c index 08ab868..3db9e8f 100644 --- a/src/modules/bluetooth/module-bluetooth-device.c +++ b/src/modules/bluetooth/module-bluetooth-device.c @@ -126,7 +126,9 @@ struct hsp_info { pa_hook_slot *source_state_changed_slot; }; -struct userdata { +struct bluetooth_device { + pa_msgobject parent; + pa_core *core; pa_module *module; @@ -176,6 +178,15 @@ struct userdata { pa_bool_t filter_added; }; +enum { + BLUETOOTH_DEVICE_MESSAGE_SET_PROFILE /* IO thread termination switch profiles to Off */, + BLUETOOTH_DEVICE_MESSAGE_MAX +}; + +typedef struct bluetooth_device bluetooth_device; +PA_DEFINE_PRIVATE_CLASS(bluetooth_device, pa_msgobject); +#define BLUETOOTH_DEVICE(o) (bluetooth_device_cast(o)) + #define FIXED_LATENCY_PLAYBACK_A2DP (25*PA_USEC_PER_MSEC) #define FIXED_LATENCY_RECORD_A2DP (25*PA_USEC_PER_MSEC) #define FIXED_LATENCY_PLAYBACK_HSP (125*PA_USEC_PER_MSEC) @@ -185,10 +196,10 @@ struct userdata { #define USE_SCO_OVER_PCM(u) (u->profile == PROFILE_HSP && (u->hsp.sco_sink && u->hsp.sco_source)) -static int init_bt(struct userdata *u); -static int init_profile(struct userdata *u); +static int init_bt(struct bluetooth_device *u); +static int init_profile(struct bluetooth_device *u); -static int service_send(struct userdata *u, const bt_audio_msg_header_t *msg) { +static int service_send(struct bluetooth_device *u, const bt_audio_msg_header_t *msg) { ssize_t r; pa_assert(u); @@ -215,7 +226,7 @@ static int service_send(struct userdata *u, const bt_audio_msg_header_t *msg) { return -1; } -static int service_recv(struct userdata *u, bt_audio_msg_header_t *msg, size_t room) { +static int service_recv(struct bluetooth_device *u, bt_audio_msg_header_t *msg, size_t room) { ssize_t r; pa_assert(u); @@ -267,7 +278,7 @@ read_fail: return -1; } -static ssize_t service_expect(struct userdata*u, bt_audio_msg_header_t *rsp, size_t room, uint8_t expected_name, size_t expected_size) { +static ssize_t service_expect(struct bluetooth_device*u, bt_audio_msg_header_t *rsp, size_t room, uint8_t expected_name, size_t expected_size) { int r; pa_assert(u); @@ -294,7 +305,7 @@ static ssize_t service_expect(struct userdata*u, bt_audio_msg_header_t *rsp, siz } /* Run from main thread */ -static int parse_caps(struct userdata *u, uint8_t seid, const struct bt_get_capabilities_rsp *rsp) { +static int parse_caps(struct bluetooth_device *u, uint8_t seid, const struct bt_get_capabilities_rsp *rsp) { uint16_t bytes_left; const codec_capabilities_t *codec; @@ -375,7 +386,7 @@ static int parse_caps(struct userdata *u, uint8_t seid, const struct bt_get_capa } /* Run from main thread */ -static int get_caps(struct userdata *u, uint8_t seid) { +static int get_caps(struct bluetooth_device *u, uint8_t seid) { union { struct bt_get_capabilities_req getcaps_req; struct bt_get_capabilities_rsp getcaps_rsp; @@ -461,7 +472,7 @@ static uint8_t a2dp_default_bitpool(uint8_t freq, uint8_t mode) { } /* Run from main thread */ -static int setup_a2dp(struct userdata *u) { +static int setup_a2dp(struct bluetooth_device *u) { sbc_capabilities_t *cap; int i; @@ -665,7 +676,7 @@ static void setup_sbc(struct a2dp_info *a2dp, enum profile p) { } /* Run from main thread */ -static int set_conf(struct userdata *u) { +static int set_conf(struct bluetooth_device *u) { union { struct bt_open_req open_req; struct bt_open_rsp open_rsp; @@ -743,7 +754,7 @@ static int set_conf(struct userdata *u) { } /* from IO thread */ -static void a2dp_set_bitpool(struct userdata *u, uint8_t bitpool) +static void a2dp_set_bitpool(struct bluetooth_device *u, uint8_t bitpool) { struct a2dp_info *a2dp; @@ -777,7 +788,7 @@ static void a2dp_set_bitpool(struct userdata *u, uint8_t bitpool) /* from IO thread, except in SCO over PCM */ -static int setup_stream(struct userdata *u) { +static int setup_stream(struct bluetooth_device *u) { struct pollfd *pollfd; int one; @@ -814,7 +825,7 @@ static int setup_stream(struct userdata *u) { return 0; } -static int start_stream_fd(struct userdata *u) { +static int start_stream_fd(struct bluetooth_device *u) { union { bt_audio_msg_header_t rsp; struct bt_start_stream_req start_req; @@ -852,7 +863,7 @@ static int start_stream_fd(struct userdata *u) { } /* from IO thread */ -static int stop_stream_fd(struct userdata *u) { +static int stop_stream_fd(struct bluetooth_device *u) { union { bt_audio_msg_header_t rsp; struct bt_stop_stream_req start_req; @@ -892,7 +903,7 @@ static int stop_stream_fd(struct userdata *u) { return r; } -static void bt_transport_release(struct userdata *u) { +static void bt_transport_release(struct bluetooth_device *u) { const char *accesstype = "rw"; const pa_bluetooth_transport *t; @@ -925,7 +936,7 @@ static void bt_transport_release(struct userdata *u) { } } -static int bt_transport_acquire(struct userdata *u, pa_bool_t start) { +static int bt_transport_acquire(struct bluetooth_device *u, pa_bool_t start) { const char *accesstype = "rw"; const pa_bluetooth_transport *t; @@ -963,7 +974,7 @@ done: /* Run from IO thread */ static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) { - struct userdata *u = PA_SINK(o)->userdata; + struct bluetooth_device *u = PA_SINK(o)->userdata; pa_bool_t failed = FALSE; int r; @@ -1043,7 +1054,7 @@ static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offse /* Run from IO thread */ static int source_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) { - struct userdata *u = PA_SOURCE(o)->userdata; + struct bluetooth_device *u = PA_SOURCE(o)->userdata; pa_bool_t failed = FALSE; int r; @@ -1115,8 +1126,25 @@ static int source_process_msg(pa_msgobject *o, int code, void *data, int64_t off return (r < 0 || !failed) ? r : -1; } +/* Called from main thread context */ +static int device_process_msg(pa_msgobject *obj, int code, void *data, int64_t offset, pa_memchunk *chunk) { + struct bluetooth_device *u = BLUETOOTH_DEVICE(obj); + + switch (code) { + case BLUETOOTH_DEVICE_MESSAGE_SET_PROFILE: { + const char *profile = data; + pa_log_debug("Switch profile to %s requested", profile); + + if (pa_card_set_profile(u->card, profile, FALSE) < 0) + pa_log_debug("Failed to switch profile to %s", profile); + break; + } + } + return 0; +} + /* Run from IO thread */ -static int hsp_process_render(struct userdata *u) { +static int hsp_process_render(struct bluetooth_device *u) { int ret = 0; pa_assert(u); @@ -1180,7 +1208,7 @@ static int hsp_process_render(struct userdata *u) { } /* Run from IO thread */ -static int hsp_process_push(struct userdata *u) { +static int hsp_process_push(struct bluetooth_device *u) { int ret = 0; pa_memchunk memchunk; @@ -1266,7 +1294,7 @@ static int hsp_process_push(struct userdata *u) { } /* Run from IO thread */ -static void a2dp_prepare_buffer(struct userdata *u) { +static void a2dp_prepare_buffer(struct bluetooth_device *u) { pa_assert(u); if (u->a2dp.buffer_size >= u->link_mtu) @@ -1278,7 +1306,7 @@ static void a2dp_prepare_buffer(struct userdata *u) { } /* Run from IO thread */ -static int a2dp_process_render(struct userdata *u) { +static int a2dp_process_render(struct bluetooth_device *u) { struct a2dp_info *a2dp; struct rtp_header *header; struct rtp_payload *payload; @@ -1411,7 +1439,7 @@ static int a2dp_process_render(struct userdata *u) { return ret; } -static int a2dp_process_push(struct userdata *u) { +static int a2dp_process_push(struct bluetooth_device *u) { int ret = 0; pa_memchunk memchunk; @@ -1528,7 +1556,7 @@ static int a2dp_process_push(struct userdata *u) { return ret; } -static void a2dp_reduce_bitpool(struct userdata *u) +static void a2dp_reduce_bitpool(struct bluetooth_device *u) { struct a2dp_info *a2dp; uint8_t bitpool; @@ -1550,7 +1578,7 @@ static void a2dp_reduce_bitpool(struct userdata *u) } static void thread_func(void *userdata) { - struct userdata *u = userdata; + struct bluetooth_device *u = userdata; unsigned do_write = 0; pa_bool_t writable = FALSE; @@ -1721,6 +1749,7 @@ static void thread_func(void *userdata) { fail: /* If this was no regular exit from the loop we have to continue processing messages until we receive PA_MESSAGE_SHUTDOWN */ pa_log_debug("IO thread failed"); + pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(u), BLUETOOTH_DEVICE_MESSAGE_SET_PROFILE, "off", 0, NULL, NULL); pa_asyncmsgq_wait_for(u->thread_mq.inq, PA_MESSAGE_SHUTDOWN); finish: @@ -1730,7 +1759,7 @@ finish: /* Run from main thread */ static DBusHandlerResult filter_cb(DBusConnection *bus, DBusMessage *m, void *userdata) { DBusError err; - struct userdata *u; + struct bluetooth_device *u; pa_assert(bus); pa_assert(m); @@ -1814,7 +1843,7 @@ static void sink_set_volume_cb(pa_sink *s) { DBusMessage *m; dbus_uint16_t gain; pa_volume_t volume; - struct userdata *u; + struct bluetooth_device *u; char *k; pa_assert(s); @@ -1852,7 +1881,7 @@ static void source_set_volume_cb(pa_source *s) { DBusMessage *m; dbus_uint16_t gain; pa_volume_t volume; - struct userdata *u; + struct bluetooth_device *u; char *k; pa_assert(s); @@ -1914,7 +1943,7 @@ static char *get_name(const char *type, pa_modargs *ma, const char *device_id, p return pa_sprintf_malloc("bluez_%s.%s", type, n); } -static int sco_over_pcm_state_update(struct userdata *u, pa_bool_t changed) { +static int sco_over_pcm_state_update(struct bluetooth_device *u, pa_bool_t changed) { pa_assert(u); pa_assert(USE_SCO_OVER_PCM(u)); @@ -1958,7 +1987,7 @@ static int sco_over_pcm_state_update(struct userdata *u, pa_bool_t changed) { return 0; } -static pa_hook_result_t sink_state_changed_cb(pa_core *c, pa_sink *s, struct userdata *u) { +static pa_hook_result_t sink_state_changed_cb(pa_core *c, pa_sink *s, struct bluetooth_device *u) { pa_assert(c); pa_sink_assert_ref(s); pa_assert(u); @@ -1971,7 +2000,7 @@ static pa_hook_result_t sink_state_changed_cb(pa_core *c, pa_sink *s, struct use return PA_HOOK_OK; } -static pa_hook_result_t source_state_changed_cb(pa_core *c, pa_source *s, struct userdata *u) { +static pa_hook_result_t source_state_changed_cb(pa_core *c, pa_source *s, struct bluetooth_device *u) { pa_assert(c); pa_source_assert_ref(s); pa_assert(u); @@ -1985,7 +2014,7 @@ static pa_hook_result_t source_state_changed_cb(pa_core *c, pa_source *s, struct } /* Run from main thread */ -static int add_sink(struct userdata *u) { +static int add_sink(struct bluetooth_device *u) { char *k; if (USE_SCO_OVER_PCM(u)) { @@ -2051,7 +2080,7 @@ static int add_sink(struct userdata *u) { } /* Run from main thread */ -static int add_source(struct userdata *u) { +static int add_source(struct bluetooth_device *u) { char *k; if (USE_SCO_OVER_PCM(u)) { @@ -2122,7 +2151,7 @@ static int add_source(struct userdata *u) { } /* Run from main thread */ -static void shutdown_bt(struct userdata *u) { +static void shutdown_bt(struct bluetooth_device *u) { pa_assert(u); if (u->stream_fd >= 0) { @@ -2145,7 +2174,7 @@ static void shutdown_bt(struct userdata *u) { } } -static int bt_transport_config_a2dp(struct userdata *u) { +static int bt_transport_config_a2dp(struct bluetooth_device *u) { const pa_bluetooth_transport *t; struct a2dp_info *a2dp = &u->a2dp; a2dp_sbc_t *config; @@ -2263,7 +2292,7 @@ static int bt_transport_config_a2dp(struct userdata *u) { return 0; } -static int bt_transport_config(struct userdata *u) { +static int bt_transport_config(struct bluetooth_device *u) { if (u->profile == PROFILE_HSP || u->profile == PROFILE_HFGW) { u->block_size = u->link_mtu; u->sample_spec.format = PA_SAMPLE_S16LE; @@ -2276,7 +2305,7 @@ static int bt_transport_config(struct userdata *u) { } /* Run from main thread */ -static int bt_transport_open(struct userdata *u) { +static int bt_transport_open(struct bluetooth_device *u) { if (bt_transport_acquire(u, FALSE) < 0) return -1; @@ -2284,7 +2313,7 @@ static int bt_transport_open(struct userdata *u) { } /* Run from main thread */ -static int init_bt(struct userdata *u) { +static int init_bt(struct bluetooth_device *u) { pa_assert(u); shutdown_bt(u); @@ -2304,7 +2333,7 @@ static int init_bt(struct userdata *u) { } /* Run from main thread */ -static int setup_bt(struct userdata *u) { +static int setup_bt(struct bluetooth_device *u) { const pa_bluetooth_device *d; const pa_bluetooth_transport *t; @@ -2350,7 +2379,7 @@ static int setup_bt(struct userdata *u) { } /* Run from main thread */ -static int init_profile(struct userdata *u) { +static int init_profile(struct bluetooth_device *u) { int r = 0; pa_assert(u); pa_assert(u->profile != PROFILE_OFF); @@ -2374,7 +2403,7 @@ static int init_profile(struct userdata *u) { } /* Run from main thread */ -static void stop_thread(struct userdata *u) { +static void stop_thread(struct bluetooth_device *u) { char *k; pa_assert(u); @@ -2436,7 +2465,7 @@ static void stop_thread(struct userdata *u) { } /* Run from main thread */ -static int start_thread(struct userdata *u) { +static int start_thread(struct bluetooth_device *u) { pa_assert(u); pa_assert(!u->thread); pa_assert(!u->rtpoll); @@ -2497,7 +2526,7 @@ static int start_thread(struct userdata *u) { return 0; } -static void save_sco_volume_callbacks(struct userdata *u) { +static void save_sco_volume_callbacks(struct bluetooth_device *u) { pa_assert(u); pa_assert(USE_SCO_OVER_PCM(u)); @@ -2505,7 +2534,7 @@ static void save_sco_volume_callbacks(struct userdata *u) { u->hsp.sco_source_set_volume = u->hsp.sco_source->set_volume; } -static void restore_sco_volume_callbacks(struct userdata *u) { +static void restore_sco_volume_callbacks(struct bluetooth_device *u) { pa_assert(u); pa_assert(USE_SCO_OVER_PCM(u)); @@ -2515,7 +2544,7 @@ static void restore_sco_volume_callbacks(struct userdata *u) { /* Run from main thread */ static int card_set_profile(pa_card *c, pa_card_profile *new_profile) { - struct userdata *u; + struct bluetooth_device *u; enum profile *d; pa_queue *inputs = NULL, *outputs = NULL; const pa_bluetooth_device *device; @@ -2608,7 +2637,7 @@ static int card_set_profile(pa_card *c, pa_card_profile *new_profile) { } /* Run from main thread */ -static int add_card(struct userdata *u, const pa_bluetooth_device *device) { +static int add_card(struct bluetooth_device *u, const pa_bluetooth_device *device) { pa_card_new_data data; pa_bool_t b; pa_card_profile *p; @@ -2753,7 +2782,7 @@ static int add_card(struct userdata *u, const pa_bluetooth_device *device) { } /* Run from main thread */ -static const pa_bluetooth_device* find_device(struct userdata *u, const char *address, const char *path) { +static const pa_bluetooth_device* find_device(struct bluetooth_device *u, const char *address, const char *path) { const pa_bluetooth_device *d = NULL; pa_assert(u); @@ -2790,7 +2819,7 @@ static const pa_bluetooth_device* find_device(struct userdata *u, const char *ad } /* Run from main thread */ -static int setup_dbus(struct userdata *u) { +static int setup_dbus(struct bluetooth_device *u) { DBusError err; dbus_error_init(&err); @@ -2809,7 +2838,7 @@ static int setup_dbus(struct userdata *u) { int pa__init(pa_module* m) { pa_modargs *ma; uint32_t channels; - struct userdata *u; + struct bluetooth_device *u; const char *address, *path; DBusError err; char *mike, *speaker, *transport; @@ -2824,13 +2853,16 @@ int pa__init(pa_module* m) { goto fail; } - m->userdata = u = pa_xnew0(struct userdata, 1); + u = pa_msgobject_new(bluetooth_device); + memset(((char*)u)+sizeof(u->parent), 0, sizeof(*u)-sizeof(u->parent)); + m->userdata = u; u->module = m; u->core = m->core; u->service_fd = -1; u->stream_fd = -1; u->sample_spec = m->core->default_sample_spec; u->modargs = ma; + u->parent.process_msg = device_process_msg; if (pa_modargs_get_value(ma, "sco_sink", NULL) && !(u->hsp.sco_sink = pa_namereg_get(m->core, pa_modargs_get_value(ma, "sco_sink", NULL), PA_NAMEREG_SINK))) { @@ -2933,7 +2965,7 @@ fail: } int pa__get_n_used(pa_module *m) { - struct userdata *u; + struct bluetooth_device *u; pa_assert(m); pa_assert_se(u = m->userdata); @@ -2944,7 +2976,7 @@ int pa__get_n_used(pa_module *m) { } void pa__done(pa_module *m) { - struct userdata *u; + struct bluetooth_device *u; pa_assert(m); -- 1.7.4.1