[vlc-commits] [Git][videolan/vlc][3.0.x] 4 commits: DBus control: Extract method ProcessPlaylistChanged
Steve Lhomme (@robUx4)
gitlab at videolan.org
Wed Jan 11 05:27:56 UTC 2023
Steve Lhomme pushed to branch 3.0.x at VideoLAN / VLC
Commits:
70c34c35 by Jorge Bellon-Castro at 2023-01-11T05:06:51+00:00
DBus control: Extract method ProcessPlaylistChanged
Extract switch body for track append and track remove events.
This simplifies adding independent logic to both cases.
- - - - -
0f6129e0 by Jorge Bellon-Castro at 2023-01-11T05:06:51+00:00
DBus control: do not query index of item if known
The track index is sometimes known when serialising a track's metadata.
This moves the index query outside the metadata serialisation function
when necessary.
- - - - -
7a1c58ac by Jorge Bellon-Castro at 2023-01-11T05:06:51+00:00
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
- - - - -
4c12f2ea by Jorge Bellon at 2023-01-11T05:06:51+00:00
DBus control module: return DBus error message instead of entering an infinite loop
- - - - -
4 changed files:
- modules/control/dbus/dbus.c
- modules/control/dbus/dbus_player.c
- modules/control/dbus/dbus_tracklist.c
- modules/control/dbus/dbus_tracklist.h
Changes:
=====================================
modules/control/dbus/dbus.c
=====================================
@@ -92,6 +92,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
@@ -518,6 +522,34 @@ static int GetPollFds( intf_thread_t *p_intf, struct pollfd *p_fds )
return i_fds;
}
+
+/**
+ * ProcessPlaylistChanged() reacts to tracks being either inserted or removed from the playlist
+ *
+ * This function must be called by ProcessEvents only
+ *
+ * @param intf_thread_t *p_intf This interface thread state
+ * @param callback_info_t *p_events the list of events to process
+ */
+static void ProcessPlaylistChanged( intf_thread_t *p_intf,
+ vlc_dictionary_t *player_properties,
+ vlc_dictionary_t *tracklist_properties )
+{
+ playlist_t *playlist = p_intf->p_sys->p_playlist;
+ playlist_Lock(playlist);
+ bool b_can_play = !playlist_IsEmpty(playlist);
+ playlist_Unlock(playlist);
+
+ if( b_can_play != p_intf->p_sys->b_can_play )
+ {
+ p_intf->p_sys->b_can_play = b_can_play;
+ vlc_dictionary_insert( player_properties, "CanPlay", NULL );
+ }
+
+ if( !vlc_dictionary_has_key( tracklist_properties, "Tracks" ) )
+ vlc_dictionary_insert( tracklist_properties, "Tracks", NULL );
+}
+
/**
* ProcessEvents() reacts to a list of events originating from other VLC threads
*
@@ -529,13 +561,19 @@ static int GetPollFds( intf_thread_t *p_intf, struct pollfd *p_fds )
static void ProcessEvents( intf_thread_t *p_intf,
callback_info_t **p_events, int i_events )
{
- bool b_can_play = p_intf->p_sys->b_can_play;
-
vlc_dictionary_t player_properties, tracklist_properties, root_properties;
vlc_dictionary_init( &player_properties, 0 );
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 )
@@ -582,23 +620,29 @@ static void ProcessEvents( intf_thread_t *p_intf,
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:
- {
- playlist_t *p_playlist = p_intf->p_sys->p_playlist;
- PL_LOCK;
- b_can_play = playlist_CurrentSize( p_playlist ) > 0;
- PL_UNLOCK;
-
- if( b_can_play != p_intf->p_sys->b_can_play )
- {
- p_intf->p_sys->b_can_play = b_can_play;
- vlc_dictionary_insert( &player_properties, "CanPlay", NULL );
+ 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;
}
-
- if( !vlc_dictionary_has_key( &tracklist_properties, "Tracks" ) )
- vlc_dictionary_insert( &tracklist_properties, "Tracks", NULL );
+ ProcessPlaylistChanged( p_intf, &player_properties, &tracklist_properties );
break;
- }
case SIGNAL_VOLUME_MUTED:
case SIGNAL_VOLUME_CHANGE:
vlc_dictionary_insert( &player_properties, "Volume", NULL );
@@ -1058,9 +1102,21 @@ static int AllCallback( vlc_object_t *p_this, const char *psz_var,
info.signal = SIGNAL_VOLUME_MUTED;
}
else if( !strcmp( "playlist-item-append", psz_var ) )
- info.signal = SIGNAL_PLAYLIST_ITEM_APPEND;
+ {
+ playlist_item_t *items[] = {newval.p_address};
+ info = (callback_info_t){
+ .signal = SIGNAL_PLAYLIST_ITEM_APPEND,
+ .items_appended = tracklist_append_event_create(items[0]->i_id, items, 1)
+ };
+ }
else if( !strcmp( "playlist-item-deleted", psz_var ) )
- info.signal = SIGNAL_PLAYLIST_ITEM_DELETED;
+ {
+ playlist_item_t *item = newval.p_address;
+ info = (callback_info_t){
+ .signal = SIGNAL_PLAYLIST_ITEM_DELETED,
+ .items_removed = tracklist_remove_event_create(item->i_id, 1)
+ };
+ }
else if( !strcmp( "random", psz_var ) )
info.signal = SIGNAL_RANDOM;
else if( !strcmp( "fullscreen", psz_var ) )
=====================================
modules/control/dbus/dbus_player.c
=====================================
@@ -514,6 +514,7 @@ MarshalMetadata( intf_thread_t *p_intf, DBusMessageIter *container )
item = playlist_CurrentPlayingItem( playlist );
if( item != NULL )
+ // TODO: vlc_object_hold this
result = GetInputMeta( item, container );
else
{ // avoid breaking the type marshalling
=====================================
modules/control/dbus/dbus_tracklist.c
=====================================
@@ -39,6 +39,69 @@
#include "dbus_tracklist.h"
#include "dbus_common.h"
+
+tracklist_append_event_t *tracklist_append_event_create(size_t index, playlist_item_t *const items[], size_t count) {
+ tracklist_append_event_t* result = malloc(sizeof(tracklist_append_event_t) + sizeof(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) {
+ // We can't hold a playlist_item_t, so we copy it and hold onto its input
+ result->items[i] = *items[i];
+ input_item_Hold(items[i]->p_input);
+ }
+ 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) {
+ // Release referenced input
+ input_item_Release(event->items[i].p_input);
+ }
+ free(event);
+}
+
+void tracklist_remove_event_destroy(tracklist_remove_event_t *event) {
+ free(event);
+}
+
+static DBusHandlerResult InvalidTrackId(DBusConnection *p_conn,
+ DBusMessage *p_from,
+ const char *trackId,
+ void *p_this) {
+ msg_Err((vlc_object_t *)p_this, "Invalid track id: %s", trackId);
+
+ DBusMessage *p_msg = dbus_message_new_error_printf(
+ p_from, DBUS_ERROR_UNKNOWN_OBJECT, "Invalid track id: %s", trackId);
+ if (!p_msg)
+ return DBUS_HANDLER_RESULT_NEED_MEMORY;
+ REPLY_SEND;
+}
+
+static DBusHandlerResult InvalidArguments(DBusConnection *p_conn,
+ DBusMessage *p_from,
+ void *p_this) {
+ msg_Err((vlc_object_t *)p_this, "Invalid arguments");
+
+ DBusMessage *p_msg = dbus_message_new_error(p_from, DBUS_ERROR_INVALID_ARGS,
+ "Invalid arguments");
+ if (!p_msg)
+ return DBUS_HANDLER_RESULT_NEED_MEMORY;
+ REPLY_SEND;
+}
+
DBUS_METHOD( AddTrack )
{
REPLY_INIT;
@@ -135,41 +198,48 @@ DBUS_METHOD( GetTracksMetadata )
if( DBUS_TYPE_ARRAY != dbus_message_iter_get_arg_type( &in_args ) )
{
- msg_Err( (vlc_object_t*) p_this, "Invalid arguments" );
- return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ return InvalidArguments(p_conn, p_from, p_this);
}
dbus_message_iter_recurse( &in_args, &track_ids );
dbus_message_iter_open_container( &args, DBUS_TYPE_ARRAY, "a{sv}", &meta );
- while( DBUS_TYPE_OBJECT_PATH ==
- dbus_message_iter_get_arg_type( &track_ids ) )
+ bool id_valid = true;
+ while( DBUS_TYPE_OBJECT_PATH == dbus_message_iter_get_arg_type( &track_ids ) )
{
dbus_message_iter_get_basic( &track_ids, &psz_track_id );
if( 1 != sscanf( psz_track_id, MPRIS_TRACKID_FORMAT, &i_track_id ) )
{
- msg_Err( (vlc_object_t*) p_this, "Invalid track id: %s",
- psz_track_id );
- continue;
+ id_valid = false;
+ break;
}
- PL_LOCK;
- for( int i = 0; i < p_playlist->current.i_size; i++ )
+ playlist_item_t *item = NULL;
+ playlist_Lock(p_playlist);
+ item = playlist_ItemGetById(p_playlist, i_track_id);
+ if (item)
{
- playlist_item_t *item = p_playlist->current.p_elems[i];
+ GetInputMeta(item, &meta);
+ }
+ playlist_Unlock(p_playlist);
- if( item->i_id == i_track_id )
- {
- GetInputMeta( item, &meta );
- break;
- }
+ if (!item)
+ {
+ id_valid = false;
+ break;
}
- PL_UNLOCK;
dbus_message_iter_next( &track_ids );
}
+ if( !id_valid )
+ {
+ dbus_message_iter_abandon_container( &args, &meta );
+ dbus_message_unref(p_msg);
+ return InvalidTrackId(p_conn, p_from, psz_track_id, p_this);
+ }
+
dbus_message_iter_close_container( &args, &meta );
REPLY_SEND;
}
@@ -198,26 +268,21 @@ DBUS_METHOD( GoTo )
}
if( 1 != sscanf( psz_track_id, MPRIS_TRACKID_FORMAT, &i_track_id ) )
- {
- msg_Err( (vlc_object_t*) p_this, "Invalid track id %s", psz_track_id );
- return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
- }
+ goto invalid_track_id;
PL_LOCK;
+ playlist_item_t *item = playlist_ItemGetById( p_playlist, i_track_id );
+ if( item )
+ playlist_ViewPlay( p_playlist, item->p_parent, item );
+ PL_UNLOCK;
- for( int i = 0; i < p_playlist->current.i_size; i++ )
- {
- playlist_item_t *item = p_playlist->current.p_elems[i];
+ if( !item )
+ goto invalid_track_id;
- if( item->i_id == i_track_id )
- {
- playlist_ViewPlay( p_playlist, item->p_parent, item );
- break;
- }
- }
-
- PL_UNLOCK;
REPLY_SEND;
+
+invalid_track_id:
+ return InvalidTrackId(p_conn, p_from, psz_track_id, p_this);
}
DBUS_METHOD( RemoveTrack )
@@ -244,60 +309,66 @@ DBUS_METHOD( RemoveTrack )
}
if( 1 != sscanf( psz_id, MPRIS_TRACKID_FORMAT, &i_id ) )
- {
- msg_Err( (vlc_object_t*) p_this, "Invalid track id: %s", psz_id );
- return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
- }
+ goto invalid_track_id;
PL_LOCK;
+ playlist_item_t *item = playlist_ItemGetById( p_playlist, i_id );
+ if( item )
+ playlist_NodeDelete( p_playlist, item );
+ PL_UNLOCK;
- for( int i = 0; i < p_playlist->current.i_size; i++ )
- {
- playlist_item_t *item = p_playlist->current.p_elems[i];
-
- if( item->i_id == i_id )
- {
- playlist_NodeDelete( p_playlist, item );
- break;
- }
- }
+ if( !item )
+ goto invalid_track_id;
- PL_UNLOCK;
REPLY_SEND;
+
+invalid_track_id:
+ return InvalidTrackId(p_conn, p_from, psz_id, p_this);
+}
+
+static int MarshalTrack( DBusMessageIter *iter, int id )
+{
+ char *psz_track_id = NULL;
+ int ret = VLC_SUCCESS;
+
+ if (asprintf(&psz_track_id, MPRIS_TRACKID_FORMAT, id) == -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;
- playlist_t *p_playlist = p_intf->p_sys->p_playlist;
+ playlist_t *p_playlist = p_intf->p_sys->p_playlist;
dbus_message_iter_open_container( container, DBUS_TYPE_ARRAY, "o",
&tracks );
- PL_LOCK;
+ playlist_Lock(p_playlist);
for( int i = 0; i < p_playlist->current.i_size; i++ )
{
playlist_item_t *item = p_playlist->current.p_elems[i];
-
- if( ( -1 == asprintf( &psz_track_id,
- MPRIS_TRACKID_FORMAT,
- item->i_id ) ) ||
- !dbus_message_iter_append_basic( &tracks,
- DBUS_TYPE_OBJECT_PATH,
- &psz_track_id ) )
+ int err = MarshalTrack( &tracks, item->i_id );
+ if (err != VLC_SUCCESS)
{
- PL_UNLOCK;
+ playlist_Unlock(p_playlist);
dbus_message_iter_abandon_container( container, &tracks );
- return VLC_ENOMEM;
+ return err;
}
-
- free( psz_track_id );
}
- PL_UNLOCK;
+ playlist_Unlock(p_playlist);
if( !dbus_message_iter_close_container( container, &tracks ) )
return VLC_ENOMEM;
@@ -499,8 +570,66 @@ 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,
+ playlist_item_t *item )
+{
+ (void) index; // unused
+
+ 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(item, &meta);
+
+ if( unlikely(!dbus_message_iter_close_container( &args,
+ &meta )) )
+ return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+ if ( MarshalTrack( &args, item->i_id ) != 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 )
@@ -509,5 +638,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;
}
=====================================
modules/control/dbus/dbus_tracklist.h
=====================================
@@ -29,6 +29,7 @@
#include <vlc_common.h>
#include <vlc_interface.h>
+#include <vlc_playlist.h>
#include "dbus_common.h"
#define DBUS_MPRIS_TRACKLIST_INTERFACE "org.mpris.MediaPlayer2.TrackList"
@@ -37,6 +38,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;
+ 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,
+ 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 inline 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 inline 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,
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/18a5a49a6d9d0a2f9e5890faca567cb805417f1f...4c12f2eacbb094929e5066e9be285f9eded50f35
--
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/18a5a49a6d9d0a2f9e5890faca567cb805417f1f...4c12f2eacbb094929e5066e9be285f9eded50f35
You're receiving this email because of your account on code.videolan.org.
VideoLAN code repository instance
More information about the vlc-commits
mailing list