[vlc-devel] [PATCH 19/33] chromecast: move the packet receiver in the communication handler

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


---
 modules/stream_out/chromecast/cast.cpp            | 171 +---------------------
 modules/stream_out/chromecast/chromecast.h        |   1 +
 modules/stream_out/chromecast/chromecast_ctrl.cpp | 166 ++++++++++++++++++++-
 3 files changed, 169 insertions(+), 169 deletions(-)

diff --git a/modules/stream_out/chromecast/cast.cpp b/modules/stream_out/chromecast/cast.cpp
index c797ffb..e51d26a 100644
--- a/modules/stream_out/chromecast/cast.cpp
+++ b/modules/stream_out/chromecast/cast.cpp
@@ -44,8 +44,6 @@
 #include <google/protobuf/io/zero_copy_stream_impl.h>
 #include <google/protobuf/io/coded_stream.h>
 
-#define PACKET_MAX_LEN 10 * 1024
-
 struct sout_stream_sys_t
 {
     sout_stream_sys_t(intf_sys_t *intf)
@@ -59,7 +57,6 @@ struct sout_stream_sys_t
         delete p_intf;
     }
 
-    int i_sock_fd;
     vlc_tls_creds_t *p_creds;
 
     vlc_thread_t chromecastThread;
@@ -76,13 +73,6 @@ struct sout_stream_sys_t
 
 #define SOUT_CFG_PREFIX "sout-chromecast-"
 
-/* deadline regarding pings sent from receiver */
-#define PING_WAIT_TIME 6000
-#define PING_WAIT_RETRIES 0
-/* deadline regarding pong we expect after pinging the receiver */
-#define PONG_WAIT_TIME 500
-#define PONG_WAIT_RETRIES 2
-
 /*****************************************************************************
  * Local prototypes
  *****************************************************************************/
@@ -199,9 +189,9 @@ static int Open(vlc_object_t *p_this)
         return VLC_EGENERIC;
     }
 
-    p_sys->i_sock_fd = connectChromecast(p_stream, psz_ipChromecast);
+    p_sys->p_intf->i_sock_fd = connectChromecast(p_stream, psz_ipChromecast);
     free(psz_ipChromecast);
