[vlc-devel] [PATCH 07/33] chromecast: move processMessage() in the communication handler

Steve Lhomme robux4 at videolabs.io
Wed Dec 23 12:58:26 CET 2015


---
 modules/stream_out/chromecast/cast.cpp            | 235 +++-------------------
 modules/stream_out/chromecast/chromecast.h        |   7 +
 modules/stream_out/chromecast/chromecast_ctrl.cpp | 188 ++++++++++++++++-
 3 files changed, 217 insertions(+), 213 deletions(-)

diff --git a/modules/stream_out/chromecast/cast.cpp b/modules/stream_out/chromecast/cast.cpp
index 9b1f0ca..cf4c966 100644
--- a/modules/stream_out/chromecast/cast.cpp
+++ b/modules/stream_out/chromecast/cast.cpp
@@ -45,19 +45,22 @@
 #include <google/protobuf/io/zero_copy_stream_impl.h>
 #include <google/protobuf/io/coded_stream.h>
 
-#include "../../misc/webservices/json.h"
-
 #define PACKET_MAX_LEN 10 * 1024
 #define PACKET_HEADER_LEN 4
 
 struct sout_stream_sys_t
 {
     sout_stream_sys_t(intf_sys_t *intf)
-        : p_tls(NULL),
-          i_status(CHROMECAST_DISCONNECTED), p_out(NULL)
-        ,p_intf(intf)
+        : p_tls(NULL)
+        , p_out(NULL)
+        , p_intf(intf)
     {
     }
+    
+    ~sout_stream_sys_t()
+    {
+        delete p_intf;
+    }
 
     int i_sock_fd;
     vlc_tls_creds_t *p_creds;
@@ -65,10 +68,6 @@ struct sout_stream_sys_t
 
     vlc_thread_t chromecastThread;
 
-    int i_status;
-    vlc_mutex_t lock;
-    vlc_cond_t loadCommandCond;
-
     sout_stream_t *p_out;
     intf_sys_t * const p_intf;
 };
@@ -213,7 +212,7 @@ static int Open(vlc_object_t *p_this)
         Clean(p_stream);
         return VLC_EGENERIC;
     }
-    p_sys->i_status = CHROMECAST_TLS_CONNECTED;
+    p_sys->p_intf->i_status = CHROMECAST_TLS_CONNECTED;
 
     char psz_localIP[NI_MAXNUMERICHOST];
     if (net_GetSockAddress(p_sys->i_sock_fd, psz_localIP, NULL))
@@ -249,9 +248,6 @@ static int Open(vlc_object_t *p_this)
         return VLC_EGENERIC;
     }
 
-    vlc_mutex_init(&p_sys->lock);
-    vlc_cond_init(&p_sys->loadCommandCond);
-
     // Start the Chromecast event thread.
     if (vlc_clone(&p_sys->chromecastThread, chromecastThread, p_stream,
                   VLC_THREAD_PRIORITY_LOW))
@@ -268,20 +264,20 @@ static int Open(vlc_object_t *p_this)
     // 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;
-    vlc_mutex_lock(&p_sys->lock);
-    while (p_sys->i_status != CHROMECAST_MEDIA_LOAD_SENT)
+    vlc_mutex_lock(&p_intf->lock);
+    while (p_sys->p_intf->i_status != CHROMECAST_MEDIA_LOAD_SENT)
     {
-        i_ret = vlc_cond_timedwait(&p_sys->loadCommandCond, &p_sys->lock, deadline);
+        i_ret = vlc_cond_timedwait(&p_sys->p_intf->loadCommandCond, &p_intf->lock, deadline);
         if (i_ret == ETIMEDOUT)
         {
             msg_Err(p_stream, "Timeout reached before sending the media loading command");
-            vlc_mutex_unlock(&p_sys->lock);
+            vlc_mutex_unlock(&p_intf->lock);
             vlc_cancel(p_sys->chromecastThread);
             Clean(p_stream);
             return VLC_EGENERIC;
         }
     }
-    vlc_mutex_unlock(&p_sys->lock);
+    vlc_mutex_unlock(&p_intf->lock);
 
     /* Even uglier: sleep more to let to the Chromecast initiate the connection
      * to the http server. */
@@ -309,7 +305,7 @@ static void Close(vlc_object_t *p_this)
     vlc_cancel(p_sys->chromecastThread);
     vlc_join(p_sys->chromecastThread, NULL);
 
