* [PATCH BlueZ] audio/avrcp: Poll GetPlayStatus when position changed event unsupported
@ 2026-09-23 8:00 Frédéric Danis
2026-09-23 11:04 ` [BlueZ] " bluez.test.bot
2026-09-23 13:55 ` [PATCH BlueZ] " Luiz Augusto von Dentz
0 siblings, 2 replies; 4+ messages in thread
From: Frédéric Danis @ 2026-09-23 8:00 UTC (permalink / raw)
To: linux-bluetooth
Some remote targets do not support the AVRCP_EVENT_PLAYBACK_POS_CHANGED
notification, meaning bluetoothd never learns about track position
updates for such devices.
When this event is not present in the capabilities reported by the
remote, fall back to polling AVRCP_GET_PLAY_STATUS once a second so
the media player position stays in sync. Polling is only kept running
while playback is actively progressing (playing/forward-seek/
reverse-seek) and is stopped otherwise, and is torn down on session
destruction.
Assisted-by: Copilot CLI:claude-sonnet-5
---
profiles/audio/avrcp.c | 64 +++++++++++++++++++++++++++++++++++++++++-
1 file changed, 63 insertions(+), 1 deletion(-)
diff --git a/profiles/audio/avrcp.c b/profiles/audio/avrcp.c
index df5f97eaf..105538cdc 100644
--- a/profiles/audio/avrcp.c
+++ b/profiles/audio/avrcp.c
@@ -247,7 +247,9 @@ struct avrcp {
unsigned int control_id;
unsigned int browsing_id;
unsigned int browsing_timer;
+ unsigned int position_timer;
uint16_t supported_events;
+ bool pos_changed_supported;
uint8_t transaction;
struct pending_pdu *pending_pdu;
};
@@ -341,6 +343,7 @@ static const uint32_t company_ids[] = {
static void avrcp_register_notification(struct avrcp *session, uint8_t event);
static GList *player_list_settings(struct avrcp_player *player);
+static void avrcp_get_play_status(struct avrcp *session);
static void avrcp_browsing_record(sdp_record_t *record, sdp_data_t *version)
{
@@ -2224,6 +2227,56 @@ static const char *status_to_string(uint8_t status)
}
}
+static bool avrcp_poll_play_status(gpointer user_data)
+{
+ struct avrcp *session = user_data;
+
+ avrcp_get_play_status(session);
+
+ return TRUE;
+}
+
+static void avrcp_stop_pos_polling(struct avrcp *session)
+{
+ if (session->position_timer == 0)
+ return;
+
+ timeout_remove(session->position_timer);
+ session->position_timer = 0;
+}
+
+static void avrcp_start_pos_polling(struct avrcp *session)
+{
+ if (session->position_timer > 0)
+ return;
+
+ session->position_timer = timeout_add_seconds(1,
+ avrcp_poll_play_status,
+ session, NULL);
+}
+
+/*
+ * Poll GetPlayStatus once a second to resync position while playing when
+ * the remote does not support AVRCP_EVENT_PLAYBACK_POS_CHANGED. Polling is
+ * paused whenever playback is not actively progressing.
+ */
+static void avrcp_update_pos_polling(struct avrcp *session, uint8_t status)
+{
+ if (session->pos_changed_supported)
+ return;
+
+ switch (status) {
+ case AVRCP_PLAY_STATUS_PLAYING:
+ case AVRCP_PLAY_STATUS_FWD_SEEK:
+ case AVRCP_PLAY_STATUS_REV_SEEK:
+ avrcp_start_pos_polling(session);
+ break;
+ default:
+ avrcp_stop_pos_polling(session);
+ break;
+ }
+}
+
static gboolean avrcp_get_play_status_rsp(struct avctp *conn, uint8_t code,
uint8_t subunit, uint8_t transaction,
uint8_t *operands, size_t operand_count,
@@ -2252,6 +2305,8 @@ static gboolean avrcp_get_play_status_rsp(struct avctp *conn, uint8_t code,
media_player_set_position(mp, position);
media_player_set_status(mp, status_to_string(status));
+ avrcp_update_pos_polling(session, status);
+
return FALSE;
}
@@ -4128,6 +4183,9 @@ static gboolean avrcp_get_capabilities_resp(struct avctp *conn, uint8_t code,
}
}
+ session->pos_changed_supported =
+ !!(events & (1 << AVRCP_EVENT_PLAYBACK_POS_CHANGED));
+
if (!session->controller || !session->controller->player)
return FALSE;
@@ -4140,7 +4198,8 @@ static gboolean avrcp_get_capabilities_resp(struct avctp *conn, uint8_t code,
!(events & (1 << AVRCP_EVENT_SETTINGS_CHANGED)))
avrcp_list_player_attributes(session);
- if (!(events & (1 << AVRCP_EVENT_STATUS_CHANGED)))
+ if (!(events & (1 << AVRCP_EVENT_STATUS_CHANGED)) ||
+ !session->pos_changed_supported)
avrcp_get_play_status(session);
if (!(events & (1 << AVRCP_EVENT_STATUS_CHANGED)))
@@ -4470,6 +4529,9 @@ static void session_destroy(struct avrcp *session, int err)
if (session->browsing_timer > 0)
timeout_remove(session->browsing_timer);
+ if (session->position_timer > 0)
+ timeout_remove(session->position_timer);
+
if (session->controller != NULL)
controller_destroy(session);
--
2.43.0
^ permalink raw reply related [flat|nested] 4+ messages in thread
* RE: [BlueZ] audio/avrcp: Poll GetPlayStatus when position changed event unsupported
2026-09-23 8:00 [PATCH BlueZ] audio/avrcp: Poll GetPlayStatus when position changed event unsupported Frédéric Danis
@ 2026-09-23 11:04 ` bluez.test.bot
2026-09-23 13:55 ` [PATCH BlueZ] " Luiz Augusto von Dentz
1 sibling, 0 replies; 4+ messages in thread
From: bluez.test.bot @ 2026-09-23 11:04 UTC (permalink / raw)
To: linux-bluetooth, frederic.danis
[-- Attachment #1: Type: text/plain, Size: 7480 bytes --]
This is automated email and please do not reply to this email!
Dear submitter,
Thank you for submitting the patches to the linux bluetooth mailing list.
This is a CI test results with your patch series:
PW Link:https://patchwork.kernel.org/series/1172004/
---Test result---
Test Summary:
CheckPatch PASS 0.51 seconds
GitLint PASS 1.17 seconds
BuildEll PASS 19.48 seconds
BluezMake PASS 386.90 seconds
MakeCheck PASS 2.67 seconds
MakeDistcheck PASS 138.47 seconds
CheckValgrind PASS 149.37 seconds
CheckSmatch PASS 287.84 seconds
bluezmakeextell PASS 93.00 seconds
TestFunctional FAIL 1132.21 seconds
IncrementalBuild PASS 383.61 seconds
ScanBuild PASS 1124.56 seconds
Details
##############################
Test: TestFunctional - FAIL
Desc: Run test-functional
Output:
FAIL functional.test_bap::test_bap_unicast_set_transport_created[hosts9-vm3-legacy]: failed on setup with "pytest_bluezenv.rpc.RemoteError: End Of File (EOF).
<pexpect.popen_spawn.PopenSpawn object at 0x7f0ab7b1e7b0>
searcher: searcher_re:
0: re.compile(b'Device has been removed|Device 00:AA:01:00:00:42 not available')
Remote traceback:
Traceback (most recent call last):
File "/usr/local/lib/python3.14/dist-packages/pytest_bluezenv/../pytest_bluezenv/rpc.py", line 102, in server_stream
result = method(*msg["a"], **msg["kw"])
File "/usr/local/lib/python3.14/dist-packages/pytest_bluezenv/../pytest_bluezenv/env.py", line 256, in call_plugin
return getattr(self.plugins[name], method)(*a, **kw)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^
File "/usr/local/lib/python3.14/dist-packages/pytest_bluezenv/../pytest_bluezenv/host_plugins.py", line 441, in expect
ret = ctl.expect(*a, **kw)
File "/usr/lib/python3/dist-packages/pexpect/spawnbase.py", line 354, in expect
return self.expect_list(compiled_pattern_list,
~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^
timeout, searchwindowsize, async_)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/pexpect/spawnbase.py", line 383, in expect_list
return exp.expect_loop(timeout)
~~~~~~~~~~~~~~~^^^^^^^^^
File "/usr/lib/python3/dist-packages/pexpect/expect.py", line 179, in expect_loop
return self.eof(e)
~~~~~~~~^^^
File "/usr/lib/python3/dist-packages/pexpect/expect.py", line 122, in eof
raise exc
pexpect.exceptions.EOF: End Of File (EOF).
<pexpect.popen_spawn.PopenSpawn object at 0x7f0ab7b1e7b0>
searcher: searcher_re:
0: re.compile(b'Device has been removed|Device 00:AA:01:00:00:42 not available')"
FAIL functional.test_bap::test_bap_unicast_set_transport_created[hosts9-vm3-legacy]: failed on teardown with "pytest_bluezenv.plugin.CoredumpWarning: Core dump: test-bluezenv-hosts9.2-bluetoothctl-1790159931-120.core
/usr/bin/gdb: warning: Couldn't determine a path for the index cache directory.
[New LWP 120]
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/usr/lib/x86_64-linux-gnu/libthread_db.so.1".
Core was generated by `/home/runner/work/bluez/bluez/src/src/client/bluetoothctl -a auto:NoInputNoOutput --init-script /home/runner/work/bluez/bluez/src/src/test/../client/scripts/bap-sink-lc3-right.bt'.
Program terminated with signal SIGABRT, Aborted.
#0 __pthread_kill_implementation (threadid=<optimized out>, signo=6, no_tid=0) at ./nptl/pthread_kill.c:44
warning: 44 ./nptl/pthread_kill.c: No such file or directory
Thread 1 (Thread 0x7fba8f957d40 (LWP 120)):
#0 __pthread_kill_implementation (threadid=<optimized out>, signo=6, no_tid=0) at ./nptl/pthread_kill.c:44
tid = <optimized out>
ret = 0
pd = <optimized out>
old_mask = {__val = {140730558660480}}
ret = <optimized out>
#1 __pthread_kill_internal (threadid=<optimized out>, signo=6) at ./nptl/pthread_kill.c:89
No locals.
#2 __GI___pthread_kill (threadid=<optimized out>, signo=signo@entry=6) at ./nptl/pthread_kill.c:100
No locals.
#3 0x00007fba8ff96b7e in __GI_raise (sig=sig@entry=6) at ../sysdeps/posix/raise.c:26
ret = <optimized out>
#4 0x00007fba8ff798ec in __GI_abort () at ./stdlib/abort.c:77
act = {__sigaction_handler = {sa_handler = 0x7c2a8ede1440, sa_sigaction = 0x7c2a8ede1440}, sa_mask = {__val = {140439258023203, 140730558660496, 140439256476592, 7791336406271877491, 140439258023072, 140730558660576, 140439267555473, 140439268605984, 140439246334784, 0, 140439258023072, 4294967295, 140439239786496, 140730558660624, 140439256147459, 140439258023072}}, sa_flags = -1897983936, sa_restorer = 0x7cda8ede01c0}
#5 0x00007fba907f7fe2 in ?? () from /usr/lib/x86_64-linux-gnu/libdbus-1.so.3
No symbol table info available.
#6 0x00007fba908234c1 in _dbus_warn_check_failed () from /usr/lib/x86_64-linux-gnu/libdbus-1.so.3
No symbol table info available.
#7 0x000055a7c4f7200a in cancel_request (conn=<optimized out>, msg=0x7cba8edf1040, user_data=<optimized out>) at client/agent.c:258
No locals.
#8 0x000055a7c5006131 in process_message (connection=0x7cda8ede01c0, message=0x7cba8edf1040, method=0x55a7c50e75e0 <auto_methods+320>, iface_user_data=<optimized out>) at gdbus/object.c:293
reply = <optimized out>
#9 0x00007fba908040f4 in dbus_connection_dispatch () from /usr/lib/x86_64-linux-gnu/libdbus-1.so.3
No symbol table info available.
#10 0x000055a7c4ff5d98 in message_dispatch (data=0x7cda8ede01c0) at gdbus/mainloop.c:59
conn = 0x7cda8ede01c0
#11 0x00007fba9089bb9b in ?? () from /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0
No symbol table info available.
#12 0x00007fba9089d1d7 in ?? () from /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0
No symbol table info available.
#13 0x00007fba9089d577 in g_main_loop_run () from /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0
No symbol table info available.
#14 0x000055a7c5039539 in mainloop_run () at src/shared/mainloop-glib.c:65
No locals.
#15 0x000055a7c5039e6b in mainloop_run_with_signal (func=func@entry=0x55a7c5030eb0 <signal_callback>, user_data=user_data@entry=0x0) at src/shared/mainloop-notify.c:196
data = 0x7bea8ede1810
io = 0x7bfa8ede1f50
ret = <optimized out>
#16 0x000055a7c503508c in bt_shell_run () at src/shared/shell.c:1476
status = <optimized out>
submenu = <optimized out>
#17 0x000055a7c4f5a915 in main (argc=<optimized out>, argv=<optimized out>) at client/main.c:4228
client = 0x7cba8ede0440
status = <optimized out>
timeout = <optimized out>
timeout_id = <optimized out>"
https://github.com/bluez/bluez/pull/2570
---
Regards,
Linux Bluetooth
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH BlueZ] audio/avrcp: Poll GetPlayStatus when position changed event unsupported
2026-09-23 8:00 [PATCH BlueZ] audio/avrcp: Poll GetPlayStatus when position changed event unsupported Frédéric Danis
2026-09-23 11:04 ` [BlueZ] " bluez.test.bot
@ 2026-09-23 13:55 ` Luiz Augusto von Dentz
2026-09-23 14:27 ` Frédéric Danis
1 sibling, 1 reply; 4+ messages in thread
From: Luiz Augusto von Dentz @ 2026-09-23 13:55 UTC (permalink / raw)
To: Frédéric Danis; +Cc: linux-bluetooth
Hi Frederic,
On Wed, Sep 23, 2026 at 4:02 AM Frédéric Danis
<frederic.danis@collabora.com> wrote:
>
> Some remote targets do not support the AVRCP_EVENT_PLAYBACK_POS_CHANGED
> notification, meaning bluetoothd never learns about track position
> updates for such devices.
>
> When this event is not present in the capabilities reported by the
> remote, fall back to polling AVRCP_GET_PLAY_STATUS once a second so
> the media player position stays in sync. Polling is only kept running
> while playback is actively progressing (playing/forward-seek/
> reverse-seek) and is stopped otherwise, and is torn down on session
> destruction.
Back in the days AVRCP was introduced we decided not to poll the
status and instead have the upper layer trigger it via
https://github.com/bluez/bluez/blob/master/doc/org.bluez.MediaPlayer.rst#uint32-position-readonly,
that said I do agree that perhaps it is better to it with directly by
bluetoothd since so many years have passed and some manufactorers
insist in not having AVRCP_EVENT_PLAYBACK_POS_CHANGED implemented.
> Assisted-by: Copilot CLI:claude-sonnet-5
> ---
> profiles/audio/avrcp.c | 64 +++++++++++++++++++++++++++++++++++++++++-
> 1 file changed, 63 insertions(+), 1 deletion(-)
>
> diff --git a/profiles/audio/avrcp.c b/profiles/audio/avrcp.c
> index df5f97eaf..105538cdc 100644
> --- a/profiles/audio/avrcp.c
> +++ b/profiles/audio/avrcp.c
> @@ -247,7 +247,9 @@ struct avrcp {
> unsigned int control_id;
> unsigned int browsing_id;
> unsigned int browsing_timer;
> + unsigned int position_timer;
> uint16_t supported_events;
> + bool pos_changed_supported;
> uint8_t transaction;
> struct pending_pdu *pending_pdu;
> };
> @@ -341,6 +343,7 @@ static const uint32_t company_ids[] = {
>
> static void avrcp_register_notification(struct avrcp *session, uint8_t event);
> static GList *player_list_settings(struct avrcp_player *player);
> +static void avrcp_get_play_status(struct avrcp *session);
>
> static void avrcp_browsing_record(sdp_record_t *record, sdp_data_t *version)
> {
> @@ -2224,6 +2227,56 @@ static const char *status_to_string(uint8_t status)
> }
> }
>
> +static bool avrcp_poll_play_status(gpointer user_data)
> +{
> + struct avrcp *session = user_data;
> +
> + avrcp_get_play_status(session);
> +
> + return TRUE;
> +}
> +
> +static void avrcp_stop_pos_polling(struct avrcp *session)
> +{
> + if (session->position_timer == 0)
> + return;
> +
> + timeout_remove(session->position_timer);
> + session->position_timer = 0;
> +}
> +
> +static void avrcp_start_pos_polling(struct avrcp *session)
> +{
> + if (session->position_timer > 0)
> + return;
> +
> + session->position_timer = timeout_add_seconds(1,
> + avrcp_poll_play_status,
> + session, NULL);
> +}
> +
> +/*
> + * Poll GetPlayStatus once a second to resync position while playing when
> + * the remote does not support AVRCP_EVENT_PLAYBACK_POS_CHANGED. Polling is
> + * paused whenever playback is not actively progressing.
> + */
> +static void avrcp_update_pos_polling(struct avrcp *session, uint8_t status)
> +{
> + if (session->pos_changed_supported)
> + return;
> +
> + switch (status) {
> + case AVRCP_PLAY_STATUS_PLAYING:
> + case AVRCP_PLAY_STATUS_FWD_SEEK:
> + case AVRCP_PLAY_STATUS_REV_SEEK:
> + avrcp_start_pos_polling(session);
Btw, if I recall correctly, position tracking really breaks when the
user seeks the stream using the player progression bar, which
interrupts the continuous timer. So, if the player does either
AVRCP_PLAY_STATUS_FWD_SEEK or AVRCP_PLAY_STATUS_REV_SEEK then we can
resink the position once, afaik iOS media player doesn't use them
either, thus why the whole polling thing is needed to capture non
continuguos skips that are not advertised.
> + break;
> + default:
> + avrcp_stop_pos_polling(session);
> + break;
> + }
> +}
> +
> static gboolean avrcp_get_play_status_rsp(struct avctp *conn, uint8_t code,
> uint8_t subunit, uint8_t transaction,
> uint8_t *operands, size_t operand_count,
> @@ -2252,6 +2305,8 @@ static gboolean avrcp_get_play_status_rsp(struct avctp *conn, uint8_t code,
> media_player_set_position(mp, position);
> media_player_set_status(mp, status_to_string(status));
>
> + avrcp_update_pos_polling(session, status);
> +
> return FALSE;
> }
>
> @@ -4128,6 +4183,9 @@ static gboolean avrcp_get_capabilities_resp(struct avctp *conn, uint8_t code,
> }
> }
>
> + session->pos_changed_supported =
> + !!(events & (1 << AVRCP_EVENT_PLAYBACK_POS_CHANGED));
> +
> if (!session->controller || !session->controller->player)
> return FALSE;
>
> @@ -4140,7 +4198,8 @@ static gboolean avrcp_get_capabilities_resp(struct avctp *conn, uint8_t code,
> !(events & (1 << AVRCP_EVENT_SETTINGS_CHANGED)))
> avrcp_list_player_attributes(session);
>
> - if (!(events & (1 << AVRCP_EVENT_STATUS_CHANGED)))
> + if (!(events & (1 << AVRCP_EVENT_STATUS_CHANGED)) ||
> + !session->pos_changed_supported)
> avrcp_get_play_status(session);
>
> if (!(events & (1 << AVRCP_EVENT_STATUS_CHANGED)))
> @@ -4470,6 +4529,9 @@ static void session_destroy(struct avrcp *session, int err)
> if (session->browsing_timer > 0)
> timeout_remove(session->browsing_timer);
>
> + if (session->position_timer > 0)
> + timeout_remove(session->position_timer);
> +
> if (session->controller != NULL)
> controller_destroy(session);
>
> --
> 2.43.0
>
>
--
Luiz Augusto von Dentz
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH BlueZ] audio/avrcp: Poll GetPlayStatus when position changed event unsupported
2026-09-23 13:55 ` [PATCH BlueZ] " Luiz Augusto von Dentz
@ 2026-09-23 14:27 ` Frédéric Danis
0 siblings, 0 replies; 4+ messages in thread
From: Frédéric Danis @ 2026-09-23 14:27 UTC (permalink / raw)
To: Luiz Augusto von Dentz; +Cc: linux-bluetooth
Hi Luiz,
On 23/09/2026 15:55, Luiz Augusto von Dentz wrote:
> Hi Frederic,
>
> On Wed, Sep 23, 2026 at 4:02 AM Frédéric Danis
> <frederic.danis@collabora.com> wrote:
>> Some remote targets do not support the AVRCP_EVENT_PLAYBACK_POS_CHANGED
>> notification, meaning bluetoothd never learns about track position
>> updates for such devices.
>>
>> When this event is not present in the capabilities reported by the
>> remote, fall back to polling AVRCP_GET_PLAY_STATUS once a second so
>> the media player position stays in sync. Polling is only kept running
>> while playback is actively progressing (playing/forward-seek/
>> reverse-seek) and is stopped otherwise, and is torn down on session
>> destruction.
> Back in the days AVRCP was introduced we decided not to poll the
> status and instead have the upper layer trigger it via
> https://github.com/bluez/bluez/blob/master/doc/org.bluez.MediaPlayer.rst#uint32-position-readonly,
> that said I do agree that perhaps it is better to it with directly by
> bluetoothd since so many years have passed and some manufactorers
> insist in not having AVRCP_EVENT_PLAYBACK_POS_CHANGED implemented.
This property may be cached by the DBus framework used, and so iiuc
reading it will not trigger GetPlayStatus.
>> Assisted-by: Copilot CLI:claude-sonnet-5
>> ---
>> profiles/audio/avrcp.c | 64 +++++++++++++++++++++++++++++++++++++++++-
>> 1 file changed, 63 insertions(+), 1 deletion(-)
>>
>> diff --git a/profiles/audio/avrcp.c b/profiles/audio/avrcp.c
>> index df5f97eaf..105538cdc 100644
>> --- a/profiles/audio/avrcp.c
>> +++ b/profiles/audio/avrcp.c
>> @@ -247,7 +247,9 @@ struct avrcp {
>> unsigned int control_id;
>> unsigned int browsing_id;
>> unsigned int browsing_timer;
>> + unsigned int position_timer;
>> uint16_t supported_events;
>> + bool pos_changed_supported;
>> uint8_t transaction;
>> struct pending_pdu *pending_pdu;
>> };
>> @@ -341,6 +343,7 @@ static const uint32_t company_ids[] = {
>>
>> static void avrcp_register_notification(struct avrcp *session, uint8_t event);
>> static GList *player_list_settings(struct avrcp_player *player);
>> +static void avrcp_get_play_status(struct avrcp *session);
>>
>> static void avrcp_browsing_record(sdp_record_t *record, sdp_data_t *version)
>> {
>> @@ -2224,6 +2227,56 @@ static const char *status_to_string(uint8_t status)
>> }
>> }
>>
>> +static bool avrcp_poll_play_status(gpointer user_data)
>> +{
>> + struct avrcp *session = user_data;
>> +
>> + avrcp_get_play_status(session);
>> +
>> + return TRUE;
>> +}
>> +
>> +static void avrcp_stop_pos_polling(struct avrcp *session)
>> +{
>> + if (session->position_timer == 0)
>> + return;
>> +
>> + timeout_remove(session->position_timer);
>> + session->position_timer = 0;
>> +}
>> +
>> +static void avrcp_start_pos_polling(struct avrcp *session)
>> +{
>> + if (session->position_timer > 0)
>> + return;
>> +
>> + session->position_timer = timeout_add_seconds(1,
>> + avrcp_poll_play_status,
>> + session, NULL);
>> +}
>> +
>> +/*
>> + * Poll GetPlayStatus once a second to resync position while playing when
>> + * the remote does not support AVRCP_EVENT_PLAYBACK_POS_CHANGED. Polling is
>> + * paused whenever playback is not actively progressing.
>> + */
>> +static void avrcp_update_pos_polling(struct avrcp *session, uint8_t status)
>> +{
>> + if (session->pos_changed_supported)
>> + return;
>> +
>> + switch (status) {
>> + case AVRCP_PLAY_STATUS_PLAYING:
>> + case AVRCP_PLAY_STATUS_FWD_SEEK:
>> + case AVRCP_PLAY_STATUS_REV_SEEK:
>> + avrcp_start_pos_polling(session);
> Btw, if I recall correctly, position tracking really breaks when the
> user seeks the stream using the player progression bar, which
> interrupts the continuous timer. So, if the player does either
> AVRCP_PLAY_STATUS_FWD_SEEK or AVRCP_PLAY_STATUS_REV_SEEK then we can
> resink the position once, afaik iOS media player doesn't use them
> either, thus why the whole polling thing is needed to capture non
> continuguos skips that are not advertised.
>
>> + break;
>> + default:
>> + avrcp_stop_pos_polling(session);
>> + break;
>> + }
>> +}
>> +
>> static gboolean avrcp_get_play_status_rsp(struct avctp *conn, uint8_t code,
>> uint8_t subunit, uint8_t transaction,
>> uint8_t *operands, size_t operand_count,
>> @@ -2252,6 +2305,8 @@ static gboolean avrcp_get_play_status_rsp(struct avctp *conn, uint8_t code,
>> media_player_set_position(mp, position);
>> media_player_set_status(mp, status_to_string(status));
>>
>> + avrcp_update_pos_polling(session, status);
>> +
>> return FALSE;
>> }
>>
>> @@ -4128,6 +4183,9 @@ static gboolean avrcp_get_capabilities_resp(struct avctp *conn, uint8_t code,
>> }
>> }
>>
>> + session->pos_changed_supported =
>> + !!(events & (1 << AVRCP_EVENT_PLAYBACK_POS_CHANGED));
>> +
>> if (!session->controller || !session->controller->player)
>> return FALSE;
>>
>> @@ -4140,7 +4198,8 @@ static gboolean avrcp_get_capabilities_resp(struct avctp *conn, uint8_t code,
>> !(events & (1 << AVRCP_EVENT_SETTINGS_CHANGED)))
>> avrcp_list_player_attributes(session);
>>
>> - if (!(events & (1 << AVRCP_EVENT_STATUS_CHANGED)))
>> + if (!(events & (1 << AVRCP_EVENT_STATUS_CHANGED)) ||
>> + !session->pos_changed_supported)
>> avrcp_get_play_status(session);
>>
>> if (!(events & (1 << AVRCP_EVENT_STATUS_CHANGED)))
>> @@ -4470,6 +4529,9 @@ static void session_destroy(struct avrcp *session, int err)
>> if (session->browsing_timer > 0)
>> timeout_remove(session->browsing_timer);
>>
>> + if (session->position_timer > 0)
>> + timeout_remove(session->position_timer);
>> +
>> if (session->controller != NULL)
>> controller_destroy(session);
>>
>> --
>> 2.43.0
>>
>>
>
--
Frédéric Danis
Senior Software Engineer
Collabora Ltd.
Platinum Building, St John's Innovation Park, Cambridge CB4 0DS, United Kingdom
Registered in England & Wales, no. 5513718
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2026-09-23 14:27 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-23 8:00 [PATCH BlueZ] audio/avrcp: Poll GetPlayStatus when position changed event unsupported Frédéric Danis
2026-09-23 11:04 ` [BlueZ] " bluez.test.bot
2026-09-23 13:55 ` [PATCH BlueZ] " Luiz Augusto von Dentz
2026-09-23 14:27 ` Frédéric Danis
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox