[vlc-devel] [PATCH 2/2] chromecast/chromecast_ctrl: set a new sout everytime a new file is loaded

Steve Lhomme robux4 at videolabs.io
Fri Jan 15 17:18:02 CET 2016


using the new variable "input-prepare"
use a different enum to keep track of the command sent
handle play/pause via the Chromecast
---
 modules/stream_out/chromecast/cast.cpp            |   4 +-
 modules/stream_out/chromecast/chromecast.h        |  39 ++-
 modules/stream_out/chromecast/chromecast_ctrl.cpp | 395 ++++++++++++++++++----
 3 files changed, 374 insertions(+), 64 deletions(-)

diff --git a/modules/stream_out/chromecast/cast.cpp b/modules/stream_out/chromecast/cast.cpp
index c97511a..22db8d5 100644
--- a/modules/stream_out/chromecast/cast.cpp
+++ b/modules/stream_out/chromecast/cast.cpp
@@ -83,10 +83,10 @@ static const char *const ppsz_sout_options[] = {
 
 vlc_module_begin ()
 
-    set_shortname(N_("Chromecast"))
+    set_shortname( "cc_sout" )
     set_description(N_("Chromecast stream output"))
     set_capability("sout stream", 0)
-    add_shortcut("chromecast")
+    add_shortcut("cc_sout")
     set_category(CAT_SOUT)
     set_subcategory(SUBCAT_SOUT_STREAM)
     set_callbacks(Open, Close)
diff --git a/modules/stream_out/chromecast/chromecast.h b/modules/stream_out/chromecast/chromecast.h
index 759f011..42a19e5 100644
--- a/modules/stream_out/chromecast/chromecast.h
+++ b/modules/stream_out/chromecast/chromecast.h
@@ -55,18 +55,29 @@ enum connection_status
     CHROMECAST_TLS_CONNECTED,
     CHROMECAST_AUTHENTICATED,
     CHROMECAST_APP_STARTED,
-    CHROMECAST_MEDIA_LOAD_SENT,
     CHROMECAST_CONNECTION_DEAD,
 };
 
