diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/modules/bluetooth/bluetooth-util.c | 7 | ||||
-rw-r--r-- | src/modules/bluetooth/module-bluetooth-device.c | 54 | ||||
-rw-r--r-- | src/modules/bluetooth/module-bluetooth-discover.c | 2 | ||||
-rw-r--r-- | src/modules/bluetooth/sbc.c | 14 | ||||
-rw-r--r-- | src/modules/bluetooth/sbc.h | 22 |
5 files changed, 61 insertions, 38 deletions
diff --git a/src/modules/bluetooth/bluetooth-util.c b/src/modules/bluetooth/bluetooth-util.c index 9e30f89a..912697e6 100644 --- a/src/modules/bluetooth/bluetooth-util.c +++ b/src/modules/bluetooth/bluetooth-util.c @@ -114,15 +114,14 @@ void pa_bluetooth_device_free(pa_bluetooth_device *d) { static pa_bool_t device_is_loaded(pa_bluetooth_device *d) { pa_assert(d); - return d->device_info_valid && d->audio_sink_info_valid && d->headset_info_valid; + return d->device_info_valid && (d->audio_sink_info_valid || d->headset_info_valid); } static pa_bool_t device_is_audio(pa_bluetooth_device *d) { pa_assert(d); pa_assert(d->device_info_valid); - pa_assert(d->audio_sink_info_valid); - pa_assert(d->headset_info_valid); + pa_assert(d->audio_sink_info_valid || d->headset_info_valid); return d->device_info_valid > 0 && (d->audio_sink_info_valid > 0 || d->headset_info_valid > 0); @@ -653,10 +652,12 @@ static DBusHandlerResult filter_cb(DBusConnection *bus, DBusMessage *m, void *us } else if (dbus_message_has_interface(m, "org.bluez.Headset")) { if (parse_audio_property(y, &d->headset_connected, &arg_i) < 0) goto fail; + d->headset_info_valid = 1; } else if (dbus_message_has_interface(m, "org.bluez.AudioSink")) { if (parse_audio_property(y, &d->audio_sink_connected, &arg_i) < 0) goto fail; + d->audio_sink_info_valid = 1; } pa_assert_se(y->mode == MODE_DISCOVER); diff --git a/src/modules/bluetooth/module-bluetooth-device.c b/src/modules/bluetooth/module-bluetooth-device.c index 7d601e73..1b61a6fc 100644 --- a/src/modules/bluetooth/module-bluetooth-device.c +++ b/src/modules/bluetooth/module-bluetooth-device.c @@ -57,9 +57,6 @@ #define MAX_BITPOOL 64 #define MIN_BITPOOL 2U -#define SOL_SCO 17 -#define SCO_TXBUFS 0x03 -#define SCO_RXBUFS 0x04 PA_MODULE_AUTHOR("Joao Paulo Rechi Vita"); PA_MODULE_DESCRIPTION("Bluetooth audio sink and source"); @@ -78,6 +75,10 @@ PA_MODULE_USAGE( "sco_sink=<SCO over PCM sink name> " "sco_source=<SCO over PCM source name>"); +/* TODO: not close fd when entering suspend mode in a2dp */ + +/* TODO: BT_PCM_FLAG_NREC */ + static const char* const valid_modargs[] = { "name", "card_name", @@ -160,6 +161,8 @@ struct userdata { int service_write_type, service_read_type; }; +#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); @@ -653,7 +656,7 @@ static int set_conf(struct userdata *u) { return 0; } -/* from IO thread */ +/* from IO thread, except in SCO over PCM */ static int start_stream_fd(struct userdata *u) { union { bt_audio_msg_header_t rsp; @@ -689,9 +692,6 @@ static int start_stream_fd(struct userdata *u) { return -1; } -/* setsockopt(u->stream_fd, SOL_SCO, SCO_TXBUFS, &period_count, sizeof(period_count)); */ -/* setsockopt(u->stream_fd, SOL_SCO, SCO_SNDBUF, &period_count, sizeof(period_count)); */ - pa_make_fd_nonblock(u->stream_fd); pa_make_socket_low_delay(u->stream_fd); @@ -876,7 +876,7 @@ static int hsp_process_render(struct userdata *u) { pa_assert(l != 0); if (l < 0) { - if (errno == EINTR) + if (errno == EINTR || errno == EAGAIN) continue; else { pa_log_error("Failed to write data to SCO socket: %s", pa_cstrerror(errno)); @@ -921,7 +921,7 @@ static int hsp_process_push(struct userdata *u) { pa_memblock_release(memchunk.memblock); if (l <= 0) { - if (l < 0 && errno == EINTR) + if (l < 0 && (errno == EINTR || errno == EAGAIN)) continue; else { pa_log_error("Failed to read data from SCO socket: %s", l < 0 ? pa_cstrerror(errno) : "EOF"); @@ -951,7 +951,7 @@ static int a2dp_process_render(struct userdata *u) { void *d; const void *p; unsigned frame_count; - int written; + size_t written; uint64_t writing_at; pa_assert(u); @@ -977,14 +977,14 @@ static int a2dp_process_render(struct userdata *u) { writing_at = u->write_index; do { - int encoded; + ssize_t encoded; if (!u->write_memchunk.memblock) pa_sink_render_full(u->sink, u->block_size, &u->write_memchunk); p = (const uint8_t*) pa_memblock_acquire(u->write_memchunk.memblock) + u->write_memchunk.index; encoded = sbc_encode(&a2dp->sbc, - (void*) p, u->write_memchunk.length, + p, u->write_memchunk.length, d, left, &written); @@ -999,10 +999,11 @@ static int a2dp_process_render(struct userdata *u) { return -1; } - pa_assert(written >= 0); - pa_assert((size_t) encoded <= u->write_memchunk.length); + pa_assert((size_t) encoded == sbc_get_codesize(&a2dp->sbc)); + pa_assert((size_t) written <= left); + pa_assert((size_t) written == sbc_get_frame_length(&a2dp->sbc)); /* pa_log_debug("SBC: encoded: %d; written: %d", encoded, written); */ @@ -1021,7 +1022,7 @@ static int a2dp_process_render(struct userdata *u) { frame_count++; - } while ((uint8_t*) d - (uint8_t*) a2dp->buffer + written < (ptrdiff_t) u->link_mtu); + } while (((uint8_t*) d - ((uint8_t*) a2dp->buffer + sbc_get_frame_length(&a2dp->sbc))) < (ptrdiff_t) u->link_mtu); /* write it to the fifo */ memset(a2dp->buffer, 0, sizeof(*header) + sizeof(*payload)); @@ -1044,7 +1045,7 @@ static int a2dp_process_render(struct userdata *u) { pa_assert(l != 0); if (l < 0) { - if (errno == EINTR) + if (errno == EINTR || errno == EAGAIN) continue; else { pa_log_error("Failed to write data to socket: %s", pa_cstrerror(errno)); @@ -1126,6 +1127,8 @@ static void thread_func(void *userdata) { } if (writable && do_write) { + if (u->write_index == 0) + u->started_at = pa_rtclock_usec(); if (u->profile == PROFILE_A2DP) { if (a2dp_process_render(u) < 0) @@ -1162,8 +1165,8 @@ static void thread_func(void *userdata) { /* Hmm, nothing to do. Let's sleep */ if (pollfd) - pollfd->events = (short) (((u->sink && PA_SINK_IS_OPENED(u->sink->thread_info.state) && !writable) ? POLLOUT : 0) | - (u->source && PA_SOURCE_IS_OPENED(u->source->thread_info.state) ? POLLIN : 0)); + pollfd->events = (short) (((u->sink && PA_SINK_IS_LINKED(u->sink->thread_info.state) && !writable) ? POLLOUT : 0) | + (u->source && PA_SOURCE_IS_LINKED(u->source->thread_info.state) ? POLLIN : 0)); if ((ret = pa_rtpoll_run(u->rtpoll, TRUE)) < 0) goto fail; @@ -1357,8 +1360,6 @@ static char *get_name(const char *type, pa_modargs *ma, const char *device_id, p return pa_sprintf_malloc("bluez_%s.%s", type, n); } -#define USE_SCO_OVER_PCM(u) (u->profile == PROFILE_HSP && (u->hsp.sco_sink && u->hsp.sco_source)) - static void sco_over_pcm_state_update(struct userdata *u) { pa_assert(u); pa_assert(USE_SCO_OVER_PCM(u)); @@ -1373,11 +1374,14 @@ static void sco_over_pcm_state_update(struct userdata *u) { if ((init_bt(u) < 0) || (init_profile(u) < 0)) pa_log("Can't resume SCO over PCM"); + start_stream_fd(u); } else { if (u->service_fd < 0) return; + stop_stream_fd(u); + pa_log_debug("Closing SCO over PCM"); pa_close(u->service_fd); u->service_fd = -1; @@ -1627,15 +1631,19 @@ static int start_thread(struct userdata *u) { pa_assert(!u->rtpoll); pa_assert(!u->rtpoll_item); + u->rtpoll = pa_rtpoll_new(); + pa_thread_mq_init(&u->thread_mq, u->core->mainloop, u->rtpoll); + if (USE_SCO_OVER_PCM(u)) { + if (start_stream_fd(u) < 0) + return -1; + pa_sink_ref(u->sink); pa_source_ref(u->source); + /* FIXME: monitor stream_fd error */ return 0; } - u->rtpoll = pa_rtpoll_new(); - pa_thread_mq_init(&u->thread_mq, u->core->mainloop, u->rtpoll); - if (!(u->thread = pa_thread_new(thread_func, u))) { pa_log_error("Failed to create IO thread"); stop_thread(u); diff --git a/src/modules/bluetooth/module-bluetooth-discover.c b/src/modules/bluetooth/module-bluetooth-discover.c index 521a9127..4586d8ca 100644 --- a/src/modules/bluetooth/module-bluetooth-discover.c +++ b/src/modules/bluetooth/module-bluetooth-discover.c @@ -75,7 +75,7 @@ static void load_module_for_device(struct userdata *u, pa_bluetooth_device *d, p /* Oh, awesome, a new device has shown up and been connected! */ - args = pa_sprintf_malloc("address=\"%s\" path=\"%s\"", d->address, d->path); + args = pa_sprintf_malloc("address=\"%s\" path=\"%s\" profile=\"%s\"", d->address, d->path, d->headset_connected ? "hsp" : "a2dp"); if (pa_modargs_get_value(u->modargs, "sco_sink", NULL) && pa_modargs_get_value(u->modargs, "sco_source", NULL)) { diff --git a/src/modules/bluetooth/sbc.c b/src/modules/bluetooth/sbc.c index a33ed571..6fa54796 100644 --- a/src/modules/bluetooth/sbc.c +++ b/src/modules/bluetooth/sbc.c @@ -1044,8 +1044,10 @@ int sbc_decode(sbc_t *sbc, void *input, int input_len, void *output, return framelen; } -int sbc_encode(sbc_t *sbc, void *input, int input_len, void *output, - int output_len, int *written) +ssize_t sbc_encode(sbc_t *sbc, + const void *input, size_t input_len, + void *output, size_t output_len, + size_t *written) { struct sbc_priv *priv; int framelen, samples; @@ -1133,9 +1135,9 @@ void sbc_finish(sbc_t *sbc) memset(sbc, 0, sizeof(sbc_t)); } -int sbc_get_frame_length(sbc_t *sbc) +size_t sbc_get_frame_length(sbc_t *sbc) { - int ret; + size_t ret; uint8_t subbands, channels, blocks, joint; struct sbc_priv *priv; @@ -1164,7 +1166,7 @@ int sbc_get_frame_length(sbc_t *sbc) return ret; } -int sbc_get_frame_duration(sbc_t *sbc) +unsigned sbc_get_frame_duration(sbc_t *sbc) { uint8_t subbands, blocks; uint16_t frequency; @@ -1202,7 +1204,7 @@ int sbc_get_frame_duration(sbc_t *sbc) return (1000000 * blocks * subbands) / frequency; } -uint16_t sbc_get_codesize(sbc_t *sbc) +size_t sbc_get_codesize(sbc_t *sbc) { uint16_t subbands, channels, blocks; struct sbc_priv *priv; diff --git a/src/modules/bluetooth/sbc.h b/src/modules/bluetooth/sbc.h index f9d506bc..25a12885 100644 --- a/src/modules/bluetooth/sbc.h +++ b/src/modules/bluetooth/sbc.h @@ -31,6 +31,7 @@ extern "C" { #endif #include <stdint.h> +#include <sys/types.h> /* sampling frequency */ #define SBC_FREQ_16000 0x00 @@ -84,11 +85,22 @@ int sbc_reinit(sbc_t *sbc, unsigned long flags); int sbc_parse(sbc_t *sbc, void *input, int input_len); int sbc_decode(sbc_t *sbc, void *input, int input_len, void *output, int output_len, int *len); -int sbc_encode(sbc_t *sbc, void *input, int input_len, void *output, - int output_len, int *written); -int sbc_get_frame_length(sbc_t *sbc); -int sbc_get_frame_duration(sbc_t *sbc); -uint16_t sbc_get_codesize(sbc_t *sbc); + +/* Encodes ONE input block into ONE output block */ +ssize_t sbc_encode(sbc_t *sbc, + const void *input, size_t input_len, + void *output, size_t output_len, + size_t *written); + +/* Returns the output block size in bytes */ +size_t sbc_get_frame_length(sbc_t *sbc); + +/* Returns the time one input/output block takes to play in msec*/ +unsigned sbc_get_frame_duration(sbc_t *sbc); + +/* Returns the input block size in bytes */ +size_t sbc_get_codesize(sbc_t *sbc); + const char *sbc_get_implementation_info(sbc_t *sbc); void sbc_finish(sbc_t *sbc); |