Skip to content

Commit 71d0735

Browse files
committed
PCM client delay reporting for A2DP sink profile
This feature will not work unless there will be a proper delay reporting implementation in BlueZ (for A2DP sink profile).
1 parent 724891b commit 71d0735

10 files changed

+106
-7
lines changed

doc/bluealsa-api.txt

+7
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,13 @@ Properties object Device [readonly]
122122

123123
Approximate PCM delay in 1/10 of millisecond.
124124

125+
uint16 ClientDelay [readwrite]
126+
127+
Approximate client side delay in 1/10 of millisecond.
128+
This property shall be set by the client in order to
129+
account for the client side delay when capturing or
130+
playing audio respectively for PCM source or sink.
131+
125132
boolean SoftVolume [readwrite]
126133

127134
This property determines whether BlueALSA will make

src/ba-transport.c

+27
Original file line numberDiff line numberDiff line change
@@ -1292,6 +1292,33 @@ int ba_transport_pcm_get_delay(const struct ba_transport_pcm *pcm) {
12921292
return pcm->delay;
12931293
}
12941294

1295+
int ba_transport_pcm_set_delay(
1296+
struct ba_transport_pcm *pcm,
1297+
int delay) {
1298+
1299+
const struct ba_transport *t = pcm->t;
1300+
1301+
pcm->client_delay = delay;
1302+
1303+
/* Forward client delay to BlueZ, but only in case of A2DP sink profile,
1304+
* so it will be sent to connected Bluetooth client, e.g. phone. */
1305+
if (t->type.profile == BA_TRANSPORT_PROFILE_A2DP_SINK) {
1306+
1307+
GError *err = NULL;
1308+
g_dbus_set_property(config.dbus, t->bluez_dbus_owner, t->bluez_dbus_path,
1309+
BLUEZ_IFACE_MEDIA_TRANSPORT, "Delay", g_variant_new_uint16(delay), &err);
1310+
1311+
if (err != NULL) {
1312+
if (err->code != G_DBUS_ERROR_PROPERTY_READ_ONLY)
1313+
warn("Couldn't set A2DP transport delay: %s", err->message);
1314+
g_error_free(err);
1315+
}
1316+
1317+
}
1318+
1319+
return 0;
1320+
}
1321+
12951322
unsigned int ba_transport_pcm_volume_level_to_bt(
12961323
const struct ba_transport_pcm *pcm,
12971324
int value) {

src/ba-transport.h

+5
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,8 @@ struct ba_transport_pcm {
110110
/* Overall PCM delay in 1/10 of millisecond, caused by
111111
* audio encoding or decoding and data transfer. */
112112
unsigned int delay;
113+
/* Client delay in 1/10 of millisecond. */
114+
unsigned int client_delay;
113115

114116
/* internal software volume control */
115117
bool soft_volume;
@@ -369,6 +371,9 @@ bool ba_transport_pcm_is_active(
369371

370372
int ba_transport_pcm_get_delay(
371373
const struct ba_transport_pcm *pcm);
374+
int ba_transport_pcm_set_delay(
375+
struct ba_transport_pcm *pcm,
376+
int delay);
372377

373378
unsigned int ba_transport_pcm_volume_level_to_bt(
374379
const struct ba_transport_pcm *pcm,

src/bluealsa-dbus.c

+15
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,10 @@ static GVariant *ba_variant_new_pcm_delay(const struct ba_transport_pcm *pcm) {
133133
return g_variant_new_uint16(ba_transport_pcm_get_delay(pcm));
134134
}
135135

136+
static GVariant *ba_variant_new_pcm_client_delay(const struct ba_transport_pcm *pcm) {
137+
return g_variant_new_uint16(pcm->client_delay);
138+
}
139+
136140
static GVariant *ba_variant_new_pcm_soft_volume(const struct ba_transport_pcm *pcm) {
137141
return g_variant_new_boolean(pcm->soft_volume);
138142
}
@@ -160,6 +164,7 @@ static void ba_variant_populate_pcm(GVariantBuilder *props, const struct ba_tran
160164
g_variant_builder_add(props, "{sv}", "Sampling", ba_variant_new_pcm_sampling(pcm));
161165
g_variant_builder_add(props, "{sv}", "Codec", ba_variant_new_pcm_codec(pcm));
162166
g_variant_builder_add(props, "{sv}", "Delay", ba_variant_new_pcm_delay(pcm));
167+
g_variant_builder_add(props, "{sv}", "ClientDelay", ba_variant_new_pcm_client_delay(pcm));
163168
g_variant_builder_add(props, "{sv}", "SoftVolume", ba_variant_new_pcm_soft_volume(pcm));
164169
g_variant_builder_add(props, "{sv}", "Volume", ba_variant_new_pcm_volume(pcm));
165170
}
@@ -706,6 +711,8 @@ static GVariant *bluealsa_pcm_get_property(const char *property,
706711
return ba_variant_new_pcm_codec(pcm);
707712
if (strcmp(property, "Delay") == 0)
708713
return ba_variant_new_pcm_delay(pcm);
714+
if (strcmp(property, "ClientDelay") == 0)
715+
return ba_variant_new_pcm_client_delay(pcm);
709716
if (strcmp(property, "SoftVolume") == 0)
710717
return ba_variant_new_pcm_soft_volume(pcm);
711718
if (strcmp(property, "Volume") == 0)
@@ -721,6 +728,12 @@ static bool bluealsa_pcm_set_property(const char *property, GVariant *value,
721728

722729
struct ba_transport_pcm *pcm = (struct ba_transport_pcm *)userdata;
723730

731+
if (strcmp(property, "ClientDelay") == 0) {
732+
ba_transport_pcm_set_delay(pcm, g_variant_get_uint16(value));
733+
bluealsa_dbus_pcm_update(pcm, BA_DBUS_PCM_UPDATE_CLIENT_DELAY);
734+
return TRUE;
735+
}
736+
724737
if (strcmp(property, "SoftVolume") == 0) {
725738
pcm->soft_volume = g_variant_get_boolean(value);
726739
bluealsa_dbus_pcm_update(pcm, BA_DBUS_PCM_UPDATE_SOFT_VOLUME);
@@ -822,6 +835,8 @@ void bluealsa_dbus_pcm_update(struct ba_transport_pcm *pcm, unsigned int mask) {
822835
g_variant_builder_add(&props, "{sv}", "Codec", ba_variant_new_pcm_codec(pcm));
823836
if (mask & BA_DBUS_PCM_UPDATE_DELAY)
824837
g_variant_builder_add(&props, "{sv}", "Delay", ba_variant_new_pcm_delay(pcm));
838+
if (mask & BA_DBUS_PCM_UPDATE_CLIENT_DELAY)
839+
g_variant_builder_add(&props, "{sv}", "ClientDelay", ba_variant_new_pcm_client_delay(pcm));
825840
if (mask & BA_DBUS_PCM_UPDATE_SOFT_VOLUME)
826841
g_variant_builder_add(&props, "{sv}", "SoftVolume", ba_variant_new_pcm_soft_volume(pcm));
827842
if (mask & BA_DBUS_PCM_UPDATE_VOLUME)

src/bluealsa-dbus.h

+8-7
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,14 @@
2222
#include "ba-device.h"
2323
#include "ba-transport.h"
2424

25-
#define BA_DBUS_PCM_UPDATE_FORMAT (1 << 0)
26-
#define BA_DBUS_PCM_UPDATE_CHANNELS (1 << 1)
27-
#define BA_DBUS_PCM_UPDATE_SAMPLING (1 << 2)
28-
#define BA_DBUS_PCM_UPDATE_CODEC (1 << 3)
29-
#define BA_DBUS_PCM_UPDATE_DELAY (1 << 4)
30-
#define BA_DBUS_PCM_UPDATE_SOFT_VOLUME (1 << 5)
31-
#define BA_DBUS_PCM_UPDATE_VOLUME (1 << 6)
25+
#define BA_DBUS_PCM_UPDATE_FORMAT (1 << 0)
26+
#define BA_DBUS_PCM_UPDATE_CHANNELS (1 << 1)
27+
#define BA_DBUS_PCM_UPDATE_SAMPLING (1 << 2)
28+
#define BA_DBUS_PCM_UPDATE_CODEC (1 << 3)
29+
#define BA_DBUS_PCM_UPDATE_DELAY (1 << 4)
30+
#define BA_DBUS_PCM_UPDATE_CLIENT_DELAY (1 << 5)
31+
#define BA_DBUS_PCM_UPDATE_SOFT_VOLUME (1 << 6)
32+
#define BA_DBUS_PCM_UPDATE_VOLUME (1 << 7)
3233

3334
#define BA_DBUS_RFCOMM_UPDATE_FEATURES (1 << 0)
3435
#define BA_DBUS_RFCOMM_UPDATE_BATTERY (1 << 1)

src/bluealsa-iface.c

+8
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,13 @@ static const GDBusPropertyInfo bluealsa_iface_pcm_Delay = {
196196
-1, "Delay", "q", G_DBUS_PROPERTY_INFO_FLAGS_READABLE, NULL
197197
};
198198

199+
static const GDBusPropertyInfo bluealsa_iface_pcm_ClientDelay = {
200+
-1, "ClientDelay", "q",
201+
G_DBUS_PROPERTY_INFO_FLAGS_READABLE |
202+
G_DBUS_PROPERTY_INFO_FLAGS_WRITABLE,
203+
NULL
204+
};
205+
199206
static const GDBusPropertyInfo bluealsa_iface_pcm_SoftVolume = {
200207
-1, "SoftVolume", "b",
201208
G_DBUS_PROPERTY_INFO_FLAGS_READABLE |
@@ -220,6 +227,7 @@ static const GDBusPropertyInfo *bluealsa_iface_pcm_properties[] = {
220227
&bluealsa_iface_pcm_Sampling,
221228
&bluealsa_iface_pcm_Codec,
222229
&bluealsa_iface_pcm_Delay,
230+
&bluealsa_iface_pcm_ClientDelay,
223231
&bluealsa_iface_pcm_SoftVolume,
224232
&bluealsa_iface_pcm_Volume,
225233
NULL,

src/shared/dbus-client.c

+11
Original file line numberDiff line numberDiff line change
@@ -639,6 +639,12 @@ dbus_bool_t bluealsa_dbus_pcm_update(
639639
int type = -1;
640640

641641
switch (property) {
642+
case BLUEALSA_PCM_CLIENT_DELAY:
643+
_property = "ClientDelay";
644+
variant = DBUS_TYPE_UINT16_AS_STRING;
645+
value = &pcm->client_delay;
646+
type = DBUS_TYPE_UINT16;
647+
break;
642648
case BLUEALSA_PCM_SOFT_VOLUME:
643649
_property = "SoftVolume";
644650
variant = DBUS_TYPE_BOOLEAN_AS_STRING;
@@ -937,6 +943,11 @@ static dbus_bool_t bluealsa_dbus_message_iter_get_pcm_props_cb(const char *key,
937943
goto fail;
938944
dbus_message_iter_get_basic(variant, &pcm->delay);
939945
}
946+
else if (strcmp(key, "ClientDelay") == 0) {
947+
if (type != (type_expected = DBUS_TYPE_UINT16))
948+
goto fail;
949+
dbus_message_iter_get_basic(variant, &pcm->client_delay);
950+
}
940951
else if (strcmp(key, "SoftVolume") == 0) {
941952
if (type != (type_expected = DBUS_TYPE_BOOLEAN))
942953
goto fail;

src/shared/dbus-client.h

+3
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ struct ba_service_props {
8282
/**
8383
* BlueALSA PCM object property. */
8484
enum ba_pcm_property {
85+
BLUEALSA_PCM_CLIENT_DELAY,
8586
BLUEALSA_PCM_SOFT_VOLUME,
8687
BLUEALSA_PCM_VOLUME,
8788
};
@@ -116,6 +117,8 @@ struct ba_pcm {
116117
char codec[16];
117118
/* approximate PCM delay */
118119
dbus_uint16_t delay;
120+
/* approximate client delay */
121+
dbus_uint16_t client_delay;
119122
/* software volume */
120123
dbus_bool_t soft_volume;
121124

utils/aplay/aplay.c

+21
Original file line numberDiff line numberDiff line change
@@ -607,6 +607,27 @@ static void *pcm_worker_routine(struct pcm_worker *w) {
607607
/* move leftovers to the beginning and reposition tail */
608608
ffb_shift(&buffer, frames * w->ba_pcm.channels);
609609

610+
snd_pcm_sframes_t delay_frames;
611+
if ((ret = snd_pcm_delay(w->pcm, &delay_frames)) != 0)
612+
warn("Couldn't get PCM delay: %s", snd_strerror(ret));
613+
else {
614+
615+
const int delay = delay_frames * 10000 / w->ba_pcm.sampling;
616+
if (abs(delay - w->ba_pcm.client_delay) >= 500 /* update if >= 50ms */) {
617+
618+
w->ba_pcm.client_delay = delay;
619+
620+
DBusError err = DBUS_ERROR_INIT;
621+
if (!bluealsa_dbus_pcm_update(&dbus_ctx, &w->ba_pcm, BLUEALSA_PCM_CLIENT_DELAY, &err)) {
622+
error("Couldn't update PCM: %s", err.message);
623+
dbus_error_free(&err);
624+
goto fail;
625+
}
626+
627+
}
628+
629+
}
630+
610631
}
611632

612633
fail:

utils/cli/cli.c

+1
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,7 @@ static void print_properties(const struct ba_pcm *pcm, DBusError *err) {
218218
print_codecs(pcm->pcm_path, err);
219219
printf("Selected codec: %s\n", pcm->codec);
220220
printf("Delay: %#.1f ms\n", (double)pcm->delay / 10);
221+
printf("ClientDelay: %#.1f ms\n", (double)pcm->client_delay / 10);
221222
printf("SoftVolume: %s\n", pcm->soft_volume ? "Y" : "N");
222223
print_volume(pcm);
223224
print_mute(pcm);

0 commit comments

Comments
 (0)