DBus control: add more TrackList signals

Implements the following signals for the
org.mpris.MediaPlayer2.TrackList interface:

- TrackAdded: a track was inserted to the list
- TrackRemoved: a track was removed from the list
This commit is contained in:
Jorge Bellon-Castro 2023-01-02 16:18:22 +01:00 committed by Felix Paul Kühne
parent b2a5d6cc75
commit c839ffd9a6
3 changed files with 239 additions and 14 deletions

View File

@ -89,6 +89,10 @@ static const DBusObjectPathVTable dbus_mpris_vtable = {
typedef struct
{
int signal;
union {
tracklist_append_event_t *items_appended;
tracklist_remove_event_t *items_removed;
};
} callback_info_t;
enum
@ -639,6 +643,14 @@ static void ProcessEvents( intf_thread_t *p_intf,
vlc_dictionary_init( &tracklist_properties, 0 );
vlc_dictionary_init( &root_properties, 0 );
// In case multiple *_ITEM_APPEND or *_ITEM_DELETED events appear on the
// list, the elements in their respective map values will be linked in
// order.
// We keep the tail of the list in order to append the elements to the end
// of each list.
tracklist_append_event_t *last_append = NULL;
tracklist_remove_event_t *last_remove = NULL;
for( int i = 0; i < i_events; i++ )
{
switch( p_events[i]->signal )
@ -653,9 +665,27 @@ static void ProcessEvents( intf_thread_t *p_intf,
vlc_dictionary_insert( &player_properties, "Metadata", NULL );
break;
case SIGNAL_PLAYLIST_ITEM_APPEND:
if( !last_append ) {
assert (!vlc_dictionary_has_key( &tracklist_properties, "TrackAdded" ) );
vlc_dictionary_insert( &tracklist_properties, "TrackAdded", p_events[i]->items_appended );
last_append = p_events[i]->items_appended;
} else {
last_append->change_ev.next = &p_events[i]->items_appended->change_ev;
last_append = p_events[i]->items_appended;
}
ProcessPlaylistChanged( p_intf, &player_properties, &tracklist_properties );
break;
case SIGNAL_PLAYLIST_ITEM_DELETED:
if( !last_remove ) {
assert (!vlc_dictionary_has_key( &tracklist_properties, "TrackRemoved" ) );
vlc_dictionary_insert( &tracklist_properties, "TrackRemoved", p_events[i]->items_removed );
last_remove = p_events[i]->items_removed;
} else {
last_remove->change_ev.next = &p_events[i]->items_removed->change_ev;
last_remove = p_events[i]->items_removed;
}
ProcessPlaylistChanged( p_intf, &player_properties, &tracklist_properties );
break;
case SIGNAL_VOLUME_MUTED:
@ -1018,18 +1048,22 @@ playlist_on_items_added(vlc_playlist_t *playlist, size_t index,
vlc_playlist_item_t *const items[], size_t count,
void *data)
{
tracklist_append_event_t *append_event = tracklist_append_event_create(index, items, count);
add_event_signal(data,
&(callback_info_t){ .signal = SIGNAL_PLAYLIST_ITEM_APPEND });
(void) playlist; (void) index; (void) items; (void) count;
&(callback_info_t){ .signal = SIGNAL_PLAYLIST_ITEM_APPEND,
.items_appended = append_event });
(void) playlist;
}
static void
playlist_on_items_removed(vlc_playlist_t *playlist,
size_t index, size_t count, void *data)
{
tracklist_remove_event_t *remove_event = tracklist_remove_event_create(index, count);
add_event_signal(data,
&(callback_info_t){ .signal = SIGNAL_PLAYLIST_ITEM_DELETED });
(void) playlist; (void) index; (void) count;
&(callback_info_t){ .signal = SIGNAL_PLAYLIST_ITEM_DELETED,
.items_removed = remove_event });
(void) playlist;
}
static void

View File

@ -36,6 +36,42 @@
#include "dbus_tracklist.h"
#include "dbus_common.h"
tracklist_append_event_t *tracklist_append_event_create(size_t index, vlc_playlist_item_t *const items[], size_t count) {
tracklist_append_event_t* result = malloc(sizeof(tracklist_append_event_t) + sizeof(vlc_playlist_item_t *[count]));
if (!result)
return result;
*result = (tracklist_append_event_t) { .change_ev = { .index = index, .count = count } };
for (size_t i = 0; i < count; ++i) {
result->items[i] = items[i];
vlc_playlist_item_Hold(items[i]);
}
return result;
}
tracklist_remove_event_t *tracklist_remove_event_create(size_t index, size_t count) {
tracklist_remove_event_t* result = malloc(sizeof(tracklist_remove_event_t));
if (!result)
return result;
*result = (tracklist_remove_event_t) { .change_ev = { .index = index, .count = count } };
return result;
}
void tracklist_append_event_destroy(tracklist_append_event_t *event) {
if (!event)
return;
for (size_t i = 0; i < event->change_ev.count; ++i) {
vlc_playlist_item_Release(event->items[i]);
}
free(event);
}
void tracklist_remove_event_destroy(tracklist_remove_event_t *event) {
free(event);
}
DBUS_METHOD( AddTrack )
{
REPLY_INIT;
@ -242,11 +278,29 @@ invalid_track_id:
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
static int MarshalTrack( DBusMessageIter *iter, size_t index )
{
char *psz_track_id = NULL;
int ret = VLC_SUCCESS;
if (asprintf(&psz_track_id, MPRIS_TRACKID_FORMAT, index) == -1)
ret = VLC_ENOMEM;
if (ret == VLC_SUCCESS &&
!dbus_message_iter_append_basic( iter,
DBUS_TYPE_OBJECT_PATH,
&psz_track_id ) )
{
ret = VLC_ENOMEM;
}
free( psz_track_id );
return ret;
}
static int
MarshalTracks( intf_thread_t *p_intf, DBusMessageIter *container )
{
DBusMessageIter tracks;
char *psz_track_id = NULL;
vlc_playlist_t *playlist = p_intf->p_sys->playlist;
dbus_message_iter_open_container( container, DBUS_TYPE_ARRAY, "o",
@ -257,16 +311,12 @@ MarshalTracks( intf_thread_t *p_intf, DBusMessageIter *container )
vlc_playlist_Unlock(playlist);
for (size_t i = 0; i < pl_size; i++)
{
if (asprintf(&psz_track_id, MPRIS_TRACKID_FORMAT, i) == -1 ||
!dbus_message_iter_append_basic( &tracks,
DBUS_TYPE_OBJECT_PATH,
&psz_track_id ) )
int err = MarshalTrack( &tracks, i );
if (err != VLC_SUCCESS)
{
dbus_message_iter_abandon_container( container, &tracks );
return VLC_ENOMEM;
return err;
}
free( psz_track_id );
}
if( !dbus_message_iter_close_container( container, &tracks ) )
@ -467,8 +517,64 @@ PropertiesChangedSignal( intf_thread_t *p_intf,
}
/**
* TrackListPropertiesChangedEmit: Emits the
* org.freedesktop.DBus.Properties.PropertiesChanged signal
* TrackAddedSignal: synthetizes and sends the
* org.mpris.MediaPlayer2.TrackList.TrackAdded signal
*/
static DBusHandlerResult
TrackAddedSignal( intf_thread_t *p_intf,
size_t index,
vlc_playlist_item_t *item )
{
DBusConnection *p_conn = p_intf->p_sys->p_conn;
DBusMessageIter meta;
SIGNAL_INIT( "MediaPlayer2.TrackList",
DBUS_MPRIS_OBJECT_PATH,
"TrackAdded" );
OUT_ARGUMENTS;
if( unlikely(!dbus_message_iter_open_container( &args,
DBUS_TYPE_ARRAY, "a{sv}",
&meta )) )
return DBUS_HANDLER_RESULT_NEED_MEMORY;
GetInputMeta(index, item, &meta);
if( unlikely(!dbus_message_iter_close_container( &args,
&meta )) )
return DBUS_HANDLER_RESULT_NEED_MEMORY;
if ( MarshalTrack( &args, index ) != VLC_SUCCESS )
return DBUS_HANDLER_RESULT_NEED_MEMORY;
SIGNAL_SEND;
}
/**
* TrackRemovedSignal: synthetizes and sends the
* org.mpris.MediaPlayer2.TrackList.TrackRemoved signal
*/
static DBusHandlerResult
TrackRemovedSignal( intf_thread_t *p_intf, size_t index )
{
DBusConnection *p_conn = p_intf->p_sys->p_conn;
SIGNAL_INIT( "MediaPlayer2.TrackList",
DBUS_MPRIS_OBJECT_PATH,
"TrackRemoved" );
OUT_ARGUMENTS;
if ( MarshalTrack( &args, index ) != VLC_SUCCESS )
return DBUS_HANDLER_RESULT_NEED_MEMORY;
SIGNAL_SEND;
}
/**
* TrackListPropertiesChangedEmit: Emits the following signals:
* - org.freedesktop.DBus.Properties.PropertiesChanged
* - org.mpris.MediaPlayer2.TrackList.TrackAdded
*/
int TrackListPropertiesChangedEmit( intf_thread_t * p_intf,
vlc_dictionary_t * p_changed_properties )
@ -477,5 +583,35 @@ int TrackListPropertiesChangedEmit( intf_thread_t * p_intf,
return VLC_SUCCESS;
PropertiesChangedSignal( p_intf, p_changed_properties );
if( vlc_dictionary_has_key( p_changed_properties, "TrackAdded" ) ) {
tracklist_append_event_t *added_tracks =
vlc_dictionary_value_for_key( p_changed_properties, "TrackAdded" );
while (added_tracks) {
for (size_t i = 0; i < added_tracks->change_ev.count; ++i) {
TrackAddedSignal( p_intf,
added_tracks->change_ev.index + i,
added_tracks->items[i] );
}
added_tracks = tracklist_append_event_next(added_tracks);
}
tracklist_append_event_destroy( added_tracks );
}
if( vlc_dictionary_has_key( p_changed_properties, "TrackRemoved" ) ) {
tracklist_remove_event_t *removed_tracks =
vlc_dictionary_value_for_key( p_changed_properties, "TrackRemoved" );
while (removed_tracks) {
for (size_t i = 0; i < removed_tracks->change_ev.count; ++i) {
TrackRemovedSignal( p_intf, removed_tracks->change_ev.index + i );
}
removed_tracks = tracklist_remove_event_next(removed_tracks);
}
tracklist_remove_event_destroy( removed_tracks );
}
return VLC_SUCCESS;
}

View File

@ -36,6 +36,61 @@
#define DBUS_MPRIS_NOTRACK "/org/mpris/MediaPlayer2/TrackList/NoTrack"
#define DBUS_MPRIS_APPEND "/org/mpris/MediaPlayer2/TrackList/Append"
struct tracklist_change_event {
size_t index;
size_t count;
struct tracklist_change_event *next;
};
struct tracklist_append_event {
struct tracklist_change_event change_ev;
vlc_playlist_item_t *items[];
};
struct tracklist_remove_event {
struct tracklist_change_event change_ev;
};
typedef struct tracklist_append_event tracklist_append_event_t;
typedef struct tracklist_remove_event tracklist_remove_event_t;
/* Creates an event holding what items have been appended to a tracklist.
* The event data will be used to generate TrackAdded DBus signals later on.
*/
tracklist_append_event_t *
tracklist_append_event_create( size_t index,
vlc_playlist_item_t *const items[],
size_t count );
/* Creates an event holding what items have been removed from a tracklist.
* The event data will be used to generate TrackRemoved DBus signals later on.
*/
tracklist_remove_event_t *
tracklist_remove_event_create( size_t index, size_t count );
/* Releases any resources reserved for this event */
void tracklist_append_event_destroy( tracklist_append_event_t *event );
void tracklist_remove_event_destroy( tracklist_remove_event_t *event );
/* Gets next event in the list */
static tracklist_append_event_t *
tracklist_append_event_next( tracklist_append_event_t *event ) {
if( !event )
return NULL;
char *p = (char *) event->change_ev.next;
return (tracklist_append_event_t *)
(p - offsetof(struct tracklist_append_event, change_ev));
}
static tracklist_remove_event_t *
tracklist_remove_event_next( tracklist_remove_event_t *event ) {
if( !event )
return NULL;
char *p = (char *) event->change_ev.next;
return (tracklist_remove_event_t *)
(p - offsetof(struct tracklist_remove_event, change_ev));
}
/* Handle incoming dbus messages */
DBusHandlerResult handle_tracklist ( DBusConnection *p_conn,
DBusMessage *p_from,