[vlc-commits] chromecast: Move ChromecastCommunication in its own file

Hugo Beauzée-Luyssen git at videolan.org
Tue Feb 21 14:00:55 CET 2017


vlc | branch: master | Hugo Beauzée-Luyssen <hugo at beauzee.fr> | Fri Feb 17 15:31:38 2017 +0100| [bf234d5733cc6a171cfebaa3edba88fdd853b21e] | committer: Hugo Beauzée-Luyssen

chromecast: Move ChromecastCommunication in its own file

> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=bf234d5733cc6a171cfebaa3edba88fdd853b21e
---

 modules/stream_out/Makefile.am                     |   2 +-
 modules/stream_out/chromecast/chromecast.h         |  14 +
 .../chromecast/chromecast_communication.cpp        | 463 +++++++++++++++++++++
 modules/stream_out/chromecast/chromecast_ctrl.cpp  | 440 --------------------
 4 files changed, 478 insertions(+), 441 deletions(-)

diff --git a/modules/stream_out/Makefile.am b/modules/stream_out/Makefile.am
index a598bcc..f30069e 100644
--- a/modules/stream_out/Makefile.am
+++ b/modules/stream_out/Makefile.am
@@ -87,7 +87,7 @@ libdemux_chromecast_plugin_la_CPPFLAGS = $(AM_CPPFLAGS) -Istream_out/chromecast
 libstream_out_chromecast_plugin_la_SOURCES = stream_out/chromecast/cast.cpp stream_out/chromecast/chromecast.h \
                                              stream_out/chromecast/cast_channel.proto \
                                              stream_out/chromecast/chromecast_common.h stream_out/chromecast/chromecast_ctrl.cpp \
-                                             misc/webservices/json.h misc/webservices/json.c
+                                             misc/webservices/json.h misc/webservices/json.c stream_out/chromecast/chromecast_communication.cpp
 nodist_libstream_out_chromecast_plugin_la_SOURCES = stream_out/chromecast/cast_channel.pb.cc
 libstream_out_chromecast_plugin_la_CPPFLAGS = $(AM_CPPFLAGS) -Istream_out/chromecast $(CHROMECAST_CFLAGS)
 libstream_out_chromecast_plugin_la_LIBADD = $(CHROMECAST_LIBS) $(SOCKET_LIBS)
diff --git a/modules/stream_out/chromecast/chromecast.h b/modules/stream_out/chromecast/chromecast.h
index cf1763c..27406bd 100644
--- a/modules/stream_out/chromecast/chromecast.h
+++ b/modules/stream_out/chromecast/chromecast.h
@@ -46,10 +46,24 @@
 static const std::string DEFAULT_CHOMECAST_RECEIVER = "receiver-0";
 /* see https://developers.google.com/cast/docs/reference/messages */
 static const std::string NAMESPACE_MEDIA            = "urn:x-cast:com.google.cast.media";
+static const std::string NAMESPACE_DEVICEAUTH       = "urn:x-cast:com.google.cast.tp.deviceauth";
+static const std::string NAMESPACE_CONNECTION       = "urn:x-cast:com.google.cast.tp.connection";
+static const std::string NAMESPACE_HEARTBEAT        = "urn:x-cast:com.google.cast.tp.heartbeat";
+static const std::string NAMESPACE_RECEIVER         = "urn:x-cast:com.google.cast.receiver";
+
 
 #define CHROMECAST_CONTROL_PORT 8009
 #define HTTP_PORT               8010
 
