1 /*****************************************************************************
2  * chromecast.cpp: Chromecast module for vlc
3  *****************************************************************************
4  * Copyright © 2014-2015 VideoLAN
5  *
6  * Authors: Adrien Maglo <magsoft@videolan.org>
7  *          Jean-Baptiste Kempf <jb@videolan.org>
8  *          Steve Lhomme <robux4@videolabs.io>
9  *
10  * This program is free software; you can redistribute it and/or modify it
11  * under the terms of the GNU Lesser General Public License as published by
12  * the Free Software Foundation; either version 2.1 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  * GNU Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public License
21  * along with this program; if not, write to the Free Software Foundation,
22  * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23  *****************************************************************************/
24 
25 /*****************************************************************************
26  * Preamble
27  *****************************************************************************/
28 
29 #ifndef VLC_CHROMECAST_H
30 #define VLC_CHROMECAST_H
31 
32 #include <vlc_common.h>
33 #include <vlc_plugin.h>
34 #include <vlc_tls.h>
35 #include <vlc_interrupt.h>
36 #include <vlc_httpd.h>
37 
38 #include <atomic>
39 #include <sstream>
40 #include <queue>
41 
42 #ifndef PROTOBUF_INLINE_NOT_IN_HEADERS
43 # define PROTOBUF_INLINE_NOT_IN_HEADERS 0
44 #endif
45 #include "cast_channel.pb.h"
46 #include "chromecast_common.h"
47 
48 #define PACKET_HEADER_LEN 4
49 
50 // Media player Chromecast app id
51 static const std::string DEFAULT_CHOMECAST_RECEIVER = "receiver-0";
52 /* see https://developers.google.com/cast/docs/reference/messages */
53 static const std::string NAMESPACE_MEDIA            = "urn:x-cast:com.google.cast.media";
54 static const std::string NAMESPACE_DEVICEAUTH       = "urn:x-cast:com.google.cast.tp.deviceauth";
55 static const std::string NAMESPACE_CONNECTION       = "urn:x-cast:com.google.cast.tp.connection";
56 static const std::string NAMESPACE_HEARTBEAT        = "urn:x-cast:com.google.cast.tp.heartbeat";
57 static const std::string NAMESPACE_RECEIVER         = "urn:x-cast:com.google.cast.receiver";
58 
59 
60 #define CHROMECAST_CONTROL_PORT 8009
61 #define HTTP_PORT               8010
62 
63 #define PACKET_MAX_LEN 10 * 1024
64 
65 //#define CHROMECAST_VERBOSE
66 
67 // Media player Chromecast app id
68 #define APP_ID "CC1AD845" // Default media player aka DEFAULT_MEDIA_RECEIVER_APPLICATION_ID
69 
70 enum States
71 {
72     // An authentication request has been sent
73     Authenticating,
74     // We are sending a connection request
75     Connecting,
76     // We are connected to the chromecast but the receiver app is not running.
77     Connected,
78     // We are launching the media receiver app
79     Launching,
80     // The application is ready, but idle
81     Ready,
82     // The chromecast rejected the media
83     LoadFailed,
84     // A media session is being initiated
85     Loading,
86     Buffering,
87     Playing,
88     Paused,
89     Stopping,
90     Stopped,
91     // Something went wrong and the connection is dead.
92     Dead,
93     // Another playback started on the same cast device
94     TakenOver,
95 };
96 
97 class ChromecastCommunication
98 {
99 public:
100     ChromecastCommunication( vlc_object_t* module,
101                              std::string serverPath, unsigned int serverPort,
102                              const char* targetIP, unsigned int devicePort );
103     ~ChromecastCommunication();
104     /**
105      * @brief disconnect close the connection with the chromecast
106      */
107     void disconnect();
108 
109     static const unsigned kInvalidId = 0;
110 
111     /* All msg*() methods return kInvalidId on error, 1 or the receiver/player
112      * request ID on success */
113 
114     unsigned msgPing();
115     unsigned msgPong();
116     unsigned msgConnect( const std::string& destinationId );
117 
118     unsigned msgReceiverLaunchApp();
119     unsigned msgReceiverGetStatus();
120     unsigned msgReceiverClose(const std::string& destinationId);
121     unsigned msgAuth();
122     unsigned msgPlayerLoad( const std::string& destinationId,
123                             const std::string& mime, const vlc_meta_t *p_meta );
124     unsigned msgPlayerPlay( const std::string& destinationId, int64_t mediaSessionId );
125     unsigned msgPlayerStop( const std::string& destinationId, int64_t mediaSessionId );
126     unsigned msgPlayerPause( const std::string& destinationId, int64_t mediaSessionId );
127     unsigned msgPlayerGetStatus( const std::string& destinationId );
128     unsigned msgPlayerSeek( const std::string& destinationId, int64_t mediaSessionId,
129                             const std::string & currentTime );
130     unsigned msgPlayerSetVolume( const std::string& destinationId, int64_t mediaSessionId,
131                                  float volume, bool mute);
132     ssize_t receive( uint8_t *p_data, size_t i_size, int i_timeout, bool *pb_timeout );
133 
getServerIp()134     const std::string getServerIp()
135     {
136         return m_serverIp;
137     }
138 private:
139     int sendMessage(const castchannel::CastMessage &msg);
140 
141     int buildMessage(const std::string & namespace_,
142                      const std::string & payload,
143                      const std::string & destinationId = DEFAULT_CHOMECAST_RECEIVER,
144                      castchannel::CastMessage_PayloadType payloadType = castchannel::CastMessage_PayloadType_STRING);
145     int pushMediaPlayerMessage( const std::string& destinationId, const std::stringstream & payload );
146     std::string GetMedia( const std::string& mime, const vlc_meta_t *p_meta );
147     unsigned getNextReceiverRequestId();
148     unsigned getNextRequestId();
149 
150 private:
151     vlc_object_t* m_module;
152     vlc_tls_creds_t *m_creds;
153     vlc_tls_t *m_tls;
154     unsigned m_receiver_requestId;
155     unsigned m_requestId;
156     std::string m_serverIp;
157     const std::string m_serverPath;
158     const unsigned m_serverPort;
159 };
160 
161 /*****************************************************************************
162  * intf_sys_t: description and status of interface
163  *****************************************************************************/
164 struct intf_sys_t
165 {
166     enum QueueableMessages
167     {
168         Stop,
169     };
170     intf_sys_t(vlc_object_t * const p_this, int local_port, std::string device_addr,
171                int device_port, httpd_host_t *);
172     ~intf_sys_t();
173 
174     void setRetryOnFail(bool);
175     void setHasInput(const std::string mime_type = "");
176 
177     void setOnInputEventCb(on_input_event_itf on_input_event, void *on_input_event_data);
178     void setDemuxEnabled(bool enabled, on_paused_changed_itf on_paused_changed,
179                          void *on_paused_changed_data);
180     void requestPlayerStop();
181     States state() const;
182 
183     void setPacing(bool do_pace);
184     int pace();
185     void sendInputEvent(enum cc_input_event event, union cc_input_arg arg);
186     mtime_t getPauseDelay();
187 
188     unsigned int getHttpStreamPort() const;
189     std::string getHttpStreamPath() const;
190     std::string getHttpArtRoot() const;
191 
192     int httpd_file_fill( uint8_t *psz_request, uint8_t **pp_data, int *pi_data );
193     void interrupt_wake_up();
194 private:
195     void reinit();
196     bool handleMessages();
197 
198     bool processMessage(const castchannel::CastMessage &msg);
199     void queueMessage( QueueableMessages msg );
200 
201     void setPauseState(bool paused);
202     bool isFinishedPlaying();
203     bool isStateError() const;
204     bool isStatePlaying() const;
205     bool isStateReady() const;
206     void tryLoad();
207     void doStop();
208 
209     void setMeta( vlc_meta_t *p_meta );
210 
211     mtime_t getPlaybackTimestamp();
212 
213     double getPlaybackPosition() const;
214 
215     void setInitialTime( mtime_t time );
216     // Sets the current state and signal the associated wait cond.
217     // This must be called with the lock held
218     void setState( States state );
219 
220     void mainLoop();
221     void processAuthMessage( const castchannel::CastMessage& msg );
222     void processHeartBeatMessage( const castchannel::CastMessage& msg );
223     bool processReceiverMessage( const castchannel::CastMessage& msg );
224     void processMediaMessage( const castchannel::CastMessage& msg );
225     void processConnectionMessage( const castchannel::CastMessage& msg );
226 
227 private:
228     static void* ChromecastThread(void* p_data);
229 
230     static mtime_t get_time(void*);
231 
232     static int pace(void*);
233     static void send_input_event(void *, enum cc_input_event event, union cc_input_arg arg);
234     static void set_demux_enabled(void *, bool, on_paused_changed_itf, void *);
235 
236     static void set_pause_state(void*, bool paused);
237 
238     static void set_meta(void*, vlc_meta_t *p_meta);
239 
240     void prepareHttpArtwork();
241 
242     static mtime_t      timeCCToVLC(double);
243     static std::string  timeVLCToCC(mtime_t);
244 
245 private:
246     vlc_object_t  * const m_module;
247     const int      m_device_port;
248     std::string    m_mime;
249     std::string    m_device_addr;
250 
251     std::string m_appTransportId;
252     unsigned m_last_request_id;
253     int64_t m_mediaSessionId;
254 
255     mutable vlc_mutex_t  m_lock;
256     vlc_cond_t   m_stateChangedCond;
257     vlc_cond_t   m_pace_cond;
258     vlc_thread_t m_chromecastThread;
259 
260     on_input_event_itf    m_on_input_event;
261     void                 *m_on_input_event_data;
262 
263     on_paused_changed_itf m_on_paused_changed;
264     void                 *m_on_paused_changed_data;
265 
266     ChromecastCommunication *m_communication;
267     std::queue<QueueableMessages> m_msgQueue;
268     States m_state;
269     bool m_retry_on_fail;
270     bool m_played_once;
271     bool m_request_stop;
272     bool m_request_load;
273     bool m_paused;
274     bool m_input_eof;
275     bool m_cc_eof;
276     bool m_pace;
277     bool m_interrupted;
278 
279     vlc_meta_t *m_meta;
280 
281     vlc_interrupt_t *m_ctl_thread_interrupt;
282 
283     struct httpd_info_t {
284         httpd_info_t( httpd_host_t* host, int port );
285         ~httpd_info_t();
286 
287         httpd_host_t *m_host;
288         int           m_port;
289         httpd_url_t  *m_url;
290         std::string   m_root;
291     } const m_httpd;
292 
293     httpd_file_t     *m_httpd_file;
294     std::string       m_art_http_ip;
295     char             *m_art_url;
296     unsigned          m_art_idx;
297 
298     mtime_t           m_cc_time_last_request_date;
299     mtime_t           m_cc_time_date;
300     mtime_t           m_cc_time;
301 
302     /* shared structure with the demux-filter */
303     chromecast_common      m_common;
304 
305     /* Heartbeat */
306     uint8_t m_pingRetriesLeft;
307 };
308 
309 #endif /* VLC_CHROMECAST_H */
310