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

Thomas Guillem thomas at gllm.fr
Mon Mar 30 14:53:04 CEST 2020


Still planned to do it. I'm working from home with a baby, so don't trust the deadlines I give you...

On Mon, Mar 30, 2020, at 14:49, Kartik Ohri wrote:
> Hi! Its been a few days so I wanted to ask were you able to test the patch and how did the testing go ?
> 
> On Thu, Mar 26, 2020 at 4:47 PM Kartik Ohri <kartikohri13 at gmail.com> wrote:
>> Thanks for volunteering to test. I tested the plugin myself again with the new changes to make sure you don't encounter much errors. I made a fix to prevent a segmentation fault issue. I don't know how to use asan otherwise I would have tested with it as well.
>> 
>> On Thu, Mar 26, 2020 at 4:41 PM Kartik Ohri <kartikohri13 at gmail.com> 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 | 545 ++++++++++++++++++++++++++++++++++++
>>>  2 files changed, 549 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..74571efdaa
>>>  --- /dev/null
>>>  +++ b/modules/misc/listenbrainz.c
>>>  @@ -0,0 +1,545 @@
>>>  +/*****************************************************************************
>>>  + * listenbrainz.c : ListenBrainz submission plugin
>>>  + * ListenBrainz Submit Listens API 1
>>>  + * https://api.listenbrainz.org/1/submit-listens
>>>  + *****************************************************************************
>>>  + * Copyright (C) 2020 VLC authors and VideoLAN
>>>  + *
>>>  + * Author: Kartik Ohri <kartikohri13 at gmail dot com>
>>>  + *
>>>  + * 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>
>>>  +#include <vlc_interrupt.h>
>>>  +
>>>  +typedef struct listen_t {
>>>  + char *psz_artist;
>>>  + char *psz_title;
>>>  + char *psz_album;
>>>  + char *psz_track_number;
>>>  + int i_length;
>>>  + char *psz_musicbrainz_recording_id;
>>>  + time_t date;
>>>  +} listen_t;
>>>  +
>>>  +typedef struct VLC_VECTOR (listen_t) vlc_vector_listen_t;
>>>  +
>>>  +struct intf_sys_t {
>>>  + vlc_vector_listen_t queue;
>>>  +
>>>  + vlc_player_t *player;
>>>  + 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
>>>  + vlc_interrupt_t *interrupt;
>>>  + bool live;
>>>  +
>>>  + 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
>>>  + vlc_tick_t time_played;
>>>  +};
>>>  +
>>>  +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_recording_id);
>>>  + FREENULL (p_song->psz_track_number);
>>>  + p_song->date = 0;
>>>  +}
>>>  +
>>>  +static void ReadMetaData (intf_thread_t *p_this , input_item_t *item)
>>>  +{
>>>  + intf_sys_t *p_sys = p_this->p_sys;
>>>  +
>>>  + if (item == NULL)
>>>  + return;
>>>  +
>>>  + vlc_mutex_lock (&p_sys->lock);
>>>  +
>>>  + p_sys->b_meta_read = true;
>>>  + time (&p_sys->p_current_song.date);
>>>  +
>>>  +#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); \
>>>  + else \
>>>  + msg_Dbg (p_this, #b" missing."); \
>>>  + free(psz_data); \
>>>  + } while (0)
>>>  +
>>>  + RETRIEVE_METADATA(p_sys->p_current_song.psz_artist , Artist);
>>>  + if (!p_sys->p_current_song.psz_artist)
>>>  + {
>>>  + DeleteSong (&p_sys->p_current_song);
>>>  + goto error;
>>>  + }
>>>  +
>>>  + RETRIEVE_METADATA(p_sys->p_current_song.psz_title , Title);
>>>  + if (!p_sys->p_current_song.psz_title)
>>>  + {
>>>  + DeleteSong (&p_sys->p_current_song);
>>>  + goto error;
>>>  + }
>>>  +
>>>  + RETRIEVE_METADATA(p_sys->p_current_song.psz_album , Album);
>>>  + RETRIEVE_METADATA(p_sys->p_current_song.psz_musicbrainz_recording_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);
>>>  +
>>>  +error:
>>>  + vlc_mutex_unlock (&p_sys->lock);
>>>  +
>>>  +#undef RETRIEVE_METADATA
>>>  +}
>>>  +
>>>  +static void Enqueue (intf_thread_t *p_this)
>>>  +{
>>>  + intf_sys_t *p_sys = p_this->p_sys;
>>>  +
>>>  + p_sys->b_meta_read = false;
>>>  + vlc_mutex_lock (&p_sys->lock);
>>>  +
>>>  + if (EMPTY_STR(p_sys->p_current_song.psz_artist) ||
>>>  + EMPTY_STR(p_sys->p_current_song.psz_title))
>>>  + {
>>>  + msg_Dbg (p_this , "Missing artist or title, not submitting");
>>>  + goto error;
>>>  + }
>>>  +
>>>  + if (p_sys->p_current_song.i_length == 0)
>>>  + p_sys->p_current_song.i_length = p_sys->time_played;
>>>  +
>>>  + if (p_sys->time_played < 30)
>>>  + {
>>>  + msg_Dbg (p_this , "Song not listened long enough, not submitting");
>>>  + goto error;
>>>  + }
>>>  +
>>>  + msg_Dbg (p_this , "Song will be submitted.");
>>>  + vlc_vector_push (&p_sys->queue , p_sys->p_current_song);
>>>  + vlc_cond_signal (&p_sys->wait);
>>>  + vlc_mutex_unlock (&p_sys->lock);
>>>  + return;
>>>  +
>>>  +error:
>>>  + DeleteSong (&p_sys->p_current_song);
>>>  + 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))
>>>  + return;
>>>  +
>>>  + if (!p_sys->b_meta_read && state >= VLC_PLAYER_STATE_PLAYING)
>>>  + {
>>>  + input_item_t *item = vlc_player_GetCurrentMedia (p_sys->player);
>>>  + ReadMetaData (intf , item);
>>>  + return;
>>>  + }
>>>  +
>>>  + if (state == VLC_PLAYER_STATE_STOPPED)
>>>  + Enqueue (intf);
>>>  +}
>>>  +
>>>  +static void OnTimerUpdate (const struct vlc_player_timer_point *value , void *data)
>>>  +{
>>>  + intf_thread_t *intf = data;
>>>  + intf_sys_t *p_sys = intf->p_sys;
>>>  + p_sys->time_played = SEC_FROM_VLC_TICK (value->ts - VLC_TICK_0);
>>>  +}
>>>  +
>>>  +static void OnTimerStopped (vlc_tick_t system_date , void *data) { }
>>>  +
>>>  +static void OnCurrentMediaChanged (vlc_player_t *player , input_item_t *new_media , void *data)
>>>  +{
>>>  + intf_thread_t *intf = data;
>>>  + Enqueue (intf);
>>>  +
>>>  + intf_sys_t *p_sys = intf->p_sys;
>>>  + p_sys->b_meta_read = false;
>>>  +
>>>  + if (!new_media || vlc_player_GetVideoTrackCount (player))
>>>  + return;
>>>  +
>>>  + p_sys->time_played = 0;
>>>  + if (input_item_IsPreparsed (new_media))
>>>  + ReadMetaData (intf , new_media);
>>>  +}
>>>  +
>>>  +static char *PreparePayload (intf_thread_t *p_this)
>>>  +{
>>>  + intf_sys_t *p_sys = p_this->p_sys;
>>>  + struct vlc_memstream payload;
>>>  + vlc_memstream_open (&payload);
>>>  +
>>>  + if (p_sys->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->queue.size ; i_song++)
>>>  + {
>>>  + listen_t *p_song = &p_sys->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_recording_id))
>>>  + vlc_memstream_printf (&payload , ", \"additional_info\": {\"recording_mbid\":\"%s\"} " ,
>>>  + vlc_uri_decode (p_song->psz_musicbrainz_recording_id));
>>>  + vlc_memstream_printf (&payload , "}}");
>>>  + }
>>>  +
>>>  + vlc_memstream_printf (&payload , "]}");
>>>  +
>>>  + int i_status = vlc_memstream_close (&payload);
>>>  + if (!i_status)
>>>  + {
>>>  + msg_Dbg (p_this , "Payload: %s" , payload.ptr);
>>>  + return payload.ptr;
>>>  + }
>>>  + else
>>>  + return NULL;
>>>  +}
>>>  +
>>>  +static char *PrepareRequest (intf_thread_t *p_this , char *payload)
>>>  +{
>>>  + intf_sys_t *p_sys = p_this->p_sys;
>>>  + struct vlc_memstream request;
>>>  +
>>>  + 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" , strlen (payload));
>>>  + vlc_memstream_puts (&request , "\r\n");
>>>  + vlc_memstream_puts (&request , payload);
>>>  + vlc_memstream_puts (&request , "\r\n\r\n");
>>>  +
>>>  + free (payload);
>>>  +
>>>  + int i_status = vlc_memstream_close (&request);
>>>  + if (!i_status)
>>>  + return request.ptr;
>>>  + else
>>>  + return NULL;
>>>  +}
>>>  +
>>>  +static int SendRequest (intf_thread_t *p_this , char *request)
>>>  +{
>>>  + 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 (request);
>>>  + return VLC_EGENERIC;
>>>  + }
>>>  +
>>>  + i_ret = vlc_tls_Write (sock , request , strlen (request));
>>>  + free (request);
>>>  +
>>>  + if (i_ret == -1)
>>>  + {
>>>  + vlc_tls_Close (sock);
>>>  + return VLC_EGENERIC;
>>>  + }
>>>  +
>>>  + 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 VLC_EGENERIC;
>>>  + }
>>>  + p_buffer[ i_ret ] = '\0';
>>>  +
>>>  + if (strstr (( char * ) p_buffer , "200"))
>>>  + {
>>>  + vlc_vector_clear (&p_sys->queue);
>>>  + msg_Dbg (p_this , "Submission successful!");
>>>  + return 1;
>>>  + }
>>>  + else if (strstr (( char * ) p_buffer , "401"))
>>>  + msg_Warn (p_this , "Authentication Error");
>>>  + else
>>>  + msg_Warn (p_this , "Invalid Request");
>>>  +
>>>  + return VLC_EGENERIC;
>>>  +}
>>>  +
>>>  +static int Configure (intf_thread_t *p_intf)
>>>  +{
>>>  + int i_ret;
>>>  + char *psz_submission_url , *psz_url;
>>>  + intf_sys_t *p_sys = p_intf->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 0;
>>>  + }
>>>  +
>>>  + 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 > 0)
>>>  + {
>>>  + vlc_UrlParse (&p_sys->p_submit_url , psz_url);
>>>  + free (psz_url);
>>>  + free (p_sys);
>>>  + return 1;
>>>  + }
>>>  + }
>>>  +
>>>  + 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 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));
>>>  +
>>>  + if (!p_sys)
>>>  + return VLC_ENOMEM;
>>>  +
>>>  + p_intf->p_sys = p_sys;
>>>  + p_sys->live = true;
>>>  +
>>>  + if (!Configure (p_intf))
>>>  + return VLC_EGENERIC;
>>>  +
>>>  + static struct vlc_player_cbs const player_cbs =
>>>  + {
>>>  + .on_state_changed = PlayerStateChanged ,
>>>  + .on_current_media_changed = OnCurrentMediaChanged ,
>>>  + };
>>>  + static struct vlc_player_timer_cbs const timer_cbs =
>>>  + {
>>>  + .on_update = OnTimerUpdate ,
>>>  + .on_discontinuity = OnTimerStopped ,
>>>  + };
>>>  +
>>>  + vlc_playlist_t *playlist = vlc_intf_GetMainPlaylist (p_intf);
>>>  + p_sys->player = vlc_playlist_GetPlayer (playlist);
>>>  +
>>>  + vlc_player_Lock (p_sys->player);
>>>  + p_sys->player_listener = vlc_player_AddListener (p_sys->player , &player_cbs , p_intf);
>>>  + vlc_player_Unlock (p_sys->player);
>>>  +
>>>  + if (!p_sys->player_listener)
>>>  + goto error;
>>>  +
>>>  + p_sys->timer_listener = vlc_player_AddTimer (p_sys->player , VLC_TICK_FROM_SEC (1) , &timer_cbs , p_intf);
>>>  + if (!p_sys->timer_listener)
>>>  + goto error;
>>>  +
>>>  + p_sys->interrupt = vlc_interrupt_create();
>>>  + if (unlikely(p_sys->interrupt == NULL))
>>>  + goto error;
>>>  +
>>>  + 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))
>>>  + {
>>>  + vlc_interrupt_destroy(p_sys->interrupt);
>>>  + goto error;
>>>  + }
>>>  +
>>>  + vlc_vector_init(&p_sys->queue);
>>>  + return VLC_SUCCESS;
>>>  +
>>>  +error:
>>>  + vlc_player_Lock (p_sys->player);
>>>  + if (p_sys->player_listener)
>>>  + vlc_player_RemoveListener (p_sys->player , p_sys->player_listener);
>>>  + if (p_sys->timer_listener)
>>>  + vlc_player_RemoveTimer (p_sys->player , p_sys->timer_listener);
>>>  + vlc_player_Unlock (p_sys->player);
>>>  + free (p_sys);
>>>  + return VLC_EGENERIC;
>>>  +}
>>>  +
>>>  +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_mutex_lock(&p_sys->lock);
>>>  + p_sys->live = false;
>>>  + vlc_cond_signal (&p_sys->wait);
>>>  + vlc_mutex_unlock(&p_sys->lock);
>>>  +
>>>  + vlc_interrupt_kill(p_sys->interrupt);
>>>  + vlc_join (p_sys->thread , NULL);
>>>  + vlc_interrupt_destroy(p_sys->interrupt);
>>>  +
>>>  + vlc_vector_clear (&p_sys->queue);
>>>  + vlc_UrlClean (&p_sys->p_submit_url);
>>>  +
>>>  + vlc_player_Lock (p_sys->player);
>>>  + vlc_player_RemoveListener (p_sys->player , p_sys->player_listener);
>>>  + vlc_player_Unlock (p_sys->player);
>>>  +
>>>  + vlc_player_RemoveTimer (p_sys->player , p_sys->timer_listener);
>>>  +
>>>  + free (p_sys);
>>>  +}
>>>  +
>>>  +static void *Run (void *data)
>>>  +{
>>>  + intf_thread_t *p_intf = data;
>>>  + bool b_wait = 0;
>>>  + char *request , *payload;
>>>  +
>>>  + intf_sys_t *p_sys = p_intf->p_sys;
>>>  +
>>>  + vlc_interrupt_set(p_sys->interrupt);
>>>  +
>>>  + for (;;)
>>>  + {
>>>  + vlc_mutex_lock (&p_sys->lock);
>>>  + if (b_wait)
>>>  + {
>>>  + vlc_tick_t deadline = vlc_tick_now() + VLC_TICK_FROM_SEC (60);
>>>  + int ret = 0;
>>>  + while (p_sys->live && ret == 0) // wait for 1 min
>>>  + ret = vlc_cond_timedwait (&p_sys->wait , &p_sys->lock, deadline);
>>>  + }
>>>  +
>>>  + while (p_sys->live && p_sys->queue.size == 0)
>>>  + vlc_cond_wait (&p_sys->wait , &p_sys->lock);
>>>  +
>>>  + if (!p_sys->live)
>>>  + {
>>>  + vlc_mutex_unlock (&p_sys->lock);
>>>  + return NULL;
>>>  + }
>>>  +
>>>  + payload = PreparePayload (p_intf);
>>>  + vlc_mutex_unlock (&p_sys->lock);
>>>  +
>>>  + if (!payload)
>>>  + {
>>>  + msg_Warn (p_intf , "Error: Unable to generate payload");
>>>  + break;
>>>  + }
>>>  +
>>>  + request = PrepareRequest (p_intf , payload);
>>>  + if (!request)
>>>  + {
>>>  + msg_Warn (p_intf , "Error: Unable to generate request body");
>>>  + break;
>>>  + }
>>>  +
>>>  + int i_status = SendRequest (p_intf , request);
>>>  + if (i_status)
>>>  + {
>>>  + msg_Warn (p_intf , "Error: Could not transmit request");
>>>  + b_wait = 1;
>>>  + continue;
>>>  + }
>>>  +
>>>  + b_wait = 0;
>>>  + }
>>>  +
>>>  + return NULL;
>>>  +}
>>>  +
>>>  -- 
>>>  2.20.1
>>> 
> _______________________________________________
> 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/20200330/2f915d2e/attachment-0001.html>


More information about the vlc-devel mailing list