[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