[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