-
Notifications
You must be signed in to change notification settings - Fork 0
/
chromecast.h
162 lines (145 loc) · 4.32 KB
/
chromecast.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
#pragma once
#include "globals.h"
#include "connection.h"
#include "castchannel.h"
#include <fstream>
namespace cc
{
static std::string dest;
static std::string mediaSession;
bool sendMessage(const Connection &conn, const std::string &ns, const std::string &message)
{
if (s_verbose) {
std::cout << "Sending to '" << dest << "': '" << ns << ": '" << message << "'" << std::endl;
}
CastMessage msg;
msg._payload_type = CastMessage::STRING;
msg._protocol_version = CastMessage::CASTV2_1_0;
msg._namespace = ns;
msg._source_id = "sender-0";
msg._destination_id = dest.empty() ? "receiver-0" : dest;
msg._payload_utf8 = message;
const uint32_t byteSize = htonl(uint32_t(msg.size()));
std::basic_string<uint8_t> buffer(sizeof byteSize, '\0');
memcpy(buffer.data(), &byteSize, sizeof byteSize);
std::basic_string<uint8_t> contents;
contents.reserve(1024);
if (!msg.serialize(&buffer)) {
puts("Failed to serialize");
return false;
}
return conn.write(buffer);
}
namespace ns {
enum Namespace {
Connection = 0,
Receiver,
Heartbeat,
Media,
NamespacesCount
};
static const char *strings[ns::NamespacesCount] = {
"urn:x-cast:com.google.cast.tp.connection",
"urn:x-cast:com.google.cast.receiver",
"urn:x-cast:com.google.cast.tp.heartbeat",
"urn:x-cast:com.google.cast.media"
};
}// namespace ns
namespace msg
{
enum Type {
Connect = 0,
Ping,
Pong,
GetStatus,
MediaStatus,
SimpleMessageCount
};
}//namespace msgs
static int s_requestId = 1;
bool sendSimple(const Connection &conn, const msg::Type type, const ns::Namespace urn)
{
static const char *msgs[msg::SimpleMessageCount] = {
"{\"type\": \"CONNECT\"}",
"{\"type\": \"PING\"}",
"{\"type\": \"PONG\"}",
"{\"type\": \"GET_STATUS\", \"requestId\": 1}",
"{\"type\": \"MEDIA_STATUS\"}"
};
if (urn >= ns::NamespacesCount) {
return false;
}
if (type >= msg::SimpleMessageCount) {
return false;
}
if (type == msg::GetStatus && mediaSession != "") {
return sendMessage(conn,
ns::strings[ns::Media],
"{ "
" \"type\": \"GET_STATUS\", "
" \"requestId\": " + std::to_string(s_requestId++) + ", "
" \"mediaSessionId\": \"" + mediaSession + "\""
"}"
);
}
const bool wasVerbose = s_verbose;
if (type == msg::Ping || type == msg::Pong) {
// too much spam
s_verbose = false;
}
const bool ret = sendMessage(conn, ns::strings[urn], msgs[type]);
s_verbose = wasVerbose;
return ret;
}
bool seek(const Connection &conn, double position)
{
if (mediaSession.empty()) {
std::cerr << "Can't seek without media session" << std::endl;
return false;
}
return sendMessage(conn,
ns::strings[ns::Media],
"{ "
" \"type\": \"SEEK\", "
" \"requestId\": " + std::to_string(s_requestId++) + ", "
" \"mediaSessionId\": \"" + mediaSession + "\", "
" \"currentTime\": " + std::to_string(position) +
"}"
);
}
bool sendSimpleMedia(const Connection &conn, const std::string &command)
{
if (mediaSession.empty()) {
std::cerr << "Can't seek without media session" << std::endl;
return false;
}
return sendMessage(conn,
ns::strings[ns::Media],
"{ "
" \"type\": \"" + command + "\", "
" \"requestId\": " + std::to_string(s_requestId++) + ", "
" \"mediaSessionId\": \"" + mediaSession + "\" "
"}"
);
}
bool loadMedia(const Connection &conn, const std::string &video, double position)
{
if (video.empty()) {
puts("Can't load empty video");
return false;
}
return sendMessage(conn,
ns::strings[ns::Media],
"{ "
" \"type\": \"LOAD\", "
" \"requestId\": " + std::to_string(s_requestId++) + ", "
" \"media\": {"
" \"contentId\": \"" + video + "\", "
" \"streamType\": \"BUFFERED\", "
" \"contentType\": \"x-youtube/video\" "
" }, "
" \"currentTime\": " + std::to_string(position) +
"}"
);
}
} //namespace cc