+/* deadline regarding pings sent from receiver */
+#define PING_WAIT_TIME 6000
+#define PING_WAIT_RETRIES 0
+
+#define PACKET_MAX_LEN 10 * 1024
+
+// Media player Chromecast app id
+#define APP_ID "CC1AD845" // Default media player aka DEFAULT_MEDIA_RECEIVER_APPLICATION_ID
+
 // Status
 enum connection_status
 {
diff --git a/modules/stream_out/chromecast/chromecast_communication.cpp b/modules/stream_out/chromecast/chromecast_communication.cpp
new file mode 100644
index 0000000..8c2e93b
--- /dev/null
+++ b/modules/stream_out/chromecast/chromecast_communication.cpp
@@ -0,0 +1,463 @@
+/*****************************************************************************
+ * chromecast_communication.cpp: Handle chromecast protocol messages
+ *****************************************************************************
+ * Copyright © 2014-2017 VideoLAN
+ *
+ * Authors: Adrien Maglo <magsoft at videolan.org>
+ *          Jean-Baptiste Kempf <jb at videolan.org>
+ *          Steve Lhomme <robux4 at videolabs.io>
+ *          Hugo Beauzée-Luyssen <hugo at beauzee.fr>
+ *
+ * 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 "chromecast.h"
+#ifdef HAVE_POLL
+# include <poll.h>
+#endif
+
+/* deadline regarding pong we expect after pinging the receiver */
+#define PONG_WAIT_TIME 500
+#define PONG_WAIT_RETRIES 2
+
+ChromecastCommunication::ChromecastCommunication( vlc_object_t* p_module )
+    : p_module( p_module )
+    , i_sock_fd( -1 )
+    , p_creds( NULL )
+    , p_tls( NULL )
+    , i_receiver_requestId( 0 )
+    , i_requestId( 0 )
+{
+}
+
+bool ChromecastCommunication::connect( const char* targetIP, unsigned int devicePort )
+{
+    if (devicePort == 0)
+        devicePort = CHROMECAST_CONTROL_PORT;
+    i_sock_fd = net_ConnectTCP( p_module, targetIP, devicePort);
+    if (i_sock_fd < 0)
+        return false;
+
+    char psz_localIP[NI_MAXNUMERICHOST];
+    if ( net_GetSockAddress( i_sock_fd, psz_localIP, NULL ) )
+    {
+        msg_Err( p_module, "Cannot get local IP address" );
+        return false;
+    }
+    serverIp = psz_localIP;
+
+    p_creds = vlc_tls_ClientCreate( p_module->obj.parent );
+    if (p_creds == NULL)
+    {
+        msg_Err( p_module, "Failed to create TLS client" );
+        net_Close(i_sock_fd);
+        return false;
+    }
+
+    p_tls = vlc_tls_ClientSessionCreateFD( p_creds, i_sock_fd, targetIP, "tcps", NULL, NULL );
+
+    if (p_tls == NULL)
+    {
+        msg_Err( p_module, "Failed to create client session" );
+        net_Close(i_sock_fd);
+        vlc_tls_Delete(p_creds);
+        return false;
+    }
+    return true;
+}
+
+ChromecastCommunication::~ChromecastCommunication()
+{
+    disconnect();
+}
+
+void ChromecastCommunication::disconnect()
+{
+    if ( p_tls != NULL )
+    {
+        vlc_tls_Close(p_tls);
+        vlc_tls_Delete(p_creds);
+        p_tls = NULL;
+    }
+}
+
+/**
+ * @brief Build a CastMessage to send to the Chromecast
+ * @param namespace_ the message namespace
+ * @param payloadType the payload type (CastMessage_PayloadType_STRING or
+ * CastMessage_PayloadType_BINARY
+ * @param payload the payload
+ * @param destinationId the destination idenifier
+ * @return the generated CastMessage
+ */
+void ChromecastCommunication::buildMessage(const std::string & namespace_,
+                              const std::string & payload,
+                              const std::string & destinationId,
+                              castchannel::CastMessage_PayloadType payloadType)
+{
+    castchannel::CastMessage msg;
+
+    msg.set_protocol_version(castchannel::CastMessage_ProtocolVersion_CASTV2_1_0);
+    msg.set_namespace_(namespace_);
+    msg.set_payload_type(payloadType);
+    msg.set_source_id("sender-vlc");
+    msg.set_destination_id(destinationId);
+    if (payloadType == castchannel::CastMessage_PayloadType_STRING)
+        msg.set_payload_utf8(payload);
+    else // CastMessage_PayloadType_BINARY
+        msg.set_payload_binary(payload);
+
+    sendMessage(msg);
+}
+
+/**
+ * @brief Receive a data packet from the Chromecast
+ * @param p_module the module to log with
+ * @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
+ */
+int ChromecastCommunication::recvPacket(bool *b_msgReceived,
+                          uint32_t &i_payloadSize,
+                          unsigned *pi_received, uint8_t *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. */
+    ssize_t val = vlc_poll_i11e(ufd, 1, *pi_wait_delay);
+    if ( val == -1 && errno != EINTR )
+        return -1;
+
+    if (val == 0)
+    {
+        if (*pb_pingTimeout)
+        {
+            if (!*pi_wait_retries)
+            {
+                msg_Err( p_module, "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_module, "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 = 0;
+    if ( ufd[0].revents & POLLIN )
+    {
+        /* we have received stuff */
+
+        /* Packet structure:
+         * +------------------------------------+------------------------------+
+         * | Payload size (uint32_t big endian) |         Payload data         |
+         * +------------------------------------+------------------------------+ */
+        while (*pi_received < PACKET_HEADER_LEN)
+        {
+            // We receive the header.
+            i_ret = tls_Recv(p_tls, p_data + *pi_received, PACKET_HEADER_LEN - *pi_received);
+            if (i_ret <= 0)
+                return i_ret;
+            *pi_received += i_ret;
+        }
+
+        // We receive the payload.
+
+        // Get the size of the payload
+        i_payloadSize = U32_AT( p_data );
+        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_module, "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;
+    }
+
+    if ( val == -1 && errno == EINTR )
+        /* we have stuff to send */
+        i_ret = 1;
+
+    return i_ret;
+}
+
+
+/*****************************************************************************
+ * Message preparation
+ *****************************************************************************/
+void ChromecastCommunication::msgAuth()
+{
+    castchannel::DeviceAuthMessage authMessage;
+    authMessage.mutable_challenge();
+
+    buildMessage(NAMESPACE_DEVICEAUTH, authMessage.SerializeAsString(),
+                 DEFAULT_CHOMECAST_RECEIVER, castchannel::CastMessage_PayloadType_BINARY);
+}
+
+
+void ChromecastCommunication::msgPing()
+{
+    std::string s("{\"type\":\"PING\"}");
+    buildMessage( NAMESPACE_HEARTBEAT, s, DEFAULT_CHOMECAST_RECEIVER );
+}
+
+
+void ChromecastCommunication::msgPong()
+{
+    std::string s("{\"type\":\"PONG\"}");
+    buildMessage( NAMESPACE_HEARTBEAT, s, DEFAULT_CHOMECAST_RECEIVER );
+}
+
+void ChromecastCommunication::msgConnect( const std::string& destinationId )
+{
+    std::string s("{\"type\":\"CONNECT\"}");
+    buildMessage( NAMESPACE_CONNECTION, s, destinationId );
+}
+
+void ChromecastCommunication::msgReceiverClose( const std::string& destinationId )
+{
+    std::string s("{\"type\":\"CLOSE\"}");
+    buildMessage( NAMESPACE_CONNECTION, s, destinationId );
+}
+
+void ChromecastCommunication::msgReceiverGetStatus()
+{
+    std::stringstream ss;
+    ss << "{\"type\":\"GET_STATUS\","
+       <<  "\"requestId\":" << i_receiver_requestId++ << "}";
+
+    buildMessage( NAMESPACE_RECEIVER, ss.str(), DEFAULT_CHOMECAST_RECEIVER );
+}
+
+void ChromecastCommunication::msgReceiverLaunchApp()
+{
+    std::stringstream ss;
+    ss << "{\"type\":\"LAUNCH\","
+       <<  "\"appId\":\"" << APP_ID << "\","
+       <<  "\"requestId\":" << i_receiver_requestId++ << "}";
+
+    buildMessage( NAMESPACE_RECEIVER, ss.str(), DEFAULT_CHOMECAST_RECEIVER );
+}
+
+void ChromecastCommunication::msgPlayerGetStatus( const std::string& destinationId )
+{
+    std::stringstream ss;
+    ss << "{\"type\":\"GET_STATUS\","
+       <<  "\"requestId\":" << i_requestId++
+       << "}";
+
+    pushMediaPlayerMessage( destinationId, ss );
+}
+
+std::string ChromecastCommunication::GetMedia( unsigned int i_port,
+                                               const std::string& title, const std::string& artwork,
+                                               const std::string& mime )
+{
+    std::stringstream ss;
+
+    if ( title.size() )
+    {
+        ss << "\"metadata\":{"
+           << " \"metadataType\":0"
+           << ",\"title\":\"" << title << "\"";
+
+        if ( artwork.size() && !strncmp(artwork.c_str(), "http", 4))
+            ss << ",\"images\":[\"" << artwork << "\"]";
+
+        ss << "},";
+    }
+
+    std::stringstream chromecast_url;
+    chromecast_url << "http://" << serverIp << ":" << i_port << "/stream";
+
+    msg_Dbg( p_module, "s_chromecast_url: %s", chromecast_url.str().c_str());
+
+    ss << "\"contentId\":\"" << chromecast_url.str() << "\""
+       << ",\"streamType\":\"LIVE\""
+       << ",\"contentType\":\"" << mime << "\"";
+
+    return ss.str();
+}
+
+void ChromecastCommunication::msgPlayerLoad( const std::string& destinationId, unsigned int i_port,
+                                             const std::string& title, const std::string& artwork,
+                                             const std::string& mime )
+{
+    std::stringstream ss;
+    ss << "{\"type\":\"LOAD\","
+       <<  "\"media\":{" << GetMedia( i_port, title, artwork, mime ) << "},"
+       <<  "\"autoplay\":\"false\","
+       <<  "\"requestId\":" << i_requestId++
+       << "}";
+
+    pushMediaPlayerMessage( destinationId, ss );
+}
+
+void ChromecastCommunication::msgPlayerPlay( const std::string& destinationId, const std::string& mediaSessionId )
+{
+    assert(!mediaSessionId.empty());
+
+    std::stringstream ss;
+    ss << "{\"type\":\"PLAY\","
+       <<  "\"mediaSessionId\":" << mediaSessionId << ","
+       <<  "\"requestId\":" << i_requestId++
+       << "}";
+
+    pushMediaPlayerMessage( destinationId, ss );
+}
+
+void ChromecastCommunication::msgPlayerStop( const std::string& destinationId, const std::string& mediaSessionId )
+{
+    assert(!mediaSessionId.empty());
+
+    std::stringstream ss;
+    ss << "{\"type\":\"STOP\","
+       <<  "\"mediaSessionId\":" << mediaSessionId << ","
+       <<  "\"requestId\":" << i_requestId++
+       << "}";
+
+    pushMediaPlayerMessage( destinationId, ss );
+}
+
+void ChromecastCommunication::msgPlayerPause( const std::string& destinationId, const std::string& mediaSessionId )
+{
+    assert(!mediaSessionId.empty());
+
+    std::stringstream ss;
+    ss << "{\"type\":\"PAUSE\","
+       <<  "\"mediaSessionId\":" << mediaSessionId << ","
+       <<  "\"requestId\":" << i_requestId++
+       << "}";
+
+    pushMediaPlayerMessage( destinationId, ss );
+}
+
+void ChromecastCommunication::msgPlayerSetVolume( const std::string& destinationId, const std::string& mediaSessionId, float f_volume, bool b_mute )
+{
+    assert(!mediaSessionId.empty());
+
+    if ( f_volume < 0.0 || f_volume > 1.0)
+        return;
+
+    std::stringstream ss;
+    ss << "{\"type\":\"SET_VOLUME\","
+       <<  "\"volume\":{\"level\":" << f_volume << ",\"muted\":" << ( b_mute ? "true" : "false" ) << "},"
+       <<  "\"mediaSessionId\":" << mediaSessionId << ","
+       <<  "\"requestId\":" << i_requestId++
+       << "}";
+
+    pushMediaPlayerMessage( destinationId, ss );
+}
+
+void ChromecastCommunication::msgPlayerSeek( const std::string& destinationId, const std::string& mediaSessionId, const std::string& currentTime )
+{
+    assert(!mediaSessionId.empty());
+
+    std::stringstream ss;
+    ss << "{\"type\":\"SEEK\","
+       <<  "\"currentTime\":" << currentTime << ","
+       <<  "\"mediaSessionId\":" << mediaSessionId << ","
+       <<  "\"requestId\":" << i_requestId++
+       << "}";
+
+    pushMediaPlayerMessage( destinationId, ss );
+}
+
+/**
+ * @brief Send a message to the Chromecast
+ * @param msg the CastMessage to send
+ * @return vlc error code
+ */
+int ChromecastCommunication::sendMessage( const castchannel::CastMessage &msg )
+{
+    int i_size = msg.ByteSize();
+    uint8_t *p_data = new(std::nothrow) uint8_t[PACKET_HEADER_LEN + i_size];
+    if (p_data == NULL)
+        return VLC_ENOMEM;
+
+#ifndef NDEBUG
+    msg_Dbg( p_module, "sendMessage: %s->%s %s", msg.namespace_().c_str(), msg.destination_id().c_str(), msg.payload_utf8().c_str());
+#endif
+
+    SetDWBE(p_data, i_size);
+    msg.SerializeWithCachedSizesToArray(p_data + PACKET_HEADER_LEN);
+
+    int i_ret = tls_Send(p_tls, p_data, PACKET_HEADER_LEN + i_size);
+    delete[] p_data;
+    if (i_ret == PACKET_HEADER_LEN + i_size)
+        return VLC_SUCCESS;
+
+    msg_Warn( p_module, "failed to send message %s (%s)", msg.payload_utf8().c_str(), strerror( errno ) );
+
+    return VLC_EGENERIC;
+}
+
+void ChromecastCommunication::pushMediaPlayerMessage( const std::string& destinationId, const std::stringstream & payload )
+{
+    assert(!destinationId.empty());
+    buildMessage( NAMESPACE_MEDIA, payload.str(), destinationId );
+}
diff --git a/modules/stream_out/chromecast/chromecast_ctrl.cpp b/modules/stream_out/chromecast/chromecast_ctrl.cpp
index 70d069f..4b17c58 100644
--- a/modules/stream_out/chromecast/chromecast_ctrl.cpp
+++ b/modules/stream_out/chromecast/chromecast_ctrl.cpp
@@ -34,121 +34,15 @@
 
 #include <cassert>
 #include <cerrno>
-#ifdef HAVE_POLL
-# include <poll.h>
-#endif
 
 #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
 
 static const mtime_t SEEK_FORWARD_OFFSET = 1000000;
 
-static const std::string NAMESPACE_DEVICEAUTH       = "urn:x-cast:com.google.cast.tp.deviceauth";
-static const std::string NAMESPACE_CONNECTION       = "urn:x-cast:com.google.cast.tp.connection";
-static const std::string NAMESPACE_HEARTBEAT        = "urn:x-cast:com.google.cast.tp.heartbeat";
-static const std::string NAMESPACE_RECEIVER         = "urn:x-cast:com.google.cast.receiver";
-
-ChromecastCommunication::ChromecastCommunication( vlc_object_t* p_module )
-    : p_module( p_module )
-    , i_sock_fd( -1 )
-    , p_creds( NULL )
-    , p_tls( NULL )
-    , i_receiver_requestId( 0 )
-    , i_requestId( 0 )
-{
-}
-
-bool ChromecastCommunication::connect( const char* targetIP, unsigned int devicePort )
-{
-    if (devicePort == 0)
-        devicePort = CHROMECAST_CONTROL_PORT;
-    i_sock_fd = net_ConnectTCP( p_module, targetIP, devicePort);
-    if (i_sock_fd < 0)
-        return false;
-
-    char psz_localIP[NI_MAXNUMERICHOST];
-    if ( net_GetSockAddress( i_sock_fd, psz_localIP, NULL ) )
-    {
-        msg_Err( p_module, "Cannot get local IP address" );
-        return false;
-    }
-    serverIp = psz_localIP;
-
-    p_creds = vlc_tls_ClientCreate( p_module->obj.parent );
-    if (p_creds == NULL)
-    {
-        msg_Err( p_module, "Failed to create TLS client" );
-        net_Close(i_sock_fd);
-        return false;
-    }
-
-    p_tls = vlc_tls_ClientSessionCreateFD( p_creds, i_sock_fd, targetIP, "tcps", NULL, NULL );
-
-    if (p_tls == NULL)
-    {
-        msg_Err( p_module, "Failed to create client session" );
-        net_Close(i_sock_fd);
-        vlc_tls_Delete(p_creds);
-        return false;
-    }
-    return true;
-}
-
-ChromecastCommunication::~ChromecastCommunication()
-{
-    disconnect();
-}
-
-void ChromecastCommunication::disconnect()
-{
-    if ( p_tls != NULL )
-    {
-        vlc_tls_Close(p_tls);
-        vlc_tls_Delete(p_creds);
-        p_tls = NULL;
-    }
-}
-
-/**
- * @brief Build a CastMessage to send to the Chromecast
- * @param namespace_ the message namespace
- * @param payloadType the payload type (CastMessage_PayloadType_STRING or
- * CastMessage_PayloadType_BINARY
- * @param payload the payload
- * @param destinationId the destination idenifier
- * @return the generated CastMessage
- */
-void ChromecastCommunication::buildMessage(const std::string & namespace_,
-                              const std::string & payload,
-                              const std::string & destinationId,
-                              castchannel::CastMessage_PayloadType payloadType)
-{
-    castchannel::CastMessage msg;
-
-    msg.set_protocol_version(castchannel::CastMessage_ProtocolVersion_CASTV2_1_0);
-    msg.set_namespace_(namespace_);
-    msg.set_payload_type(payloadType);
-    msg.set_source_id("sender-vlc");
-    msg.set_destination_id(destinationId);
-    if (payloadType == castchannel::CastMessage_PayloadType_STRING)
-        msg.set_payload_utf8(payload);
-    else // CastMessage_PayloadType_BINARY
-        msg.set_payload_binary(payload);
-
-    sendMessage(msg);
-}
-
 /*****************************************************************************
  * intf_sys_t: class definition
  *****************************************************************************/
@@ -283,126 +177,6 @@ void intf_sys_t::disconnectChromecast()
     receiverState = RECEIVER_IDLE;
 }
 
-
-/**
- * @brief Receive a data packet from the Chromecast
- * @param p_module the module to log with
- * @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
- */
-int ChromecastCommunication::recvPacket(bool *b_msgReceived,
-                          uint32_t &i_payloadSize,
-                          unsigned *pi_received, uint8_t *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. */
-    ssize_t val = vlc_poll_i11e(ufd, 1, *pi_wait_delay);
-    if ( val == -1 && errno != EINTR )
-        return -1;
-
-    if (val == 0)
-    {
-        if (*pb_pingTimeout)
-        {
-            if (!*pi_wait_retries)
-            {
-                msg_Err( p_module, "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_module, "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 = 0;
-    if ( ufd[0].revents & POLLIN )
-    {
-        /* we have received stuff */
-
-        /* Packet structure:
-         * +------------------------------------+------------------------------+
-         * | Payload size (uint32_t big endian) |         Payload data         |
-         * +------------------------------------+------------------------------+ */
-        while (*pi_received < PACKET_HEADER_LEN)
-        {
-            // We receive the header.
-            i_ret = tls_Recv(p_tls, p_data + *pi_received, PACKET_HEADER_LEN - *pi_received);
-            if (i_ret <= 0)
-                return i_ret;
-            *pi_received += i_ret;
-        }
-
-        // We receive the payload.
-
-        // Get the size of the payload
-        i_payloadSize = U32_AT( p_data );
-        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_module, "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;
-    }
-
-    if ( val == -1 && errno == EINTR )
-        /* we have stuff to send */
-        i_ret = 1;
-
-    return i_ret;
-}
-
 /**
  * @brief Process a message received from the Chromecast
  * @param msg the CastMessage to process
@@ -707,222 +481,8 @@ void intf_sys_t::processMessage(const castchannel::CastMessage &msg)
     }
 }
 
-/*****************************************************************************
- * Message preparation
- *****************************************************************************/
-void ChromecastCommunication::msgAuth()
-{
-    castchannel::DeviceAuthMessage authMessage;
-    authMessage.mutable_challenge();
-
-    buildMessage(NAMESPACE_DEVICEAUTH, authMessage.SerializeAsString(),
-                 DEFAULT_CHOMECAST_RECEIVER, castchannel::CastMessage_PayloadType_BINARY);
-}
-
-
-void ChromecastCommunication::msgPing()
-{
-    std::string s("{\"type\":\"PING\"}");
-    buildMessage( NAMESPACE_HEARTBEAT, s, DEFAULT_CHOMECAST_RECEIVER );
-}
 
 
-void ChromecastCommunication::msgPong()
-{
-    std::string s("{\"type\":\"PONG\"}");
-    buildMessage( NAMESPACE_HEARTBEAT, s, DEFAULT_CHOMECAST_RECEIVER );
-}
-
-void ChromecastCommunication::msgConnect( const std::string& destinationId )
-{
-    std::string s("{\"type\":\"CONNECT\"}");
-    buildMessage( NAMESPACE_CONNECTION, s, destinationId );
-}
-
-void ChromecastCommunication::msgReceiverClose( const std::string& destinationId )
-{
-    std::string s("{\"type\":\"CLOSE\"}");
-    buildMessage( NAMESPACE_CONNECTION, s, destinationId );
-}
-
-void ChromecastCommunication::msgReceiverGetStatus()
-{
-    std::stringstream ss;
-    ss << "{\"type\":\"GET_STATUS\","
-       <<  "\"requestId\":" << i_receiver_requestId++ << "}";
-
-    buildMessage( NAMESPACE_RECEIVER, ss.str(), DEFAULT_CHOMECAST_RECEIVER );
-}
-
-void ChromecastCommunication::msgReceiverLaunchApp()
-{
-    std::stringstream ss;
-    ss << "{\"type\":\"LAUNCH\","
-       <<  "\"appId\":\"" << APP_ID << "\","
-       <<  "\"requestId\":" << i_receiver_requestId++ << "}";
-
-    buildMessage( NAMESPACE_RECEIVER, ss.str(), DEFAULT_CHOMECAST_RECEIVER );
-}
-
-void ChromecastCommunication::msgPlayerGetStatus( const std::string& destinationId )
-{
-    std::stringstream ss;
-    ss << "{\"type\":\"GET_STATUS\","
-       <<  "\"requestId\":" << i_requestId++
-       << "}";
-
-    pushMediaPlayerMessage( destinationId, ss );
-}
-
-std::string ChromecastCommunication::GetMedia( unsigned int i_port,
-                                               const std::string& title, const std::string& artwork,
-                                               const std::string& mime )
-{
-    std::stringstream ss;
-
-    if ( title.size() )
-    {
-        ss << "\"metadata\":{"
-           << " \"metadataType\":0"
-           << ",\"title\":\"" << title << "\"";
-
-        if ( artwork.size() && !strncmp(artwork.c_str(), "http", 4))
-            ss << ",\"images\":[\"" << artwork << "\"]";
-
-        ss << "},";
-    }
-
-    std::stringstream chromecast_url;
-    chromecast_url << "http://" << serverIp << ":" << i_port << "/stream";
-
-    msg_Dbg( p_module, "s_chromecast_url: %s", chromecast_url.str().c_str());
-
-    ss << "\"contentId\":\"" << chromecast_url.str() << "\""
-       << ",\"streamType\":\"LIVE\""
-       << ",\"contentType\":\"" << mime << "\"";
-
-    return ss.str();
-}
-
-void ChromecastCommunication::msgPlayerLoad( const std::string& destinationId, unsigned int i_port,
-                                             const std::string& title, const std::string& artwork,
-                                             const std::string& mime )
-{
-    std::stringstream ss;
-    ss << "{\"type\":\"LOAD\","
-       <<  "\"media\":{" << GetMedia( i_port, title, artwork, mime ) << "},"
-       <<  "\"autoplay\":\"false\","
-       <<  "\"requestId\":" << i_requestId++
-       << "}";
-
-    pushMediaPlayerMessage( destinationId, ss );
-}
-
-void ChromecastCommunication::msgPlayerPlay( const std::string& destinationId, const std::string& mediaSessionId )
-{
-    assert(!mediaSessionId.empty());
-
-    std::stringstream ss;
-    ss << "{\"type\":\"PLAY\","
-       <<  "\"mediaSessionId\":" << mediaSessionId << ","
-       <<  "\"requestId\":" << i_requestId++
-       << "}";
-
-    pushMediaPlayerMessage( destinationId, ss );
-}
-
-void ChromecastCommunication::msgPlayerStop( const std::string& destinationId, const std::string& mediaSessionId )
-{
-    assert(!mediaSessionId.empty());
-
-    std::stringstream ss;
-    ss << "{\"type\":\"STOP\","
-       <<  "\"mediaSessionId\":" << mediaSessionId << ","
-       <<  "\"requestId\":" << i_requestId++
-       << "}";
-
-    pushMediaPlayerMessage( destinationId, ss );
-}
-
-void ChromecastCommunication::msgPlayerPause( const std::string& destinationId, const std::string& mediaSessionId )
-{
-    assert(!mediaSessionId.empty());
-
-    std::stringstream ss;
-    ss << "{\"type\":\"PAUSE\","
-       <<  "\"mediaSessionId\":" << mediaSessionId << ","
-       <<  "\"requestId\":" << i_requestId++
-       << "}";
-
-    pushMediaPlayerMessage( destinationId, ss );
-}
-
-void ChromecastCommunication::msgPlayerSetVolume( const std::string& destinationId, const std::string& mediaSessionId, float f_volume, bool b_mute )
-{
-    assert(!mediaSessionId.empty());
-
-    if ( f_volume < 0.0 || f_volume > 1.0)
-        return;
-
-    std::stringstream ss;
-    ss << "{\"type\":\"SET_VOLUME\","
-       <<  "\"volume\":{\"level\":" << f_volume << ",\"muted\":" << ( b_mute ? "true" : "false" ) << "},"
-       <<  "\"mediaSessionId\":" << mediaSessionId << ","
-       <<  "\"requestId\":" << i_requestId++
-       << "}";
-
-    pushMediaPlayerMessage( destinationId, ss );
-}
-
-void ChromecastCommunication::msgPlayerSeek( const std::string& destinationId, const std::string& mediaSessionId, const std::string& currentTime )
-{
-    assert(!mediaSessionId.empty());
-
-    std::stringstream ss;
-    ss << "{\"type\":\"SEEK\","
-       <<  "\"currentTime\":" << currentTime << ","
-       <<  "\"mediaSessionId\":" << mediaSessionId << ","
-       <<  "\"requestId\":" << i_requestId++
-       << "}";
-
-    pushMediaPlayerMessage( destinationId, ss );
-}
-
-/**
- * @brief Send a message to the Chromecast
- * @param msg the CastMessage to send
- * @return vlc error code
- */
-int ChromecastCommunication::sendMessage( const castchannel::CastMessage &msg )
-{
-    int i_size = msg.ByteSize();
-    uint8_t *p_data = new(std::nothrow) uint8_t[PACKET_HEADER_LEN + i_size];
-    if (p_data == NULL)
-        return VLC_ENOMEM;
-
-#ifndef NDEBUG
-    msg_Dbg( p_module, "sendMessage: %s->%s %s", msg.namespace_().c_str(), msg.destination_id().c_str(), msg.payload_utf8().c_str());
-#endif
-
-    SetDWBE(p_data, i_size);
-    msg.SerializeWithCachedSizesToArray(p_data + PACKET_HEADER_LEN);
-
-    int i_ret = tls_Send(p_tls, p_data, PACKET_HEADER_LEN + i_size);
-    delete[] p_data;
-    if (i_ret == PACKET_HEADER_LEN + i_size)
-        return VLC_SUCCESS;
-
-    msg_Warn( p_module, "failed to send message %s (%s)", msg.payload_utf8().c_str(), strerror( errno ) );
-
-    return VLC_EGENERIC;
-}
-
-void ChromecastCommunication::pushMediaPlayerMessage( const std::string& destinationId, const std::stringstream & payload )
-{
-    assert(!destinationId.empty());
-    buildMessage( NAMESPACE_MEDIA, payload.str(), destinationId );
-}
-
 /*****************************************************************************
  * Chromecast thread
  *****************************************************************************/



More information about the vlc-commits mailing list