+enum command_status {
+    NO_CMD_PENDING,
+    CMD_LOAD_SENT,
+    CMD_PLAYBACK_SENT,
+    CMD_SEEK_SENT,
+};
+
 struct intf_sys_t
 {
     intf_sys_t(intf_thread_t * const intf);
     ~intf_sys_t();
 
-    intf_thread_t  * const p_stream;
+    intf_thread_t  * const p_intf;
+    input_thread_t *p_input;
     std::string    serverIP;
+    std::string    mime;
+    std::string    muxer;
+
     std::string appTransportId;
+    std::string mediaSessionId;
 
     int i_sock_fd;
     vlc_tls_creds_t *p_creds;
@@ -80,6 +91,9 @@ struct intf_sys_t
     void msgReceiverClose(std::string destinationId);
 
     void handleMessages();
+    void sendPlayerCmd();
+
+    void InputUpdated( input_thread_t * );
 
     connection_status getConnectionStatus() const
     {
@@ -91,7 +105,7 @@ struct intf_sys_t
         if (conn_status != status)
         {
 #ifndef NDEBUG
-            msg_Dbg(p_stream, "change Chromecast connection status from %d to %d", conn_status, status);
+            msg_Dbg(p_intf, "change Chromecast connection status from %d to %d", conn_status, status);
 #endif
             conn_status = status;
             vlc_cond_broadcast(&loadCommandCond);
@@ -109,6 +123,8 @@ struct intf_sys_t
     void msgReceiverGetStatus();
 
     void msgPlayerLoad();
+    void msgPlayerPlay();
+    void msgPlayerPause();
 
     void processMessage(const castchannel::CastMessage &msg);
 
@@ -120,10 +136,27 @@ private:
                       const std::string & destinationId = DEFAULT_CHOMECAST_RECEIVER,
                       castchannel::CastMessage_PayloadType payloadType = castchannel::CastMessage_PayloadType_STRING);
 
+    void setPlayerStatus(enum command_status status) {
+        if (cmd_status != status)
+        {
+            msg_Dbg(p_intf, "change Chromecast command status from %d to %d", cmd_status, status);
+            cmd_status = status;
+        }
+    }
+
     enum connection_status conn_status;
+    enum command_status    cmd_status;
 
     unsigned i_receiver_requestId;
     unsigned i_requestId;
+    unsigned i_sout_id;
+
+    std::string       s_sout;
+    std::string       s_chromecast_url;
+    std::string GetMedia();
+
+    void plugOutputRedirection();
+    void unplugOutputRedirection();
 };
 
 #endif /* VLC_CHROMECAST_H */
diff --git a/modules/stream_out/chromecast/chromecast_ctrl.cpp b/modules/stream_out/chromecast/chromecast_ctrl.cpp
index 0439b73..ff59f3f 100644
--- a/modules/stream_out/chromecast/chromecast_ctrl.cpp
+++ b/modules/stream_out/chromecast/chromecast_ctrl.cpp
@@ -32,6 +32,7 @@
 
 #include "chromecast.h"
 
+#include <vlc_input.h>
 #include <vlc_playlist.h>
 #include <vlc_threads.h>
 
@@ -69,6 +70,10 @@ static const std::string NAMESPACE_RECEIVER         = "urn:x-cast:com.google.cas
  *****************************************************************************/
 static int Open(vlc_object_t *);
 static void Close(vlc_object_t *);
+static int CurrentChanged( vlc_object_t *, char const *,
+                          vlc_value_t, vlc_value_t, void * );
+static int InputEvent( vlc_object_t *, char const *,
+                       vlc_value_t, vlc_value_t, void * );
 static void Clean(intf_thread_t *);
 
 static void *ChromecastThread(void *data);
@@ -109,9 +114,12 @@ int Open(vlc_object_t *p_this)
 {
     intf_thread_t *p_intf = reinterpret_cast<intf_thread_t*>(p_this);
     intf_sys_t *p_sys = new(std::nothrow) intf_sys_t(p_intf);
+    mtime_t deadline;
+    int i_ret;
     if (unlikely(p_sys == NULL))
         return VLC_ENOMEM;
 
+    playlist_t *p_playlist = pl_Get( p_intf );
     char *psz_ipChromecast = var_InheritString(p_intf, CONTROL_CFG_PREFIX "addr");
     if (psz_ipChromecast == NULL)
     {
@@ -142,9 +150,20 @@ int Open(vlc_object_t *p_this)
     char *psz_mux = var_InheritString(p_intf, CONTROL_CFG_PREFIX "mux");
     if (psz_mux == NULL)
     {
-        Clean(p_intf);
-        return VLC_EGENERIC;
+        msg_Err(p_intf, "Bad muxer provided");
+        goto error;
     }
+    p_sys->muxer = psz_mux; /* TODO get the MIME type from the playlist/input ? */
+    free(psz_mux);
+
+    psz_mux = var_InheritString(p_intf, CONTROL_CFG_PREFIX "mime");
+    if (psz_mux == NULL)
+    {
+        msg_Err(p_intf, "Bad MIME type provided");
+        goto error;
+    }
+    p_sys->mime = psz_mux; /* TODO get the MIME type from the playlist/input ? */
+    free(psz_mux);
 
     // Start the Chromecast event thread.
     if (vlc_clone(&p_sys->chromecastThread, ChromecastThread, p_intf,
@@ -160,10 +179,10 @@ int Open(vlc_object_t *p_this)
      * the HTTP server. */
 
     // Lock the sout thread until we have sent the media loading command to the Chromecast.
-    int i_ret = 0;
-    const mtime_t deadline = mdate() + 6 * CLOCK_FREQ;
+    i_ret = 0;
+    deadline = mdate() + 6 * CLOCK_FREQ;
     vlc_mutex_lock(&p_sys->lock);
-    while (p_sys->getConnectionStatus() != CHROMECAST_MEDIA_LOAD_SENT)
+    while (p_sys->getConnectionStatus() != CHROMECAST_APP_STARTED)
     {
         i_ret = vlc_cond_timedwait(&p_sys->loadCommandCond, &p_sys->lock, deadline);
         if (i_ret == ETIMEDOUT)
@@ -183,7 +202,12 @@ int Open(vlc_object_t *p_this)
 
     p_intf->p_sys = p_sys;
 
+    var_AddCallback( p_playlist, "input-prepare", CurrentChanged, p_intf );
     return VLC_SUCCESS;
+
+error:
+    delete p_sys;
+    return VLC_EGENERIC;
 }
 
 
@@ -195,12 +219,14 @@ void Close(vlc_object_t *p_this)
     intf_thread_t *p_intf = reinterpret_cast<intf_thread_t*>(p_this);
     intf_sys_t *p_sys = p_intf->p_sys;
 
+    playlist_t *p_playlist = pl_Get( p_intf );
+    var_DelCallback( p_playlist, "input-prepare", CurrentChanged, p_intf );
+
     vlc_cancel(p_sys->chromecastThread);
     vlc_join(p_sys->chromecastThread, NULL);
 
     switch (p_sys->getConnectionStatus())
     {
-    case CHROMECAST_MEDIA_LOAD_SENT:
     case CHROMECAST_APP_STARTED:
         // Generate the close messages.
         p_sys->msgReceiverClose(p_sys->appTransportId);
@@ -218,9 +244,9 @@ void Close(vlc_object_t *p_this)
 /**
  * @brief Clean and release the variables in a sout_stream_sys_t structure
  */
-void Clean(intf_thread_t *p_stream)
+void Clean(intf_thread_t *p_intf)
 {
-    intf_sys_t *p_sys = p_stream->p_sys;
+    intf_sys_t *p_sys = p_intf->p_sys;
 
     p_sys->disconnectChromecast();
 
@@ -257,11 +283,14 @@ void intf_sys_t::buildMessage(const std::string & namespace_,
 }
 
 intf_sys_t::intf_sys_t(intf_thread_t * const p_this)
- : p_stream(p_this)
- , p_tls(NULL)
- , conn_status(CHROMECAST_DISCONNECTED)
- , i_receiver_requestId(0)
- , i_requestId(0)
+    :p_intf(p_this)
+    ,p_input(NULL)
+    ,p_tls(NULL)
+    ,conn_status(CHROMECAST_DISCONNECTED)
+    ,cmd_status(NO_CMD_PENDING)
+    ,i_receiver_requestId(0)
+    ,i_requestId(0)
+    ,i_sout_id(0)
 {
     vlc_mutex_init(&lock);
     vlc_cond_init(&loadCommandCond);
@@ -273,18 +302,202 @@ intf_sys_t::~intf_sys_t()
     vlc_mutex_destroy(&lock);
 }
 
+static int CurrentChanged( vlc_object_t *p_this, char const *psz_var,
+                          vlc_value_t oldval, vlc_value_t val, void *p_data )
+{
+    intf_thread_t *p_intf = static_cast<intf_thread_t *>(p_data);
+    intf_sys_t *p_sys = p_intf->p_sys;
+    input_thread_t *p_input = static_cast<input_thread_t *>(val.p_address);
+
+    VLC_UNUSED(p_this);
+    VLC_UNUSED(psz_var);
+
+    assert( p_sys->p_input == NULL || p_sys->p_input == oldval.p_address );
+
+    p_sys->InputUpdated( p_input );
+
+    return VLC_SUCCESS;
+}
+
+
+void intf_sys_t::unplugOutputRedirection()
+{
+    msg_Dbg( p_intf, "unplug output redirection from input %s", input_GetItem( p_input )->psz_name );
+        var_SetString( p_input, "sout", NULL );
+}
+
+void intf_sys_t::plugOutputRedirection()
+{
+    msg_Dbg( p_intf, "plug output redirection on input %s", input_GetItem( p_input )->psz_name );
+        msg_Dbg(p_intf, "force sout to %s", s_sout.c_str());
+        var_SetString( p_input, "sout", s_sout.c_str() );
+}
+
+void intf_sys_t::InputUpdated( input_thread_t *p_input )
+{
+    vlc_mutex_lock(&lock);
+    msg_Dbg( p_intf, "%ld InputUpdated p_input:%p was:%p playlist_Status:%d", GetCurrentThreadId(), (void*)p_input, (void*)this->p_input, playlist_Status( pl_Get(p_intf) ) );
+
+    if ( this->p_input == p_input )
+    {
+        vlc_mutex_unlock(&lock);
+        return;
+    }
+
+    if( this->p_input != NULL )
+    {
+        vlc_mutex_unlock(&lock);
+        var_DelCallback( this->p_input, "intf-event", InputEvent, p_intf );
+        vlc_mutex_lock(&lock);
+        unplugOutputRedirection();
+    }
+
+    this->p_input = p_input;
+
+    if( this->p_input != NULL )
+    {
+        var_AddCallback( p_input, "intf-event", InputEvent, p_intf );
+
+        mutex_cleanup_push(&lock);
+        while (!conn_status != CHROMECAST_CONNECTION_DEAD)
+        {
+            msg_Dbg(p_intf, "InputUpdated waiting for Chromecast connection, current %d", conn_status);
+            vlc_cond_wait(&loadCommandCond, &lock);
+        }
+        vlc_cleanup_pop();
+
+        if (conn_status == CHROMECAST_CONNECTION_DEAD)
+        {
+            msg_Warn(p_intf, "no Chromecast hook possible");
+            vlc_mutex_unlock(&lock);
+            return;
+        }
+
+        assert(!p_input->b_preparsing);
+
+        int i_port = var_InheritInteger(p_intf, CONTROL_CFG_PREFIX "http-port");
+
+        {
+            std::stringstream ssout;
+            ssout << '#';
+            ssout << "cc_sout{http-port=" << i_port << ",mux=" << muxer << ",mime=" << mime << ",uid=" << i_sout_id++ << "}";
+            s_sout = ssout.str();
+        }
+        if (conn_status != CHROMECAST_CONNECTION_DEAD)
+        {
+            plugOutputRedirection();
+        }
+    }
+    vlc_mutex_unlock(&lock);
+}
+
+void intf_sys_t::sendPlayerCmd()
+{
+    if (!p_input)
+    {
+        msg_Warn(p_intf, "no input");
+        return;
+    }
+
+    assert(!p_input->b_preparsing);
+
+    if (conn_status != CHROMECAST_APP_STARTED)
+    {
+        msg_Dbg(p_intf, "don't send playback command until the app is started");
+        return;
+    }
+
+#ifndef NDEBUG
+    msg_Dbg( p_intf, "sendPlayerCmd input_state:%d mediaSessionId:'%s' cmd_status:%d", (int)var_GetInteger( p_input, "state" ), mediaSessionId.c_str(), cmd_status );
+#endif
+    switch( var_GetInteger( p_input, "state" ) )
+    {
+    case OPENING_S:
+        if (!mediaSessionId.empty()) {
+            msg_Warn(p_intf, "opening when a session was still opened:%s", mediaSessionId.c_str());
+#if 0
+            msgPlayerStop();
+#endif
+            //mediaSessionId = "";
+        }
+        else
+        //playback_start_chromecast = -1.0;
+        if (cmd_status == NO_CMD_PENDING) {
+            msgPlayerLoad();
+            setPlayerStatus(CMD_LOAD_SENT);
+        }
+        break;
+    case PLAYING_S:
+        if (!mediaSessionId.empty()) {
+            msgPlayerPlay();
+            setPlayerStatus(CMD_PLAYBACK_SENT);
+        } else if (cmd_status == NO_CMD_PENDING) {
+            msgPlayerLoad();
+            setPlayerStatus(CMD_LOAD_SENT);
+        }
+        break;
+    case PAUSE_S:
+        if (!mediaSessionId.empty()) {
+            msgPlayerPause();
+            setPlayerStatus(CMD_PLAYBACK_SENT);
+        } else if (cmd_status == NO_CMD_PENDING) {
+            msgPlayerLoad();
+            setPlayerStatus(CMD_LOAD_SENT);
+        }
+        break;
+    case END_S:
+#if 0
+        /* the MediaPlayer app doesn't like to be stopped, it won't restart after that */
+        if (!mediaSessionId.empty() /* && receiverState == RECEIVER_BUFFERING */) {
+            msgPlayerStop();
+
+            /* TODO reset the sout as we'll need another one for the next load */
+            //var_SetString( p_input, "sout", NULL );
+            //mediaSessionId = ""; // it doesn't seem to send a status update like it should
+            //setPlayerStatus(NO_CMD_PENDING); /* TODO: may not be needed */
+        }
+#endif
+        break;
+    default:
+        //msgClose();
+        break;
+    }
+}
+
+static int InputEvent( vlc_object_t *p_this, char const *psz_var,
+                       vlc_value_t oldval, vlc_value_t val, void *p_data )
+{
+    input_thread_t *p_input = reinterpret_cast<input_thread_t*>(p_this);
+    intf_thread_t *p_intf = static_cast<intf_thread_t*>(p_data);
+    intf_sys_t *p_sys = p_intf->p_sys;
+
+    VLC_UNUSED(psz_var);
+    VLC_UNUSED(oldval);
+
+    assert(p_input == p_sys->p_input);
+
+    if( val.i_int == INPUT_EVENT_STATE )
+    {
+        msg_Info(p_this, "%ld playback state changed %d", GetCurrentThreadId(), (int)var_GetInteger( p_input, "state" ));
+        vlc_mutex_locker locker(&p_sys->lock);
+        p_sys->sendPlayerCmd();
+    }
+
+    return VLC_SUCCESS;
+}
+
 /**
  * @brief Connect to the Chromecast
- * @param p_stream the sout_stream_t structure
+ * @param p_intf the sout_stream_t structure
  * @return the opened socket file descriptor or -1 on error
  */
 int intf_sys_t::connectChromecast(char *psz_ipChromecast)
 {
-    int fd = net_ConnectTCP(p_stream, psz_ipChromecast, CHROMECAST_CONTROL_PORT);
+    int fd = net_ConnectTCP(p_intf, psz_ipChromecast, CHROMECAST_CONTROL_PORT);
     if (fd < 0)
         return -1;
 
-    p_creds = vlc_tls_ClientCreate(VLC_OBJECT(p_stream));
+    p_creds = vlc_tls_ClientCreate(VLC_OBJECT(p_intf));
     if (p_creds == NULL)
     {
         net_Close(fd);
@@ -322,13 +535,13 @@ void intf_sys_t::disconnectChromecast()
 
 /**
  * @brief Receive a data packet from the Chromecast
- * @param p_stream the sout_stream_t structure
+ * @param p_intf the sout_stream_t structure
  * @param b_msgReceived returns true if a message has been entirely received else false
  * @param i_payloadSize returns the payload size of the message received
  * @return the number of bytes received of -1 on error
  */
 // Use here only C linkage and POD types as this function is a cancelation point.
-extern "C" int recvPacket(vlc_object_t *p_stream, bool &b_msgReceived,
+extern "C" int recvPacket(vlc_object_t *p_intf, bool &b_msgReceived,
                           uint32_t &i_payloadSize, int i_sock_fd, vlc_tls_t *p_tls,
                           unsigned *pi_received, uint8_t *p_data, bool *pb_pingTimeout,
                           int *pi_wait_delay, int *pi_wait_retries)
@@ -347,7 +560,7 @@ extern "C" int recvPacket(vlc_object_t *p_stream, bool &b_msgReceived,
         {
             if (!*pi_wait_retries)
             {
-                msg_Err(p_stream, "No PONG answer received from the Chromecast");
+                msg_Err(p_intf, "No PONG answer received from the Chromecast");
                 return 0; // Connection died
             }
             (*pi_wait_retries)--;
@@ -357,7 +570,7 @@ extern "C" int recvPacket(vlc_object_t *p_stream, bool &b_msgReceived,
             /* now expect a pong */
             *pi_wait_delay = PONG_WAIT_TIME;
             *pi_wait_retries = PONG_WAIT_RETRIES;
-            msg_Warn(p_stream, "No PING received from the Chromecast, sending a PING");
+            msg_Warn(p_intf, "No PING received from the Chromecast, sending a PING");
         }
         *pb_pingTimeout = true;
     }
@@ -393,7 +606,7 @@ extern "C" int recvPacket(vlc_object_t *p_stream, bool &b_msgReceived,
     if (i_payloadSize > i_maxPayloadSize)
     {
         // Error case: the packet sent by the Chromecast is too long: we drop it.
-        msg_Err(p_stream, "Packet too long: droping its data");
+        msg_Err(p_intf, "Packet too long: droping its data");
 
         uint32_t i_size = i_payloadSize - (*pi_received - PACKET_HEADER_LEN);
         if (i_size > i_maxPayloadSize)
@@ -437,7 +650,7 @@ void intf_sys_t::processMessage(const castchannel::CastMessage &msg)
     const std::string & namespace_ = msg.namespace_();
 
 #ifndef NDEBUG
-    msg_Dbg(p_stream,"processMessage: %s->%s %s", namespace_.c_str(), msg.destination_id().c_str(), msg.payload_utf8().c_str());
+    msg_Dbg(p_intf,"processMessage: %s->%s %s", namespace_.c_str(), msg.destination_id().c_str(), msg.payload_utf8().c_str());
 #endif
 
     if (namespace_ == NAMESPACE_DEVICEAUTH)
@@ -447,11 +660,11 @@ void intf_sys_t::processMessage(const castchannel::CastMessage &msg)
 
         if (authMessage.has_error())
         {
-            msg_Err(p_stream, "Authentification error: %d", authMessage.error().error_type());
+            msg_Err(p_intf, "Authentification error: %d", authMessage.error().error_type());
         }
         else if (!authMessage.has_response())
         {
-            msg_Err(p_stream, "Authentification message has no response field");
+            msg_Err(p_intf, "Authentification message has no response field");
         }
         else
         {
@@ -468,16 +681,16 @@ void intf_sys_t::processMessage(const castchannel::CastMessage &msg)
 
         if (type == "PING")
         {
-            msg_Dbg(p_stream, "PING received from the Chromecast");
+            msg_Dbg(p_intf, "PING received from the Chromecast");
             msgPong();
         }
         else if (type == "PONG")
         {
-            msg_Dbg(p_stream, "PONG received from the Chromecast");
+            msg_Dbg(p_intf, "PONG received from the Chromecast");
         }
         else
         {
-            msg_Warn(p_stream, "Heartbeat command not supported: %s", type.c_str());
+            msg_Warn(p_intf, "Heartbeat command not supported: %s", type.c_str());
         }
 
         json_value_free(p_data);
@@ -515,9 +728,8 @@ void intf_sys_t::processMessage(const castchannel::CastMessage &msg)
                 {
                     msgConnect(appTransportId);
                     setConnectionStatus(CHROMECAST_APP_STARTED);
-                    msgPlayerLoad();
-                    setConnectionStatus(CHROMECAST_MEDIA_LOAD_SENT);
-                    vlc_cond_signal(&loadCommandCond);
+                        /* now we can start the Chromecast playback */
+                        sendPlayerCmd();
                 }
             }
             else
@@ -526,14 +738,13 @@ void intf_sys_t::processMessage(const castchannel::CastMessage &msg)
                 {
                 /* If the app is no longer present */
                 case CHROMECAST_APP_STARTED:
-                case CHROMECAST_MEDIA_LOAD_SENT:
-                    msg_Warn(p_stream, "app is no longer present. closing");
+                    msg_Warn(p_intf, "app is no longer present. closing");
                     msgReceiverClose(appTransportId);
                     setConnectionStatus(CHROMECAST_CONNECTION_DEAD);
                     break;
 
                 case CHROMECAST_AUTHENTICATED:
-                    msg_Dbg(p_stream, "Chromecast was running no app, launch media_app");
+                    msg_Dbg(p_intf, "Chromecast was running no app, launch media_app");
                     appTransportId = "";
                     msgReceiverLaunchApp();
                     break;
@@ -547,12 +758,12 @@ void intf_sys_t::processMessage(const castchannel::CastMessage &msg)
         else if (type == "LAUNCH_ERROR")
         {
             json_value reason = (*p_data)["reason"];
-            msg_Err(p_stream, "Failed to start the MediaPlayer: %s",
+            msg_Err(p_intf, "Failed to start the MediaPlayer: %s",
                     (const char *)reason);
         }
         else
         {
-            msg_Warn(p_stream, "Receiver command not supported: %s",
+            msg_Warn(p_intf, "Receiver command not supported: %s",
                     msg.payload_utf8().c_str());
         }
 
@@ -566,24 +777,37 @@ void intf_sys_t::processMessage(const castchannel::CastMessage &msg)
         if (type == "MEDIA_STATUS")
         {
             json_value status = (*p_data)["status"];
-            msg_Dbg(p_stream, "Player state: %s sessionId:%d",
+            msg_Dbg(p_intf, "Player state: %s sessionId:%d",
                     status[0]["playerState"].operator const char *(),
                     (int)(json_int_t) status[0]["mediaSessionId"]);
+
+            char session_id[32];
+            if( snprintf( session_id, sizeof(session_id), "%" PRId64, (json_int_t) status[0]["mediaSessionId"] ) >= (int)sizeof(session_id) )
+            {
+                msg_Err( p_intf, "snprintf() truncated string for mediaSessionId" );
+                session_id[sizeof(session_id) - 1] = '\0';
+            }
+            if (!mediaSessionId.empty() && session_id[0] && mediaSessionId != session_id) {
+                msg_Warn(p_intf, "different mediaSessionId detected %s was %s", mediaSessionId.c_str(), this->mediaSessionId.c_str());
+                //p_sys->msgPlayerLoad();
+            }
+
+            mediaSessionId = session_id;
         }
         else if (type == "LOAD_FAILED")
         {
-            msg_Err(p_stream, "Media load failed");
+            msg_Err(p_intf, "Media load failed");
             msgReceiverClose(appTransportId);
             vlc_mutex_locker locker(&lock);
             setConnectionStatus(CHROMECAST_CONNECTION_DEAD);
         }
         else if (type == "INVALID_REQUEST")
         {
-            msg_Dbg(p_stream, "We sent an invalid request reason:%s", (*p_data)["reason"].operator const char *());
+            msg_Dbg(p_intf, "We sent an invalid request reason:%s", (*p_data)["reason"].operator const char *());
         }
         else
         {
-            msg_Warn(p_stream, "Media command not supported: %s",
+            msg_Warn(p_intf, "Media command not supported: %s",
                     msg.payload_utf8().c_str());
         }
 
@@ -597,19 +821,19 @@ void intf_sys_t::processMessage(const castchannel::CastMessage &msg)
 
         if (type == "CLOSE")
         {
-            msg_Warn(p_stream, "received close message");
+            msg_Warn(p_intf, "received close message");
             vlc_mutex_locker locker(&lock);
             setConnectionStatus(CHROMECAST_CONNECTION_DEAD);
         }
         else
         {
-            msg_Warn(p_stream, "Connection command not supported: %s",
+            msg_Warn(p_intf, "Connection command not supported: %s",
                     type.c_str());
         }
     }
     else
     {
-        msg_Err(p_stream, "Unknown namespace: %s", msg.namespace_().c_str());
+        msg_Err(p_intf, "Unknown namespace: %s", msg.namespace_().c_str());
     }
 }
 
@@ -672,22 +896,75 @@ void intf_sys_t::msgReceiverLaunchApp()
 }
 
 
-void intf_sys_t::msgPlayerLoad()
+std::string intf_sys_t::GetMedia()
 {
-    char *psz_mime = var_InheritString(p_stream, CONTROL_CFG_PREFIX "mime");
-    if (psz_mime == NULL)
-        return;
-
+    std::stringstream ss;
+
+    input_item_t * p_item = input_GetItem(p_input);
+    if ( p_item )
+    {
+        char *psz_name = input_item_GetTitleFbName( p_item );
+        ss << "\"metadata\":{"
+           << " \"metadataType\":0"
+           << ",\"title\":\"" << psz_name << "\"";
+
+        char *psz_arturl = input_item_GetArtworkURL( p_item );
+        if ( psz_arturl && !strncmp(psz_arturl, "http", 4))
+            ss << ",\"images\":[\"" << psz_arturl << "\"]";
+        free( psz_arturl );
+
+        ss << "},";
+        free( psz_name );
+
+        std::stringstream chromecast_url;
+        int i_port = var_InheritInteger(p_intf, CONTROL_CFG_PREFIX "http-port");
+        chromecast_url << "http://" << serverIP << ":" << i_port << "/stream";
+        s_chromecast_url = chromecast_url.str();
+
+        msg_Dbg(p_intf,"s_chromecast_url: %s", s_chromecast_url.c_str());
+    }
+
+    ss << "\"contentId\":\"" << s_chromecast_url << "\""
+       << ",\"streamType\":\"LIVE\""
+       << ",\"contentType\":\"" << mime << "\"";
+
+    return ss.str();
+}
+
+void intf_sys_t::msgPlayerLoad()
+{
     std::stringstream ss;
     ss << "{\"type\":\"LOAD\","
-       <<  "\"media\":{\"contentId\":\"http://" << serverIP << ":"
-           << var_InheritInteger(p_stream, CONTROL_CFG_PREFIX"http-port")
-           << "/stream\","
-       <<             "\"streamType\":\"LIVE\","
-       <<             "\"contentType\":\"" << std::string(psz_mime) << "\"},"
-       <<  "\"requestId\":" << i_requestId++ << "}";
+       <<  "\"media\":{" << GetMedia() << "},"
+       <<  "\"autoplay\":\"false\","
+       <<  "\"requestId\":" << i_requestId++
+       << "}";
+
+    buildMessage(NAMESPACE_MEDIA, ss.str(), appTransportId);
+}
+
+void intf_sys_t::msgPlayerPlay()
+{
+    assert(!mediaSessionId.empty());
+
+    std::stringstream ss;
+    ss << "{\"type\":\"PLAY\","
+       <<  "\"mediaSessionId\":" << mediaSessionId << ","
+       <<  "\"requestId\":" << i_requestId++
+       << "}";
+
+    buildMessage(NAMESPACE_MEDIA, ss.str(), appTransportId);
+}
+
+void intf_sys_t::msgPlayerPause()
+{
+    assert(!mediaSessionId.empty());
 
-    free(psz_mime);
+    std::stringstream ss;
+    ss << "{\"type\":\"PAUSE\","
+       <<  "\"mediaSessionId\":" << mediaSessionId << ","
+       <<  "\"requestId\":" << i_requestId++
+       << "}";
 
     buildMessage(NAMESPACE_MEDIA, ss.str(), appTransportId);
 }
@@ -705,7 +982,7 @@ int intf_sys_t::sendMessage(const castchannel::CastMessage &msg)
         return VLC_ENOMEM;
 
 #ifndef NDEBUG
-    msg_Dbg(p_stream, "sendMessage: %s->%s %s", msg.namespace_().c_str(), msg.destination_id().c_str(), msg.payload_utf8().c_str());
+    msg_Dbg(p_intf, "sendMessage: %s->%s %s", msg.namespace_().c_str(), msg.destination_id().c_str(), msg.payload_utf8().c_str());
 #endif
 
     SetDWBE(p_data, i_size);
@@ -727,8 +1004,8 @@ static void* ChromecastThread(void* p_data)
 {
     int canc = vlc_savecancel();
     // Not cancellation-safe part.
-    intf_thread_t *p_stream = reinterpret_cast<intf_thread_t*>(p_data);
-    intf_sys_t *p_sys = p_stream->p_sys;
+    intf_thread_t *p_intf = reinterpret_cast<intf_thread_t*>(p_data);
+    intf_sys_t *p_sys = p_intf->p_sys;
 
     p_sys->msgAuth();
     vlc_restorecancel(canc);
@@ -756,7 +1033,7 @@ void intf_sys_t::handleMessages()
 
     bool b_msgReceived = false;
     uint32_t i_payloadSize = 0;
-    int i_ret = recvPacket(VLC_OBJECT(p_stream), b_msgReceived, i_payloadSize, i_sock_fd,
+    int i_ret = recvPacket(VLC_OBJECT(p_intf), b_msgReceived, i_payloadSize, i_sock_fd,
                            p_tls, &i_received, p_packet, &b_pingTimeout,
                            &i_waitdelay, &i_retries);
 
@@ -769,7 +1046,7 @@ void intf_sys_t::handleMessages()
     if ((i_ret < 0 && errno != EAGAIN) || i_ret == 0)
 #endif
     {
-        msg_Err(p_stream, "The connection to the Chromecast died (receiving).");
+        msg_Err(p_intf, "The connection to the Chromecast died (receiving).");
         vlc_mutex_locker locker(&lock);
         setConnectionStatus(CHROMECAST_CONNECTION_DEAD);
         vlc_restorecancel(canc);
-- 
2.6.0.windows.1



More information about the vlc-devel mailing list