[vlc-devel] [PATCH 1/3] libvlc: media_player: add program API

Thomas Guillem thomas at gllm.fr
Fri Oct 2 15:53:48 CEST 2020


Add events, selection, and list API.

Like the for the media track list, this API use an opaque structure
libvlc_player_programlist_t to iterate through all programs. This avoid
the usage of *** from a public API.
---
 include/vlc/libvlc_events.h       |  17 +++
 include/vlc/libvlc_media_player.h | 131 ++++++++++++++++++++
 lib/libvlc.sym                    |   8 ++
 lib/media_player.c                | 196 ++++++++++++++++++++++++++----
 4 files changed, 329 insertions(+), 23 deletions(-)

diff --git a/include/vlc/libvlc_events.h b/include/vlc/libvlc_events.h
index 5cd545097e7..073e06893e9 100644
--- a/include/vlc/libvlc_events.h
+++ b/include/vlc/libvlc_events.h
@@ -129,6 +129,10 @@ enum libvlc_event_e {
     /** A track was updated, cf. media_player_es_changed in \ref
      * libvlc_event_t.u to get the id of the updated track. */
     libvlc_MediaPlayerESUpdated,
+    libvlc_MediaPlayerProgramAdded,
+    libvlc_MediaPlayerProgramDeleted,
+    libvlc_MediaPlayerProgramSelected,
+    libvlc_MediaPlayerProgramUpdated,
     /**
      * The title list changed, call
      * libvlc_media_player_get_full_title_descriptions() to get the new list.
@@ -370,6 +374,19 @@ typedef struct libvlc_event_t
             const char *psz_selected_id;
         } media_player_es_selection_changed;
 
+        /* ProgramAdded, ProgramDeleted, ProgramUpdated */
+        struct
+        {
+            int i_id;
+        } media_player_program_changed;
+
+        /* ProgramSelected */
+        struct
+        {
+            int i_unselected_id;
+            int i_selected_id;
+        } media_player_program_selection_changed;
+
         struct
         {
             float volume;
diff --git a/include/vlc/libvlc_media_player.h b/include/vlc/libvlc_media_player.h
index 7dec44f1af2..6f45ec69e06 100644
--- a/include/vlc/libvlc_media_player.h
+++ b/include/vlc/libvlc_media_player.h
@@ -1452,6 +1452,137 @@ int libvlc_media_player_add_slave( libvlc_media_player_t *p_mi,
                                    libvlc_media_slave_type_t i_type,
                                    const char *psz_uri, bool b_select );
 
+typedef struct libvlc_player_program_t
+{
+    /** Id used for libvlc_media_player_select_program() */
+    int i_group_id;
+    /** Program name, always valid */
+    char *psz_name;
+    /** True if the program is selected */
+    bool b_selected;
+    /** True if the program is scrambled */
+    bool b_scrambled;
+} libvlc_player_program_t;
+
+/**
+ * Opaque struct containing a list of program
+ */
+typedef struct libvlc_player_programlist_t libvlc_player_programlist_t;
+
+/**
+ * Delete a program struct
+ *
+ * \version LibVLC 4.0.0 and later.
+ *
+ * \param program returned by libvlc_media_player_get_selected_program() or
+ * libvlc_media_player_get_program_from_id()
+ *
+ */
+LIBVLC_API void
+libvlc_player_program_delete( libvlc_player_program_t *program );
+
+/**
+ * Get the number of programs in a programlist
+ *
+ * \version LibVLC 4.0.0 and later.
+ *
+ * \param list valid programlist
+ *
+ * \return number of programs, or 0 if the list is empty
+ */
+LIBVLC_API size_t
+libvlc_player_programlist_count( const libvlc_player_programlist_t *list );
+
+/**
+ * Get a program at a specific index
+ *
+ * \warning The behaviour is undefined if the index is not valid.
+ *
+ * \version LibVLC 4.0.0 and later.
+ *
+ * \param list valid programlist
+ * \param index valid index in the range [0; count[
+ *
+ * \return a valid program (can't be NULL if libvlc_player_programlist_count()
+ * returned a valid count)
+ */
+LIBVLC_API libvlc_player_program_t *
+libvlc_player_programlist_at( libvlc_player_programlist_t *list, size_t index );
+
+/**
+ * Release a programlist
+ *
+ * \version LibVLC 4.0.0 and later.
+ *
+ * \see libvlc_media_get_programlist
+ * \see libvlc_media_player_get_programlist
+ *
+ * \param list valid programlist
+ */
+LIBVLC_API void
+libvlc_player_programlist_delete( libvlc_player_programlist_t *list );
+
+/**
+ * Select program with a given program id.
+ *
+ * \note program ids are sent via the libvlc_MediaPlayerProgramAdded event or
+ * can be fetch via libvlc_media_player_get_programlist()
+ *
+ * \version LibVLC 4.0.0 or later
+ *
+ * \param p_mi opaque media player handle
+ * \param program_id
+ */
+LIBVLC_API void libvlc_media_player_select_program_id( libvlc_media_player_t *p_mi, int program_id);
+
+/**
+ * Get the selected program
+ *
+ * \version LibVLC 4.0.0 or later
+ *
+ * \param p_mi opaque media player handle
+ *
+ * \return a valid program struct or NULL if no programs are selected. The
+ * program need to be freed with libvlc_player_program_delete().
+ */
+LIBVLC_API libvlc_player_program_t *
+libvlc_media_player_get_selected_program( libvlc_media_player_t *p_mi);
+
+/**
+ * Get a program struct from a program id
+ *
+ * \version LibVLC 4.0.0 or later
+ *
+ * \param p_mi opaque media player handle
+ * \param i_group_id program id
+ *
+ * \return a valid program struct or NULL if the group_id is not found. The
+ * program need to be freed with libvlc_player_program_delete().
+ */
+LIBVLC_API libvlc_player_program_t *
+libvlc_media_player_get_program_from_id( libvlc_media_player_t *p_mi, int i_group_id );
+
+/**
+ * Get the program list
+ *
+ * \version LibVLC 4.0.0 and later.
+ * \note This program list is a snapshot of the current programs when this
+ * function is called. If a program is updated after this call, the user will
+ * need to call this function again to get the updated program.
+ *
+ * The program list can be used to get program informations and to select
+ * specific programs.
+ *
+ * \param p_mi the media player
+ * \param type type of the program list to request
+ *
+ * \return a valid libvlc_media_programlist_t or NULL in case of error or empty
+ * list, delete with libvlc_media_programlist_delete()
+ */
+LIBVLC_API libvlc_player_programlist_t *
+libvlc_media_player_get_programlist( libvlc_media_player_t *p_mi );
+
+
 /** \defgroup libvlc_video LibVLC video controls
  * @{
  */
diff --git a/lib/libvlc.sym b/lib/libvlc.sym
index ea3e886dbb0..ebdd2db6295 100644
--- a/lib/libvlc.sym
+++ b/lib/libvlc.sym
@@ -190,6 +190,14 @@ libvlc_media_player_select_track
 libvlc_media_player_unselect_track_type
 libvlc_media_player_select_tracks
 libvlc_media_player_select_tracks_by_ids
+libvlc_player_program_delete
+libvlc_player_programlist_count
+libvlc_player_programlist_at
+libvlc_player_programlist_delete
+libvlc_media_player_select_program_id
+libvlc_media_player_get_selected_program
+libvlc_media_player_get_program_from_id
+libvlc_media_player_get_programlist
 libvlc_media_release
 libvlc_media_retain
 libvlc_media_save_meta
diff --git a/lib/media_player.c b/lib/media_player.c
index 4db7f96af05..28b65c7ce37 100644
--- a/lib/media_player.c
+++ b/lib/media_player.c
@@ -306,20 +306,24 @@ on_program_list_changed(vlc_player_t *player,
                         enum vlc_player_list_action action,
                         const struct vlc_player_program *prgm, void* data)
 {
-    (void) action;
-    (void) prgm;
-
+    (void) player;
     libvlc_media_player_t *mp = data;
 
-    const struct vlc_player_program *selected =
-        vlc_player_GetSelectedProgram(player);
-    if (!selected)
-        return;
-
     libvlc_event_t event;
-    event.type = libvlc_MediaPlayerScrambledChanged;
-    event.u.media_player_scrambled_changed.new_scrambled = selected->scrambled;
+    switch (action)
+    {
+        case VLC_PLAYER_LIST_ADDED:
+            event.type = libvlc_MediaPlayerProgramAdded;
+            break;
+        case VLC_PLAYER_LIST_REMOVED:
+            event.type = libvlc_MediaPlayerProgramDeleted;
+            break;
+        case VLC_PLAYER_LIST_UPDATED:
+            event.type = libvlc_MediaPlayerProgramUpdated;
+            break;
+    }
 
+    event.u.media_player_program_changed.i_id = prgm->group_id;
     libvlc_event_send(&mp->event_manager, &event);
 }
 
@@ -327,22 +331,13 @@ static void
 on_program_selection_changed(vlc_player_t *player, int unselected_id,
                              int selected_id, void *data)
 {
-    (void) unselected_id;
-
+    (void) player;
     libvlc_media_player_t *mp = data;
 
-    if (selected_id == -1)
-        return;
-
-    const struct vlc_player_program *program =
-        vlc_player_GetSelectedProgram(player);
-
-    if (unlikely(program == NULL)) /* can happen when the player is stopping */
-        return;
-
     libvlc_event_t event;
-    event.type = libvlc_MediaPlayerScrambledChanged;
-    event.u.media_player_scrambled_changed.new_scrambled = program->scrambled;
+    event.type = libvlc_MediaPlayerProgramSelected;
+    event.u.media_player_program_selection_changed.i_unselected_id = unselected_id;
+    event.u.media_player_program_selection_changed.i_selected_id = selected_id;
 
     libvlc_event_send(&mp->event_manager, &event);
 }
@@ -2039,6 +2034,161 @@ int libvlc_media_player_set_equalizer( libvlc_media_player_t *p_mi, libvlc_equal
     return 0;
 }
 
+
+static libvlc_player_program_t *
+libvlc_player_program_new(const struct vlc_player_program *program)
+{
+    libvlc_player_program_t *libprogram = malloc(sizeof(*libprogram));
+    if (libprogram == NULL)
+        return NULL;
+
+    libprogram->i_group_id = program->group_id;
+    libprogram->psz_name = strdup(program->name);
+    libprogram->b_selected = program->selected;
+    libprogram->b_scrambled = program->scrambled;
+
+    return libprogram;
+}
+
+void
+libvlc_player_program_delete( libvlc_player_program_t *program )
+{
+    free( program->psz_name );
+    free( program );
+}
+
+void libvlc_media_player_select_program_id( libvlc_media_player_t *p_mi,
+                                            int program_id)
+{
+    vlc_player_t *player = p_mi->player;
+
+    vlc_player_Lock(player);
+
+    vlc_player_SelectProgram(player, program_id);
+
+    vlc_player_Unlock(player);
+}
+
+libvlc_player_program_t *
+libvlc_media_player_get_selected_program( libvlc_media_player_t *p_mi)
+{
+    vlc_player_t *player = p_mi->player;
+
+    vlc_player_Lock(player);
+
+    const struct vlc_player_program *program = vlc_player_GetSelectedProgram( player );
+    if( program == NULL )
+    {
+        vlc_player_Unlock(player);
+        return NULL;
+    }
+    libvlc_player_program_t *libprogram = libvlc_player_program_new(program);
+
+    vlc_player_Unlock(player);
+
+    return libprogram;
+}
+
+libvlc_player_program_t *
+libvlc_media_player_get_program_from_id( libvlc_media_player_t *p_mi, int i_group_id )
+{
+    vlc_player_t *player = p_mi->player;
+
+    vlc_player_Lock(player);
+
+    libvlc_player_program_t *libprogram = NULL;
+
+    size_t count = vlc_player_GetProgramCount(player);
+    for (size_t i = 0; i < count; ++i)
+    {
+        const struct vlc_player_program *program =
+            vlc_player_GetProgramAt(player, i);
+        assert(program);
+        if (program->group_id == i_group_id)
+        {
+            libprogram = libvlc_player_program_new(program);
+            break;
+        }
+    }
+
+    vlc_player_Unlock(player);
+
+    return libprogram;
+}
+
+struct libvlc_player_programlist_t
+{
+    size_t count;
+    libvlc_player_program_t *programs[];
+};
+
+size_t
+libvlc_player_programlist_count( const libvlc_player_programlist_t *list )
+{
+    return list->count;
+}
+
+libvlc_player_program_t *
+libvlc_player_programlist_at( libvlc_player_programlist_t *list, size_t index )
+{
+    assert(index < list->count);
+    return list->programs[index];
+}
+
+void
+libvlc_player_programlist_delete( libvlc_player_programlist_t *list )
+{
+    for (size_t i = 0; i < list->count; ++i)
+        libvlc_player_program_delete(list->programs[i]);
+    free(list);
+}
+
+libvlc_player_programlist_t *
+libvlc_media_player_get_programlist( libvlc_media_player_t *p_mi )
+{
+    vlc_player_t *player = p_mi->player;
+
+    vlc_player_Lock(player);
+
+    size_t count = vlc_player_GetProgramCount(player);
+    if (count == 0)
+        goto error;
+
+    size_t size;
+    if( mul_overflow( count, sizeof(libvlc_player_program_t *), &size) )
+        goto error;
+    if( add_overflow( size, sizeof(libvlc_player_programlist_t), &size) )
+        goto error;
+
+    libvlc_player_programlist_t *list = malloc( size );
+    if( list == NULL )
+        goto error;
+
+    list->count = 0;
+    for (size_t i = 0; i < count; ++i)
+    {
+        const struct vlc_player_program *program =
+            vlc_player_GetProgramAt(player, i);
+        assert(program);
+        list->programs[i] = libvlc_player_program_new(program);
+        if (list->programs[i] == NULL)
+        {
+            libvlc_player_programlist_delete(list);
+            goto error;
+        }
+
+        list->count++;
+    }
+
+    vlc_player_Unlock(player);
+
+    return list;
+
+error:
+    vlc_player_Unlock(player);
+    return NULL;
+}
+
 static const char roles[][16] =
 {
     [libvlc_role_Music] =         "music",
-- 
2.28.0



More information about the vlc-devel mailing list