Twitch SDK (Internal)
rtmp.h
Go to the documentation of this file.
1 #pragma once
2 
4 
5 namespace ttv
6 {
7  namespace broadcast
8  {
9  enum
10  {
12  };
13 
18  enum Chunktype : uint8_t
19  {
24  };
25 
30  enum Channel : uint8_t
31  {
39  };
40 
45  enum PacketType : uint8_t
46  {
54 
56 
59 
62  RTMP_PKT_AMF3 = 0x11,
63 
66  RTMP_PKT_AMF0 = 0x14,
67 
69  };
70 
75  enum CtlType : uint8_t
76  {
84  };
85 
87  template <class Inserter>
88  inline void InsertBigEndian32 (Inserter it, uint32_t val)
89  {
90  auto p = reinterpret_cast<uint8_t*>(&val);
91  *it++ = p[3];
92  *it++ = p[2];
93  *it++ = p[1];
94  *it++ = p[0];
95  }
96 
97  template <class Inserter>
98  inline void InsertBigEndian (Inserter it, uint32_t val)
99  {
100  auto p = reinterpret_cast<uint8_t*>(&val);
101  *it++ = p[2];
102  *it++ = p[1];
103  *it++ = p[0];
104  }
105 
106  template <class Inserter>
107  inline void InsertBigEndian (Inserter it, uint16_t val)
108  {
109  auto p = reinterpret_cast<uint8_t*>(&val);
110  *it++ = p[1];
111  *it++ = p[0];
112  }
113 
114  inline uint32_t BigToLittle(uint32_t source)
115  {
116  uint32_t target = 0;
117 
118  auto pSource = reinterpret_cast<uint8_t*> (&source);
119  auto pTarget = reinterpret_cast<uint8_t*> (&target);
120  pTarget[0] = pSource[3];
121  pTarget[1] = pSource[2];
122  pTarget[2] = pSource[1];
123  pTarget[3] = pSource[0];
124 
125  return target;
126  }
127 
128  inline uint32_t BigToLittle(flv::uint24_t source)
129  {
130  uint32_t target = 0;
131 
132  auto pTarget = reinterpret_cast<uint8_t*> (&target);
133  pTarget[0] = source[2];
134  pTarget[1] = source[1];
135  pTarget[2] = source[0];
136 
137  return target;
138  }
140 
141  struct ChunkHeader
142  {
144  uint8_t streamId;
145  uint32_t timestamp;
146  uint32_t packetLength;
148  uint32_t messageStreamId;
149  };
150 
151  inline size_t GetChunkSize(char firstByteOfChunk)
152  {
153  Chunktype type = static_cast<Chunktype>(firstByteOfChunk >> 6);
154 
155  // if this assert hits we got a really big chunk header
156  assert ((firstByteOfChunk & 0x3f) != 0x3f);
157 
158  switch (type)
159  {
161  return 4;
163  return 8;
165  return 12;
166  case RTMP_CHUNKTYPE_NONE:
167  default:
168  return 1;
169  }
170  }
171 
172  inline ChunkHeader PopulateChunkHeader(const uint8_t* buffer)
173  {
174  #pragma clang diagnostic push
175  #pragma clang diagnostic ignored "-Wold-style-cast"
176  int pos = 0;
177 
178  ChunkHeader h;
179  h.type = static_cast<Chunktype>(buffer[pos] >> 6);
180  h.streamId = buffer[pos++] & 0x3f;
181 
182  if (h.type != RTMP_CHUNKTYPE_NONE)
183  {
184  flv::uint24_t* as24 = (flv::uint24_t*)&buffer[pos];
185  pos+=3;
186  h.timestamp = BigToLittle(*as24);
187  }
188  if (h.type < RTMP_CHUNKTYPE_SMALL)
189  {
190  flv::uint24_t* as24 = (flv::uint24_t*)&buffer[pos];
191  pos+=3;
192  h.packetLength = BigToLittle(*as24);
193  h.messageType = static_cast<PacketType>(buffer[pos++]);
194  }
195  if (h.type == RTMP_CHUNKTYPE_LARGE)
196  {
197  uint8_t* p=reinterpret_cast<uint8_t*>(&h.messageStreamId);
198  memcpy(p, buffer+pos, 4);
199  pos+=4;
200  }
201 
202  return h;
203  #pragma clang diagnostic pop
204  }
205 
206  typedef uint8_t RtmpMessageheader[16];
207 
209  {
210  public:
211  enum State
212  {
215  Used
216  };
217 
219  : mState(Invalid) { }
220 
222  {
223  assert(mState != Used || mDataWritten == mPacketLength);
224  }
225 
227  uint32_t timestamp,
228  uint32_t packetLength,
230  uint32_t messageStreamId)
231  : mChunkChannel(chunkChannel)
232  , mTimestamp(timestamp)
233  , mPacketLength(packetLength)
234  , mMessageType(messageType)
235  , mMessageStreamId(messageStreamId)
236  , mState(New)
237  , mDataWritten(0) { }
238 
240  {
241  *this = rhs;
242  }
243 
245  {
246  if (&rhs != this)
247  {
248  memcpy(this, &rhs, sizeof(RtmpMessageDetails));
249  }
250  return *this;
251  }
252 
253  inline bool IsNew() const {return mState == New;}
254  inline bool IsValid() const {return mState != Invalid;}
255  uint32_t Length() const {return mPacketLength;}
256  void DataWritten(uint32_t length) { assert(mState == Used); mDataWritten+= length; }
257 
258  inline size_t PackMessageHeader (RtmpMessageheader header)
259  {
260  assert (mState == Used || mState == New);
261  if (mState == Invalid)
262  {
263  return 0;
264  }
265 
266  auto type = mState == New ? RTMP_CHUNKTYPE_LARGE : RTMP_CHUNKTYPE_NONE;
267  assert (mChunkChannel != RTMP_CHANNEL_INVALID);
268  size_t pos = 0;
269 
270  header[pos++] = (type << 6) + mChunkChannel;
271 
272  uint32_t shortTimestamp = std::min(0xFFFFFFU, mTimestamp);
273 
274  if (type != RTMP_CHUNKTYPE_NONE)
275  {
276  auto p = reinterpret_cast<uint8_t*>(&shortTimestamp);
277  header[pos++] = p[2];
278  header[pos++] = p[1];
279  header[pos++] = p[0];
280  }
282  {
283  auto p = reinterpret_cast<uint8_t*>(&mPacketLength);
284  header[pos++] = p[2];
285  header[pos++] = p[1];
286  header[pos++] = p[0];
287  header[pos++] = mMessageType;
288  }
289 
290  if (type == RTMP_CHUNKTYPE_LARGE)
291  {
292  auto p = reinterpret_cast<uint32_t*>(&header[pos]);
293  *p = mMessageStreamId;
294  pos+=4;
295  }
296 
297  if (shortTimestamp == 0xFFFFFF)
298  {
299  auto p = reinterpret_cast<uint8_t*>(&mTimestamp);
300  header[pos++] = p[3];
301  header[pos++] = p[2];
302  header[pos++] = p[1];
303  header[pos++] = p[0];
304  }
305 
306  mState = Used;
307  return pos;
308  }
309 
310  private:
312  uint32_t mTimestamp;
313  uint32_t mPacketLength;
317  uint32_t mDataWritten;
318  };
319 
320  /*
321  inline size_t CreateMessageHeader (RtmpMessageheader header,
322  Chunktype type,
323  ttv::Channel chunkChannel,
324  uint32_t timestamp,
325  uint32_t packetLength,
326  PacketType messageType,
327  uint32_t messageStreamId)
328  {
329  assert (chunkChannel != RTMP_CHANNEL_INVALID);
330  size_t pos = 0;
331 
332  header[pos++] = (type << 6) + chunkChannel;
333 
334  if (type != RTMP_CHUNKTYPE_NONE)
335  {
336  auto p = reinterpret_cast<uint8_t*>(&timestamp);
337  header[pos++] = p[2];
338  header[pos++] = p[1];
339  header[pos++] = p[0];
340  }
341  if (type < RTMP_CHUNKTYPE_SMALL)
342  {
343  auto p = reinterpret_cast<uint8_t*>(&packetLength);
344  header[pos++] = p[2];
345  header[pos++] = p[1];
346  header[pos++] = p[0];
347  header[pos++] = messageType;
348  }
349 
350  if (type == RTMP_CHUNKTYPE_LARGE)
351  {
352  auto p = reinterpret_cast<uint32_t*>(&header[pos]);
353  *p = messageStreamId;
354  pos+=4;
355  }
356 
357  return pos;
358  }
359  */
360  }
361 }
uint32_t mMessageStreamId
Definition: rtmp.h:315
needs to be chopped up
Definition: rtmp.h:68
amf3 metadata body
Definition: rtmp.h:60
Chunktype type
Definition: rtmp.h:143
PacketType messageType
Definition: rtmp.h:147
Responds with the ping&#39;s timestamp, so RTT can be calculated (4B)
Definition: rtmp.h:83
See RTMP_CTL_* below for possible values.
Definition: rtmp.h:51
cmd-name, trans-id, amf3 body
Definition: rtmp.h:62
uint32_t mTimestamp
Definition: rtmp.h:312
RtmpMessageDetails()
Definition: rtmp.h:218
Channel
Definition: rtmp.h:30
CtlType
Definition: rtmp.h:75
amf0 metadata body
Definition: rtmp.h:64
uint8_t uint24_t[3]
Definition: flvformat.h:29
uint32_t messageStreamId
Definition: rtmp.h:148
uint32_t Length() const
Definition: rtmp.h:255
uint32_t mDataWritten
Definition: rtmp.h:317
JSON (JavaScript Object Notation).
Definition: adsapi.h:16
No payloads actually documented...
Definition: rtmp.h:55
PacketType
Definition: rtmp.h:45
Data: stream-id (4B)
Definition: rtmp.h:77
uint32_t timestamp
Definition: rtmp.h:145
#define assert(expr)
Definition: assertion.h:47
bool IsValid() const
Definition: rtmp.h:254
Data: stream-id (4B)
Definition: rtmp.h:78
RtmpMessageDetails(const RtmpMessageDetails &rhs)
Definition: rtmp.h:239
bool IsNew() const
Definition: rtmp.h:253
void InsertBigEndian(Inserter it, uint32_t val)
Definition: rtmp.h:98
uint32_t mPacketLength
Definition: rtmp.h:313
~RtmpMessageDetails()
Definition: rtmp.h:221
amf0 shared object command (don&#39;t support)
Definition: rtmp.h:65
State mState
Definition: rtmp.h:316
Definition: rtmp.h:141
cmd-name, trans-id, amf0 body
Definition: rtmp.h:66
uint8_t streamId
Definition: rtmp.h:144
Definition: rtmp.h:58
Data: timestamp (4B)
Definition: rtmp.h:82
Chunktype
Definition: rtmp.h:18
Definition: rtmp.h:57
Not a real value according to the standard.
Definition: rtmp.h:47
void DataWritten(uint32_t length)
Definition: rtmp.h:256
uint32_t BigToLittle(uint32_t source)
Definition: rtmp.h:114
uint8_t RtmpMessageheader[16]
Definition: rtmp.h:206
RtmpMessageDetails(Channel chunkChannel, uint32_t timestamp, uint32_t packetLength, PacketType messageType, uint32_t messageStreamId)
Definition: rtmp.h:226
size_t PackMessageHeader(RtmpMessageheader header)
Definition: rtmp.h:258
Data: stream-id, buffer-length in milliseconds (*** 8B ***)
Definition: rtmp.h:80
Channel mChunkChannel
Definition: rtmp.h:311
void InsertBigEndian32(Inserter it, uint32_t val)
Definition: rtmp.h:88
ChunkHeader PopulateChunkHeader(const uint8_t *buffer)
Definition: rtmp.h:172
amf3 shared object command (don&#39;t support)
Definition: rtmp.h:61
Server telling client it&#39;s not live, Data: stream-id (4B)
Definition: rtmp.h:81
Data: stream-id (4B)
Definition: rtmp.h:79
size_t GetChunkSize(char firstByteOfChunk)
Definition: rtmp.h:151
uint32_t packetLength
Definition: rtmp.h:146
PacketType mMessageType
Definition: rtmp.h:314
RtmpMessageDetails & operator=(const RtmpMessageDetails &rhs)
Definition: rtmp.h:244