summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/modules/bluetooth/bluetooth-util.c15
-rw-r--r--src/modules/bluetooth/module-bluetooth-device.c57
-rw-r--r--src/modules/bluetooth/module-bluetooth-discover.c2
-rw-r--r--src/modules/bluetooth/module-bluetooth-proximity.c4
-rw-r--r--src/modules/bluetooth/sbc.c14
-rw-r--r--src/modules/bluetooth/sbc.h22
-rw-r--r--src/modules/module-hal-detect.c3
-rw-r--r--src/pulsecore/sink.c2
8 files changed, 74 insertions, 45 deletions
diff --git a/src/modules/bluetooth/bluetooth-util.c b/src/modules/bluetooth/bluetooth-util.c
index dfd3a306..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);
@@ -604,7 +603,7 @@ static DBusHandlerResult filter_cb(DBusConnection *bus, DBusMessage *m, void *us
pa_bluetooth_device_free(d);
}
- return DBUS_HANDLER_RESULT_HANDLED;
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
} else if (dbus_message_is_signal(m, "org.bluez.Adapter", "DeviceCreated")) {
const char *path;
@@ -617,7 +616,7 @@ static DBusHandlerResult filter_cb(DBusConnection *bus, DBusMessage *m, void *us
pa_log_debug("Device %s created", path);
found_device(y, path);
- return DBUS_HANDLER_RESULT_HANDLED;
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
} else if (dbus_message_is_signal(m, "org.bluez.Manager", "AdapterAdded")) {
const char *path;
@@ -630,7 +629,7 @@ static DBusHandlerResult filter_cb(DBusConnection *bus, DBusMessage *m, void *us
pa_log_debug("Adapter %s created", path);
found_adapter(y, path);
- return DBUS_HANDLER_RESULT_HANDLED;
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
} else if (dbus_message_is_signal(m, "org.bluez.Headset", "PropertyChanged") ||
dbus_message_is_signal(m, "org.bluez.AudioSink", "PropertyChanged") ||
@@ -653,17 +652,19 @@ 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);
run_callback(y, d, TRUE);
}
- return DBUS_HANDLER_RESULT_HANDLED;
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
fail:
diff --git a/src/modules/bluetooth/module-bluetooth-device.c b/src/modules/bluetooth/module-bluetooth-device.c
index 495bc82f..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);
@@ -700,6 +700,9 @@ static int start_stream_fd(struct userdata *u) {
pollfd->fd = u->stream_fd;
pollfd->events = pollfd->revents = 0;
+ u->read_index = 0;
+ u->write_index = 0;
+
return 0;
}
@@ -873,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));
@@ -918,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");
@@ -948,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);
@@ -974,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);
@@ -996,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); */
@@ -1018,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));
@@ -1041,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));
@@ -1123,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)
@@ -1159,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;
@@ -1354,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));
@@ -1370,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;
@@ -1624,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/module-bluetooth-proximity.c b/src/modules/bluetooth/module-bluetooth-proximity.c
index a3b525ee..c8d7b4d9 100644
--- a/src/modules/bluetooth/module-bluetooth-proximity.c
+++ b/src/modules/bluetooth/module-bluetooth-proximity.c
@@ -302,7 +302,7 @@ static DBusHandlerResult filter_func(DBusConnection *connection, DBusMessage *m,
bonding_new(u, a);
- return DBUS_HANDLER_RESULT_HANDLED;
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
} else if (dbus_message_is_signal(m, "org.bluez.Adapter", "BondingRemoved")) {
@@ -315,7 +315,7 @@ static DBusHandlerResult filter_func(DBusConnection *connection, DBusMessage *m,
bonding_remove(u, a);
- return DBUS_HANDLER_RESULT_HANDLED;
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
finish:
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);
diff --git a/src/modules/module-hal-detect.c b/src/modules/module-hal-detect.c
index fe601100..9b0d71c9 100644
--- a/src/modules/module-hal-detect.c
+++ b/src/modules/module-hal-detect.c
@@ -452,7 +452,8 @@ static void device_added_cb(LibHalContext *context, const char *udi) {
finish:
if (dbus_error_is_set(&error)) {
- pa_log_error("D-Bus error while parsing HAL data: %s: %s", error.name, error.message);
+ if (!dbus_error_has_name(&error, "org.freedesktop.Hal.NoSuchProperty"))
+ pa_log_error("D-Bus error while parsing HAL data: %s: %s", error.name, error.message);
dbus_error_free(&error);
}
}
diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c
index ff8700c7..c725595f 100644
--- a/src/pulsecore/sink.c
+++ b/src/pulsecore/sink.c
@@ -1921,6 +1921,8 @@ pa_bool_t pa_device_init_icon(pa_proplist *p, pa_bool_t is_sink) {
t = "phone";
else if (pa_streq(ff, "portable"))
t = "multimedia-player";
+ else if (pa_streq(ff, "tv"))
+ t = "video-display";
}
if (!t)