-    switch (p_sys->i_status)
+    switch (p_sys->p_intf->i_status)
     {
     case CHROMECAST_MEDIA_LOAD_SENT:
     case CHROMECAST_APP_STARTED:
@@ -338,8 +334,6 @@ static void Clean(sout_stream_t *p_stream)
 
     if (p_sys->p_out)
     {
-        vlc_mutex_destroy(&p_sys->lock);
-        vlc_cond_destroy(&p_sys->loadCommandCond);
         sout_StreamChainDelete(p_sys->p_out, p_sys->p_out);
     }
 
@@ -393,7 +387,7 @@ static void disconnectChromecast(sout_stream_t *p_stream)
         vlc_tls_SessionDelete(p_sys->p_tls);
         vlc_tls_Delete(p_sys->p_creds);
         p_sys->p_tls = NULL;
-        p_sys->i_status = CHROMECAST_DISCONNECTED;
+        p_sys->p_intf->i_status = CHROMECAST_DISCONNECTED;
     }
 }
 
@@ -565,185 +559,6 @@ extern "C" int recvPacket(sout_stream_t *p_stream, bool &b_msgReceived,
 }
 
 
-/**
- * @brief Process a message received from the Chromecast
- * @param p_stream the sout_stream_t structure
- * @param msg the CastMessage to process
- * @return 0 if the message has been successfuly processed else -1
- */
-static int processMessage(sout_stream_t *p_stream, const castchannel::CastMessage &msg)
-{
-    int i_ret = 0;
-    sout_stream_sys_t *p_sys = p_stream->p_sys;
-    std::string namespace_ = msg.namespace_();
-
-    if (namespace_ == NAMESPACE_DEVICEAUTH)
-    {
-        castchannel::DeviceAuthMessage authMessage;
-        authMessage.ParseFromString(msg.payload_binary());
-
-        if (authMessage.has_error())
-        {
-            msg_Err(p_stream, "Authentification error: %d", authMessage.error().error_type());
-            i_ret = -1;
-        }
-        else if (!authMessage.has_response())
-        {
-            msg_Err(p_stream, "Authentification message has no response field");
-            i_ret = -1;
-        }
-        else
-        {
-            vlc_mutex_locker locker(&p_sys->lock);
-            p_sys->i_status = CHROMECAST_AUTHENTICATED;
-            p_sys->p_intf->msgConnect(DEFAULT_CHOMECAST_RECEIVER);
-            p_sys->p_intf->msgReceiverLaunchApp();
-        }
-    }
-    else if (namespace_ == NAMESPACE_HEARTBEAT)
-    {
-        json_value *p_data = json_parse(msg.payload_utf8().c_str());
-        std::string type((*p_data)["type"]);
-
-        if (type == "PING")
-        {
-            msg_Dbg(p_stream, "PING received from the Chromecast");
-            p_sys->p_intf->msgPong();
-        }
-        else if (type == "PONG")
-        {
-            msg_Dbg(p_stream, "PONG received from the Chromecast");
-        }
-        else
-        {
-            msg_Err(p_stream, "Heartbeat command not supported: %s", type.c_str());
-            i_ret = -1;
-        }
-
-        json_value_free(p_data);
-    }
-    else if (namespace_ == NAMESPACE_RECEIVER)
-    {
-        json_value *p_data = json_parse(msg.payload_utf8().c_str());
-        std::string type((*p_data)["type"]);
-
-        if (type == "RECEIVER_STATUS")
-        {
-            json_value applications = (*p_data)["status"]["applications"];
-            const json_value *p_app = NULL;
-            for (unsigned i = 0; i < applications.u.array.length; ++i)
-            {
-                std::string appId(applications[i]["appId"]);
-                if (appId == APP_ID)
-                {
-                    p_app = &applications[i];
-                    vlc_mutex_lock(&p_sys->lock);
-                    if (p_sys->p_intf->appTransportId.empty())
-                        p_sys->p_intf->appTransportId = std::string(applications[i]["transportId"]);
-                    vlc_mutex_unlock(&p_sys->lock);
-                    break;
-                }
-            }
-
-            vlc_mutex_lock(&p_sys->lock);
-            if ( p_app )
-            {
-                if (!p_sys->p_intf->appTransportId.empty()
-                        && p_sys->i_status == CHROMECAST_AUTHENTICATED)
-                {
-                    p_sys->i_status = CHROMECAST_APP_STARTED;
-                    p_sys->p_intf->msgConnect(p_sys->p_intf->appTransportId);
-                    p_sys->p_intf->msgPlayerLoad();
-                    p_sys->i_status = CHROMECAST_MEDIA_LOAD_SENT;
-                    vlc_cond_signal(&p_sys->loadCommandCond);
-                }
-            }
-            else
-            {
-                switch(p_sys->i_status)
-                {
-                /* 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");
-                    p_sys->p_intf->msgReceiverClose(p_sys->p_intf->appTransportId);
-                    p_sys->i_status = CHROMECAST_CONNECTION_DEAD;
-                    // ft
-                default:
-                    break;
-                }
-
-            }
-            vlc_mutex_unlock(&p_sys->lock);
-        }
-        else
-        {
-            msg_Err(p_stream, "Receiver command not supported: %s",
-                    msg.payload_utf8().c_str());
-            i_ret = -1;
-        }
-
-        json_value_free(p_data);
-    }
-    else if (namespace_ == NAMESPACE_MEDIA)
-    {
-        json_value *p_data = json_parse(msg.payload_utf8().c_str());
-        std::string type((*p_data)["type"]);
-
-        if (type == "MEDIA_STATUS")
-        {
-            json_value status = (*p_data)["status"];
-            msg_Dbg(p_stream, "Player state: %s",
-                    status[0]["playerState"].operator const char *());
-        }
-        else if (type == "LOAD_FAILED")
-        {
-            msg_Err(p_stream, "Media load failed");
-            p_sys->p_intf->msgReceiverClose(p_sys->p_intf->appTransportId);
-            vlc_mutex_lock(&p_sys->lock);
-            p_sys->i_status = CHROMECAST_CONNECTION_DEAD;
-            vlc_mutex_unlock(&p_sys->lock);
-        }
-        else
-        {
-            msg_Err(p_stream, "Media command not supported: %s",
-                    msg.payload_utf8().c_str());
-            i_ret = -1;
-        }
-
-        json_value_free(p_data);
-    }
-    else if (namespace_ == NAMESPACE_CONNECTION)
-    {
-        json_value *p_data = json_parse(msg.payload_utf8().c_str());
-        std::string type((*p_data)["type"]);
-        json_value_free(p_data);
-
-        if (type == "CLOSE")
-        {
-            msg_Warn(p_stream, "received close message");
-            vlc_mutex_lock(&p_sys->lock);
-            p_sys->i_status = CHROMECAST_CONNECTION_DEAD;
-            vlc_mutex_unlock(&p_sys->lock);
-        }
-        else
-        {
-            msg_Err(p_stream, "Connection command not supported: %s",
-                    type.c_str());
-            i_ret = -1;
-        }
-    }
-    else
-    {
-        msg_Err(p_stream, "Unknown namespace: %s", msg.namespace_().c_str());
-        i_ret = -1;
-    }
-
-    return i_ret;
-}
-
-
-
 /*****************************************************************************
  * Chromecast thread
  *****************************************************************************/
@@ -783,8 +598,8 @@ static void* chromecastThread(void* p_data)
 #endif
         {
             msg_Err(p_stream, "The connection to the Chromecast died.");
-            vlc_mutex_locker locker(&p_sys->lock);
-            p_sys->i_status = CHROMECAST_CONNECTION_DEAD;
+            vlc_mutex_locker locker(&p_sys->p_intf->lock);
+            p_sys->p_intf->i_status = CHROMECAST_CONNECTION_DEAD;
             break;
         }
 
@@ -798,7 +613,7 @@ static void* chromecastThread(void* p_data)
         {
             castchannel::CastMessage msg;
             msg.ParseFromArray(p_packet + PACKET_HEADER_LEN, i_payloadSize);
-            processMessage(p_stream, msg);
+            p_sys->p_intf->processMessage(msg);
         }
 
         // Send the answer messages if there is any.
@@ -812,18 +627,18 @@ static void* chromecastThread(void* p_data)
 #endif
             {
                 msg_Err(p_stream, "The connection to the Chromecast died.");
-                vlc_mutex_locker locker(&p_sys->lock);
-                p_sys->i_status = CHROMECAST_CONNECTION_DEAD;
+                vlc_mutex_locker locker(&p_sys->p_intf->lock);
+                p_sys->p_intf->i_status = CHROMECAST_CONNECTION_DEAD;
             }
         }
 
-        vlc_mutex_lock(&p_sys->lock);
-        if ( p_sys->i_status == CHROMECAST_CONNECTION_DEAD )
+        vlc_mutex_lock(&p_sys->p_intf->lock);
+        if ( p_sys->p_intf->i_status == CHROMECAST_CONNECTION_DEAD )
         {
-            vlc_mutex_unlock(&p_sys->lock);
+            vlc_mutex_unlock(&p_sys->p_intf->lock);
             break;
         }
-        vlc_mutex_unlock(&p_sys->lock);
+        vlc_mutex_unlock(&p_sys->p_intf->lock);
 
         vlc_restorecancel(canc);
     }
diff --git a/modules/stream_out/chromecast/chromecast.h b/modules/stream_out/chromecast/chromecast.h
index fa01fa5..9cdd1bb 100644
--- a/modules/stream_out/chromecast/chromecast.h
+++ b/modules/stream_out/chromecast/chromecast.h
@@ -66,6 +66,9 @@ struct intf_sys_t
     std::string    serverIP;
     std::string appTransportId;
 
+    vlc_mutex_t  lock;
+    vlc_cond_t   loadCommandCond;
+
     void msgAuth();
     void msgReceiverClose(std::string destinationId);
     void msgPing();
@@ -77,8 +80,12 @@ struct intf_sys_t
 
     void msgPlayerLoad();
 
+    int i_status;
+
     std::queue<castchannel::CastMessage> messagesToSend;
     unsigned i_requestId;
+
+    int processMessage(const castchannel::CastMessage &msg);
 };
 
 #endif /* VLC_CHROMECAST_H */
diff --git a/modules/stream_out/chromecast/chromecast_ctrl.cpp b/modules/stream_out/chromecast/chromecast_ctrl.cpp
index 3e45cbb..e0da352 100644
--- a/modules/stream_out/chromecast/chromecast_ctrl.cpp
+++ b/modules/stream_out/chromecast/chromecast_ctrl.cpp
@@ -36,6 +36,8 @@
 
 #include <sstream>
 
+#include "../../misc/webservices/json.h"
+
 // Media player Chromecast app id
 #define APP_ID "CC1AD845" // Default media player
 
@@ -52,7 +54,7 @@
  */
 static castchannel::CastMessage buildMessage(std::string namespace_,
                                 castchannel::CastMessage_PayloadType payloadType,
-                                std::string payload, std::string destinationId = "receiver-0")
+                                std::string payload, std::string destinationId = DEFAULT_CHOMECAST_RECEIVER)
 {
     castchannel::CastMessage msg;
 
@@ -70,13 +72,193 @@ static castchannel::CastMessage buildMessage(std::string namespace_,
 }
 
 intf_sys_t::intf_sys_t(sout_stream_t * const p_this)
- :p_stream(p_this)
- ,i_requestId(0)
+ : p_stream(p_this)
+ , i_status(CHROMECAST_DISCONNECTED)
+ , i_requestId(0)
 {
+    vlc_mutex_init(&lock);
+    vlc_cond_init(&loadCommandCond);
 }
 
 intf_sys_t::~intf_sys_t()
 {
+    vlc_cond_destroy(&loadCommandCond);
+    vlc_mutex_destroy(&lock);
+}
+
+/**
+ * @brief Process a message received from the Chromecast
+ * @param msg the CastMessage to process
+ * @return 0 if the message has been successfuly processed else -1
+ */
+int intf_sys_t::processMessage(const castchannel::CastMessage &msg)
+{
+    int i_ret = 0;
+    std::string namespace_ = msg.namespace_();
+
+    if (namespace_ == NAMESPACE_DEVICEAUTH)
+    {
+        castchannel::DeviceAuthMessage authMessage;
+        authMessage.ParseFromString(msg.payload_binary());
+
+        if (authMessage.has_error())
+        {
+            msg_Err(p_stream, "Authentification error: %d", authMessage.error().error_type());
+            i_ret = -1;
+        }
+        else if (!authMessage.has_response())
+        {
+            msg_Err(p_stream, "Authentification message has no response field");
+            i_ret = -1;
+        }
+        else
+        {
+            vlc_mutex_locker locker(&lock);
+            i_status = CHROMECAST_AUTHENTICATED;
+            msgConnect(DEFAULT_CHOMECAST_RECEIVER);
+            msgReceiverLaunchApp();
+        }
+    }
+    else if (namespace_ == NAMESPACE_HEARTBEAT)
+    {
+        json_value *p_data = json_parse(msg.payload_utf8().c_str());
+        std::string type((*p_data)["type"]);
+
+        if (type == "PING")
+        {
+            msg_Dbg(p_stream, "PING received from the Chromecast");
+            msgPong();
+        }
+        else if (type == "PONG")
+        {
+            msg_Dbg(p_stream, "PONG received from the Chromecast");
+        }
+        else
+        {
+            msg_Err(p_stream, "Heartbeat command not supported: %s", type.c_str());
+            i_ret = -1;
+        }
+
+        json_value_free(p_data);
+    }
+    else if (namespace_ == NAMESPACE_RECEIVER)
+    {
+        json_value *p_data = json_parse(msg.payload_utf8().c_str());
+        std::string type((*p_data)["type"]);
+
+        if (type == "RECEIVER_STATUS")
+        {
+            json_value applications = (*p_data)["status"]["applications"];
+            const json_value *p_app = NULL;
+            for (unsigned i = 0; i < applications.u.array.length; ++i)
+            {
+                std::string appId(applications[i]["appId"]);
+                if (appId == APP_ID)
+                {
+                    p_app = &applications[i];
+                    vlc_mutex_lock(&lock);
+                    if (appTransportId.empty())
+                        appTransportId = std::string(applications[i]["transportId"]);
+                    vlc_mutex_unlock(&lock);
+                    break;
+                }
+            }
+
+            vlc_mutex_lock(&lock);
+            if ( p_app )
+            {
+                if (!appTransportId.empty()
+                        && i_status == CHROMECAST_AUTHENTICATED)
+                {
+                    i_status = CHROMECAST_APP_STARTED;
+                    msgConnect(appTransportId);
+                    msgPlayerLoad();
+                    i_status = CHROMECAST_MEDIA_LOAD_SENT;
+                    vlc_cond_signal(&loadCommandCond);
+                }
+            }
+            else
+            {
+                switch(i_status)
+                {
+                /* 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");
+                    msgReceiverClose(appTransportId);
+                    i_status = CHROMECAST_CONNECTION_DEAD;
+                    // ft
+                default:
+                    break;
+                }
+
+            }
+            vlc_mutex_unlock(&lock);
+        }
+        else
+        {
+            msg_Err(p_stream, "Receiver command not supported: %s",
+                    msg.payload_utf8().c_str());
+            i_ret = -1;
+        }
+
+        json_value_free(p_data);
+    }
+    else if (namespace_ == NAMESPACE_MEDIA)
+    {
+        json_value *p_data = json_parse(msg.payload_utf8().c_str());
+        std::string type((*p_data)["type"]);
+
+        if (type == "MEDIA_STATUS")
+        {
+            json_value status = (*p_data)["status"];
+            msg_Dbg(p_stream, "Player state: %s",
+                    status[0]["playerState"].operator const char *());
+        }
+        else if (type == "LOAD_FAILED")
+        {
+            msg_Err(p_stream, "Media load failed");
+            msgReceiverClose(appTransportId);
+            vlc_mutex_lock(&lock);
+            i_status = CHROMECAST_CONNECTION_DEAD;
+            vlc_mutex_unlock(&lock);
+        }
+        else
+        {
+            msg_Err(p_stream, "Media command not supported: %s",
+                    msg.payload_utf8().c_str());
+            i_ret = -1;
+        }
+
+        json_value_free(p_data);
+    }
+    else if (namespace_ == NAMESPACE_CONNECTION)
+    {
+        json_value *p_data = json_parse(msg.payload_utf8().c_str());
+        std::string type((*p_data)["type"]);
+        json_value_free(p_data);
+
+        if (type == "CLOSE")
+        {
+            msg_Warn(p_stream, "received close message");
+            vlc_mutex_lock(&lock);
+            i_status = CHROMECAST_CONNECTION_DEAD;
+            vlc_mutex_unlock(&lock);
+        }
+        else
+        {
+            msg_Err(p_stream, "Connection command not supported: %s",
+                    type.c_str());
+            i_ret = -1;
+        }
+    }
+    else
+    {
+        msg_Err(p_stream, "Unknown namespace: %s", msg.namespace_().c_str());
+        i_ret = -1;
+    }
+
+    return i_ret;
 }
 
 /*****************************************************************************
-- 
2.6.3



More information about the vlc-devel mailing list