1 /*
2  * Copyright (C) 2011 Raphael Coeffic
3  *
4  * For the code parts originating from rtmpdump (rtmpsrv.c):
5  *  Copyright (C) 2009 Andrej Stepanchuk
6  *  Copyright (C) 2009 Howard Chu
7  *
8  * This file is part of SEMS, a free SIP media server.
9  *
10  * SEMS is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version. This program is released under
14  * the GPL with the additional exemption that compiling, linking,
15  * and/or using OpenSSL is allowed.
16  *
17  * For a license to use the SEMS software under conditions
18  * other than those described here, or to purchase support for this
19  * software, please contact iptel.org by e-mail at the following addresses:
20  *    info@iptel.org
21  *
22  * SEMS is distributed in the hope that it will be useful,
23  * but WITHOUT ANY WARRANTY; without even the implied warranty of
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
25  * GNU General Public License for more details.
26  *
27  * You should have received a copy of the GNU General Public License
28  * along with this program; if not, write to the Free Software
29  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
30  */
31 
32 #include <string.h>
33 
34 #include "RtmpSender.h"
35 #include "RtmpUtils.h"
36 #include "log.h"
37 
RtmpSender(RTMP * r)38 RtmpSender::RtmpSender(RTMP* r)
39   : has_work(false),
40     p_rtmp(r),
41     running(false)
42 {
43 }
44 
~RtmpSender()45 RtmpSender::~RtmpSender()
46 {
47   // flush the packet queue
48   m_q_send.lock();
49   while(!q_send.empty()){
50       RTMPPacket p = q_send.front();
51       q_send.pop();
52       RTMPPacket_Free(&p);
53   }
54   m_q_send.unlock();
55 }
56 
push_back(const RTMPPacket & p)57 int RtmpSender::push_back(const RTMPPacket& p)
58 {
59   RTMPPacket np = p;
60   if(!RTMPPacket_Alloc(&np,np.m_nBodySize)){
61     ERROR("could not allocate packet.\n");
62     return 0;
63   }
64   memcpy(np.m_body,p.m_body,p.m_nBodySize);
65 
66   m_q_send.lock();
67   q_send.push(np);
68   has_work.set(!q_send.empty());
69   m_q_send.unlock();
70 
71   return 1;
72 }
73 
run()74 void RtmpSender::run()
75 {
76   running.set(true);
77 
78   while(running.get()){
79 
80     //wait for some work
81     // (at most 1s)
82     //DBG("waiting for work...\n");
83     has_work.wait_for();//_to(1000);
84 
85     // send packets in the queue
86     m_q_send.lock();
87     while(!q_send.empty()){
88       RTMPPacket p = q_send.front();
89       q_send.pop();
90       m_q_send.unlock();
91 
92       if((p.m_nBodySize > (unsigned)p_rtmp->m_outChunkSize) &&
93 	 (p.m_packetType == RTMP_PACKET_TYPE_AUDIO)) {
94 	// adapt chunk size to the maximum body size
95 	// (TODO: set a reasonable max value (spec: 64K))
96 	p_rtmp->m_outChunkSize = p.m_nBodySize;
97 	SendChangeChunkSize();
98       }
99 
100       if(!RTMP_SendPacket(p_rtmp,&p,FALSE)) {
101 	ERROR("could not send packet.\n");
102       }
103 
104       RTMPPacket_Free(&p);
105 
106       m_q_send.lock();
107     }
108     has_work.set(!q_send.empty());
109     m_q_send.unlock();
110   }
111 }
112 
on_stop()113 void RtmpSender::on_stop()
114 {
115   running.set(false);
116 }
117 
SendChangeChunkSize()118 int RtmpSender::SendChangeChunkSize()
119 {
120   RTMPPacket packet;
121   char pbuf[384], *pend = pbuf+sizeof(pbuf);
122 
123   packet.m_nChannel   = 0x02;
124   packet.m_headerType = RTMP_PACKET_SIZE_LARGE;
125   packet.m_packetType = 0x01; // SetChunkSize
126   packet.m_nTimeStamp = 0;
127   packet.m_nInfoField2 = 0;
128   packet.m_hasAbsTimestamp = 0;
129   packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
130 
131   packet.m_nBodySize = 4;
132 
133   AMF_EncodeInt32(packet.m_body, pend, p_rtmp->m_outChunkSize);
134   DBG("changing send chunk size to %i\n",p_rtmp->m_outChunkSize);
135 
136   return RTMP_SendPacket(p_rtmp,&packet,FALSE);
137 }
138 
SendConnectResult(double txn)139 int RtmpSender::SendConnectResult(double txn)
140 {
141   RTMPPacket packet;
142   char pbuf[384], *pend = pbuf+sizeof(pbuf);
143   AMFObject obj;
144   AMFObjectProperty p, op;
145   AVal av;
146 
147   packet.m_nChannel   = CONTROL_CHANNEL;
148   packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
149   packet.m_packetType = INVOKE_PTYPE;
150   packet.m_nTimeStamp = 0;
151   packet.m_nInfoField2 = 0;
152   packet.m_hasAbsTimestamp = 0;
153   packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
154 
155   char *enc = packet.m_body;
156   enc = AMF_EncodeString(enc, pend, &av__result);
157   enc = AMF_EncodeNumber(enc, pend, txn);
158   *enc++ = AMF_OBJECT;
159 
160   STR2AVAL(av, "FMS/3,5,1,525");
161   enc = AMF_EncodeNamedString(enc, pend, &av_fmsVer, &av);
162   enc = AMF_EncodeNamedNumber(enc, pend, &av_capabilities, 31.0);
163   enc = AMF_EncodeNamedNumber(enc, pend, &av_mode, 1.0);
164   *enc++ = 0;
165   *enc++ = 0;
166   *enc++ = AMF_OBJECT_END;
167 
168   *enc++ = AMF_OBJECT;
169 
170   enc = AMF_EncodeNamedString(enc, pend, &av_level, &av_status);
171   STR2AVAL(av, "NetConnection.Connect.Success");
172   enc = AMF_EncodeNamedString(enc, pend, &av_code, &av);
173   STR2AVAL(av, "Connection succeeded.");
174   enc = AMF_EncodeNamedString(enc, pend, &av_description, &av);
175   enc = AMF_EncodeNamedNumber(enc, pend, &av_objectEncoding, p_rtmp->m_fEncoding);
176   STR2AVAL(p.p_name, "version");
177   STR2AVAL(p.p_vu.p_aval, "3,5,1,525");
178   p.p_type = AMF_STRING;
179   obj.o_num = 1;
180   obj.o_props = &p;
181   op.p_type = AMF_OBJECT;
182   STR2AVAL(op.p_name, "data");
183   op.p_vu.p_object = obj;
184   enc = AMFProp_Encode(&op, enc, pend);
185   *enc++ = 0;
186   *enc++ = 0;
187   *enc++ = AMF_OBJECT_END;
188   *enc++ = 0;
189   *enc++ = 0;
190   *enc++ = AMF_OBJECT_END;
191 
192   packet.m_nBodySize = enc - packet.m_body;
193 
194   return push_back(packet);
195 }
196 
SendRegisterResult(double txn,const char * str)197 int RtmpSender::SendRegisterResult(double txn, const char* str)
198 {
199   RTMPPacket packet;
200   char pbuf[512], *pend = pbuf+sizeof(pbuf);
201 
202   packet.m_nChannel   = CONTROL_CHANNEL;
203   packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
204   packet.m_packetType = INVOKE_PTYPE;
205   packet.m_nTimeStamp = 0;
206   packet.m_nInfoField2 = 0;
207   packet.m_hasAbsTimestamp = 0;
208   packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
209 
210   AVal av;
211   char *enc = packet.m_body;
212 
213   enc = AMF_EncodeString(enc, pend, &av__result);
214   enc = AMF_EncodeNumber(enc, pend, txn);
215   *enc++ = AMF_NULL;
216   *enc++ = AMF_OBJECT;
217 
218   enc = AMF_EncodeNamedString(enc, pend, &av_level, &av_status);
219   STR2AVAL(av, str);
220   enc = AMF_EncodeNamedString(enc, pend, &av_uri, &av);
221   *enc++ = 0;
222   *enc++ = 0;
223   *enc++ = AMF_OBJECT_END;
224 
225   packet.m_nBodySize = enc - packet.m_body;
226 
227   return push_back(packet);
228 }
229 
SendErrorResult(double txn,const char * str)230 int RtmpSender::SendErrorResult(double txn, const char* str)
231 {
232   RTMPPacket packet;
233   char pbuf[512], *pend = pbuf+sizeof(pbuf);
234 
235   packet.m_nChannel   = CONTROL_CHANNEL;
236   packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
237   packet.m_packetType = INVOKE_PTYPE;
238   packet.m_nTimeStamp = 0;
239   packet.m_nInfoField2 = 0;
240   packet.m_hasAbsTimestamp = 0;
241   packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
242 
243   AVal av;
244   char *enc = packet.m_body;
245 
246   enc = AMF_EncodeString(enc, pend, &av__error);
247   enc = AMF_EncodeNumber(enc, pend, txn);
248   *enc++ = AMF_NULL;
249   *enc++ = AMF_OBJECT;
250 
251   enc = AMF_EncodeNamedString(enc, pend, &av_level, &av_error);
252   STR2AVAL(av, str);
253   enc = AMF_EncodeNamedString(enc, pend, &av_code, &av);
254   *enc++ = 0;
255   *enc++ = 0;
256   *enc++ = AMF_OBJECT_END;
257 
258   packet.m_nBodySize = enc - packet.m_body;
259 
260   return push_back(packet);
261 }
262 
SendResultNumber(double txn,double ID)263 int RtmpSender::SendResultNumber(double txn, double ID)
264 {
265   RTMPPacket packet;
266   char pbuf[256], *pend = pbuf+sizeof(pbuf);
267 
268   packet.m_nChannel   = CONTROL_CHANNEL;
269   packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
270   packet.m_packetType = INVOKE_PTYPE;
271   packet.m_nTimeStamp = 0;
272   packet.m_nInfoField2 = 0;
273   packet.m_hasAbsTimestamp = 0;
274   packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
275 
276   char *enc = packet.m_body;
277   enc = AMF_EncodeString(enc, pend, &av__result);
278   enc = AMF_EncodeNumber(enc, pend, txn);
279   *enc++ = AMF_NULL;
280   enc = AMF_EncodeNumber(enc, pend, ID);
281 
282   packet.m_nBodySize = enc - packet.m_body;
283 
284   return push_back(packet);
285 }
286 
287 
SendPlayStart()288 int RtmpSender::SendPlayStart()
289 {
290   RTMPPacket packet;
291   char pbuf[384], *pend = pbuf+sizeof(pbuf);
292 
293   packet.m_nChannel   = CONTROL_CHANNEL;
294   packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
295   packet.m_packetType = INVOKE_PTYPE;
296   packet.m_nTimeStamp = 0;
297   packet.m_nInfoField2 = 0;
298   packet.m_hasAbsTimestamp = 0;
299   packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
300 
301   char *enc = packet.m_body;
302   enc = AMF_EncodeString(enc, pend, &av_onStatus);
303   enc = AMF_EncodeNumber(enc, pend, 0);
304 
305   *enc++ = AMF_NULL;//rco: seems to be needed
306   *enc++ = AMF_OBJECT;
307 
308   enc = AMF_EncodeNamedString(enc, pend, &av_level, &av_status);
309   enc = AMF_EncodeNamedString(enc, pend, &av_code, &av_NetStream_Play_Start);
310   enc = AMF_EncodeNamedString(enc, pend, &av_description, &av_Started_playing);
311   enc = AMF_EncodeNamedString(enc, pend, &av_details, &p_rtmp->Link.playpath);
312   enc = AMF_EncodeNamedString(enc, pend, &av_clientid, &av_clientid);
313   *enc++ = 0;
314   *enc++ = 0;
315   *enc++ = AMF_OBJECT_END;
316 
317   packet.m_nBodySize = enc - packet.m_body;
318   return push_back(packet);
319 }
320 
SendPlayStop()321 int RtmpSender::SendPlayStop()
322 {
323   RTMPPacket packet;
324   char pbuf[384], *pend = pbuf+sizeof(pbuf);
325 
326   packet.m_nChannel   = CONTROL_CHANNEL;
327   packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
328   packet.m_packetType = INVOKE_PTYPE;
329   packet.m_nTimeStamp = 0;
330   packet.m_nInfoField2 = 0;
331   packet.m_hasAbsTimestamp = 0;
332   packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
333 
334   char *enc = packet.m_body;
335   enc = AMF_EncodeString(enc, pend, &av_onStatus);
336   enc = AMF_EncodeNumber(enc, pend, 0);
337 
338   *enc++ = AMF_NULL;//rco: needed!
339   *enc++ = AMF_OBJECT;
340 
341   enc = AMF_EncodeNamedString(enc, pend, &av_level, &av_status);
342   enc = AMF_EncodeNamedString(enc, pend, &av_code, &av_NetStream_Play_Stop);
343   enc = AMF_EncodeNamedString(enc, pend, &av_description, &av_Stopped_playing);
344   enc = AMF_EncodeNamedString(enc, pend, &av_details, &p_rtmp->Link.playpath);
345   enc = AMF_EncodeNamedString(enc, pend, &av_clientid, &av_clientid);
346   *enc++ = 0;
347   *enc++ = 0;
348   *enc++ = AMF_OBJECT_END;
349 
350   packet.m_nBodySize = enc - packet.m_body;
351   return push_back(packet);
352 }
353 
SendPause(int DoPause,int iTime)354 int RtmpSender::SendPause(int DoPause, int iTime)
355 {
356   RTMPPacket packet;
357   char pbuf[256], *pend = pbuf + sizeof(pbuf);
358   char *enc;
359 
360   packet.m_nChannel = 0x08;	/* video channel */
361   packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
362   packet.m_packetType = 0x14;	/* invoke */
363   packet.m_nTimeStamp = 0;
364   packet.m_nInfoField2 = 0;
365   packet.m_hasAbsTimestamp = 0;
366   packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
367 
368   enc = packet.m_body;
369   enc = AMF_EncodeString(enc, pend, &av_pause);
370   enc = AMF_EncodeNumber(enc, pend, ++p_rtmp->m_numInvokes);
371   *enc++ = AMF_NULL;
372   enc = AMF_EncodeBoolean(enc, pend, DoPause);
373   enc = AMF_EncodeNumber(enc, pend, (double)iTime);
374 
375   packet.m_nBodySize = enc - packet.m_body;
376 
377   DBG("%d, pauseTime=%d", DoPause, iTime);
378   return push_back(packet);
379 }
380 
381 /*
382 from http://jira.red5.org/confluence/display/docs/Ping:
383 
384 Ping is the most mysterious message in RTMP and till now we haven't fully interpreted it yet. In summary, Ping message is used as a special command that are exchanged between client and server. This page aims to document all known Ping messages. Expect the list to grow.
385 
386 The type of Ping packet is 0x4 and contains two mandatory parameters and two optional parameters. The first parameter is the type of Ping and in short integer. The second parameter is the target of the ping. As Ping is always sent in Channel 2 (control channel) and the target object in RTMP header is always 0 which means the Connection object, it's necessary to put an extra parameter to indicate the exact target object the Ping is sent to. The second parameter takes this responsibility. The value has the same meaning as the target object field in RTMP header. (The second value could also be used as other purposes, like RTT Ping/Pong. It is used as the timestamp.) The third and fourth parameters are optional and could be looked upon as the parameter of the Ping packet. Below is an unexhausted list of Ping messages.
387 
388     * type 0: Clear the stream. No third and fourth parameters. The second parameter could be 0. After the connection is established, a Ping 0,0 will be sent from server to client. The message will also be sent to client on the start of Play and in response of a Seek or Pause/Resume request. This Ping tells client to re-calibrate the clock with the timestamp of the next packet server sends.
389     * type 1: Tell the stream to clear the playing buffer.
390     * type 3: Buffer time of the client. The third parameter is the buffer time in millisecond.
391     * type 4: Reset a stream. Used together with type 0 in the case of VOD. Often sent before type 0.
392     * type 6: Ping the client from server. The second parameter is the current time.
393     * type 7: Pong reply from client. The second parameter is the time the server sent with his ping request.
394     * type 26: SWFVerification request
395     * type 27: SWFVerification response
396 */
397 int
SendCtrl(short nType,unsigned int nObject,unsigned int nTime)398 RtmpSender::SendCtrl(short nType, unsigned int nObject, unsigned int nTime)
399 {
400   RTMPPacket packet;
401   char pbuf[256], *pend = pbuf + sizeof(pbuf);
402   int nSize;
403   char *buf;
404 
405   DBG("sending ctrl. type: 0x%04x", (unsigned short)nType);
406 
407   packet.m_nChannel = 0x02;	/* control channel (ping) */
408   packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
409   packet.m_packetType = 0x04;	/* ctrl */
410   packet.m_nTimeStamp = 0;	/* RTMP_GetTime(); */
411   packet.m_nInfoField2 = 0;
412   packet.m_hasAbsTimestamp = 0;
413   packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
414 
415   switch(nType) {
416   case 0x03: nSize = 10; break;	/* buffer time */
417   case 0x1A: nSize = 3; break;	/* SWF verify request */
418   case 0x1B: nSize = 44; break;	/* SWF verify response */
419   default: nSize = 6; break;
420   }
421 
422   packet.m_nBodySize = nSize;
423 
424   buf = packet.m_body;
425   buf = AMF_EncodeInt16(buf, pend, nType);
426 
427   if (nType == 0x1B)
428     {
429 #ifdef CRYPTO
430       memcpy(buf, rtmp.Link.SWFVerificationResponse, 42);
431       DBG("Sending SWFVerification response: ");
432       RTMP_LogHex(RTMP_LOGDEBUG, (uint8_t *)packet.m_body, packet.m_nBodySize);
433 #endif
434     }
435   else if (nType == 0x1A)
436     {
437 	  *buf = nObject & 0xff;
438 	}
439   else
440     {
441       if (nSize > 2)
442 	buf = AMF_EncodeInt32(buf, pend, nObject);
443 
444       if (nSize > 6)
445 	buf = AMF_EncodeInt32(buf, pend, nTime);
446     }
447 
448   return push_back(packet);
449 }
450 
SendStreamBegin()451 int RtmpSender::SendStreamBegin()
452 {
453   return SendCtrl(0, 1, 0);
454 }
455 
SendStreamEOF()456 int RtmpSender::SendStreamEOF()
457 {
458   return SendCtrl(1, 1, 0);
459 }
460 
SendCallStatus(int status)461 int RtmpSender::SendCallStatus(int status)
462 {
463   RTMPPacket packet;
464   char pbuf[384], *pend = pbuf+sizeof(pbuf);
465 
466   packet.m_nChannel   = CONTROL_CHANNEL;
467   packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
468   packet.m_packetType = INVOKE_PTYPE;
469   packet.m_nTimeStamp = 0;
470   packet.m_nInfoField2 = 0;
471   packet.m_hasAbsTimestamp = 0;
472   packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
473 
474   char *enc = packet.m_body;
475   enc = AMF_EncodeString(enc, pend, &av_onStatus);
476   enc = AMF_EncodeNumber(enc, pend, 0);
477 
478   *enc++ = AMF_NULL;//rco: needed!
479   *enc++ = AMF_OBJECT;
480   enc = AMF_EncodeNamedString(enc, pend, &av_level, &av_status);
481   enc = AMF_EncodeNamedString(enc, pend, &av_code, &av_Sono_Call_Status);
482   enc = AMF_EncodeNamedNumber(enc, pend, &av_status_code, status);
483   *enc++ = 0;
484   *enc++ = 0;
485   *enc++ = AMF_OBJECT_END;
486 
487   packet.m_nBodySize = enc - packet.m_body;
488   return push_back(packet);
489 }
490 
NotifyIncomingCall(const string & uri)491 int RtmpSender::NotifyIncomingCall(const string& uri)
492 {
493   RTMPPacket packet;
494   char pbuf[384], *pend = pbuf+sizeof(pbuf);
495 
496   packet.m_nChannel   = CONTROL_CHANNEL;
497   packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
498   packet.m_packetType = INVOKE_PTYPE;
499   packet.m_nTimeStamp = 0;
500   packet.m_nInfoField2 = 0;
501   packet.m_hasAbsTimestamp = 0;
502   packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
503 
504   char *enc = packet.m_body;
505   enc = AMF_EncodeString(enc, pend, &av_onStatus);
506   enc = AMF_EncodeNumber(enc, pend, 0);
507 
508   *enc++ = AMF_NULL;//rco: needed!
509   *enc++ = AMF_OBJECT;
510   AVal tmp_uri = _AVC(uri.c_str());
511   enc = AMF_EncodeNamedString(enc, pend, &av_level, &av_status);
512   enc = AMF_EncodeNamedString(enc, pend, &av_code, &av_Sono_Call_Incoming);
513   enc = AMF_EncodeNamedString(enc, pend, &av_uri, &tmp_uri);
514   *enc++ = 0;
515   *enc++ = 0;
516   *enc++ = AMF_OBJECT_END;
517 
518   packet.m_nBodySize = enc - packet.m_body;
519   return push_back(packet);
520 }
521 
522