summaryrefslogtreecommitdiffstats
path: root/src/modules/bluetooth
diff options
context:
space:
mode:
Diffstat (limited to 'src/modules/bluetooth')
-rw-r--r--src/modules/bluetooth/module-bluetooth-device.c76
1 files changed, 64 insertions, 12 deletions
diff --git a/src/modules/bluetooth/module-bluetooth-device.c b/src/modules/bluetooth/module-bluetooth-device.c
index ecb5e83d..dbec00d4 100644
--- a/src/modules/bluetooth/module-bluetooth-device.c
+++ b/src/modules/bluetooth/module-bluetooth-device.c
@@ -64,8 +64,11 @@ PA_MODULE_LOAD_ONCE(FALSE);
PA_MODULE_USAGE(
"name=<name for the card/sink/source, to be prefixed> "
"card_name=<name for the card> "
+ "card_properties=<properties for the card> "
"sink_name=<name for the sink> "
+ "sink_properties=<properties for the sink> "
"source_name=<name for the source> "
+ "source_properties=<properties for the source> "
"address=<address of the device> "
"profile=<a2dp|hsp> "
"rate=<sample rate> "
@@ -84,8 +87,11 @@ PA_MODULE_USAGE(
static const char* const valid_modargs[] = {
"name",
"card_name",
+ "card_properties",
"sink_name",
+ "sink_properties",
"source_name",
+ "source_properties",
"address",
"profile",
"rate",
@@ -174,6 +180,8 @@ struct userdata {
#define FIXED_LATENCY_PLAYBACK_HSP (125*PA_USEC_PER_MSEC)
#define FIXED_LATENCY_RECORD_HSP (25*PA_USEC_PER_MSEC)
+#define MAX_PLAYBACK_CATCH_UP_USEC (100*PA_USEC_PER_MSEC)
+
#ifdef NOKIA
#define USE_SCO_OVER_PCM(u) (u->profile == PROFILE_HSP && (u->hsp.sco_sink && u->hsp.sco_source))
#endif
@@ -1296,15 +1304,37 @@ static void thread_func(void *userdata) {
if ((!u->source || !PA_SOURCE_IS_LINKED(u->source->thread_info.state)) && do_write <= 0 && writable) {
pa_usec_t time_passed;
- uint64_t should_have_written;
+ pa_usec_t audio_sent;
/* Hmm, there is no input stream we could synchronize
* to. So let's do things by time */
time_passed = pa_rtclock_usec() - u->started_at;
- should_have_written = pa_usec_to_bytes(time_passed, &u->sample_spec);
+ audio_sent = pa_bytes_to_usec(u->write_index, &u->sample_spec);
+
+ if (audio_sent <= time_passed) {
+ pa_usec_t audio_to_send = time_passed - audio_sent;
+
+ /* Never try to catch up for more than 100ms */
+ if (u->write_index > 0 && audio_to_send > MAX_PLAYBACK_CATCH_UP_USEC) {
+ pa_usec_t skip_usec;
+ uint64_t skip_bytes;
+ pa_memchunk tmp;
+
+ skip_usec = audio_to_send - MAX_PLAYBACK_CATCH_UP_USEC;
+ skip_bytes = pa_usec_to_bytes(skip_usec, &u->sample_spec);
+
+ pa_log_warn("Skipping %llu us (= %llu bytes) in audio stream",
+ (unsigned long long) skip_usec,
+ (unsigned long long) skip_bytes);
- do_write = u->write_index <= should_have_written;
+ pa_sink_render_full(u->sink, skip_bytes, &tmp);
+ pa_memblock_unref(tmp.memblock);
+ u->write_index += skip_bytes;
+ }
+
+ do_write = 1;
+ }
}
if (writable && do_write > 0) {
@@ -1596,6 +1626,12 @@ static int add_sink(struct userdata *u) {
data.name = get_name("sink", u->modargs, u->address, &b);
data.namereg_fail = b;
+ if (pa_modargs_get_proplist(u->modargs, "sink_properties", data.proplist, PA_UPDATE_REPLACE) < 0) {
+ pa_log("Invalid properties");
+ pa_sink_new_data_done(&data);
+ return -1;
+ }
+
u->sink = pa_sink_new(u->core, &data, PA_SINK_HARDWARE|PA_SINK_LATENCY | (u->profile == PROFILE_HSP ? PA_SINK_HW_VOLUME_CTRL : 0));
pa_sink_new_data_done(&data);
@@ -1608,9 +1644,9 @@ static int add_sink(struct userdata *u) {
u->sink->parent.process_msg = sink_process_msg;
pa_sink_set_max_request(u->sink, u->block_size);
- u->sink->fixed_latency =
- (u->profile == PROFILE_A2DP ? FIXED_LATENCY_PLAYBACK_A2DP : FIXED_LATENCY_PLAYBACK_HSP) +
- pa_bytes_to_usec(u->block_size, &u->sample_spec);
+ pa_sink_set_fixed_latency(u->sink,
+ (u->profile == PROFILE_A2DP ? FIXED_LATENCY_PLAYBACK_A2DP : FIXED_LATENCY_PLAYBACK_HSP) +
+ pa_bytes_to_usec(u->block_size, &u->sample_spec));
}
if (u->profile == PROFILE_HSP) {
@@ -1648,6 +1684,12 @@ static int add_source(struct userdata *u) {
data.name = get_name("source", u->modargs, u->address, &b);
data.namereg_fail = b;
+ if (pa_modargs_get_proplist(u->modargs, "source_properties", data.proplist, PA_UPDATE_REPLACE) < 0) {
+ pa_log("Invalid properties");
+ pa_source_new_data_done(&data);
+ return -1;
+ }
+
u->source = pa_source_new(u->core, &data, PA_SOURCE_HARDWARE|PA_SOURCE_LATENCY | (u->profile == PROFILE_HSP ? PA_SOURCE_HW_VOLUME_CTRL : 0));
pa_source_new_data_done(&data);
@@ -1659,9 +1701,9 @@ static int add_source(struct userdata *u) {
u->source->userdata = u;
u->source->parent.process_msg = source_process_msg;
- u->source->fixed_latency =
- (/* u->profile == PROFILE_A2DP ? FIXED_LATENCY_RECORD_A2DP : */ FIXED_LATENCY_RECORD_HSP) +
- pa_bytes_to_usec(u->block_size, &u->sample_spec);
+ pa_source_set_fixed_latency(u->source,
+ (/* u->profile == PROFILE_A2DP ? FIXED_LATENCY_RECORD_A2DP : */ FIXED_LATENCY_RECORD_HSP) +
+ pa_bytes_to_usec(u->block_size, &u->sample_spec));
}
if (u->profile == PROFILE_HSP) {
@@ -1939,13 +1981,17 @@ 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 char *default_profile, const pa_bluetooth_device *device) {
+static int add_card(struct userdata *u, const pa_bluetooth_device *device) {
pa_card_new_data data;
pa_bool_t b;
pa_card_profile *p;
enum profile *d;
const char *ff;
char *n;
+ const char *default_profile;
+
+ pa_assert(u);
+ pa_assert(device);
pa_card_new_data_init(&data);
data.driver = __FILE__;
@@ -1966,6 +2012,12 @@ static int add_card(struct userdata *u, const char *default_profile, const pa_bl
data.name = get_name("card", u->modargs, device->address, &b);
data.namereg_fail = b;
+ if (pa_modargs_get_proplist(u->modargs, "card_properties", data.proplist, PA_UPDATE_REPLACE) < 0) {
+ pa_log("Invalid properties");
+ pa_card_new_data_done(&data);
+ return -1;
+ }
+
data.profiles = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
/* we base hsp/a2dp availability on UUIDs.
@@ -2008,7 +2060,7 @@ static int add_card(struct userdata *u, const char *default_profile, const pa_bl
*d = PROFILE_OFF;
pa_hashmap_put(data.profiles, p->name, p);
- if (default_profile) {
+ if ((default_profile = pa_modargs_get_value(u->modargs, "profile", NULL))) {
if (pa_hashmap_get(data.profiles, default_profile))
pa_card_new_data_set_profile(&data, default_profile);
else
@@ -2154,7 +2206,7 @@ int pa__init(pa_module* m) {
goto fail;
/* Add the card structure. This will also initialize the default profile */
- if (add_card(u, pa_modargs_get_value(ma, "profile", NULL), device) < 0)
+ if (add_card(u, device) < 0)
goto fail;
/* Connect to the BT service and query capabilities */