-    if (p_sys->i_sock_fd < 0)
+    if (p_sys->p_intf->i_sock_fd < 0)
     {
         msg_Err(p_stream, "Could not connect the Chromecast");
         Clean(p_stream);
@@ -210,7 +200,7 @@ static int Open(vlc_object_t *p_this)
     p_sys->p_intf->setConnectionStatus(CHROMECAST_TLS_CONNECTED);
 
     char psz_localIP[NI_MAXNUMERICHOST];
-    if (net_GetSockAddress(p_sys->i_sock_fd, psz_localIP, NULL))
+    if (net_GetSockAddress(p_sys->p_intf->i_sock_fd, psz_localIP, NULL))
     {
         msg_Err(p_this, "Cannot get local IP address");
         Clean(p_stream);
@@ -388,118 +378,6 @@ static void disconnectChromecast(sout_stream_t *p_stream)
 
 
 
-/**
- * @brief Receive a data packet from the Chromecast
- * @param p_stream 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(sout_stream_t *p_stream, bool &b_msgReceived,
-                          uint32_t &i_payloadSize, int i_sock_fd, vlc_tls_t *p_tls,
-                          unsigned *pi_received, char *p_data, bool *pb_pingTimeout,
-                          int *pi_wait_delay, int *pi_wait_retries)
-{
-    struct pollfd ufd[1];
-    ufd[0].fd = i_sock_fd;
-    ufd[0].events = POLLIN;
-
-    /* The Chromecast normally sends a PING command every 5 seconds or so.
-     * If we do not receive one after 6 seconds, we send a PING.
-     * If after this PING, we do not receive a PONG, then we consider the
-     * connection as dead. */
-    if (poll(ufd, 1, *pi_wait_delay) == 0)
-    {
-        if (*pb_pingTimeout)
-        {
-            if (!*pi_wait_retries)
-            {
-                msg_Err(p_stream, "No PONG answer received from the Chromecast");
-                return 0; // Connection died
-            }
-            (*pi_wait_retries)--;
-        }
-        else
-        {
-            /* 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");
-        }
-        *pb_pingTimeout = true;
-    }
-    else
-    {
-        *pb_pingTimeout = false;
-        /* reset to default ping waiting */
-        *pi_wait_delay = PING_WAIT_TIME;
-        *pi_wait_retries = PING_WAIT_RETRIES;
-    }
-
-    int i_ret;
-
-    /* Packet structure:
-     * +------------------------------------+------------------------------+
-     * | Payload size (uint32_t big endian) |         Payload data         |
-     * +------------------------------------+------------------------------+ */
-    if (*pi_received < PACKET_HEADER_LEN)
-    {
-        // We receive the header.
-        i_ret = tls_Recv(p_tls, p_data, PACKET_HEADER_LEN - *pi_received);
-        if (i_ret <= 0)
-            return i_ret;
-        *pi_received += i_ret;
-    }
-    else
-    {
-        // We receive the payload.
-
-        // Get the size of the payload
-        memcpy(&i_payloadSize, p_data, PACKET_HEADER_LEN);
-        i_payloadSize = hton32(i_payloadSize);
-        const uint32_t i_maxPayloadSize = PACKET_MAX_LEN - PACKET_HEADER_LEN;
-
-        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");
-
-            uint32_t i_size = i_payloadSize - (*pi_received - PACKET_HEADER_LEN);
-            if (i_size > i_maxPayloadSize)
-                i_size = i_maxPayloadSize;
-
-            i_ret = tls_Recv(p_tls, p_data + PACKET_HEADER_LEN, i_size);
-            if (i_ret <= 0)
-                return i_ret;
-            *pi_received += i_ret;
-
-            if (*pi_received < i_payloadSize + PACKET_HEADER_LEN)
-                return i_ret;
-
-            *pi_received = 0;
-            return -1;
-        }
-
-        // Normal case
-        i_ret = tls_Recv(p_tls, p_data + *pi_received,
-                         i_payloadSize - (*pi_received - PACKET_HEADER_LEN));
-        if (i_ret <= 0)
-            return i_ret;
-        *pi_received += i_ret;
-
-        if (*pi_received < i_payloadSize + PACKET_HEADER_LEN)
-            return i_ret;
-
-        assert(*pi_received == i_payloadSize + PACKET_HEADER_LEN);
-        *pi_received = 0;
-        b_msgReceived = true;
-        return i_ret;
-    }
-
-    return i_ret;
-}
-
 
 /*****************************************************************************
  * Chromecast thread
@@ -511,53 +389,12 @@ static void* chromecastThread(void* p_data)
     sout_stream_t *p_stream = reinterpret_cast<sout_stream_t*>(p_data);
     sout_stream_sys_t* p_sys = p_stream->p_sys;
 
-    unsigned i_received = 0;
-    char p_packet[PACKET_MAX_LEN];
-    bool b_pingTimeout = false;
-
-    int i_waitdelay = PING_WAIT_TIME;
-    int i_retries = PING_WAIT_RETRIES;
-
     p_sys->p_intf->msgAuth();
     p_sys->p_intf->sendMessages();
     vlc_restorecancel(canc);
 
     while (1)
     {
-        bool b_msgReceived = false;
-        uint32_t i_payloadSize = 0;
-        int i_ret = recvPacket(p_stream, b_msgReceived, i_payloadSize, p_sys->i_sock_fd,
-                               p_sys->p_intf->p_tls, &i_received, p_packet, &b_pingTimeout,
-                               &i_waitdelay, &i_retries);
-
-        canc = vlc_savecancel();
-        // Not cancellation-safe part.
-
-#if defined(_WIN32)
-        if ((i_ret < 0 && WSAGetLastError() != WSAEWOULDBLOCK) || (i_ret == 0))
-#else
-        if ((i_ret < 0 && errno != EAGAIN) || i_ret == 0)
-#endif
-        {
-            msg_Err(p_stream, "The connection to the Chromecast died.");
-            vlc_mutex_locker locker(&p_sys->p_intf->lock);
-            p_sys->p_intf->setConnectionStatus(CHROMECAST_CONNECTION_DEAD);
-            break;
-        }
-
-        if (b_pingTimeout)
-        {
-            p_sys->p_intf->msgPing();
-            p_sys->p_intf->msgReceiverGetStatus();
-        }
-
-        if (b_msgReceived)
-        {
-            castchannel::CastMessage msg;
-            msg.ParseFromArray(p_packet + PACKET_HEADER_LEN, i_payloadSize);
-            p_sys->p_intf->processMessage(msg);
-        }
-
         p_sys->p_intf->handleMessages();
 
         vlc_mutex_lock(&p_sys->p_intf->lock);
@@ -567,8 +404,6 @@ static void* chromecastThread(void* p_data)
             break;
         }
         vlc_mutex_unlock(&p_sys->p_intf->lock);
-
-        vlc_restorecancel(canc);
     }
 
     return NULL;
diff --git a/modules/stream_out/chromecast/chromecast.h b/modules/stream_out/chromecast/chromecast.h
index 3a1087e..6ce8984 100644
--- a/modules/stream_out/chromecast/chromecast.h
+++ b/modules/stream_out/chromecast/chromecast.h
@@ -66,6 +66,7 @@ struct intf_sys_t
     std::string    serverIP;
     std::string appTransportId;
 
+    int i_sock_fd;
     vlc_tls_t *p_tls;
 
     vlc_mutex_t  lock;
diff --git a/modules/stream_out/chromecast/chromecast_ctrl.cpp b/modules/stream_out/chromecast/chromecast_ctrl.cpp
index a9be103..415bb5b 100644
--- a/modules/stream_out/chromecast/chromecast_ctrl.cpp
+++ b/modules/stream_out/chromecast/chromecast_ctrl.cpp
@@ -38,9 +38,18 @@
 
 #include "../../misc/webservices/json.h"
 
+#define PACKET_MAX_LEN 10 * 1024
+
 // Media player Chromecast app id
 #define APP_ID "CC1AD845" // Default media player aka DEFAULT_MEDIA_RECEIVER_APPLICATION_ID
 
+/* deadline regarding pings sent from receiver */
+#define PING_WAIT_TIME 6000
+#define PING_WAIT_RETRIES 0
+/* deadline regarding pong we expect after pinging the receiver */
+#define PONG_WAIT_TIME 500
+#define PONG_WAIT_RETRIES 2
+
 #define SOUT_CFG_PREFIX "sout-chromecast-"
 
 static const std::string NAMESPACE_DEVICEAUTH       = "urn:x-cast:com.google.cast.tp.deviceauth";
@@ -95,6 +104,118 @@ intf_sys_t::~intf_sys_t()
 }
 
 /**
+ * @brief Receive a data packet from the Chromecast
+ * @param p_stream 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(sout_stream_t *p_stream, bool &b_msgReceived,
+                          uint32_t &i_payloadSize, int i_sock_fd, vlc_tls_t *p_tls,
+                          unsigned *pi_received, char *p_data, bool *pb_pingTimeout,
+                          int *pi_wait_delay, int *pi_wait_retries)
+{
+    struct pollfd ufd[1];
+    ufd[0].fd = i_sock_fd;
+    ufd[0].events = POLLIN;
+
+    /* The Chromecast normally sends a PING command every 5 seconds or so.
+     * If we do not receive one after 6 seconds, we send a PING.
+     * If after this PING, we do not receive a PONG, then we consider the
+     * connection as dead. */
+    if (poll(ufd, 1, *pi_wait_delay) == 0)
+    {
+        if (*pb_pingTimeout)
+        {
+            if (!*pi_wait_retries)
+            {
+                msg_Err(p_stream, "No PONG answer received from the Chromecast");
+                return 0; // Connection died
+            }
+            (*pi_wait_retries)--;
+        }
+        else
+        {
+            /* 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");
+        }
+        *pb_pingTimeout = true;
+    }
+    else
+    {
+        *pb_pingTimeout = false;
+        /* reset to default ping waiting */
+        *pi_wait_delay = PING_WAIT_TIME;
+        *pi_wait_retries = PING_WAIT_RETRIES;
+    }
+
+    int i_ret;
+
+    /* Packet structure:
+     * +------------------------------------+------------------------------+
+     * | Payload size (uint32_t big endian) |         Payload data         |
+     * +------------------------------------+------------------------------+ */
+    if (*pi_received < PACKET_HEADER_LEN)
+    {
+        // We receive the header.
+        i_ret = tls_Recv(p_tls, p_data, PACKET_HEADER_LEN - *pi_received);
+        if (i_ret <= 0)
+            return i_ret;
+        *pi_received += i_ret;
+    }
+    else
+    {
+        // We receive the payload.
+
+        // Get the size of the payload
+        memcpy(&i_payloadSize, p_data, PACKET_HEADER_LEN);
+        i_payloadSize = hton32(i_payloadSize);
+        const uint32_t i_maxPayloadSize = PACKET_MAX_LEN - PACKET_HEADER_LEN;
+
+        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");
+
+            uint32_t i_size = i_payloadSize - (*pi_received - PACKET_HEADER_LEN);
+            if (i_size > i_maxPayloadSize)
+                i_size = i_maxPayloadSize;
+
+            i_ret = tls_Recv(p_tls, p_data + PACKET_HEADER_LEN, i_size);
+            if (i_ret <= 0)
+                return i_ret;
+            *pi_received += i_ret;
+
+            if (*pi_received < i_payloadSize + PACKET_HEADER_LEN)
+                return i_ret;
+
+            *pi_received = 0;
+            return -1;
+        }
+
+        // Normal case
+        i_ret = tls_Recv(p_tls, p_data + *pi_received,
+                         i_payloadSize - (*pi_received - PACKET_HEADER_LEN));
+        if (i_ret <= 0)
+            return i_ret;
+        *pi_received += i_ret;
+
+        if (*pi_received < i_payloadSize + PACKET_HEADER_LEN)
+            return i_ret;
+
+        assert(*pi_received == i_payloadSize + PACKET_HEADER_LEN);
+        *pi_received = 0;
+        b_msgReceived = true;
+        return i_ret;
+    }
+
+    return i_ret;
+}
+
+/**
  * @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
@@ -385,7 +506,48 @@ int intf_sys_t::sendMessages()
 
 void intf_sys_t::handleMessages()
 {
-    int i_ret;
+    unsigned i_received = 0;
+    char p_packet[PACKET_MAX_LEN];
+    bool b_pingTimeout = false;
+
+    int i_waitdelay = PING_WAIT_TIME;
+    int i_retries = PING_WAIT_RETRIES;
+
+    bool b_msgReceived = false;
+    uint32_t i_payloadSize = 0;
+    int i_ret = recvPacket(p_stream, b_msgReceived, i_payloadSize, i_sock_fd,
+                           p_tls, &i_received, p_packet, &b_pingTimeout,
+                           &i_waitdelay, &i_retries);
+
+    int canc = vlc_savecancel();
+    // Not cancellation-safe part.
+
+#if defined(_WIN32)
+    if ((i_ret < 0 && WSAGetLastError() != WSAEWOULDBLOCK) || (i_ret == 0))
+#else
+    if ((i_ret < 0 && errno != EAGAIN) || i_ret == 0)
+#endif
+    {
+        msg_Err(p_stream, "The connection to the Chromecast died.");
+        vlc_mutex_locker locker(&lock);
+        setConnectionStatus(CHROMECAST_CONNECTION_DEAD);
+        vlc_restorecancel(canc);
+        return;
+    }
+
+    if (b_pingTimeout)
+    {
+        msgPing();
+        msgReceiverGetStatus();
+    }
+
+    if (b_msgReceived)
+    {
+        castchannel::CastMessage msg;
+        msg.ParseFromArray(p_packet + PACKET_HEADER_LEN, i_payloadSize);
+        processMessage(msg);
+    }
+
     // Send the answer messages if there is any.
     if (!messagesToSend.empty())
     {
@@ -401,4 +563,6 @@ void intf_sys_t::handleMessages()
             setConnectionStatus(CHROMECAST_CONNECTION_DEAD);
         }
     }
+
+    vlc_restorecancel(canc);
 }
-- 
2.6.3



More information about the vlc-devel mailing list