[vlc-devel] [PATCH] Add module to submit listens to ListenBrainz.

Kartik Ohri kartikohri13 at gmail.com
Tue Mar 10 15:13:57 CET 2020


On Tue, Mar 10, 2020 at 12:59 PM Thomas Guillem <thomas at gllm.fr> wrote:

> Hello, thanks for the new patches,
>
> cf. my comments
>
> On Sun, Mar 8, 2020, at 18:14, Kartik Ohri wrote:
> > From: "Kartik Ohri kartikohri13 at gmail.com" <kartikohri13 at gmail.com>
> >
> > VLC already has the audioscrobbler module to submit scrobbles to
> > last.fm and other services with a similar API. This module extends
> > that functionality to allow submission of listens to ListenBrainz.
> > The existing audioscrobbler module is incompatible with ListenBrainz
> > due to difference in authentication procedures and REST API for
> > submissions.
> >
> > The term scrobble is a trademarked term by Last.fm, therefore the
> > term listen used instead. More information about ListenBrainz is
> > available at listenbrainz [dot] org.
> > ---
> >  modules/misc/Makefile.am    |   4 +
> >  modules/misc/listenbrainz.c | 583 ++++++++++++++++++++++++++++++++++++
> >  2 files changed, 587 insertions(+)
> >  create mode 100755 modules/misc/listenbrainz.c
> >
> > diff --git a/modules/misc/Makefile.am b/modules/misc/Makefile.am
> > index 78f9b09710..ed3ef24ee6 100644
> > --- a/modules/misc/Makefile.am
> > +++ b/modules/misc/Makefile.am
> > @@ -8,6 +8,10 @@ libaudioscrobbler_plugin_la_SOURCES =
> misc/audioscrobbler.c
> >  libaudioscrobbler_plugin_la_LIBADD = $(SOCKET_LIBS)
> >  misc_LTLIBRARIES += libaudioscrobbler_plugin.la
> >
> > +liblistenbrainz_plugin_la_SOURCES = misc/listenbrainz.c
> > +liblistenbrainz_plugin_la_LIBADD = $(SOCKET_LIBS)
> > +misc_LTLIBRARIES += liblistenbrainz_plugin.la
> > +
> >  libexport_plugin_la_SOURCES = \
> >       misc/playlist/html.c \
> >       misc/playlist/m3u.c \
> > diff --git a/modules/misc/listenbrainz.c b/modules/misc/listenbrainz.c
> > new file mode 100755
> > index 0000000000..d75b87ba2e
> > --- /dev/null
> > +++ b/modules/misc/listenbrainz.c
> > @@ -0,0 +1,583 @@
> >
> +/*****************************************************************************
> > + * listenbrainz.c : ListenBrainz submission plugin
> > + * ListenBrainz Submit Listens API 1
> > + * https://api.listenbrainz.org/1/submit-listens
> > +
> >
> *****************************************************************************
> > + * Author: Kartik Ohri <kartikohri13 at gmail dot com>
> > + *
> > + * Copyright (C) 2020 VLC authors and VideoLAN
>
> Author should be bellow Copyright
>
> > + *
> > + * This program is free software; you can redistribute it and/or
> > modify it
> > + * under the terms of the GNU Lesser General Public License as
> > published by
> > + * the Free Software Foundation; either version 2.1 of the License, or
> > + * (at your option) any later version.
> > + *
> > + * This program is distributed in the hope that it will be useful,
> > + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> > + * GNU Lesser General Public License for more details.
> > + *
> > + * You should have received a copy of the GNU Lesser General Public
> > License
> > + * along with this program; if not, write to the Free Software
> > Foundation,
> > + * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
> > +
> >
> *****************************************************************************/
> > +
> > +#ifdef HAVE_CONFIG_H
> > +#include "config.h"
> > +#endif
> > +
> > +#include <assert.h>
> > +#include <time.h>
> > +
> > +#include <vlc_common.h>
> > +#include <vlc_plugin.h>
> > +#include <vlc_interface.h>
> > +#include <vlc_input_item.h>
> > +#include <vlc_dialog.h>
> > +#include <vlc_meta.h>
> > +#include <vlc_memstream.h>
> > +#include <vlc_stream.h>
> > +#include <vlc_url.h>
> > +#include <vlc_tls.h>
> > +#include <vlc_player.h>
> > +#include <vlc_playlist.h>
> > +#include <vlc_vector.h>
> > +
> > +typedef struct listen_t
> > +{
> > +    char *psz_artist;
> > +    char *psz_title;
> > +    char *psz_album;
> > +    char *psz_track_number;
> > +    int i_length;
> > +    char *psz_musicbrainz_id;
> > +    time_t date;
> > +} listen_t;
> > +
> > +typedef struct VLC_VECTOR (listen_t) vlc_vector_listen_t;
> > +
> > +struct intf_sys_t
> > +{
> > +    vlc_vector_listen_t p_queue;
>
> You don't have to add p_, that stand for pointer since the vector is not a
> pointer.
> By the way, we tend to not use this old Hungarian notation in new code.
>
> > +
> > +    vlc_playlist_t *playlist;
> > +    struct vlc_playlist_listener_id *playlist_listener;
> > +    struct vlc_player_listener_id *player_listener;
> > +    struct vlc_player_timer_id *timer_listener;
> > +
> > +    vlc_mutex_t lock;
> > +    vlc_cond_t wait;                // song to submit event
> > +    vlc_thread_t thread;            // thread to submit song
> > +
> > +    struct vlc_memstream payload, request;
>
> These 2 variables should be local to the Run() function. Cf. my comment on
> PreparePayload()
>
> > +
> > +    vlc_url_t p_submit_url;         // where to submit data
> > +    char *psz_user_token;           // authentication token
> > +
> > +    listen_t p_current_song;
> > +    bool b_meta_read;               // check if song metadata is
> > already read
> > +
> > +    int64_t i_played_time;
>
> You should use a vlc_tick_t and...
>
> > +};
> > +
> > +static int Open (vlc_object_t *);
> > +
> > +static void Close (vlc_object_t *);
> > +
> > +static void *Run (void *);
> > +
> > +#define USER_TOKEN_TEXT      N_("User token")
> > +#define USER_TOKEN_LONGTEXT  N_("The user token of your ListenBrainz
> > account")
> > +#define URL_TEXT             N_("Submission URL")
> > +#define URL_LONGTEXT         N_("The URL set for an alternative
> > ListenBrainz instance")
> > +
> >
> +/****************************************************************************
> > + * Module descriptor
> > +
> >
> ****************************************************************************/
> > +
> > +vlc_module_begin ()
> > +    set_category(CAT_INTERFACE)
> > +    set_subcategory(SUBCAT_INTERFACE_CONTROL)
> > +    set_shortname (N_ ("ListenBrainz"))
> > +    set_description (N_ ("Submit listens to ListenBrainz"))
> > +    add_string("listenbrainz_user_token", "", USER_TOKEN_TEXT,
> > USER_TOKEN_LONGTEXT, false)
> > +    add_string("listenbrainz_submission_url", "api.listenbrainz.org",
> > URL_TEXT, URL_LONGTEXT, false)
> > +    set_capability("interface", 0)
> > +    set_callbacks(Open, Close)
> > +vlc_module_end ()
> > +
> > +static void DeleteSong (listen_t *p_song)
> > +{
> > +    FREENULL (p_song->psz_artist);
> > +    FREENULL (p_song->psz_album);
> > +    FREENULL (p_song->psz_title);
> > +    FREENULL (p_song->psz_musicbrainz_id);
> > +    FREENULL (p_song->psz_track_number);
> > +    p_song->date = 0;
> > +}
> > +
> > +static void ReadMetaData (intf_thread_t *p_this)
> > +{
> > +    bool b_skip = 0;
> > +    intf_sys_t *p_sys = p_this->p_sys;
> > +
> > +    vlc_player_t *player = vlc_playlist_GetPlayer (p_sys->playlist);
> > +    input_item_t *item = vlc_player_GetCurrentMedia (player);
> > +    if ( item == NULL )
> > +        return;
> > +
> > +    vlc_mutex_lock (&p_sys->lock);
> > +
> > +    p_sys->b_meta_read = true;
> > +    time (&p_sys->p_current_song.date);
>
> use p_sys->p_current_song.date = vlc_tick_now() here
>
> I want to obtain the UNIX Timestamp here. But vlc_tick_now will give a
relative timer instead. I don't think vlc_tick_now() serves the purpose.

> > +
> > +#define RETRIEVE_METADATA(a, b) do { \
> > +        char *psz_data = input_item_Get##b(item); \
> > +        if (psz_data && *psz_data) \
> > +            a = vlc_uri_encode(psz_data); \
> > +        free(psz_data); \
> > +    } while (0)
> > +
> > +    RETRIEVE_METADATA(p_sys->p_current_song.psz_artist, Artist);
> > +    if ( !p_sys->p_current_song.psz_artist )
> > +    {
> > +        msg_Dbg (p_this, "Artist missing.");
> > +        DeleteSong (&p_sys->p_current_song);
> > +        b_skip = 1;
> > +    }
> > +
> > +    RETRIEVE_METADATA(p_sys->p_current_song.psz_title, Title);
> > +    if ( b_skip || !p_sys->p_current_song.psz_title )
> > +    {
> > +        msg_Dbg (p_this, "Track name missing.");
> > +        DeleteSong (&p_sys->p_current_song);
> > +        b_skip = 1;
> > +    }
> > +
> > +    if ( !b_skip )
> > +    {
> > +        RETRIEVE_METADATA(p_sys->p_current_song.psz_album, Album);
> > +        RETRIEVE_METADATA(p_sys->p_current_song.psz_musicbrainz_id,
> > TrackID);
> > +        RETRIEVE_METADATA(p_sys->p_current_song.psz_track_number,
> > TrackNum);
> > +        p_sys->p_current_song.i_length = SEC_FROM_VLC_TICK
> > (input_item_GetDuration (item));
> > +        msg_Dbg (p_this, "Meta data registered");
> > +        vlc_cond_signal (&p_sys->wait);
> > +    }
> > +    vlc_mutex_unlock (&p_sys->lock);
> > +
> > +#undef RETRIEVE_METADATA
> > +}
> > +
> > +static listen_t CopySong (listen_t song)
> > +{
> > +    listen_t *copy = (listen_t *) malloc (sizeof (*copy));
> > +    memset (copy, 0, sizeof (*copy));
> > +    if ( song.psz_title )
> > +        copy->psz_title = strdup (song.psz_title);
> > +    if ( song.psz_artist )
> > +        copy->psz_artist = strdup (song.psz_artist);
> > +    if ( song.psz_album )
> > +        copy->psz_album = strdup (song.psz_album);
> > +    if ( song.psz_musicbrainz_id )
> > +        copy->psz_musicbrainz_id = strdup (song.psz_musicbrainz_id);
> > +    if ( song.psz_track_number )
> > +        copy->psz_track_number = strdup (song.psz_track_number);
> > +    copy->date = song.date;
> > +    return *copy;
> > +}
> > +
> > +static void Enqueue (intf_thread_t *p_this)
> > +{
> > +    bool b_skip = 0;
> > +    intf_sys_t *p_sys = p_this->p_sys;
> > +
> > +    vlc_mutex_lock (&p_sys->lock);
> > +
> > +    if ( !p_sys->p_current_song.psz_artist ||
> > !*p_sys->p_current_song.psz_artist ||
> > +         !p_sys->p_current_song.psz_title ||
> > !*p_sys->p_current_song.psz_title )
> > +    {
> > +        msg_Dbg (p_this, "Missing artist or title, not submitting");
> > +        b_skip = 1;
> > +    }
> > +
> > +    if ( p_sys->p_current_song.i_length == 0 )
> > +        p_sys->p_current_song.i_length = p_sys->i_played_time;
> > +
> > +    if ( !b_skip && p_sys->i_played_time < 30 )
> > +    {
> > +        msg_Dbg (p_this, "Song not listened long enough, not
> > submitting");
> > +        b_skip = 1;
> > +    }
> > +
> > +    if ( !b_skip )
> > +    {
> > +        msg_Dbg (p_this, "Song will be submitted.");
> > +        listen_t p_copy_to_queue = CopySong (p_sys->p_current_song);
> > +        bool b_success = vlc_vector_push (&p_sys->p_queue,
> > p_copy_to_queue);
> > +        if ( !b_success )
> > +            msg_Warn (p_this, "Error: Unable to enqueue song");
>
> You don't need to log small allocation error since it's very very unlikely
> to happen
>
> > +    }
> > +
> > +    vlc_cond_signal (&p_sys->wait);
> > +    DeleteSong (&p_sys->p_current_song);
> > +    p_sys->b_meta_read = false;
> > +    vlc_mutex_unlock (&p_sys->lock);
> > +}
> > +
> > +static void PlayerStateChanged (vlc_player_t *player, enum
> > vlc_player_state state, void *data)
> > +{
> > +    intf_thread_t *intf = data;
> > +    intf_sys_t *p_sys = intf->p_sys;
> > +
> > +    if ( vlc_player_GetVideoTrackCount (player) )
> > +    {
> > +        msg_Dbg (intf, "Not an audio-only input, not submitting");
> > +        return;
> > +    }
> > +
> > +    if ( !p_sys->b_meta_read && state >= VLC_PLAYER_STATE_PLAYING )
> > +    {
> > +        ReadMetaData (intf);
> > +        return;
> > +    }
> > +
> > +    if ( state == VLC_PLAYER_STATE_STOPPED )
> > +        Enqueue (intf);
> > +}
> > +
> > +static void UpdateState (const struct vlc_player_timer_point *value,
>
> This function name doesn't reflect the actual callback. It should be
> something like OnTimerUpdate.
>
> > void *data)
> > +{
> > +    intf_thread_t *intf = data;
> > +    intf_sys_t *p_sys = intf->p_sys;
> > +    p_sys->i_played_time = SEC_FROM_VLC_TICK (value->ts - VLC_TICK_0);
> > +}
> > +
> > +static void PlayingStopped (vlc_tick_t system_date, void *data){}
>
> Same for PlayingStopped
>
> > +
> > +static void PlaylistItemChanged (vlc_playlist_t *playlist, ssize_t
> > index, void *data)
> > +{
> > +    VLC_UNUSED (index);
> > +
> > +    intf_thread_t *intf = data;
> > +    if ( index > 0 )
> > +        Enqueue (intf);
> > +
> > +    intf_sys_t *p_sys = intf->p_sys;
> > +    p_sys->b_meta_read = false;
> > +
> > +    vlc_player_t *player = vlc_playlist_GetPlayer (playlist);
> > +    input_item_t *item = vlc_player_GetCurrentMedia (player);
> > +
> > +    if ( !item || vlc_player_GetVideoTrackCount (player) )
> > +    {
> > +        msg_Dbg (intf, "Invalid item or not an audio-only input.");
> > +        return;
> > +    }
> > +
> > +    p_sys->i_played_time = 0;
> > +
> > +    if ( input_item_IsPreparsed (item) )
> > +        ReadMetaData (intf);
> > +}
> > +
> > +static int PreparePayload (intf_thread_t *p_this)
> > +{
> > +    intf_sys_t *p_sys = p_this->p_sys;
> > +    struct vlc_memstream payload;
> > +    vlc_memstream_open (&payload);
> > +
> > +    vlc_mutex_lock (&p_sys->lock);
> > +
> > +    if ( p_sys->p_queue.size == 1 )
> > +        vlc_memstream_printf (&payload,
> > "{\"listen_type\":\"single\",\"payload\":[");
> > +    else
> > +        vlc_memstream_printf (&payload,
> > "{\"listen_type\":\"import\",\"payload\":[");
> > +
> > +    for ( int i_song = 0; i_song < (int) p_sys->p_queue.size; i_song++
> > )
> > +    {
> > +        listen_t *p_song = &p_sys->p_queue.data[i_song];
> > +
> > +        vlc_memstream_printf (&payload, "{\"listened_at\": %"PRIu64,
> > (uint64_t) p_song->date);
> > +        vlc_memstream_printf (&payload, ", \"track_metadata\":
> > {\"artist_name\": \"%s\", ",
> > +                              vlc_uri_decode (p_song->psz_artist));
> > +        vlc_memstream_printf (&payload, " \"track_name\": \"%s\", ",
> > vlc_uri_decode (p_song->psz_title));
> > +        if ( !EMPTY_STR (p_song->psz_album) )
> > +            vlc_memstream_printf (&payload, " \"release_name\":
> > \"%s\"", vlc_uri_decode (p_song->psz_album));
> > +        if ( !EMPTY_STR (p_song->psz_musicbrainz_id) )
> > +            vlc_memstream_printf (&payload, ", \"additional_info\":
> > {\"recording_mbid\":\"%s\"} ",
> > +                                  vlc_uri_decode
> > (p_song->psz_musicbrainz_id));
> > +        vlc_memstream_printf (&payload, "}}");
> > +    }
> > +
> > +    vlc_memstream_printf (&payload, "]}");
> > +    vlc_mutex_unlock (&p_sys->lock);
> > +
> > +    int i_status = vlc_memstream_close (&payload);
> > +    if ( !i_status )
> > +        p_sys->payload = payload;
>
> After closing (with success), you can get the result of the memstream with
> payload.ptr (that you should free after usage).
> Therefore, you don't have to keep the memstream object.
>
> > +    msg_Dbg (p_this, "Payload: %s", payload.ptr);
> > +    return i_status;
>
> This function should return payload.ptr instead.
>
> > +}
> > +
> > +static int PrepareRequest (intf_thread_t *p_this)
> > +{
> > +    intf_sys_t *p_sys = p_this->p_sys;
> > +    struct vlc_memstream request;
> > +
> > +    vlc_mutex_lock (&p_sys->lock);
> > +
> > +    vlc_memstream_open (&request);
> > +    vlc_memstream_printf (&request, "POST %s HTTP/1.1\r\n",
> > p_sys->p_submit_url.psz_path);
> > +    vlc_memstream_printf (&request, "Host: %s\r\n",
> > p_sys->p_submit_url.psz_host);
> > +    vlc_memstream_printf (&request, "Authorization: Token %s\r\n",
> > p_sys->psz_user_token);
> > +    vlc_memstream_puts (&request, "User-Agent:
> > "PACKAGE"/"VERSION"\r\n");
> > +    vlc_memstream_puts (&request, "Connection: close\r\n");
> > +    vlc_memstream_puts (&request, "Accept-Encoding: identity\r\n");
> > +    vlc_memstream_printf (&request, "Content-Length: %zu\r\n",
> > p_sys->payload.length);
> > +    vlc_memstream_puts (&request, "\r\n");
> > +    vlc_memstream_write (&request, p_sys->payload.ptr,
> > p_sys->payload.length);
> > +    vlc_memstream_puts (&request, "\r\n\r\n");
> > +
> > +    free (p_sys->payload.ptr);
> > +
> > +    vlc_mutex_unlock (&p_sys->lock);
> > +
> > +    int i_status = vlc_memstream_close (&request);
> > +    if ( !i_status )
> > +        p_sys->request = request;
> > +    return i_status;
>
> Same here.
>
> > +}
> > +
> > +static int SendRequest (intf_thread_t *p_this)
> > +{
> > +    uint8_t p_buffer[1024];
> > +    int i_ret;
> > +
> > +    intf_sys_t *p_sys = p_this->p_sys;
> > +    vlc_tls_client_t *creds = vlc_tls_ClientCreate (VLC_OBJECT
> > (p_this));
> > +    vlc_tls_t *sock = vlc_tls_SocketOpenTLS (creds,
> > p_sys->p_submit_url.psz_host, 443, NULL, NULL, NULL);
> > +
> > +    if ( sock == NULL )
> > +    {
> > +        free (p_sys->request.ptr);
> > +        return 1;
> > +    }
> > +
> > +    i_ret = vlc_tls_Write (sock, p_sys->request.ptr,
> > p_sys->request.length);
> > +    free (p_sys->request.ptr);
> > +
> > +    if ( i_ret == -1 )
> > +    {
> > +        vlc_tls_Close (sock);
> > +        return 1;
> > +    }
> > +
> > +    i_ret = vlc_tls_Read (sock, p_buffer, sizeof (p_buffer) - 1,
> > false);
> > +    msg_Dbg (p_this, "Response: %s", (char *) p_buffer);
> > +    vlc_tls_Close (sock);
> > +    if ( i_ret <= 0 )
> > +    {
> > +        msg_Warn (p_this, "No response");
> > +        return 1;
> > +    }
> > +    p_buffer[i_ret] = '\0';
> > +    if ( strstr ((char *) p_buffer, "OK") )
> > +    {
> > +        vlc_vector_clear (&p_sys->p_queue);
> > +        msg_Dbg (p_this, "Submission successful!");
> > +    }
> > +    else
> > +    {
> > +        msg_Warn (p_this, "Error: %s", (char *) p_buffer);
> > +        return 1;
> > +    }
> > +
> > +    return 0;
> > +}
> > +
> > +static int Open (vlc_object_t *p_this)
> > +{
> > +    intf_thread_t *p_intf = (intf_thread_t *) p_this;
> > +    intf_sys_t *p_sys = calloc (1, sizeof (intf_sys_t));
> > +    bool b_fail = 0;
> > +    int i_ret;
> > +    char *psz_submission_url, *psz_url;
> > +
> > +    if ( !p_sys )
> > +        return VLC_ENOMEM;
> > +
> > +    p_intf->p_sys = p_sys;
> > +
> > +    p_sys->psz_user_token = var_InheritString (p_intf,
> > "listenbrainz_user_token");
> > +    if ( EMPTY_STR (p_sys->psz_user_token) )
> > +    {
> > +        free (p_sys->psz_user_token);
> > +        vlc_dialog_display_error (p_intf,
> > +                                  _ ("ListenBrainz User Token not
> > set"), "%s",
> > +                                  _ ("Please set a user token or
> > disable the ListenBrainz plugin, and restart VLC.\n"
> > +                                     " Visit
> > https://listenbrainz.org/profile/ to get a user token."));
> > +        free (p_sys);
> > +        return VLC_EGENERIC;
> > +    }
> > +
> > +    psz_submission_url = var_InheritString (p_intf,
> > "listenbrainz_submission_url");
> > +    if ( psz_submission_url )
> > +    {
> > +        i_ret = asprintf (&psz_url, "https://%s/1/submit-listens",
> > psz_submission_url);
> > +        free (psz_submission_url);
> > +        if ( i_ret == -1 )
> > +            b_fail = 1;
> > +        vlc_UrlParse (&p_sys->p_submit_url, psz_url);
> > +        free (psz_url);
> > +    }
> > +    else
> > +        b_fail = 1;
> > +
> > +    if ( b_fail )
> > +    {
> > +        vlc_dialog_display_error (p_intf,
> > +                                  _ ("ListenBrainz API URL Invalid"),
> > "%s",
> > +                                  _ ("Please set a valid endpoint URL.
> > The default value is api.listenbrainz.org ."));
> > +        free (p_sys);
> > +        return VLC_EGENERIC;
> > +    }
> > +
> > +    static struct vlc_playlist_callbacks const playlist_cbs =
> > +            {
> > +                    .on_current_index_changed = PlaylistItemChanged,
> > +            };
> > +    static struct vlc_player_cbs const player_cbs =
> > +            {
> > +                    .on_state_changed = PlayerStateChanged,
> > +            };
> > +    static struct vlc_player_timer_cbs const timer_cbs =
> > +            {
> > +                    .on_update = UpdateState,
> > +                    .on_discontinuity = PlayingStopped,
> > +            };
> > +
> > +    vlc_playlist_t *playlist = p_sys->playlist =
> > vlc_intf_GetMainPlaylist (p_intf);
> > +    vlc_player_t *player = vlc_playlist_GetPlayer (playlist);
> > +
> > +    vlc_playlist_Lock (playlist);
> > +    p_sys->playlist_listener = vlc_playlist_AddListener (playlist,
> > &playlist_cbs, p_intf, false);
> > +    if ( !p_sys->playlist_listener )
> > +    {
> > +        vlc_playlist_Unlock (playlist);
> > +        b_fail = 1;
> > +    }
> > +    else
> > +    {
> > +        p_sys->player_listener = vlc_player_AddListener (player,
> > &player_cbs, p_intf);
> > +        vlc_playlist_Unlock (playlist);
> > +        if ( !p_sys->player_listener )
> > +            b_fail = 1;
> > +        else
> > +        {
> > +            p_sys->timer_listener = vlc_player_AddTimer (player,
> > VLC_TICK_FROM_SEC (1), &timer_cbs, p_intf);
> > +            if ( !p_sys->timer_listener )
> > +                b_fail = 1;
> > +        }
> > +    }
> > +    if ( !b_fail )
> > +    {
> > +        vlc_mutex_init (&p_sys->lock);
> > +        vlc_cond_init (&p_sys->wait);
> > +
> > +        if ( vlc_clone (&p_sys->thread, Run, p_intf,
> > VLC_THREAD_PRIORITY_LOW) )
> > +            b_fail = 1;
> > +    }
> > +    if ( b_fail )
>
> This b_fail is quite hard to follow, I would suggest using goto error;
> like it's done in Activate() in modules/control/rc.c.
>
> > +    {
> > +        if ( p_sys->playlist_listener )
> > +        {
> > +            vlc_playlist_Lock (playlist);
> > +            if ( p_sys->player_listener )
> > +                vlc_player_RemoveListener (player,
> > p_sys->player_listener);
> > +            if ( p_sys->timer_listener )
> > +                vlc_player_RemoveTimer (player, p_sys->timer_listener);
> > +            vlc_playlist_RemoveListener (playlist,
> > p_sys->playlist_listener);
> > +            vlc_playlist_Unlock (playlist);
> > +        }
> > +        free (p_sys);
> > +        return VLC_EGENERIC;
> > +    }
> > +
> > +    return VLC_SUCCESS;
> > +}
> > +
> > +static void Close (vlc_object_t *p_this)
> > +{
> > +    intf_thread_t *p_intf = (intf_thread_t *) p_this;
> > +    intf_sys_t *p_sys = p_intf->p_sys;
> > +    vlc_playlist_t *playlist = p_sys->playlist;
> > +
> > +    vlc_cancel (p_sys->thread);
> > +    vlc_join (p_sys->thread, NULL);
> > +
> > +    vlc_vector_clear (&p_sys->p_queue);
> > +    vlc_UrlClean (&p_sys->p_submit_url);
> > +
> > +    vlc_playlist_Lock (playlist);
> > +    vlc_player_RemoveListener (vlc_playlist_GetPlayer (playlist),
> > p_sys->player_listener);
> > +    vlc_playlist_RemoveListener (playlist, p_sys->playlist_listener);
> > +    vlc_playlist_Unlock (playlist);
> > +
> > +    free (p_sys);
> > +}
> > +
> > +static void *Run (void *data)
> > +{
> > +    intf_thread_t *p_intf = data;
> > +    int canc = vlc_savecancel ();
> > +    int i_status;
> > +    bool b_wait = 0;
> > +
> > +    intf_sys_t *p_sys = p_intf->p_sys;
> > +
> > +    while ( 1 )
> > +    {
> > +        vlc_restorecancel (canc);
> > +
> > +        if ( b_wait )
> > +            vlc_tick_wait (vlc_tick_now () + VLC_TICK_FROM_SEC (60));
> > // wait for 1 min
> > +
> > +        vlc_mutex_lock (&p_sys->lock);
> > +        mutex_cleanup_push (&p_sys->lock) ;
> > +
> > +                while ( p_sys->p_queue.size == 0 )
> > +                    vlc_cond_wait (&p_sys->wait, &p_sys->lock);
> > +
> > +        vlc_cleanup_pop ();
> > +        vlc_mutex_unlock (&p_sys->lock);
> > +        canc = vlc_savecancel ();
> > +
> > +        i_status = PreparePayload (p_intf);
> > +        if ( i_status )
> > +        {
> > +            msg_Warn (p_intf, "Error: Unable to generate payload");
> > +            break;
> > +        }
> > +
> > +        i_status = PrepareRequest (p_intf);
> > +        if ( i_status )
> > +        {
> > +            msg_Warn (p_intf, "Error: Unable to generate request
> > body");
> > +            break;
> > +        }
> > +
> > +        i_status = SendRequest (p_intf);
> > +        if ( i_status )
> > +        {
> > +            msg_Warn (p_intf, "Error: Could not transmit request");
> > +            b_wait = 1;
> > +            continue;
> > +        }
> > +
> > +        b_wait = 0;
> > +    }
> > +
> > +    vlc_restorecancel (canc);
> > +    return NULL;
> > +}
> > +
> > --
> > 2.20.1
> >
> > _______________________________________________
> > vlc-devel mailing list
> > To unsubscribe or modify your subscription options:
> > https://mailman.videolan.org/listinfo/vlc-devel
> _______________________________________________
> vlc-devel mailing list
> To unsubscribe or modify your subscription options:
> https://mailman.videolan.org/listinfo/vlc-devel
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mailman.videolan.org/pipermail/vlc-devel/attachments/20200310/484e3399/attachment.html>


More information about the vlc-devel mailing list