|
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