|
24 | 24 | #include <string.h>
|
25 | 25 | #include <unistd.h>
|
26 | 26 |
|
| 27 | +#include <gio/gio.h> |
27 | 28 | #include <glib.h>
|
28 | 29 |
|
29 | 30 | #include "audio.h"
|
@@ -631,7 +632,9 @@ void ba_transport_pcm_volume_set(
|
631 | 632 |
|
632 | 633 | }
|
633 | 634 |
|
634 |
| -int ba_transport_pcm_volume_update(struct ba_transport_pcm *pcm) { |
| 635 | +/** |
| 636 | + * Synchronize PCM volume level with remote Bluetooth device. */ |
| 637 | +int ba_transport_pcm_volume_sync(struct ba_transport_pcm *pcm) { |
635 | 638 |
|
636 | 639 | struct ba_transport *t = pcm->t;
|
637 | 640 |
|
@@ -684,8 +687,6 @@ int ba_transport_pcm_volume_update(struct ba_transport_pcm *pcm) {
|
684 | 687 | }
|
685 | 688 |
|
686 | 689 | final:
|
687 |
| - /* notify connected clients (including requester) */ |
688 |
| - bluealsa_dbus_pcm_update(pcm, BA_DBUS_PCM_UPDATE_VOLUME); |
689 | 690 | return 0;
|
690 | 691 | }
|
691 | 692 |
|
@@ -716,20 +717,63 @@ int ba_transport_pcm_get_hardware_volume(
|
716 | 717 | return 0;
|
717 | 718 | }
|
718 | 719 |
|
719 |
| -int ba_transport_pcm_get_delay(const struct ba_transport_pcm *pcm) { |
| 720 | +/** |
| 721 | + * Get PCM playback/capture cumulative delay. */ |
| 722 | +int ba_transport_pcm_delay_get(const struct ba_transport_pcm *pcm) { |
720 | 723 |
|
721 | 724 | const struct ba_transport *t = pcm->t;
|
| 725 | + int delay = 0; |
722 | 726 |
|
723 |
| - int delay = pcm->codec_delay_dms + pcm->processing_delay_dms; |
| 727 | + delay += pcm->codec_delay_dms; |
| 728 | + delay += pcm->processing_delay_dms; |
724 | 729 |
|
725 |
| - if (t->profile & BA_TRANSPORT_PROFILE_MASK_A2DP) |
| 730 | + /* Add delay reported by BlueZ but only for A2DP Source profile. In case |
| 731 | + * of A2DP Sink, the BlueZ delay value is in fact our client delay. */ |
| 732 | + if (t->profile & BA_TRANSPORT_PROFILE_A2DP_SOURCE) |
726 | 733 | delay += t->a2dp.delay;
|
727 |
| - if (t->profile & BA_TRANSPORT_PROFILE_MASK_SCO) |
| 734 | + /* HFP/HSP profiles do not provide any delay information. However, we can |
| 735 | + * assume some arbitrary value here - for now it will be 10 ms. */ |
| 736 | + else if (t->profile & BA_TRANSPORT_PROFILE_MASK_AG) |
728 | 737 | delay += 10;
|
729 | 738 |
|
730 | 739 | return delay;
|
731 | 740 | }
|
732 | 741 |
|
| 742 | +/** |
| 743 | + * Synchronize PCM playback delay with remote Bluetooth device. */ |
| 744 | +int ba_transport_pcm_delay_sync(struct ba_transport_pcm *pcm) { |
| 745 | + |
| 746 | + struct ba_transport *t = pcm->t; |
| 747 | + int delay = 0; |
| 748 | + |
| 749 | + delay += pcm->codec_delay_dms; |
| 750 | + delay += pcm->processing_delay_dms; |
| 751 | + delay += pcm->client_delay_dms; |
| 752 | + |
| 753 | + /* In case of A2DP Sink, update the delay property of the BlueZ media |
| 754 | + * transport interface. BlueZ should forward this value to the remote |
| 755 | + * device, so it can adjust audio/video synchronization. */ |
| 756 | + if (t->profile == BA_TRANSPORT_PROFILE_A2DP_SINK && |
| 757 | + !t->a2dp.read_only_delay_quirk && |
| 758 | + abs(delay - t->a2dp.delay) >= 100 /* 10ms */) { |
| 759 | + |
| 760 | + GError *err = NULL; |
| 761 | + t->a2dp.delay = delay; |
| 762 | + g_dbus_set_property(config.dbus, t->bluez_dbus_owner, t->bluez_dbus_path, |
| 763 | + BLUEZ_IFACE_MEDIA_TRANSPORT, "Delay", g_variant_new_uint16(delay), &err); |
| 764 | + |
| 765 | + if (err != NULL) { |
| 766 | + warn("Couldn't set A2DP transport delay: %s", err->message); |
| 767 | + if (err->code == G_DBUS_ERROR_PROPERTY_READ_ONLY) |
| 768 | + t->a2dp.read_only_delay_quirk = true; |
| 769 | + g_error_free(err); |
| 770 | + } |
| 771 | + |
| 772 | + } |
| 773 | + |
| 774 | + return 0; |
| 775 | +} |
| 776 | + |
733 | 777 | const char *ba_transport_pcm_channel_to_string(
|
734 | 778 | enum ba_transport_pcm_channel channel) {
|
735 | 779 | switch (channel) {
|
|
0 commit comments