Unexpected BW Response Fix
[rtmpdump.git] / librtmp / rtmp.c
blob5311a8a866c0e6f67be550b2c5cd1bb1e0153428
1 /*
2 * Copyright (C) 2005-2008 Team XBMC
3 * http://www.xbmc.org
4 * Copyright (C) 2008-2009 Andrej Stepanchuk
5 * Copyright (C) 2009-2010 Howard Chu
7 * This file is part of librtmp.
9 * librtmp is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU Lesser General Public License as
11 * published by the Free Software Foundation; either version 2.1,
12 * or (at your option) any later version.
14 * librtmp is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with librtmp see the file COPYING. If not, write to
21 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22 * Boston, MA 02110-1301, USA.
23 * http://www.gnu.org/copyleft/lgpl.html
26 #include <stdint.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <assert.h>
31 #include "rtmp_sys.h"
32 #include "log.h"
34 #ifdef CRYPTO
35 #ifdef USE_POLARSSL
36 #include <polarssl/havege.h>
37 #elif defined(USE_GNUTLS)
38 #include <gnutls/gnutls.h>
39 #else /* USE_OPENSSL */
40 #include <openssl/ssl.h>
41 #include <openssl/rc4.h>
42 #endif
43 TLS_CTX RTMP_TLS_ctx;
44 #endif
46 #define RTMP_SIG_SIZE 1536
47 #define RTMP_LARGE_HEADER_SIZE 12
49 static const int packetSize[] = { 12, 8, 4, 1 };
51 int RTMP_ctrlC;
53 const char RTMPProtocolStrings[][7] = {
54 "RTMP",
55 "RTMPT",
56 "RTMPE",
57 "RTMPTE",
58 "RTMPS",
59 "RTMPTS",
60 "",
61 "",
62 "RTMFP"
65 const char RTMPProtocolStringsLower[][7] = {
66 "rtmp",
67 "rtmpt",
68 "rtmpe",
69 "rtmpte",
70 "rtmps",
71 "rtmpts",
72 "",
73 "",
74 "rtmfp"
77 static const char *RTMPT_cmds[] = {
78 "open",
79 "send",
80 "idle",
81 "close"
84 typedef enum {
85 RTMPT_OPEN=0, RTMPT_SEND, RTMPT_IDLE, RTMPT_CLOSE
86 } RTMPTCmd;
88 static int DumpMetaData(AMFObject *obj);
89 static int HandShake(RTMP *r, int FP9HandShake);
90 static int SocksNegotiate(RTMP *r);
92 static int SendConnectPacket(RTMP *r, RTMPPacket *cp);
93 static int SendCheckBW(RTMP *r);
94 static int SendCheckBWResult(RTMP *r, double txn);
95 static int SendDeleteStream(RTMP *r, double dStreamId);
96 static int SendFCSubscribe(RTMP *r, AVal *subscribepath);
97 static int SendPlay(RTMP *r);
98 static int SendBytesReceived(RTMP *r);
99 static int SendUsherToken(RTMP *r, AVal *usherToken);
101 #if 0 /* unused */
102 static int SendBGHasStream(RTMP *r, double dId, AVal *playpath);
103 #endif
105 static int HandleInvoke(RTMP *r, const char *body, unsigned int nBodySize);
106 static int HandleMetadata(RTMP *r, char *body, unsigned int len);
107 static void HandleChangeChunkSize(RTMP *r, const RTMPPacket *packet);
108 static void HandleAudio(RTMP *r, const RTMPPacket *packet);
109 static void HandleVideo(RTMP *r, const RTMPPacket *packet);
110 static void HandleCtrl(RTMP *r, const RTMPPacket *packet);
111 static void HandleServerBW(RTMP *r, const RTMPPacket *packet);
112 static void HandleClientBW(RTMP *r, const RTMPPacket *packet);
114 static int ReadN(RTMP *r, char *buffer, int n);
115 static int WriteN(RTMP *r, const char *buffer, int n);
117 static void DecodeTEA(AVal *key, AVal *text);
119 static int HTTP_Post(RTMP *r, RTMPTCmd cmd, const char *buf, int len);
120 static int HTTP_read(RTMP *r, int fill);
122 #ifndef _WIN32
123 static int clk_tck;
124 #endif
126 #ifdef CRYPTO
127 #include "handshake.h"
128 #endif
130 uint32_t
131 RTMP_GetTime()
133 #ifdef _DEBUG
134 return 0;
135 #elif defined(_WIN32)
136 return timeGetTime();
137 #else
138 struct tms t;
139 if (!clk_tck) clk_tck = sysconf(_SC_CLK_TCK);
140 return times(&t) * 1000 / clk_tck;
141 #endif
144 void
145 RTMP_UserInterrupt()
147 RTMP_ctrlC = TRUE;
150 void
151 RTMPPacket_Reset(RTMPPacket *p)
153 p->m_headerType = 0;
154 p->m_packetType = 0;
155 p->m_nChannel = 0;
156 p->m_nTimeStamp = 0;
157 p->m_nInfoField2 = 0;
158 p->m_hasAbsTimestamp = FALSE;
159 p->m_nBodySize = 0;
160 p->m_nBytesRead = 0;
164 RTMPPacket_Alloc(RTMPPacket *p, int nSize)
166 char *ptr = calloc(1, nSize + RTMP_MAX_HEADER_SIZE);
167 if (!ptr)
168 return FALSE;
169 p->m_body = ptr + RTMP_MAX_HEADER_SIZE;
170 p->m_nBytesRead = 0;
171 return TRUE;
174 void
175 RTMPPacket_Free(RTMPPacket *p)
177 if (p->m_body)
179 free(p->m_body - RTMP_MAX_HEADER_SIZE);
180 p->m_body = NULL;
184 void
185 RTMPPacket_Dump(RTMPPacket *p)
187 RTMP_Log(RTMP_LOGDEBUG,
188 "RTMP PACKET: packet type: 0x%02x. channel: 0x%02x. info 1: %d info 2: %d. Body size: %lu. body: 0x%02x",
189 p->m_packetType, p->m_nChannel, p->m_nTimeStamp, p->m_nInfoField2,
190 p->m_nBodySize, p->m_body ? (unsigned char)p->m_body[0] : 0);
194 RTMP_LibVersion()
196 return RTMP_LIB_VERSION;
199 void
200 RTMP_TLS_Init()
202 #ifdef CRYPTO
203 #ifdef USE_POLARSSL
204 /* Do this regardless of NO_SSL, we use havege for rtmpe too */
205 RTMP_TLS_ctx = calloc(1,sizeof(struct tls_ctx));
206 havege_init(&RTMP_TLS_ctx->hs);
207 #elif defined(USE_GNUTLS) && !defined(NO_SSL)
208 /* Technically we need to initialize libgcrypt ourselves if
209 * we're not going to call gnutls_global_init(). Ignoring this
210 * for now.
212 gnutls_global_init();
213 RTMP_TLS_ctx = malloc(sizeof(struct tls_ctx));
214 gnutls_certificate_allocate_credentials(&RTMP_TLS_ctx->cred);
215 gnutls_priority_init(&RTMP_TLS_ctx->prios, "NORMAL", NULL);
216 gnutls_certificate_set_x509_trust_file(RTMP_TLS_ctx->cred,
217 "ca.pem", GNUTLS_X509_FMT_PEM);
218 #elif !defined(NO_SSL) /* USE_OPENSSL */
219 /* libcrypto doesn't need anything special */
220 SSL_load_error_strings();
221 SSL_library_init();
222 OpenSSL_add_all_digests();
223 RTMP_TLS_ctx = SSL_CTX_new(SSLv23_method());
224 SSL_CTX_set_options(RTMP_TLS_ctx, SSL_OP_ALL);
225 SSL_CTX_set_default_verify_paths(RTMP_TLS_ctx);
226 #endif
227 #endif
230 RTMP *
231 RTMP_Alloc()
233 return calloc(1, sizeof(RTMP));
236 void
237 RTMP_Free(RTMP *r)
239 free(r);
242 void
243 RTMP_Init(RTMP *r)
245 #ifdef CRYPTO
246 if (!RTMP_TLS_ctx)
247 RTMP_TLS_Init();
248 #endif
250 memset(r, 0, sizeof(RTMP));
251 r->m_sb.sb_socket = -1;
252 r->m_inChunkSize = RTMP_DEFAULT_CHUNKSIZE;
253 r->m_outChunkSize = RTMP_DEFAULT_CHUNKSIZE;
254 r->m_nBufferMS = 30000;
255 r->m_nClientBW = 2500000;
256 r->m_nClientBW2 = 2;
257 r->m_nServerBW = 2500000;
258 r->m_fAudioCodecs = 3191.0;
259 r->m_fVideoCodecs = 252.0;
260 r->Link.timeout = 30;
261 r->Link.swfAge = 30;
264 void
265 RTMP_EnableWrite(RTMP *r)
267 r->Link.protocol |= RTMP_FEATURE_WRITE;
270 double
271 RTMP_GetDuration(RTMP *r)
273 return r->m_fDuration;
277 RTMP_IsConnected(RTMP *r)
279 return r->m_sb.sb_socket != -1;
283 RTMP_Socket(RTMP *r)
285 return r->m_sb.sb_socket;
289 RTMP_IsTimedout(RTMP *r)
291 return r->m_sb.sb_timedout;
294 void
295 RTMP_SetBufferMS(RTMP *r, int size)
297 r->m_nBufferMS = size;
300 void
301 RTMP_UpdateBufferMS(RTMP *r)
303 RTMP_SendCtrl(r, 3, r->m_stream_id, r->m_nBufferMS);
306 #undef OSS
307 #ifdef _WIN32
308 #define OSS "WIN"
309 #elif defined(__sun__)
310 #define OSS "SOL"
311 #elif defined(__APPLE__)
312 #define OSS "MAC"
313 #elif defined(__linux__)
314 #define OSS "LNX"
315 #else
316 #define OSS "GNU"
317 #endif
318 #define DEF_VERSTR OSS " 10,0,32,18"
319 static const char DEFAULT_FLASH_VER[] = DEF_VERSTR;
320 const AVal RTMP_DefaultFlashVer =
321 { (char *)DEFAULT_FLASH_VER, sizeof(DEFAULT_FLASH_VER) - 1 };
323 void
324 RTMP_SetupStream(RTMP *r,
325 int protocol,
326 AVal *host,
327 unsigned int port,
328 AVal *sockshost,
329 AVal *playpath,
330 AVal *tcUrl,
331 AVal *swfUrl,
332 AVal *pageUrl,
333 AVal *app,
334 AVal *auth,
335 AVal *swfSHA256Hash,
336 uint32_t swfSize,
337 AVal *flashVer,
338 AVal *subscribepath,
339 AVal *usherToken,
340 int dStart,
341 int dStop, int bLiveStream, long int timeout)
343 RTMP_Log(RTMP_LOGDEBUG, "Protocol : %s", RTMPProtocolStrings[protocol&7]);
344 RTMP_Log(RTMP_LOGDEBUG, "Hostname : %.*s", host->av_len, host->av_val);
345 RTMP_Log(RTMP_LOGDEBUG, "Port : %d", port);
346 RTMP_Log(RTMP_LOGDEBUG, "Playpath : %s", playpath->av_val);
348 if (tcUrl && tcUrl->av_val)
349 RTMP_Log(RTMP_LOGDEBUG, "tcUrl : %s", tcUrl->av_val);
350 if (swfUrl && swfUrl->av_val)
351 RTMP_Log(RTMP_LOGDEBUG, "swfUrl : %s", swfUrl->av_val);
352 if (pageUrl && pageUrl->av_val)
353 RTMP_Log(RTMP_LOGDEBUG, "pageUrl : %s", pageUrl->av_val);
354 if (app && app->av_val)
355 RTMP_Log(RTMP_LOGDEBUG, "app : %.*s", app->av_len, app->av_val);
356 if (auth && auth->av_val)
357 RTMP_Log(RTMP_LOGDEBUG, "auth : %s", auth->av_val);
358 if (subscribepath && subscribepath->av_val)
359 RTMP_Log(RTMP_LOGDEBUG, "subscribepath : %s", subscribepath->av_val);
360 if (usherToken && usherToken->av_val)
361 RTMP_Log(RTMP_LOGDEBUG, "NetStream.Authenticate.UsherToken : %s", usherToken->av_val);
362 if (flashVer && flashVer->av_val)
363 RTMP_Log(RTMP_LOGDEBUG, "flashVer : %s", flashVer->av_val);
364 if (dStart > 0)
365 RTMP_Log(RTMP_LOGDEBUG, "StartTime : %d msec", dStart);
366 if (dStop > 0)
367 RTMP_Log(RTMP_LOGDEBUG, "StopTime : %d msec", dStop);
369 RTMP_Log(RTMP_LOGDEBUG, "live : %s", bLiveStream ? "yes" : "no");
370 RTMP_Log(RTMP_LOGDEBUG, "timeout : %d sec", timeout);
372 #ifdef CRYPTO
373 if (swfSHA256Hash != NULL && swfSize > 0)
375 memcpy(r->Link.SWFHash, swfSHA256Hash->av_val, sizeof(r->Link.SWFHash));
376 r->Link.SWFSize = swfSize;
377 RTMP_Log(RTMP_LOGDEBUG, "SWFSHA256:");
378 RTMP_LogHex(RTMP_LOGDEBUG, r->Link.SWFHash, sizeof(r->Link.SWFHash));
379 RTMP_Log(RTMP_LOGDEBUG, "SWFSize : %lu", r->Link.SWFSize);
381 else
383 r->Link.SWFSize = 0;
385 #endif
387 if (sockshost->av_len)
389 const char *socksport = strchr(sockshost->av_val, ':');
390 char *hostname = strdup(sockshost->av_val);
392 if (socksport)
393 hostname[socksport - sockshost->av_val] = '\0';
394 r->Link.sockshost.av_val = hostname;
395 r->Link.sockshost.av_len = strlen(hostname);
397 r->Link.socksport = socksport ? atoi(socksport + 1) : 1080;
398 RTMP_Log(RTMP_LOGDEBUG, "Connecting via SOCKS proxy: %s:%d", r->Link.sockshost.av_val,
399 r->Link.socksport);
401 else
403 r->Link.sockshost.av_val = NULL;
404 r->Link.sockshost.av_len = 0;
405 r->Link.socksport = 0;
408 if (tcUrl && tcUrl->av_len)
409 r->Link.tcUrl = *tcUrl;
410 if (swfUrl && swfUrl->av_len)
411 r->Link.swfUrl = *swfUrl;
412 if (pageUrl && pageUrl->av_len)
413 r->Link.pageUrl = *pageUrl;
414 if (app && app->av_len)
415 r->Link.app = *app;
416 if (auth && auth->av_len)
418 r->Link.auth = *auth;
419 r->Link.lFlags |= RTMP_LF_AUTH;
421 if (flashVer && flashVer->av_len)
422 r->Link.flashVer = *flashVer;
423 else
424 r->Link.flashVer = RTMP_DefaultFlashVer;
425 if (subscribepath && subscribepath->av_len)
426 r->Link.subscribepath = *subscribepath;
427 if (usherToken && usherToken->av_len)
428 r->Link.usherToken = *usherToken;
429 r->Link.seekTime = dStart;
430 r->Link.stopTime = dStop;
431 if (bLiveStream)
432 r->Link.lFlags |= RTMP_LF_LIVE;
433 r->Link.timeout = timeout;
435 r->Link.protocol = protocol;
436 r->Link.hostname = *host;
437 r->Link.port = port;
438 r->Link.playpath = *playpath;
440 if (r->Link.port == 0)
442 if (protocol & RTMP_FEATURE_SSL)
443 r->Link.port = 443;
444 else if (protocol & RTMP_FEATURE_HTTP)
445 r->Link.port = 80;
446 else
447 r->Link.port = 1935;
451 enum { OPT_STR=0, OPT_INT, OPT_BOOL, OPT_CONN };
452 static const char *optinfo[] = {
453 "string", "integer", "boolean", "AMF" };
455 #define OFF(x) offsetof(struct RTMP,x)
457 static struct urlopt {
458 AVal name;
459 off_t off;
460 int otype;
461 int omisc;
462 char *use;
463 } options[] = {
464 { AVC("socks"), OFF(Link.sockshost), OPT_STR, 0,
465 "Use the specified SOCKS proxy" },
466 { AVC("app"), OFF(Link.app), OPT_STR, 0,
467 "Name of target app on server" },
468 { AVC("tcUrl"), OFF(Link.tcUrl), OPT_STR, 0,
469 "URL to played stream" },
470 { AVC("pageUrl"), OFF(Link.pageUrl), OPT_STR, 0,
471 "URL of played media's web page" },
472 { AVC("swfUrl"), OFF(Link.swfUrl), OPT_STR, 0,
473 "URL to player SWF file" },
474 { AVC("flashver"), OFF(Link.flashVer), OPT_STR, 0,
475 "Flash version string (default " DEF_VERSTR ")" },
476 { AVC("conn"), OFF(Link.extras), OPT_CONN, 0,
477 "Append arbitrary AMF data to Connect message" },
478 { AVC("playpath"), OFF(Link.playpath), OPT_STR, 0,
479 "Path to target media on server" },
480 { AVC("playlist"), OFF(Link.lFlags), OPT_BOOL, RTMP_LF_PLST,
481 "Set playlist before play command" },
482 { AVC("live"), OFF(Link.lFlags), OPT_BOOL, RTMP_LF_LIVE,
483 "Stream is live, no seeking possible" },
484 { AVC("subscribe"), OFF(Link.subscribepath), OPT_STR, 0,
485 "Stream to subscribe to" },
486 { AVC("jtv"), OFF(Link.usherToken), OPT_STR, 0,
487 "Justin.tv authentication token" },
488 { AVC("token"), OFF(Link.token), OPT_STR, 0,
489 "Key for SecureToken response" },
490 { AVC("swfVfy"), OFF(Link.lFlags), OPT_BOOL, RTMP_LF_SWFV,
491 "Perform SWF Verification" },
492 { AVC("swfAge"), OFF(Link.swfAge), OPT_INT, 0,
493 "Number of days to use cached SWF hash" },
494 { AVC("start"), OFF(Link.seekTime), OPT_INT, 0,
495 "Stream start position in milliseconds" },
496 { AVC("stop"), OFF(Link.stopTime), OPT_INT, 0,
497 "Stream stop position in milliseconds" },
498 { AVC("buffer"), OFF(m_nBufferMS), OPT_INT, 0,
499 "Buffer time in milliseconds" },
500 { AVC("timeout"), OFF(Link.timeout), OPT_INT, 0,
501 "Session timeout in seconds" },
502 { {NULL,0}, 0, 0}
505 static const AVal truth[] = {
506 AVC("1"),
507 AVC("on"),
508 AVC("yes"),
509 AVC("true"),
510 {0,0}
513 static void RTMP_OptUsage()
515 int i;
517 RTMP_Log(RTMP_LOGERROR, "Valid RTMP options are:\n");
518 for (i=0; options[i].name.av_len; i++) {
519 RTMP_Log(RTMP_LOGERROR, "%10s %-7s %s\n", options[i].name.av_val,
520 optinfo[options[i].otype], options[i].use);
524 static int
525 parseAMF(AMFObject *obj, AVal *av, int *depth)
527 AMFObjectProperty prop = {{0,0}};
528 int i;
529 char *p, *arg = av->av_val;
531 if (arg[1] == ':')
533 p = (char *)arg+2;
534 switch(arg[0])
536 case 'B':
537 prop.p_type = AMF_BOOLEAN;
538 prop.p_vu.p_number = atoi(p);
539 break;
540 case 'S':
541 prop.p_type = AMF_STRING;
542 prop.p_vu.p_aval.av_val = p;
543 prop.p_vu.p_aval.av_len = av->av_len - (p-arg);
544 break;
545 case 'N':
546 prop.p_type = AMF_NUMBER;
547 prop.p_vu.p_number = strtod(p, NULL);
548 break;
549 case 'Z':
550 prop.p_type = AMF_NULL;
551 break;
552 case 'O':
553 i = atoi(p);
554 if (i)
556 prop.p_type = AMF_OBJECT;
558 else
560 (*depth)--;
561 return 0;
563 break;
564 default:
565 return -1;
568 else if (arg[2] == ':' && arg[0] == 'N')
570 p = strchr(arg+3, ':');
571 if (!p || !*depth)
572 return -1;
573 prop.p_name.av_val = (char *)arg+3;
574 prop.p_name.av_len = p - (arg+3);
576 p++;
577 switch(arg[1])
579 case 'B':
580 prop.p_type = AMF_BOOLEAN;
581 prop.p_vu.p_number = atoi(p);
582 break;
583 case 'S':
584 prop.p_type = AMF_STRING;
585 prop.p_vu.p_aval.av_val = p;
586 prop.p_vu.p_aval.av_len = av->av_len - (p-arg);
587 break;
588 case 'N':
589 prop.p_type = AMF_NUMBER;
590 prop.p_vu.p_number = strtod(p, NULL);
591 break;
592 case 'O':
593 prop.p_type = AMF_OBJECT;
594 break;
595 default:
596 return -1;
599 else
600 return -1;
602 if (*depth)
604 AMFObject *o2;
605 for (i=0; i<*depth; i++)
607 o2 = &obj->o_props[obj->o_num-1].p_vu.p_object;
608 obj = o2;
611 AMF_AddProp(obj, &prop);
612 if (prop.p_type == AMF_OBJECT)
613 (*depth)++;
614 return 0;
617 int RTMP_SetOpt(RTMP *r, const AVal *opt, AVal *arg)
619 int i;
620 void *v;
622 for (i=0; options[i].name.av_len; i++) {
623 if (opt->av_len != options[i].name.av_len) continue;
624 if (strcasecmp(opt->av_val, options[i].name.av_val)) continue;
625 v = (char *)r + options[i].off;
626 switch(options[i].otype) {
627 case OPT_STR: {
628 AVal *aptr = v;
629 *aptr = *arg; }
630 break;
631 case OPT_INT: {
632 long l = strtol(arg->av_val, NULL, 0);
633 *(int *)v = l; }
634 break;
635 case OPT_BOOL: {
636 int j, fl;
637 fl = *(int *)v;
638 for (j=0; truth[j].av_len; j++) {
639 if (arg->av_len != truth[j].av_len) continue;
640 if (strcasecmp(arg->av_val, truth[j].av_val)) continue;
641 fl |= options[i].omisc; break; }
642 *(int *)v = fl;
644 break;
645 case OPT_CONN:
646 if (parseAMF(&r->Link.extras, arg, &r->Link.edepth))
647 return FALSE;
648 break;
650 break;
652 if (!options[i].name.av_len) {
653 RTMP_Log(RTMP_LOGERROR, "Unknown option %s", opt->av_val);
654 RTMP_OptUsage();
655 return FALSE;
658 return TRUE;
661 int RTMP_SetupURL(RTMP *r, char *url)
663 AVal opt, arg;
664 char *p1, *p2, *ptr = strchr(url, ' ');
665 int ret, len;
666 unsigned int port = 0;
668 if (ptr)
669 *ptr = '\0';
671 len = strlen(url);
672 ret = RTMP_ParseURL(url, &r->Link.protocol, &r->Link.hostname,
673 &port, &r->Link.playpath0, &r->Link.app);
674 if (!ret)
675 return ret;
676 r->Link.port = port;
677 r->Link.playpath = r->Link.playpath0;
679 while (ptr) {
680 *ptr++ = '\0';
681 p1 = ptr;
682 p2 = strchr(p1, '=');
683 if (!p2)
684 break;
685 opt.av_val = p1;
686 opt.av_len = p2 - p1;
687 *p2++ = '\0';
688 arg.av_val = p2;
689 ptr = strchr(p2, ' ');
690 if (ptr) {
691 *ptr = '\0';
692 arg.av_len = ptr - p2;
693 /* skip repeated spaces */
694 while(ptr[1] == ' ')
695 *ptr++ = '\0';
696 } else {
697 arg.av_len = strlen(p2);
700 /* unescape */
701 port = arg.av_len;
702 for (p1=p2; port >0;) {
703 if (*p1 == '\\') {
704 unsigned int c;
705 if (port < 3)
706 return FALSE;
707 sscanf(p1+1, "%02x", &c);
708 *p2++ = c;
709 port -= 3;
710 p1 += 3;
711 } else {
712 *p2++ = *p1++;
713 port--;
716 arg.av_len = p2 - arg.av_val;
718 ret = RTMP_SetOpt(r, &opt, &arg);
719 if (!ret)
720 return ret;
723 if (!r->Link.tcUrl.av_len)
725 r->Link.tcUrl.av_val = url;
726 if (r->Link.app.av_len)
728 if (r->Link.app.av_val < url + len)
730 /* if app is part of original url, just use it */
731 r->Link.tcUrl.av_len = r->Link.app.av_len + (r->Link.app.av_val - url);
733 else
735 len = r->Link.hostname.av_len + r->Link.app.av_len +
736 sizeof("rtmpte://:65535/");
737 r->Link.tcUrl.av_val = malloc(len);
738 r->Link.tcUrl.av_len = snprintf(r->Link.tcUrl.av_val, len,
739 "%s://%.*s:%d/%.*s",
740 RTMPProtocolStringsLower[r->Link.protocol],
741 r->Link.hostname.av_len, r->Link.hostname.av_val,
742 r->Link.port,
743 r->Link.app.av_len, r->Link.app.av_val);
744 r->Link.lFlags |= RTMP_LF_FTCU;
747 else
749 r->Link.tcUrl.av_len = strlen(url);
753 #ifdef CRYPTO
754 if ((r->Link.lFlags & RTMP_LF_SWFV) && r->Link.swfUrl.av_len)
755 RTMP_HashSWF(r->Link.swfUrl.av_val, &r->Link.SWFSize,
756 (unsigned char *)r->Link.SWFHash, r->Link.swfAge);
757 #endif
759 if (r->Link.port == 0)
761 if (r->Link.protocol & RTMP_FEATURE_SSL)
762 r->Link.port = 443;
763 else if (r->Link.protocol & RTMP_FEATURE_HTTP)
764 r->Link.port = 80;
765 else
766 r->Link.port = 1935;
768 return TRUE;
771 static int
772 add_addr_info(struct sockaddr_in *service, AVal *host, int port)
774 char *hostname;
775 int ret = TRUE;
776 if (host->av_val[host->av_len])
778 hostname = malloc(host->av_len+1);
779 memcpy(hostname, host->av_val, host->av_len);
780 hostname[host->av_len] = '\0';
782 else
784 hostname = host->av_val;
787 service->sin_addr.s_addr = inet_addr(hostname);
788 if (service->sin_addr.s_addr == INADDR_NONE)
790 struct hostent *host = gethostbyname(hostname);
791 if (host == NULL || host->h_addr == NULL)
793 RTMP_Log(RTMP_LOGERROR, "Problem accessing the DNS. (addr: %s)", hostname);
794 ret = FALSE;
795 goto finish;
797 service->sin_addr = *(struct in_addr *)host->h_addr;
800 service->sin_port = htons(port);
801 finish:
802 if (hostname != host->av_val)
803 free(hostname);
804 return ret;
808 RTMP_Connect0(RTMP *r, struct sockaddr * service)
810 int on = 1;
811 r->m_sb.sb_timedout = FALSE;
812 r->m_pausing = 0;
813 r->m_fDuration = 0.0;
815 r->m_sb.sb_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
816 if (r->m_sb.sb_socket != -1)
818 if (connect(r->m_sb.sb_socket, service, sizeof(struct sockaddr)) < 0)
820 int err = GetSockError();
821 RTMP_Log(RTMP_LOGERROR, "%s, failed to connect socket. %d (%s)",
822 __FUNCTION__, err, strerror(err));
823 RTMP_Close(r);
824 return FALSE;
827 if (r->Link.socksport)
829 RTMP_Log(RTMP_LOGDEBUG, "%s ... SOCKS negotiation", __FUNCTION__);
830 if (!SocksNegotiate(r))
832 RTMP_Log(RTMP_LOGERROR, "%s, SOCKS negotiation failed.", __FUNCTION__);
833 RTMP_Close(r);
834 return FALSE;
838 else
840 RTMP_Log(RTMP_LOGERROR, "%s, failed to create socket. Error: %d", __FUNCTION__,
841 GetSockError());
842 return FALSE;
845 /* set timeout */
847 SET_RCVTIMEO(tv, r->Link.timeout);
848 if (setsockopt
849 (r->m_sb.sb_socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(tv)))
851 RTMP_Log(RTMP_LOGERROR, "%s, Setting socket timeout to %ds failed!",
852 __FUNCTION__, r->Link.timeout);
856 setsockopt(r->m_sb.sb_socket, IPPROTO_TCP, TCP_NODELAY, (char *) &on, sizeof(on));
858 return TRUE;
862 RTMP_Connect1(RTMP *r, RTMPPacket *cp)
864 if (r->Link.protocol & RTMP_FEATURE_SSL)
866 #if defined(CRYPTO) && !defined(NO_SSL)
867 TLS_client(RTMP_TLS_ctx, r->m_sb.sb_ssl);
868 TLS_setfd(r->m_sb.sb_ssl, r->m_sb.sb_socket);
869 if (TLS_connect(r->m_sb.sb_ssl) < 0)
871 RTMP_Log(RTMP_LOGERROR, "%s, TLS_Connect failed", __FUNCTION__);
872 RTMP_Close(r);
873 return FALSE;
875 #else
876 RTMP_Log(RTMP_LOGERROR, "%s, no SSL/TLS support", __FUNCTION__);
877 RTMP_Close(r);
878 return FALSE;
880 #endif
882 if (r->Link.protocol & RTMP_FEATURE_HTTP)
884 r->m_msgCounter = 1;
885 r->m_clientID.av_val = NULL;
886 r->m_clientID.av_len = 0;
887 HTTP_Post(r, RTMPT_OPEN, "", 1);
888 if (HTTP_read(r, 1) != 0)
890 r->m_msgCounter = 0;
891 RTMP_Log(RTMP_LOGDEBUG, "%s, Could not connect for handshake", __FUNCTION__);
892 RTMP_Close(r);
893 return 0;
895 r->m_msgCounter = 0;
897 RTMP_Log(RTMP_LOGDEBUG, "%s, ... connected, handshaking", __FUNCTION__);
898 if (!HandShake(r, TRUE))
900 RTMP_Log(RTMP_LOGERROR, "%s, handshake failed.", __FUNCTION__);
901 RTMP_Close(r);
902 return FALSE;
904 RTMP_Log(RTMP_LOGDEBUG, "%s, handshaked", __FUNCTION__);
906 if (!SendConnectPacket(r, cp))
908 RTMP_Log(RTMP_LOGERROR, "%s, RTMP connect failed.", __FUNCTION__);
909 RTMP_Close(r);
910 return FALSE;
912 return TRUE;
916 RTMP_Connect(RTMP *r, RTMPPacket *cp)
918 struct sockaddr_in service;
919 if (!r->Link.hostname.av_len)
920 return FALSE;
922 memset(&service, 0, sizeof(struct sockaddr_in));
923 service.sin_family = AF_INET;
925 if (r->Link.socksport)
927 /* Connect via SOCKS */
928 if (!add_addr_info(&service, &r->Link.sockshost, r->Link.socksport))
929 return FALSE;
931 else
933 /* Connect directly */
934 if (!add_addr_info(&service, &r->Link.hostname, r->Link.port))
935 return FALSE;
938 if (!RTMP_Connect0(r, (struct sockaddr *)&service))
939 return FALSE;
941 r->m_bSendCounter = TRUE;
943 return RTMP_Connect1(r, cp);
946 static int
947 SocksNegotiate(RTMP *r)
949 unsigned long addr;
950 struct sockaddr_in service;
951 memset(&service, 0, sizeof(struct sockaddr_in));
953 add_addr_info(&service, &r->Link.hostname, r->Link.port);
954 addr = htonl(service.sin_addr.s_addr);
957 char packet[] = {
958 4, 1, /* SOCKS 4, connect */
959 (r->Link.port >> 8) & 0xFF,
960 (r->Link.port) & 0xFF,
961 (char)(addr >> 24) & 0xFF, (char)(addr >> 16) & 0xFF,
962 (char)(addr >> 8) & 0xFF, (char)addr & 0xFF,
964 }; /* NULL terminate */
966 WriteN(r, packet, sizeof packet);
968 if (ReadN(r, packet, 8) != 8)
969 return FALSE;
971 if (packet[0] == 0 && packet[1] == 90)
973 return TRUE;
975 else
977 RTMP_Log(RTMP_LOGERROR, "%s, SOCKS returned error code %d", packet[1]);
978 return FALSE;
984 RTMP_ConnectStream(RTMP *r, int seekTime)
986 RTMPPacket packet = { 0 };
988 /* seekTime was already set by SetupStream / SetupURL.
989 * This is only needed by ReconnectStream.
991 if (seekTime > 0)
992 r->Link.seekTime = seekTime;
994 r->m_mediaChannel = 0;
996 while (!r->m_bPlaying && RTMP_IsConnected(r) && RTMP_ReadPacket(r, &packet))
998 if (RTMPPacket_IsReady(&packet))
1000 if (!packet.m_nBodySize)
1001 continue;
1002 if ((packet.m_packetType == RTMP_PACKET_TYPE_AUDIO) ||
1003 (packet.m_packetType == RTMP_PACKET_TYPE_VIDEO) ||
1004 (packet.m_packetType == RTMP_PACKET_TYPE_INFO))
1006 RTMP_Log(RTMP_LOGWARNING, "Received FLV packet before play()! Ignoring.");
1007 RTMPPacket_Free(&packet);
1008 continue;
1011 RTMP_ClientPacket(r, &packet);
1012 RTMPPacket_Free(&packet);
1016 return r->m_bPlaying;
1020 RTMP_ReconnectStream(RTMP *r, int seekTime)
1022 RTMP_DeleteStream(r);
1024 RTMP_SendCreateStream(r);
1026 return RTMP_ConnectStream(r, seekTime);
1030 RTMP_ToggleStream(RTMP *r)
1032 int res;
1034 if (!r->m_pausing)
1036 if (RTMP_IsTimedout(r) && r->m_read.status == RTMP_READ_EOF)
1037 r->m_read.status = 0;
1039 res = RTMP_SendPause(r, TRUE, r->m_pauseStamp);
1040 if (!res)
1041 return res;
1043 r->m_pausing = 1;
1044 sleep(1);
1046 res = RTMP_SendPause(r, FALSE, r->m_pauseStamp);
1047 r->m_pausing = 3;
1048 return res;
1051 void
1052 RTMP_DeleteStream(RTMP *r)
1054 if (r->m_stream_id < 0)
1055 return;
1057 r->m_bPlaying = FALSE;
1059 SendDeleteStream(r, r->m_stream_id);
1060 r->m_stream_id = -1;
1064 RTMP_GetNextMediaPacket(RTMP *r, RTMPPacket *packet)
1066 int bHasMediaPacket = 0;
1068 while (!bHasMediaPacket && RTMP_IsConnected(r)
1069 && RTMP_ReadPacket(r, packet))
1071 if (!RTMPPacket_IsReady(packet))
1073 continue;
1076 bHasMediaPacket = RTMP_ClientPacket(r, packet);
1078 if (!bHasMediaPacket)
1080 RTMPPacket_Free(packet);
1082 else if (r->m_pausing == 3)
1084 if (packet->m_nTimeStamp <= r->m_mediaStamp)
1086 bHasMediaPacket = 0;
1087 #ifdef _DEBUG
1088 RTMP_Log(RTMP_LOGDEBUG,
1089 "Skipped type: %02X, size: %d, TS: %d ms, abs TS: %d, pause: %d ms",
1090 packet->m_packetType, packet->m_nBodySize,
1091 packet->m_nTimeStamp, packet->m_hasAbsTimestamp,
1092 r->m_mediaStamp);
1093 #endif
1094 continue;
1096 r->m_pausing = 0;
1100 if (bHasMediaPacket)
1101 r->m_bPlaying = TRUE;
1102 else if (r->m_sb.sb_timedout && !r->m_pausing)
1103 r->m_pauseStamp = r->m_channelTimestamp[r->m_mediaChannel];
1105 return bHasMediaPacket;
1109 RTMP_ClientPacket(RTMP *r, RTMPPacket *packet)
1111 int bHasMediaPacket = 0;
1112 switch (packet->m_packetType)
1114 case RTMP_PACKET_TYPE_CHUNK_SIZE:
1115 /* chunk size */
1116 HandleChangeChunkSize(r, packet);
1117 break;
1119 case RTMP_PACKET_TYPE_BYTES_READ_REPORT:
1120 /* bytes read report */
1121 RTMP_Log(RTMP_LOGDEBUG, "%s, received: bytes read report", __FUNCTION__);
1122 break;
1124 case RTMP_PACKET_TYPE_CONTROL:
1125 /* ctrl */
1126 HandleCtrl(r, packet);
1127 break;
1129 case RTMP_PACKET_TYPE_SERVER_BW:
1130 /* server bw */
1131 HandleServerBW(r, packet);
1132 break;
1134 case RTMP_PACKET_TYPE_CLIENT_BW:
1135 /* client bw */
1136 HandleClientBW(r, packet);
1137 break;
1139 case RTMP_PACKET_TYPE_AUDIO:
1140 /* audio data */
1141 /*RTMP_Log(RTMP_LOGDEBUG, "%s, received: audio %lu bytes", __FUNCTION__, packet.m_nBodySize); */
1142 HandleAudio(r, packet);
1143 bHasMediaPacket = 1;
1144 if (!r->m_mediaChannel)
1145 r->m_mediaChannel = packet->m_nChannel;
1146 if (!r->m_pausing)
1147 r->m_mediaStamp = packet->m_nTimeStamp;
1148 break;
1150 case RTMP_PACKET_TYPE_VIDEO:
1151 /* video data */
1152 /*RTMP_Log(RTMP_LOGDEBUG, "%s, received: video %lu bytes", __FUNCTION__, packet.m_nBodySize); */
1153 HandleVideo(r, packet);
1154 bHasMediaPacket = 1;
1155 if (!r->m_mediaChannel)
1156 r->m_mediaChannel = packet->m_nChannel;
1157 if (!r->m_pausing)
1158 r->m_mediaStamp = packet->m_nTimeStamp;
1159 break;
1161 case RTMP_PACKET_TYPE_FLEX_STREAM_SEND:
1162 /* flex stream send */
1163 RTMP_Log(RTMP_LOGDEBUG,
1164 "%s, flex stream send, size %lu bytes, not supported, ignoring",
1165 __FUNCTION__, packet->m_nBodySize);
1166 break;
1168 case RTMP_PACKET_TYPE_FLEX_SHARED_OBJECT:
1169 /* flex shared object */
1170 RTMP_Log(RTMP_LOGDEBUG,
1171 "%s, flex shared object, size %lu bytes, not supported, ignoring",
1172 __FUNCTION__, packet->m_nBodySize);
1173 break;
1175 case RTMP_PACKET_TYPE_FLEX_MESSAGE:
1176 /* flex message */
1178 RTMP_Log(RTMP_LOGDEBUG,
1179 "%s, flex message, size %lu bytes, not fully supported",
1180 __FUNCTION__, packet->m_nBodySize);
1181 /*RTMP_LogHex(packet.m_body, packet.m_nBodySize); */
1183 /* some DEBUG code */
1184 #if 0
1185 RTMP_LIB_AMFObject obj;
1186 int nRes = obj.Decode(packet.m_body+1, packet.m_nBodySize-1);
1187 if(nRes < 0) {
1188 RTMP_Log(RTMP_LOGERROR, "%s, error decoding AMF3 packet", __FUNCTION__);
1189 /*return; */
1192 obj.Dump();
1193 #endif
1195 if (HandleInvoke(r, packet->m_body + 1, packet->m_nBodySize - 1) == 1)
1196 bHasMediaPacket = 2;
1197 break;
1199 case RTMP_PACKET_TYPE_INFO:
1200 /* metadata (notify) */
1201 RTMP_Log(RTMP_LOGDEBUG, "%s, received: notify %lu bytes", __FUNCTION__,
1202 packet->m_nBodySize);
1203 if (HandleMetadata(r, packet->m_body, packet->m_nBodySize))
1204 bHasMediaPacket = 1;
1205 break;
1207 case RTMP_PACKET_TYPE_SHARED_OBJECT:
1208 RTMP_Log(RTMP_LOGDEBUG, "%s, shared object, not supported, ignoring",
1209 __FUNCTION__);
1210 break;
1212 case RTMP_PACKET_TYPE_INVOKE:
1213 /* invoke */
1214 RTMP_Log(RTMP_LOGDEBUG, "%s, received: invoke %lu bytes", __FUNCTION__,
1215 packet->m_nBodySize);
1216 /*RTMP_LogHex(packet.m_body, packet.m_nBodySize); */
1218 if (HandleInvoke(r, packet->m_body, packet->m_nBodySize) == 1)
1219 bHasMediaPacket = 2;
1220 break;
1222 case RTMP_PACKET_TYPE_FLASH_VIDEO:
1224 /* go through FLV packets and handle metadata packets */
1225 unsigned int pos = 0;
1226 uint32_t nTimeStamp = packet->m_nTimeStamp;
1228 while (pos + 11 < packet->m_nBodySize)
1230 uint32_t dataSize = AMF_DecodeInt24(packet->m_body + pos + 1); /* size without header (11) and prevTagSize (4) */
1232 if (pos + 11 + dataSize + 4 > packet->m_nBodySize)
1234 RTMP_Log(RTMP_LOGWARNING, "Stream corrupt?!");
1235 break;
1237 if (packet->m_body[pos] == 0x12)
1239 HandleMetadata(r, packet->m_body + pos + 11, dataSize);
1241 else if (packet->m_body[pos] == 8 || packet->m_body[pos] == 9)
1243 nTimeStamp = AMF_DecodeInt24(packet->m_body + pos + 4);
1244 nTimeStamp |= (packet->m_body[pos + 7] << 24);
1246 pos += (11 + dataSize + 4);
1248 if (!r->m_pausing)
1249 r->m_mediaStamp = nTimeStamp;
1251 /* FLV tag(s) */
1252 /*RTMP_Log(RTMP_LOGDEBUG, "%s, received: FLV tag(s) %lu bytes", __FUNCTION__, packet.m_nBodySize); */
1253 bHasMediaPacket = 1;
1254 break;
1256 default:
1257 RTMP_Log(RTMP_LOGDEBUG, "%s, unknown packet type received: 0x%02x", __FUNCTION__,
1258 packet->m_packetType);
1259 #ifdef _DEBUG
1260 RTMP_LogHex(RTMP_LOGDEBUG, packet->m_body, packet->m_nBodySize);
1261 #endif
1264 return bHasMediaPacket;
1267 #ifdef _DEBUG
1268 extern FILE *netstackdump;
1269 extern FILE *netstackdump_read;
1270 #endif
1272 static int
1273 ReadN(RTMP *r, char *buffer, int n)
1275 int nOriginalSize = n;
1276 int avail;
1277 char *ptr;
1279 r->m_sb.sb_timedout = FALSE;
1281 #ifdef _DEBUG
1282 memset(buffer, 0, n);
1283 #endif
1285 ptr = buffer;
1286 while (n > 0)
1288 int nBytes = 0, nRead;
1289 if (r->Link.protocol & RTMP_FEATURE_HTTP)
1291 while (!r->m_resplen)
1293 if (r->m_sb.sb_size < 144)
1295 if (!r->m_unackd)
1296 HTTP_Post(r, RTMPT_IDLE, "", 1);
1297 if (RTMPSockBuf_Fill(&r->m_sb) < 1)
1299 if (!r->m_sb.sb_timedout)
1300 RTMP_Close(r);
1301 return 0;
1304 if (HTTP_read(r, 0) == -1)
1306 RTMP_Log(RTMP_LOGDEBUG, "%s, No valid HTTP response found", __FUNCTION__);
1307 RTMP_Close(r);
1308 return 0;
1311 if (r->m_resplen && !r->m_sb.sb_size)
1312 RTMPSockBuf_Fill(&r->m_sb);
1313 avail = r->m_sb.sb_size;
1314 if (avail > r->m_resplen)
1315 avail = r->m_resplen;
1317 else
1319 avail = r->m_sb.sb_size;
1320 if (avail == 0)
1322 if (RTMPSockBuf_Fill(&r->m_sb) < 1)
1324 if (!r->m_sb.sb_timedout)
1325 RTMP_Close(r);
1326 return 0;
1328 avail = r->m_sb.sb_size;
1331 nRead = ((n < avail) ? n : avail);
1332 if (nRead > 0)
1334 memcpy(ptr, r->m_sb.sb_start, nRead);
1335 r->m_sb.sb_start += nRead;
1336 r->m_sb.sb_size -= nRead;
1337 nBytes = nRead;
1338 r->m_nBytesIn += nRead;
1339 if (r->m_bSendCounter
1340 && r->m_nBytesIn > r->m_nBytesInSent + r->m_nClientBW / 2)
1341 if (!SendBytesReceived(r))
1342 return FALSE;
1344 /*RTMP_Log(RTMP_LOGDEBUG, "%s: %d bytes\n", __FUNCTION__, nBytes); */
1345 #ifdef _DEBUG
1346 fwrite(ptr, 1, nBytes, netstackdump_read);
1347 #endif
1349 if (nBytes == 0)
1351 RTMP_Log(RTMP_LOGDEBUG, "%s, RTMP socket closed by peer", __FUNCTION__);
1352 /*goto again; */
1353 RTMP_Close(r);
1354 break;
1357 if (r->Link.protocol & RTMP_FEATURE_HTTP)
1358 r->m_resplen -= nBytes;
1360 #ifdef CRYPTO
1361 if (r->Link.rc4keyIn)
1363 RC4_encrypt(r->Link.rc4keyIn, nBytes, ptr);
1365 #endif
1367 n -= nBytes;
1368 ptr += nBytes;
1371 return nOriginalSize - n;
1374 static int
1375 WriteN(RTMP *r, const char *buffer, int n)
1377 const char *ptr = buffer;
1378 #ifdef CRYPTO
1379 char *encrypted = 0;
1380 char buf[RTMP_BUFFER_CACHE_SIZE];
1382 if (r->Link.rc4keyOut)
1384 if (n > sizeof(buf))
1385 encrypted = (char *)malloc(n);
1386 else
1387 encrypted = (char *)buf;
1388 ptr = encrypted;
1389 RC4_encrypt2(r->Link.rc4keyOut, n, buffer, ptr);
1391 #endif
1393 while (n > 0)
1395 int nBytes;
1397 if (r->Link.protocol & RTMP_FEATURE_HTTP)
1398 nBytes = HTTP_Post(r, RTMPT_SEND, ptr, n);
1399 else
1400 nBytes = RTMPSockBuf_Send(&r->m_sb, ptr, n);
1401 /*RTMP_Log(RTMP_LOGDEBUG, "%s: %d\n", __FUNCTION__, nBytes); */
1403 if (nBytes < 0)
1405 int sockerr = GetSockError();
1406 RTMP_Log(RTMP_LOGERROR, "%s, RTMP send error %d (%d bytes)", __FUNCTION__,
1407 sockerr, n);
1409 if (sockerr == EINTR && !RTMP_ctrlC)
1410 continue;
1412 RTMP_Close(r);
1413 n = 1;
1414 break;
1417 if (nBytes == 0)
1418 break;
1420 n -= nBytes;
1421 ptr += nBytes;
1424 #ifdef CRYPTO
1425 if (encrypted && encrypted != buf)
1426 free(encrypted);
1427 #endif
1429 return n == 0;
1432 #define SAVC(x) static const AVal av_##x = AVC(#x)
1434 SAVC(app);
1435 SAVC(connect);
1436 SAVC(flashVer);
1437 SAVC(swfUrl);
1438 SAVC(pageUrl);
1439 SAVC(tcUrl);
1440 SAVC(fpad);
1441 SAVC(capabilities);
1442 SAVC(audioCodecs);
1443 SAVC(videoCodecs);
1444 SAVC(videoFunction);
1445 SAVC(objectEncoding);
1446 SAVC(secureToken);
1447 SAVC(secureTokenResponse);
1448 SAVC(type);
1449 SAVC(nonprivate);
1451 static int
1452 SendConnectPacket(RTMP *r, RTMPPacket *cp)
1454 RTMPPacket packet;
1455 char pbuf[4096], *pend = pbuf + sizeof(pbuf);
1456 char *enc;
1458 if (cp)
1459 return RTMP_SendPacket(r, cp, TRUE);
1461 packet.m_nChannel = 0x03; /* control channel (invoke) */
1462 packet.m_headerType = RTMP_PACKET_SIZE_LARGE;
1463 packet.m_packetType = RTMP_PACKET_TYPE_INVOKE;
1464 packet.m_nTimeStamp = 0;
1465 packet.m_nInfoField2 = 0;
1466 packet.m_hasAbsTimestamp = 0;
1467 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
1469 enc = packet.m_body;
1470 enc = AMF_EncodeString(enc, pend, &av_connect);
1471 enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes);
1472 *enc++ = AMF_OBJECT;
1474 enc = AMF_EncodeNamedString(enc, pend, &av_app, &r->Link.app);
1475 if (!enc)
1476 return FALSE;
1477 if (r->Link.protocol & RTMP_FEATURE_WRITE)
1479 enc = AMF_EncodeNamedString(enc, pend, &av_type, &av_nonprivate);
1480 if (!enc)
1481 return FALSE;
1483 if (r->Link.flashVer.av_len)
1485 enc = AMF_EncodeNamedString(enc, pend, &av_flashVer, &r->Link.flashVer);
1486 if (!enc)
1487 return FALSE;
1489 if (r->Link.swfUrl.av_len)
1491 enc = AMF_EncodeNamedString(enc, pend, &av_swfUrl, &r->Link.swfUrl);
1492 if (!enc)
1493 return FALSE;
1495 if (r->Link.tcUrl.av_len)
1497 enc = AMF_EncodeNamedString(enc, pend, &av_tcUrl, &r->Link.tcUrl);
1498 if (!enc)
1499 return FALSE;
1501 if (!(r->Link.protocol & RTMP_FEATURE_WRITE))
1503 enc = AMF_EncodeNamedBoolean(enc, pend, &av_fpad, FALSE);
1504 if (!enc)
1505 return FALSE;
1506 enc = AMF_EncodeNamedNumber(enc, pend, &av_capabilities, 15.0);
1507 if (!enc)
1508 return FALSE;
1509 enc = AMF_EncodeNamedNumber(enc, pend, &av_audioCodecs, r->m_fAudioCodecs);
1510 if (!enc)
1511 return FALSE;
1512 enc = AMF_EncodeNamedNumber(enc, pend, &av_videoCodecs, r->m_fVideoCodecs);
1513 if (!enc)
1514 return FALSE;
1515 enc = AMF_EncodeNamedNumber(enc, pend, &av_videoFunction, 1.0);
1516 if (!enc)
1517 return FALSE;
1518 if (r->Link.pageUrl.av_len)
1520 enc = AMF_EncodeNamedString(enc, pend, &av_pageUrl, &r->Link.pageUrl);
1521 if (!enc)
1522 return FALSE;
1525 if (r->m_fEncoding != 0.0 || r->m_bSendEncoding)
1526 { /* AMF0, AMF3 not fully supported yet */
1527 enc = AMF_EncodeNamedNumber(enc, pend, &av_objectEncoding, r->m_fEncoding);
1528 if (!enc)
1529 return FALSE;
1531 if (enc + 3 >= pend)
1532 return FALSE;
1533 *enc++ = 0;
1534 *enc++ = 0; /* end of object - 0x00 0x00 0x09 */
1535 *enc++ = AMF_OBJECT_END;
1537 /* add auth string */
1538 if (r->Link.auth.av_len)
1540 enc = AMF_EncodeBoolean(enc, pend, r->Link.lFlags & RTMP_LF_AUTH);
1541 if (!enc)
1542 return FALSE;
1543 enc = AMF_EncodeString(enc, pend, &r->Link.auth);
1544 if (!enc)
1545 return FALSE;
1547 if (r->Link.extras.o_num)
1549 int i;
1550 for (i = 0; i < r->Link.extras.o_num; i++)
1552 enc = AMFProp_Encode(&r->Link.extras.o_props[i], enc, pend);
1553 if (!enc)
1554 return FALSE;
1557 packet.m_nBodySize = enc - packet.m_body;
1559 return RTMP_SendPacket(r, &packet, TRUE);
1562 #if 0 /* unused */
1563 SAVC(bgHasStream);
1565 static int
1566 SendBGHasStream(RTMP *r, double dId, AVal *playpath)
1568 RTMPPacket packet;
1569 char pbuf[1024], *pend = pbuf + sizeof(pbuf);
1570 char *enc;
1572 packet.m_nChannel = 0x03; /* control channel (invoke) */
1573 packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
1574 packet.m_packetType = RTMP_PACKET_TYPE_INVOKE;
1575 packet.m_nTimeStamp = 0;
1576 packet.m_nInfoField2 = 0;
1577 packet.m_hasAbsTimestamp = 0;
1578 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
1580 enc = packet.m_body;
1581 enc = AMF_EncodeString(enc, pend, &av_bgHasStream);
1582 enc = AMF_EncodeNumber(enc, pend, dId);
1583 *enc++ = AMF_NULL;
1585 enc = AMF_EncodeString(enc, pend, playpath);
1586 if (enc == NULL)
1587 return FALSE;
1589 packet.m_nBodySize = enc - packet.m_body;
1591 return RTMP_SendPacket(r, &packet, TRUE);
1593 #endif
1595 SAVC(createStream);
1598 RTMP_SendCreateStream(RTMP *r)
1600 RTMPPacket packet;
1601 char pbuf[256], *pend = pbuf + sizeof(pbuf);
1602 char *enc;
1604 packet.m_nChannel = 0x03; /* control channel (invoke) */
1605 packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
1606 packet.m_packetType = RTMP_PACKET_TYPE_INVOKE;
1607 packet.m_nTimeStamp = 0;
1608 packet.m_nInfoField2 = 0;
1609 packet.m_hasAbsTimestamp = 0;
1610 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
1612 enc = packet.m_body;
1613 enc = AMF_EncodeString(enc, pend, &av_createStream);
1614 enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes);
1615 *enc++ = AMF_NULL; /* NULL */
1617 packet.m_nBodySize = enc - packet.m_body;
1619 return RTMP_SendPacket(r, &packet, TRUE);
1622 SAVC(FCSubscribe);
1624 static int
1625 SendFCSubscribe(RTMP *r, AVal *subscribepath)
1627 RTMPPacket packet;
1628 char pbuf[512], *pend = pbuf + sizeof(pbuf);
1629 char *enc;
1630 packet.m_nChannel = 0x03; /* control channel (invoke) */
1631 packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
1632 packet.m_packetType = RTMP_PACKET_TYPE_INVOKE;
1633 packet.m_nTimeStamp = 0;
1634 packet.m_nInfoField2 = 0;
1635 packet.m_hasAbsTimestamp = 0;
1636 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
1638 RTMP_Log(RTMP_LOGDEBUG, "FCSubscribe: %s", subscribepath->av_val);
1639 enc = packet.m_body;
1640 enc = AMF_EncodeString(enc, pend, &av_FCSubscribe);
1641 enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes);
1642 *enc++ = AMF_NULL;
1643 enc = AMF_EncodeString(enc, pend, subscribepath);
1645 if (!enc)
1646 return FALSE;
1648 packet.m_nBodySize = enc - packet.m_body;
1650 return RTMP_SendPacket(r, &packet, TRUE);
1653 /* Justin.tv specific authentication */
1654 static const AVal av_NetStream_Authenticate_UsherToken = AVC("NetStream.Authenticate.UsherToken");
1656 static int
1657 SendUsherToken(RTMP *r, AVal *usherToken)
1659 RTMPPacket packet;
1660 char pbuf[1024], *pend = pbuf + sizeof(pbuf);
1661 char *enc;
1662 packet.m_nChannel = 0x03; /* control channel (invoke) */
1663 packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
1664 packet.m_packetType = RTMP_PACKET_TYPE_INVOKE;
1665 packet.m_nTimeStamp = 0;
1666 packet.m_nInfoField2 = 0;
1667 packet.m_hasAbsTimestamp = 0;
1668 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
1670 RTMP_Log(RTMP_LOGDEBUG, "UsherToken: %s", usherToken->av_val);
1671 enc = packet.m_body;
1672 enc = AMF_EncodeString(enc, pend, &av_NetStream_Authenticate_UsherToken);
1673 enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes);
1674 *enc++ = AMF_NULL;
1675 enc = AMF_EncodeString(enc, pend, usherToken);
1677 if (!enc)
1678 return FALSE;
1680 packet.m_nBodySize = enc - packet.m_body;
1682 return RTMP_SendPacket(r, &packet, FALSE);
1684 /******************************************/
1686 SAVC(releaseStream);
1688 static int
1689 SendReleaseStream(RTMP *r)
1691 RTMPPacket packet;
1692 char pbuf[1024], *pend = pbuf + sizeof(pbuf);
1693 char *enc;
1695 packet.m_nChannel = 0x03; /* control channel (invoke) */
1696 packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
1697 packet.m_packetType = RTMP_PACKET_TYPE_INVOKE;
1698 packet.m_nTimeStamp = 0;
1699 packet.m_nInfoField2 = 0;
1700 packet.m_hasAbsTimestamp = 0;
1701 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
1703 enc = packet.m_body;
1704 enc = AMF_EncodeString(enc, pend, &av_releaseStream);
1705 enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes);
1706 *enc++ = AMF_NULL;
1707 enc = AMF_EncodeString(enc, pend, &r->Link.playpath);
1708 if (!enc)
1709 return FALSE;
1711 packet.m_nBodySize = enc - packet.m_body;
1713 return RTMP_SendPacket(r, &packet, FALSE);
1716 SAVC(FCPublish);
1718 static int
1719 SendFCPublish(RTMP *r)
1721 RTMPPacket packet;
1722 char pbuf[1024], *pend = pbuf + sizeof(pbuf);
1723 char *enc;
1725 packet.m_nChannel = 0x03; /* control channel (invoke) */
1726 packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
1727 packet.m_packetType = RTMP_PACKET_TYPE_INVOKE;
1728 packet.m_nTimeStamp = 0;
1729 packet.m_nInfoField2 = 0;
1730 packet.m_hasAbsTimestamp = 0;
1731 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
1733 enc = packet.m_body;
1734 enc = AMF_EncodeString(enc, pend, &av_FCPublish);
1735 enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes);
1736 *enc++ = AMF_NULL;
1737 enc = AMF_EncodeString(enc, pend, &r->Link.playpath);
1738 if (!enc)
1739 return FALSE;
1741 packet.m_nBodySize = enc - packet.m_body;
1743 return RTMP_SendPacket(r, &packet, FALSE);
1746 SAVC(FCUnpublish);
1748 static int
1749 SendFCUnpublish(RTMP *r)
1751 RTMPPacket packet;
1752 char pbuf[1024], *pend = pbuf + sizeof(pbuf);
1753 char *enc;
1755 packet.m_nChannel = 0x03; /* control channel (invoke) */
1756 packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
1757 packet.m_packetType = RTMP_PACKET_TYPE_INVOKE;
1758 packet.m_nTimeStamp = 0;
1759 packet.m_nInfoField2 = 0;
1760 packet.m_hasAbsTimestamp = 0;
1761 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
1763 enc = packet.m_body;
1764 enc = AMF_EncodeString(enc, pend, &av_FCUnpublish);
1765 enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes);
1766 *enc++ = AMF_NULL;
1767 enc = AMF_EncodeString(enc, pend, &r->Link.playpath);
1768 if (!enc)
1769 return FALSE;
1771 packet.m_nBodySize = enc - packet.m_body;
1773 return RTMP_SendPacket(r, &packet, FALSE);
1776 SAVC(publish);
1777 SAVC(live);
1778 SAVC(record);
1780 static int
1781 SendPublish(RTMP *r)
1783 RTMPPacket packet;
1784 char pbuf[1024], *pend = pbuf + sizeof(pbuf);
1785 char *enc;
1787 packet.m_nChannel = 0x04; /* source channel (invoke) */
1788 packet.m_headerType = RTMP_PACKET_SIZE_LARGE;
1789 packet.m_packetType = RTMP_PACKET_TYPE_INVOKE;
1790 packet.m_nTimeStamp = 0;
1791 packet.m_nInfoField2 = r->m_stream_id;
1792 packet.m_hasAbsTimestamp = 0;
1793 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
1795 enc = packet.m_body;
1796 enc = AMF_EncodeString(enc, pend, &av_publish);
1797 enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes);
1798 *enc++ = AMF_NULL;
1799 enc = AMF_EncodeString(enc, pend, &r->Link.playpath);
1800 if (!enc)
1801 return FALSE;
1803 /* FIXME: should we choose live based on Link.lFlags & RTMP_LF_LIVE? */
1804 enc = AMF_EncodeString(enc, pend, &av_live);
1805 if (!enc)
1806 return FALSE;
1808 packet.m_nBodySize = enc - packet.m_body;
1810 return RTMP_SendPacket(r, &packet, TRUE);
1813 SAVC(deleteStream);
1815 static int
1816 SendDeleteStream(RTMP *r, double dStreamId)
1818 RTMPPacket packet;
1819 char pbuf[256], *pend = pbuf + sizeof(pbuf);
1820 char *enc;
1822 packet.m_nChannel = 0x03; /* control channel (invoke) */
1823 packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
1824 packet.m_packetType = RTMP_PACKET_TYPE_INVOKE;
1825 packet.m_nTimeStamp = 0;
1826 packet.m_nInfoField2 = 0;
1827 packet.m_hasAbsTimestamp = 0;
1828 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
1830 enc = packet.m_body;
1831 enc = AMF_EncodeString(enc, pend, &av_deleteStream);
1832 enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes);
1833 *enc++ = AMF_NULL;
1834 enc = AMF_EncodeNumber(enc, pend, dStreamId);
1836 packet.m_nBodySize = enc - packet.m_body;
1838 /* no response expected */
1839 return RTMP_SendPacket(r, &packet, FALSE);
1842 SAVC(pause);
1845 RTMP_SendPause(RTMP *r, int DoPause, int iTime)
1847 RTMPPacket packet;
1848 char pbuf[256], *pend = pbuf + sizeof(pbuf);
1849 char *enc;
1851 packet.m_nChannel = 0x08; /* video channel */
1852 packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
1853 packet.m_packetType = RTMP_PACKET_TYPE_INVOKE;
1854 packet.m_nTimeStamp = 0;
1855 packet.m_nInfoField2 = 0;
1856 packet.m_hasAbsTimestamp = 0;
1857 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
1859 enc = packet.m_body;
1860 enc = AMF_EncodeString(enc, pend, &av_pause);
1861 enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes);
1862 *enc++ = AMF_NULL;
1863 enc = AMF_EncodeBoolean(enc, pend, DoPause);
1864 enc = AMF_EncodeNumber(enc, pend, (double)iTime);
1866 packet.m_nBodySize = enc - packet.m_body;
1868 RTMP_Log(RTMP_LOGDEBUG, "%s, %d, pauseTime=%d", __FUNCTION__, DoPause, iTime);
1869 return RTMP_SendPacket(r, &packet, TRUE);
1872 int RTMP_Pause(RTMP *r, int DoPause)
1874 if (DoPause)
1875 r->m_pauseStamp = r->m_channelTimestamp[r->m_mediaChannel];
1876 return RTMP_SendPause(r, DoPause, r->m_pauseStamp);
1879 SAVC(seek);
1882 RTMP_SendSeek(RTMP *r, int iTime)
1884 RTMPPacket packet;
1885 char pbuf[256], *pend = pbuf + sizeof(pbuf);
1886 char *enc;
1888 packet.m_nChannel = 0x08; /* video channel */
1889 packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
1890 packet.m_packetType = RTMP_PACKET_TYPE_INVOKE;
1891 packet.m_nTimeStamp = 0;
1892 packet.m_nInfoField2 = 0;
1893 packet.m_hasAbsTimestamp = 0;
1894 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
1896 enc = packet.m_body;
1897 enc = AMF_EncodeString(enc, pend, &av_seek);
1898 enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes);
1899 *enc++ = AMF_NULL;
1900 enc = AMF_EncodeNumber(enc, pend, (double)iTime);
1902 packet.m_nBodySize = enc - packet.m_body;
1904 r->m_read.flags |= RTMP_READ_SEEKING;
1905 r->m_read.nResumeTS = 0;
1907 return RTMP_SendPacket(r, &packet, TRUE);
1911 RTMP_SendServerBW(RTMP *r)
1913 RTMPPacket packet;
1914 char pbuf[256], *pend = pbuf + sizeof(pbuf);
1916 packet.m_nChannel = 0x02; /* control channel (invoke) */
1917 packet.m_headerType = RTMP_PACKET_SIZE_LARGE;
1918 packet.m_packetType = RTMP_PACKET_TYPE_SERVER_BW;
1919 packet.m_nTimeStamp = 0;
1920 packet.m_nInfoField2 = 0;
1921 packet.m_hasAbsTimestamp = 0;
1922 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
1924 packet.m_nBodySize = 4;
1926 AMF_EncodeInt32(packet.m_body, pend, r->m_nServerBW);
1927 return RTMP_SendPacket(r, &packet, FALSE);
1931 RTMP_SendClientBW(RTMP *r)
1933 RTMPPacket packet;
1934 char pbuf[256], *pend = pbuf + sizeof(pbuf);
1936 packet.m_nChannel = 0x02; /* control channel (invoke) */
1937 packet.m_headerType = RTMP_PACKET_SIZE_LARGE;
1938 packet.m_packetType = RTMP_PACKET_TYPE_CLIENT_BW;
1939 packet.m_nTimeStamp = 0;
1940 packet.m_nInfoField2 = 0;
1941 packet.m_hasAbsTimestamp = 0;
1942 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
1944 packet.m_nBodySize = 5;
1946 AMF_EncodeInt32(packet.m_body, pend, r->m_nClientBW);
1947 packet.m_body[4] = r->m_nClientBW2;
1948 return RTMP_SendPacket(r, &packet, FALSE);
1951 static int
1952 SendBytesReceived(RTMP *r)
1954 RTMPPacket packet;
1955 char pbuf[256], *pend = pbuf + sizeof(pbuf);
1957 packet.m_nChannel = 0x02; /* control channel (invoke) */
1958 packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
1959 packet.m_packetType = RTMP_PACKET_TYPE_BYTES_READ_REPORT;
1960 packet.m_nTimeStamp = 0;
1961 packet.m_nInfoField2 = 0;
1962 packet.m_hasAbsTimestamp = 0;
1963 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
1965 packet.m_nBodySize = 4;
1967 AMF_EncodeInt32(packet.m_body, pend, r->m_nBytesIn); /* hard coded for now */
1968 r->m_nBytesInSent = r->m_nBytesIn;
1970 /*RTMP_Log(RTMP_LOGDEBUG, "Send bytes report. 0x%x (%d bytes)", (unsigned int)m_nBytesIn, m_nBytesIn); */
1971 return RTMP_SendPacket(r, &packet, FALSE);
1974 SAVC(_checkbw);
1976 static int
1977 SendCheckBW(RTMP *r)
1979 RTMPPacket packet;
1980 char pbuf[256], *pend = pbuf + sizeof(pbuf);
1981 char *enc;
1983 packet.m_nChannel = 0x03; /* control channel (invoke) */
1984 packet.m_headerType = RTMP_PACKET_SIZE_LARGE;
1985 packet.m_packetType = RTMP_PACKET_TYPE_INVOKE;
1986 packet.m_nTimeStamp = 0; /* RTMP_GetTime(); */
1987 packet.m_nInfoField2 = 0;
1988 packet.m_hasAbsTimestamp = 0;
1989 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
1991 enc = packet.m_body;
1992 enc = AMF_EncodeString(enc, pend, &av__checkbw);
1993 enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes);
1994 *enc++ = AMF_NULL;
1996 packet.m_nBodySize = enc - packet.m_body;
1998 /* triggers _onbwcheck and eventually results in _onbwdone */
1999 return RTMP_SendPacket(r, &packet, FALSE);
2002 SAVC(_result);
2004 static int
2005 SendCheckBWResult(RTMP *r, double txn)
2007 RTMPPacket packet;
2008 char pbuf[256], *pend = pbuf + sizeof(pbuf);
2009 char *enc;
2011 packet.m_nChannel = 0x03; /* control channel (invoke) */
2012 packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
2013 packet.m_packetType = RTMP_PACKET_TYPE_INVOKE;
2014 packet.m_nTimeStamp = 0x16 * r->m_nBWCheckCounter; /* temp inc value. till we figure it out. */
2015 packet.m_nInfoField2 = 0;
2016 packet.m_hasAbsTimestamp = 0;
2017 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
2019 enc = packet.m_body;
2020 enc = AMF_EncodeString(enc, pend, &av__result);
2021 enc = AMF_EncodeNumber(enc, pend, txn);
2022 *enc++ = AMF_NULL;
2023 enc = AMF_EncodeNumber(enc, pend, (double)r->m_nBWCheckCounter++);
2025 packet.m_nBodySize = enc - packet.m_body;
2027 return RTMP_SendPacket(r, &packet, FALSE);
2030 SAVC(ping);
2031 SAVC(pong);
2033 static int
2034 SendPong(RTMP *r, double txn)
2036 RTMPPacket packet;
2037 char pbuf[256], *pend = pbuf + sizeof(pbuf);
2038 char *enc;
2040 packet.m_nChannel = 0x03; /* control channel (invoke) */
2041 packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
2042 packet.m_packetType = RTMP_PACKET_TYPE_INVOKE;
2043 packet.m_nTimeStamp = 0x16 * r->m_nBWCheckCounter; /* temp inc value. till we figure it out. */
2044 packet.m_nInfoField2 = 0;
2045 packet.m_hasAbsTimestamp = 0;
2046 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
2048 enc = packet.m_body;
2049 enc = AMF_EncodeString(enc, pend, &av_pong);
2050 enc = AMF_EncodeNumber(enc, pend, txn);
2051 *enc++ = AMF_NULL;
2053 packet.m_nBodySize = enc - packet.m_body;
2055 return RTMP_SendPacket(r, &packet, FALSE);
2058 SAVC(play);
2060 static int
2061 SendPlay(RTMP *r)
2063 RTMPPacket packet;
2064 char pbuf[1024], *pend = pbuf + sizeof(pbuf);
2065 char *enc;
2067 packet.m_nChannel = 0x08; /* we make 8 our stream channel */
2068 packet.m_headerType = RTMP_PACKET_SIZE_LARGE;
2069 packet.m_packetType = RTMP_PACKET_TYPE_INVOKE;
2070 packet.m_nTimeStamp = 0;
2071 packet.m_nInfoField2 = r->m_stream_id; /*0x01000000; */
2072 packet.m_hasAbsTimestamp = 0;
2073 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
2075 enc = packet.m_body;
2076 enc = AMF_EncodeString(enc, pend, &av_play);
2077 enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes);
2078 *enc++ = AMF_NULL;
2080 RTMP_Log(RTMP_LOGDEBUG, "%s, seekTime=%d, stopTime=%d, sending play: %s",
2081 __FUNCTION__, r->Link.seekTime, r->Link.stopTime,
2082 r->Link.playpath.av_val);
2083 enc = AMF_EncodeString(enc, pend, &r->Link.playpath);
2084 if (!enc)
2085 return FALSE;
2087 /* Optional parameters start and len.
2089 * start: -2, -1, 0, positive number
2090 * -2: looks for a live stream, then a recorded stream,
2091 * if not found any open a live stream
2092 * -1: plays a live stream
2093 * >=0: plays a recorded streams from 'start' milliseconds
2095 if (r->Link.lFlags & RTMP_LF_LIVE)
2096 enc = AMF_EncodeNumber(enc, pend, -1000.0);
2097 else
2099 if (r->Link.seekTime > 0.0)
2100 enc = AMF_EncodeNumber(enc, pend, r->Link.seekTime); /* resume from here */
2101 else
2102 enc = AMF_EncodeNumber(enc, pend, 0.0); /*-2000.0);*/ /* recorded as default, -2000.0 is not reliable since that freezes the player if the stream is not found */
2104 if (!enc)
2105 return FALSE;
2107 /* len: -1, 0, positive number
2108 * -1: plays live or recorded stream to the end (default)
2109 * 0: plays a frame 'start' ms away from the beginning
2110 * >0: plays a live or recoded stream for 'len' milliseconds
2112 /*enc += EncodeNumber(enc, -1.0); */ /* len */
2113 if (r->Link.stopTime)
2115 enc = AMF_EncodeNumber(enc, pend, r->Link.stopTime - r->Link.seekTime);
2116 if (!enc)
2117 return FALSE;
2120 packet.m_nBodySize = enc - packet.m_body;
2122 return RTMP_SendPacket(r, &packet, TRUE);
2125 SAVC(set_playlist);
2126 SAVC(0);
2128 static int
2129 SendPlaylist(RTMP *r)
2131 RTMPPacket packet;
2132 char pbuf[1024], *pend = pbuf + sizeof(pbuf);
2133 char *enc;
2135 packet.m_nChannel = 0x08; /* we make 8 our stream channel */
2136 packet.m_headerType = RTMP_PACKET_SIZE_LARGE;
2137 packet.m_packetType = RTMP_PACKET_TYPE_INVOKE;
2138 packet.m_nTimeStamp = 0;
2139 packet.m_nInfoField2 = r->m_stream_id; /*0x01000000; */
2140 packet.m_hasAbsTimestamp = 0;
2141 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
2143 enc = packet.m_body;
2144 enc = AMF_EncodeString(enc, pend, &av_set_playlist);
2145 enc = AMF_EncodeNumber(enc, pend, 0);
2146 *enc++ = AMF_NULL;
2147 *enc++ = AMF_ECMA_ARRAY;
2148 *enc++ = 0;
2149 *enc++ = 0;
2150 *enc++ = 0;
2151 *enc++ = AMF_OBJECT;
2152 enc = AMF_EncodeNamedString(enc, pend, &av_0, &r->Link.playpath);
2153 if (!enc)
2154 return FALSE;
2155 if (enc + 3 >= pend)
2156 return FALSE;
2157 *enc++ = 0;
2158 *enc++ = 0;
2159 *enc++ = AMF_OBJECT_END;
2161 packet.m_nBodySize = enc - packet.m_body;
2163 return RTMP_SendPacket(r, &packet, TRUE);
2166 static int
2167 SendSecureTokenResponse(RTMP *r, AVal *resp)
2169 RTMPPacket packet;
2170 char pbuf[1024], *pend = pbuf + sizeof(pbuf);
2171 char *enc;
2173 packet.m_nChannel = 0x03; /* control channel (invoke) */
2174 packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
2175 packet.m_packetType = RTMP_PACKET_TYPE_INVOKE;
2176 packet.m_nTimeStamp = 0;
2177 packet.m_nInfoField2 = 0;
2178 packet.m_hasAbsTimestamp = 0;
2179 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
2181 enc = packet.m_body;
2182 enc = AMF_EncodeString(enc, pend, &av_secureTokenResponse);
2183 enc = AMF_EncodeNumber(enc, pend, 0.0);
2184 *enc++ = AMF_NULL;
2185 enc = AMF_EncodeString(enc, pend, resp);
2186 if (!enc)
2187 return FALSE;
2189 packet.m_nBodySize = enc - packet.m_body;
2191 return RTMP_SendPacket(r, &packet, FALSE);
2195 from http://jira.red5.org/confluence/display/docs/Ping:
2197 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.
2199 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.
2201 * 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.
2202 * type 1: Tell the stream to clear the playing buffer.
2203 * type 3: Buffer time of the client. The third parameter is the buffer time in millisecond.
2204 * type 4: Reset a stream. Used together with type 0 in the case of VOD. Often sent before type 0.
2205 * type 6: Ping the client from server. The second parameter is the current time.
2206 * type 7: Pong reply from client. The second parameter is the time the server sent with his ping request.
2207 * type 26: SWFVerification request
2208 * type 27: SWFVerification response
2211 RTMP_SendCtrl(RTMP *r, short nType, unsigned int nObject, unsigned int nTime)
2213 RTMPPacket packet;
2214 char pbuf[256], *pend = pbuf + sizeof(pbuf);
2215 int nSize;
2216 char *buf;
2218 RTMP_Log(RTMP_LOGDEBUG, "sending ctrl. type: 0x%04x", (unsigned short)nType);
2220 packet.m_nChannel = 0x02; /* control channel (ping) */
2221 packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
2222 packet.m_packetType = RTMP_PACKET_TYPE_CONTROL;
2223 packet.m_nTimeStamp = 0; /* RTMP_GetTime(); */
2224 packet.m_nInfoField2 = 0;
2225 packet.m_hasAbsTimestamp = 0;
2226 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
2228 switch(nType) {
2229 case 0x03: nSize = 10; break; /* buffer time */
2230 case 0x1A: nSize = 3; break; /* SWF verify request */
2231 case 0x1B: nSize = 44; break; /* SWF verify response */
2232 default: nSize = 6; break;
2235 packet.m_nBodySize = nSize;
2237 buf = packet.m_body;
2238 buf = AMF_EncodeInt16(buf, pend, nType);
2240 if (nType == 0x1B)
2242 #ifdef CRYPTO
2243 memcpy(buf, r->Link.SWFVerificationResponse, 42);
2244 RTMP_Log(RTMP_LOGDEBUG, "Sending SWFVerification response: ");
2245 RTMP_LogHex(RTMP_LOGDEBUG, (uint8_t *)packet.m_body, packet.m_nBodySize);
2246 #endif
2248 else if (nType == 0x1A)
2250 *buf = nObject & 0xff;
2252 else
2254 if (nSize > 2)
2255 buf = AMF_EncodeInt32(buf, pend, nObject);
2257 if (nSize > 6)
2258 buf = AMF_EncodeInt32(buf, pend, nTime);
2261 return RTMP_SendPacket(r, &packet, FALSE);
2264 static void
2265 AV_erase(RTMP_METHOD *vals, int *num, int i, int freeit)
2267 if (freeit)
2268 free(vals[i].name.av_val);
2269 (*num)--;
2270 for (; i < *num; i++)
2272 vals[i] = vals[i + 1];
2274 vals[i].name.av_val = NULL;
2275 vals[i].name.av_len = 0;
2276 vals[i].num = 0;
2279 void
2280 RTMP_DropRequest(RTMP *r, int i, int freeit)
2282 AV_erase(r->m_methodCalls, &r->m_numCalls, i, freeit);
2285 static void
2286 AV_queue(RTMP_METHOD **vals, int *num, AVal *av, int txn)
2288 char *tmp;
2289 if (!(*num & 0x0f))
2290 *vals = realloc(*vals, (*num + 16) * sizeof(RTMP_METHOD));
2291 tmp = malloc(av->av_len + 1);
2292 memcpy(tmp, av->av_val, av->av_len);
2293 tmp[av->av_len] = '\0';
2294 (*vals)[*num].num = txn;
2295 (*vals)[*num].name.av_len = av->av_len;
2296 (*vals)[(*num)++].name.av_val = tmp;
2299 static void
2300 AV_clear(RTMP_METHOD *vals, int num)
2302 int i;
2303 for (i = 0; i < num; i++)
2304 free(vals[i].name.av_val);
2305 free(vals);
2308 SAVC(onBWDone);
2309 SAVC(onFCSubscribe);
2310 SAVC(onFCUnsubscribe);
2311 SAVC(_onbwcheck);
2312 SAVC(_onbwdone);
2313 SAVC(_error);
2314 SAVC(close);
2315 SAVC(code);
2316 SAVC(level);
2317 SAVC(onStatus);
2318 SAVC(playlist_ready);
2319 static const AVal av_NetStream_Failed = AVC("NetStream.Failed");
2320 static const AVal av_NetStream_Play_Failed = AVC("NetStream.Play.Failed");
2321 static const AVal av_NetStream_Play_StreamNotFound =
2322 AVC("NetStream.Play.StreamNotFound");
2323 static const AVal av_NetConnection_Connect_InvalidApp =
2324 AVC("NetConnection.Connect.InvalidApp");
2325 static const AVal av_NetStream_Play_Start = AVC("NetStream.Play.Start");
2326 static const AVal av_NetStream_Play_Complete = AVC("NetStream.Play.Complete");
2327 static const AVal av_NetStream_Play_Stop = AVC("NetStream.Play.Stop");
2328 static const AVal av_NetStream_Seek_Notify = AVC("NetStream.Seek.Notify");
2329 static const AVal av_NetStream_Pause_Notify = AVC("NetStream.Pause.Notify");
2330 static const AVal av_NetStream_Play_PublishNotify =
2331 AVC("NetStream.Play.PublishNotify");
2332 static const AVal av_NetStream_Play_UnpublishNotify =
2333 AVC("NetStream.Play.UnpublishNotify");
2334 static const AVal av_NetStream_Publish_Start = AVC("NetStream.Publish.Start");
2336 /* Returns 0 for OK/Failed/error, 1 for 'Stop or Complete' */
2337 static int
2338 HandleInvoke(RTMP *r, const char *body, unsigned int nBodySize)
2340 AMFObject obj;
2341 AVal method;
2342 double txn;
2343 int ret = 0, nRes;
2344 if (body[0] != 0x02) /* make sure it is a string method name we start with */
2346 RTMP_Log(RTMP_LOGWARNING, "%s, Sanity failed. no string method in invoke packet",
2347 __FUNCTION__);
2348 return 0;
2351 nRes = AMF_Decode(&obj, body, nBodySize, FALSE);
2352 if (nRes < 0)
2354 RTMP_Log(RTMP_LOGERROR, "%s, error decoding invoke packet", __FUNCTION__);
2355 return 0;
2358 AMF_Dump(&obj);
2359 AMFProp_GetString(AMF_GetProp(&obj, NULL, 0), &method);
2360 txn = AMFProp_GetNumber(AMF_GetProp(&obj, NULL, 1));
2361 RTMP_Log(RTMP_LOGDEBUG, "%s, server invoking <%s>", __FUNCTION__, method.av_val);
2363 if (AVMATCH(&method, &av__result))
2365 AVal methodInvoked = {0};
2366 int i;
2368 for (i=0; i<r->m_numCalls; i++) {
2369 if (r->m_methodCalls[i].num == (int)txn) {
2370 methodInvoked = r->m_methodCalls[i].name;
2371 AV_erase(r->m_methodCalls, &r->m_numCalls, i, FALSE);
2372 break;
2375 if (!methodInvoked.av_val) {
2376 RTMP_Log(RTMP_LOGDEBUG, "%s, received result id %d without matching request",
2377 __FUNCTION__, txn);
2378 goto leave;
2381 RTMP_Log(RTMP_LOGDEBUG, "%s, received result for method call <%s>", __FUNCTION__,
2382 methodInvoked.av_val);
2384 if (AVMATCH(&methodInvoked, &av_connect))
2386 if (r->Link.token.av_len)
2388 AMFObjectProperty p;
2389 if (RTMP_FindFirstMatchingProperty(&obj, &av_secureToken, &p))
2391 DecodeTEA(&r->Link.token, &p.p_vu.p_aval);
2392 SendSecureTokenResponse(r, &p.p_vu.p_aval);
2395 if (r->Link.protocol & RTMP_FEATURE_WRITE)
2397 SendReleaseStream(r);
2398 SendFCPublish(r);
2400 else
2402 RTMP_SendServerBW(r);
2403 RTMP_SendCtrl(r, 3, 0, 300);
2405 RTMP_SendCreateStream(r);
2407 if (!(r->Link.protocol & RTMP_FEATURE_WRITE))
2409 /* Authenticate on Justin.tv legacy servers before sending FCSubscribe */
2410 if (r->Link.usherToken.av_len)
2411 SendUsherToken(r, &r->Link.usherToken);
2412 /* Send the FCSubscribe if live stream or if subscribepath is set */
2413 if (r->Link.subscribepath.av_len)
2414 SendFCSubscribe(r, &r->Link.subscribepath);
2415 else if (r->Link.lFlags & RTMP_LF_LIVE)
2416 SendFCSubscribe(r, &r->Link.playpath);
2419 else if (AVMATCH(&methodInvoked, &av_createStream))
2421 r->m_stream_id = (int)AMFProp_GetNumber(AMF_GetProp(&obj, NULL, 3));
2423 if (r->Link.protocol & RTMP_FEATURE_WRITE)
2425 SendPublish(r);
2427 else
2429 if (r->Link.lFlags & RTMP_LF_PLST)
2430 SendPlaylist(r);
2431 SendPlay(r);
2432 RTMP_SendCtrl(r, 3, r->m_stream_id, r->m_nBufferMS);
2435 else if (AVMATCH(&methodInvoked, &av_play) ||
2436 AVMATCH(&methodInvoked, &av_publish))
2438 r->m_bPlaying = TRUE;
2440 free(methodInvoked.av_val);
2442 else if (AVMATCH(&method, &av_onBWDone))
2444 if (!r->m_nBWCheckCounter)
2445 SendCheckBW(r);
2447 else if (AVMATCH(&method, &av_onFCSubscribe))
2449 /* SendOnFCSubscribe(); */
2451 else if (AVMATCH(&method, &av_onFCUnsubscribe))
2453 RTMP_Close(r);
2454 ret = 1;
2456 else if (AVMATCH(&method, &av_ping))
2458 SendPong(r, txn);
2460 else if (AVMATCH(&method, &av__onbwcheck))
2462 SendCheckBWResult(r, txn);
2464 else if (AVMATCH(&method, &av__onbwdone))
2466 int i;
2467 for (i = 0; i < r->m_numCalls; i++)
2468 if (AVMATCH(&r->m_methodCalls[i].name, &av__checkbw))
2470 AV_erase(r->m_methodCalls, &r->m_numCalls, i, TRUE);
2471 break;
2474 else if (AVMATCH(&method, &av__error))
2476 RTMP_Log(RTMP_LOGERROR, "rtmp server sent error");
2478 else if (AVMATCH(&method, &av_close))
2480 RTMP_Log(RTMP_LOGERROR, "rtmp server requested close");
2481 RTMP_Close(r);
2483 else if (AVMATCH(&method, &av_onStatus))
2485 AMFObject obj2;
2486 AVal code, level;
2487 AMFProp_GetObject(AMF_GetProp(&obj, NULL, 3), &obj2);
2488 AMFProp_GetString(AMF_GetProp(&obj2, &av_code, -1), &code);
2489 AMFProp_GetString(AMF_GetProp(&obj2, &av_level, -1), &level);
2491 RTMP_Log(RTMP_LOGDEBUG, "%s, onStatus: %s", __FUNCTION__, code.av_val);
2492 if (AVMATCH(&code, &av_NetStream_Failed)
2493 || AVMATCH(&code, &av_NetStream_Play_Failed)
2494 || AVMATCH(&code, &av_NetStream_Play_StreamNotFound)
2495 || AVMATCH(&code, &av_NetConnection_Connect_InvalidApp))
2497 r->m_stream_id = -1;
2498 RTMP_Close(r);
2499 RTMP_Log(RTMP_LOGERROR, "Closing connection: %s", code.av_val);
2502 else if (AVMATCH(&code, &av_NetStream_Play_Start)
2503 || AVMATCH(&code, &av_NetStream_Play_PublishNotify))
2505 int i;
2506 r->m_bPlaying = TRUE;
2507 for (i = 0; i < r->m_numCalls; i++)
2509 if (AVMATCH(&r->m_methodCalls[i].name, &av_play))
2511 AV_erase(r->m_methodCalls, &r->m_numCalls, i, TRUE);
2512 break;
2517 else if (AVMATCH(&code, &av_NetStream_Publish_Start))
2519 int i;
2520 r->m_bPlaying = TRUE;
2521 for (i = 0; i < r->m_numCalls; i++)
2523 if (AVMATCH(&r->m_methodCalls[i].name, &av_publish))
2525 AV_erase(r->m_methodCalls, &r->m_numCalls, i, TRUE);
2526 break;
2531 /* Return 1 if this is a Play.Complete or Play.Stop */
2532 else if (AVMATCH(&code, &av_NetStream_Play_Complete)
2533 || AVMATCH(&code, &av_NetStream_Play_Stop)
2534 || AVMATCH(&code, &av_NetStream_Play_UnpublishNotify))
2536 RTMP_Close(r);
2537 ret = 1;
2540 else if (AVMATCH(&code, &av_NetStream_Seek_Notify))
2542 r->m_read.flags &= ~RTMP_READ_SEEKING;
2545 else if (AVMATCH(&code, &av_NetStream_Pause_Notify))
2547 if (r->m_pausing == 1 || r->m_pausing == 2)
2549 RTMP_SendPause(r, FALSE, r->m_pauseStamp);
2550 r->m_pausing = 3;
2554 else if (AVMATCH(&method, &av_playlist_ready))
2556 int i;
2557 for (i = 0; i < r->m_numCalls; i++)
2559 if (AVMATCH(&r->m_methodCalls[i].name, &av_set_playlist))
2561 AV_erase(r->m_methodCalls, &r->m_numCalls, i, TRUE);
2562 break;
2566 else
2570 leave:
2571 AMF_Reset(&obj);
2572 return ret;
2576 RTMP_FindFirstMatchingProperty(AMFObject *obj, const AVal *name,
2577 AMFObjectProperty * p)
2579 int n;
2580 /* this is a small object search to locate the "duration" property */
2581 for (n = 0; n < obj->o_num; n++)
2583 AMFObjectProperty *prop = AMF_GetProp(obj, NULL, n);
2585 if (AVMATCH(&prop->p_name, name))
2587 *p = *prop;
2588 return TRUE;
2591 if (prop->p_type == AMF_OBJECT)
2593 if (RTMP_FindFirstMatchingProperty(&prop->p_vu.p_object, name, p))
2594 return TRUE;
2597 return FALSE;
2600 /* Like above, but only check if name is a prefix of property */
2602 RTMP_FindPrefixProperty(AMFObject *obj, const AVal *name,
2603 AMFObjectProperty * p)
2605 int n;
2606 for (n = 0; n < obj->o_num; n++)
2608 AMFObjectProperty *prop = AMF_GetProp(obj, NULL, n);
2610 if (prop->p_name.av_len > name->av_len &&
2611 !memcmp(prop->p_name.av_val, name->av_val, name->av_len))
2613 *p = *prop;
2614 return TRUE;
2617 if (prop->p_type == AMF_OBJECT)
2619 if (RTMP_FindPrefixProperty(&prop->p_vu.p_object, name, p))
2620 return TRUE;
2623 return FALSE;
2626 static int
2627 DumpMetaData(AMFObject *obj)
2629 AMFObjectProperty *prop;
2630 int n;
2631 for (n = 0; n < obj->o_num; n++)
2633 prop = AMF_GetProp(obj, NULL, n);
2634 if (prop->p_type != AMF_OBJECT)
2636 char str[256] = "";
2637 switch (prop->p_type)
2639 case AMF_NUMBER:
2640 snprintf(str, 255, "%.2f", prop->p_vu.p_number);
2641 break;
2642 case AMF_BOOLEAN:
2643 snprintf(str, 255, "%s",
2644 prop->p_vu.p_number != 0. ? "TRUE" : "FALSE");
2645 break;
2646 case AMF_STRING:
2647 snprintf(str, 255, "%.*s", prop->p_vu.p_aval.av_len,
2648 prop->p_vu.p_aval.av_val);
2649 break;
2650 case AMF_DATE:
2651 snprintf(str, 255, "timestamp:%.2f", prop->p_vu.p_number);
2652 break;
2653 default:
2654 snprintf(str, 255, "INVALID TYPE 0x%02x",
2655 (unsigned char)prop->p_type);
2657 if (prop->p_name.av_len)
2659 /* chomp */
2660 if (strlen(str) >= 1 && str[strlen(str) - 1] == '\n')
2661 str[strlen(str) - 1] = '\0';
2662 RTMP_Log(RTMP_LOGINFO, " %-22.*s%s", prop->p_name.av_len,
2663 prop->p_name.av_val, str);
2666 else
2668 if (prop->p_name.av_len)
2669 RTMP_Log(RTMP_LOGINFO, "%.*s:", prop->p_name.av_len, prop->p_name.av_val);
2670 DumpMetaData(&prop->p_vu.p_object);
2673 return FALSE;
2676 SAVC(onMetaData);
2677 SAVC(duration);
2678 SAVC(video);
2679 SAVC(audio);
2681 static int
2682 HandleMetadata(RTMP *r, char *body, unsigned int len)
2684 /* allright we get some info here, so parse it and print it */
2685 /* also keep duration or filesize to make a nice progress bar */
2687 AMFObject obj;
2688 AVal metastring;
2689 int ret = FALSE;
2691 int nRes = AMF_Decode(&obj, body, len, FALSE);
2692 if (nRes < 0)
2694 RTMP_Log(RTMP_LOGERROR, "%s, error decoding meta data packet", __FUNCTION__);
2695 return FALSE;
2698 AMF_Dump(&obj);
2699 AMFProp_GetString(AMF_GetProp(&obj, NULL, 0), &metastring);
2701 if (AVMATCH(&metastring, &av_onMetaData))
2703 AMFObjectProperty prop;
2704 /* Show metadata */
2705 RTMP_Log(RTMP_LOGINFO, "Metadata:");
2706 DumpMetaData(&obj);
2707 if (RTMP_FindFirstMatchingProperty(&obj, &av_duration, &prop))
2709 r->m_fDuration = prop.p_vu.p_number;
2710 /*RTMP_Log(RTMP_LOGDEBUG, "Set duration: %.2f", m_fDuration); */
2712 /* Search for audio or video tags */
2713 if (RTMP_FindPrefixProperty(&obj, &av_video, &prop))
2714 r->m_read.dataType |= 1;
2715 if (RTMP_FindPrefixProperty(&obj, &av_audio, &prop))
2716 r->m_read.dataType |= 4;
2717 ret = TRUE;
2719 AMF_Reset(&obj);
2720 return ret;
2723 static void
2724 HandleChangeChunkSize(RTMP *r, const RTMPPacket *packet)
2726 if (packet->m_nBodySize >= 4)
2728 r->m_inChunkSize = AMF_DecodeInt32(packet->m_body);
2729 RTMP_Log(RTMP_LOGDEBUG, "%s, received: chunk size change to %d", __FUNCTION__,
2730 r->m_inChunkSize);
2734 static void
2735 HandleAudio(RTMP *r, const RTMPPacket *packet)
2739 static void
2740 HandleVideo(RTMP *r, const RTMPPacket *packet)
2744 static void
2745 HandleCtrl(RTMP *r, const RTMPPacket *packet)
2747 short nType = -1;
2748 unsigned int tmp;
2749 if (packet->m_body && packet->m_nBodySize >= 2)
2750 nType = AMF_DecodeInt16(packet->m_body);
2751 RTMP_Log(RTMP_LOGDEBUG, "%s, received ctrl. type: %d, len: %d", __FUNCTION__, nType,
2752 packet->m_nBodySize);
2753 /*RTMP_LogHex(packet.m_body, packet.m_nBodySize); */
2755 if (packet->m_nBodySize >= 6)
2757 switch (nType)
2759 case 0:
2760 tmp = AMF_DecodeInt32(packet->m_body + 2);
2761 RTMP_Log(RTMP_LOGDEBUG, "%s, Stream Begin %d", __FUNCTION__, tmp);
2762 break;
2764 case 1:
2765 tmp = AMF_DecodeInt32(packet->m_body + 2);
2766 RTMP_Log(RTMP_LOGDEBUG, "%s, Stream EOF %d", __FUNCTION__, tmp);
2767 if (r->m_pausing == 1)
2768 r->m_pausing = 2;
2769 break;
2771 case 2:
2772 tmp = AMF_DecodeInt32(packet->m_body + 2);
2773 RTMP_Log(RTMP_LOGDEBUG, "%s, Stream Dry %d", __FUNCTION__, tmp);
2774 break;
2776 case 4:
2777 tmp = AMF_DecodeInt32(packet->m_body + 2);
2778 RTMP_Log(RTMP_LOGDEBUG, "%s, Stream IsRecorded %d", __FUNCTION__, tmp);
2779 break;
2781 case 6: /* server ping. reply with pong. */
2782 tmp = AMF_DecodeInt32(packet->m_body + 2);
2783 RTMP_Log(RTMP_LOGDEBUG, "%s, Ping %d", __FUNCTION__, tmp);
2784 RTMP_SendCtrl(r, 0x07, tmp, 0);
2785 break;
2787 /* FMS 3.5 servers send the following two controls to let the client
2788 * know when the server has sent a complete buffer. I.e., when the
2789 * server has sent an amount of data equal to m_nBufferMS in duration.
2790 * The server meters its output so that data arrives at the client
2791 * in realtime and no faster.
2793 * The rtmpdump program tries to set m_nBufferMS as large as
2794 * possible, to force the server to send data as fast as possible.
2795 * In practice, the server appears to cap this at about 1 hour's
2796 * worth of data. After the server has sent a complete buffer, and
2797 * sends this BufferEmpty message, it will wait until the play
2798 * duration of that buffer has passed before sending a new buffer.
2799 * The BufferReady message will be sent when the new buffer starts.
2800 * (There is no BufferReady message for the very first buffer;
2801 * presumably the Stream Begin message is sufficient for that
2802 * purpose.)
2804 * If the network speed is much faster than the data bitrate, then
2805 * there may be long delays between the end of one buffer and the
2806 * start of the next.
2808 * Since usually the network allows data to be sent at
2809 * faster than realtime, and rtmpdump wants to download the data
2810 * as fast as possible, we use this RTMP_LF_BUFX hack: when we
2811 * get the BufferEmpty message, we send a Pause followed by an
2812 * Unpause. This causes the server to send the next buffer immediately
2813 * instead of waiting for the full duration to elapse. (That's
2814 * also the purpose of the ToggleStream function, which rtmpdump
2815 * calls if we get a read timeout.)
2817 * Media player apps don't need this hack since they are just
2818 * going to play the data in realtime anyway. It also doesn't work
2819 * for live streams since they obviously can only be sent in
2820 * realtime. And it's all moot if the network speed is actually
2821 * slower than the media bitrate.
2823 case 31:
2824 tmp = AMF_DecodeInt32(packet->m_body + 2);
2825 RTMP_Log(RTMP_LOGDEBUG, "%s, Stream BufferEmpty %d", __FUNCTION__, tmp);
2826 if (!(r->Link.lFlags & RTMP_LF_BUFX))
2827 break;
2828 if (!r->m_pausing)
2830 r->m_pauseStamp = r->m_channelTimestamp[r->m_mediaChannel];
2831 RTMP_SendPause(r, TRUE, r->m_pauseStamp);
2832 r->m_pausing = 1;
2834 else if (r->m_pausing == 2)
2836 RTMP_SendPause(r, FALSE, r->m_pauseStamp);
2837 r->m_pausing = 3;
2839 break;
2841 case 32:
2842 tmp = AMF_DecodeInt32(packet->m_body + 2);
2843 RTMP_Log(RTMP_LOGDEBUG, "%s, Stream BufferReady %d", __FUNCTION__, tmp);
2844 break;
2846 default:
2847 tmp = AMF_DecodeInt32(packet->m_body + 2);
2848 RTMP_Log(RTMP_LOGDEBUG, "%s, Stream xx %d", __FUNCTION__, tmp);
2849 break;
2854 if (nType == 0x1A)
2856 RTMP_Log(RTMP_LOGDEBUG, "%s, SWFVerification ping received: ", __FUNCTION__);
2857 if (packet->m_nBodySize > 2 && packet->m_body[2] > 0x01)
2859 RTMP_Log(RTMP_LOGERROR,
2860 "%s: SWFVerification Type %d request not supported! Patches welcome...",
2861 __FUNCTION__, packet->m_body[2]);
2863 #ifdef CRYPTO
2864 /*RTMP_LogHex(packet.m_body, packet.m_nBodySize); */
2866 /* respond with HMAC SHA256 of decompressed SWF, key is the 30byte player key, also the last 30 bytes of the server handshake are applied */
2867 else if (r->Link.SWFSize)
2869 RTMP_SendCtrl(r, 0x1B, 0, 0);
2871 else
2873 RTMP_Log(RTMP_LOGERROR,
2874 "%s: Ignoring SWFVerification request, use --swfVfy!",
2875 __FUNCTION__);
2877 #else
2878 RTMP_Log(RTMP_LOGERROR,
2879 "%s: Ignoring SWFVerification request, no CRYPTO support!",
2880 __FUNCTION__);
2881 #endif
2885 static void
2886 HandleServerBW(RTMP *r, const RTMPPacket *packet)
2888 r->m_nServerBW = AMF_DecodeInt32(packet->m_body);
2889 RTMP_Log(RTMP_LOGDEBUG, "%s: server BW = %d", __FUNCTION__, r->m_nServerBW);
2892 static void
2893 HandleClientBW(RTMP *r, const RTMPPacket *packet)
2895 r->m_nClientBW = AMF_DecodeInt32(packet->m_body);
2896 if (packet->m_nBodySize > 4)
2897 r->m_nClientBW2 = packet->m_body[4];
2898 else
2899 r->m_nClientBW2 = -1;
2900 RTMP_Log(RTMP_LOGDEBUG, "%s: client BW = %d %d", __FUNCTION__, r->m_nClientBW,
2901 r->m_nClientBW2);
2904 static int
2905 DecodeInt32LE(const char *data)
2907 unsigned char *c = (unsigned char *)data;
2908 unsigned int val;
2910 val = (c[3] << 24) | (c[2] << 16) | (c[1] << 8) | c[0];
2911 return val;
2914 static int
2915 EncodeInt32LE(char *output, int nVal)
2917 output[0] = nVal;
2918 nVal >>= 8;
2919 output[1] = nVal;
2920 nVal >>= 8;
2921 output[2] = nVal;
2922 nVal >>= 8;
2923 output[3] = nVal;
2924 return 4;
2928 RTMP_ReadPacket(RTMP *r, RTMPPacket *packet)
2930 uint8_t hbuf[RTMP_MAX_HEADER_SIZE] = { 0 };
2931 char *header = (char *)hbuf;
2932 int nSize, hSize, nToRead, nChunk;
2933 int didAlloc = FALSE;
2935 RTMP_Log(RTMP_LOGDEBUG2, "%s: fd=%d", __FUNCTION__, r->m_sb.sb_socket);
2937 if (ReadN(r, (char *)hbuf, 1) == 0)
2939 RTMP_Log(RTMP_LOGERROR, "%s, failed to read RTMP packet header", __FUNCTION__);
2940 return FALSE;
2943 packet->m_headerType = (hbuf[0] & 0xc0) >> 6;
2944 packet->m_nChannel = (hbuf[0] & 0x3f);
2945 header++;
2946 if (packet->m_nChannel == 0)
2948 if (ReadN(r, (char *)&hbuf[1], 1) != 1)
2950 RTMP_Log(RTMP_LOGERROR, "%s, failed to read RTMP packet header 2nd byte",
2951 __FUNCTION__);
2952 return FALSE;
2954 packet->m_nChannel = hbuf[1];
2955 packet->m_nChannel += 64;
2956 header++;
2958 else if (packet->m_nChannel == 1)
2960 int tmp;
2961 if (ReadN(r, (char *)&hbuf[1], 2) != 2)
2963 RTMP_Log(RTMP_LOGERROR, "%s, failed to read RTMP packet header 3nd byte",
2964 __FUNCTION__);
2965 return FALSE;
2967 tmp = (hbuf[2] << 8) + hbuf[1];
2968 packet->m_nChannel = tmp + 64;
2969 RTMP_Log(RTMP_LOGDEBUG, "%s, m_nChannel: %0x", __FUNCTION__, packet->m_nChannel);
2970 header += 2;
2973 nSize = packetSize[packet->m_headerType];
2975 if (nSize == RTMP_LARGE_HEADER_SIZE) /* if we get a full header the timestamp is absolute */
2976 packet->m_hasAbsTimestamp = TRUE;
2978 else if (nSize < RTMP_LARGE_HEADER_SIZE)
2979 { /* using values from the last message of this channel */
2980 if (r->m_vecChannelsIn[packet->m_nChannel])
2981 memcpy(packet, r->m_vecChannelsIn[packet->m_nChannel],
2982 sizeof(RTMPPacket));
2985 nSize--;
2987 if (nSize > 0 && ReadN(r, header, nSize) != nSize)
2989 RTMP_Log(RTMP_LOGERROR, "%s, failed to read RTMP packet header. type: %x",
2990 __FUNCTION__, (unsigned int)hbuf[0]);
2991 return FALSE;
2994 hSize = nSize + (header - (char *)hbuf);
2996 if (nSize >= 3)
2998 packet->m_nTimeStamp = AMF_DecodeInt24(header);
3000 /*RTMP_Log(RTMP_LOGDEBUG, "%s, reading RTMP packet chunk on channel %x, headersz %i, timestamp %i, abs timestamp %i", __FUNCTION__, packet.m_nChannel, nSize, packet.m_nTimeStamp, packet.m_hasAbsTimestamp); */
3002 if (nSize >= 6)
3004 packet->m_nBodySize = AMF_DecodeInt24(header + 3);
3005 packet->m_nBytesRead = 0;
3006 RTMPPacket_Free(packet);
3008 if (nSize > 6)
3010 packet->m_packetType = header[6];
3012 if (nSize == 11)
3013 packet->m_nInfoField2 = DecodeInt32LE(header + 7);
3016 if (packet->m_nTimeStamp == 0xffffff)
3018 if (ReadN(r, header + nSize, 4) != 4)
3020 RTMP_Log(RTMP_LOGERROR, "%s, failed to read extended timestamp",
3021 __FUNCTION__);
3022 return FALSE;
3024 packet->m_nTimeStamp = AMF_DecodeInt32(header + nSize);
3025 hSize += 4;
3029 RTMP_LogHexString(RTMP_LOGDEBUG2, (uint8_t *)hbuf, hSize);
3031 if (packet->m_nBodySize > 0 && packet->m_body == NULL)
3033 if (!RTMPPacket_Alloc(packet, packet->m_nBodySize))
3035 RTMP_Log(RTMP_LOGDEBUG, "%s, failed to allocate packet", __FUNCTION__);
3036 return FALSE;
3038 didAlloc = TRUE;
3039 packet->m_headerType = (hbuf[0] & 0xc0) >> 6;
3042 nToRead = packet->m_nBodySize - packet->m_nBytesRead;
3043 nChunk = r->m_inChunkSize;
3044 if (nToRead < nChunk)
3045 nChunk = nToRead;
3047 /* Does the caller want the raw chunk? */
3048 if (packet->m_chunk)
3050 packet->m_chunk->c_headerSize = hSize;
3051 memcpy(packet->m_chunk->c_header, hbuf, hSize);
3052 packet->m_chunk->c_chunk = packet->m_body + packet->m_nBytesRead;
3053 packet->m_chunk->c_chunkSize = nChunk;
3056 if (ReadN(r, packet->m_body + packet->m_nBytesRead, nChunk) != nChunk)
3058 RTMP_Log(RTMP_LOGERROR, "%s, failed to read RTMP packet body. len: %lu",
3059 __FUNCTION__, packet->m_nBodySize);
3060 return FALSE;
3063 RTMP_LogHexString(RTMP_LOGDEBUG2, (uint8_t *)packet->m_body + packet->m_nBytesRead, nChunk);
3065 packet->m_nBytesRead += nChunk;
3067 /* keep the packet as ref for other packets on this channel */
3068 if (!r->m_vecChannelsIn[packet->m_nChannel])
3069 r->m_vecChannelsIn[packet->m_nChannel] = malloc(sizeof(RTMPPacket));
3070 memcpy(r->m_vecChannelsIn[packet->m_nChannel], packet, sizeof(RTMPPacket));
3072 if (RTMPPacket_IsReady(packet))
3074 /* make packet's timestamp absolute */
3075 if (!packet->m_hasAbsTimestamp)
3076 packet->m_nTimeStamp += r->m_channelTimestamp[packet->m_nChannel]; /* timestamps seem to be always relative!! */
3078 r->m_channelTimestamp[packet->m_nChannel] = packet->m_nTimeStamp;
3080 /* reset the data from the stored packet. we keep the header since we may use it later if a new packet for this channel */
3081 /* arrives and requests to re-use some info (small packet header) */
3082 r->m_vecChannelsIn[packet->m_nChannel]->m_body = NULL;
3083 r->m_vecChannelsIn[packet->m_nChannel]->m_nBytesRead = 0;
3084 r->m_vecChannelsIn[packet->m_nChannel]->m_hasAbsTimestamp = FALSE; /* can only be false if we reuse header */
3086 else
3088 packet->m_body = NULL; /* so it won't be erased on free */
3091 return TRUE;
3094 #ifndef CRYPTO
3095 static int
3096 HandShake(RTMP *r, int FP9HandShake)
3098 int i;
3099 uint32_t uptime, suptime;
3100 int bMatch;
3101 char type;
3102 char clientbuf[RTMP_SIG_SIZE + 1], *clientsig = clientbuf + 1;
3103 char serversig[RTMP_SIG_SIZE];
3105 clientbuf[0] = 0x03; /* not encrypted */
3107 uptime = htonl(RTMP_GetTime());
3108 memcpy(clientsig, &uptime, 4);
3110 memset(&clientsig[4], 0, 4);
3112 #ifdef _DEBUG
3113 for (i = 8; i < RTMP_SIG_SIZE; i++)
3114 clientsig[i] = 0xff;
3115 #else
3116 for (i = 8; i < RTMP_SIG_SIZE; i++)
3117 clientsig[i] = (char)(rand() % 256);
3118 #endif
3120 if (!WriteN(r, clientbuf, RTMP_SIG_SIZE + 1))
3121 return FALSE;
3123 if (ReadN(r, &type, 1) != 1) /* 0x03 or 0x06 */
3124 return FALSE;
3126 RTMP_Log(RTMP_LOGDEBUG, "%s: Type Answer : %02X", __FUNCTION__, type);
3128 if (type != clientbuf[0])
3129 RTMP_Log(RTMP_LOGWARNING, "%s: Type mismatch: client sent %d, server answered %d",
3130 __FUNCTION__, clientbuf[0], type);
3132 if (ReadN(r, serversig, RTMP_SIG_SIZE) != RTMP_SIG_SIZE)
3133 return FALSE;
3135 /* decode server response */
3137 memcpy(&suptime, serversig, 4);
3138 suptime = ntohl(suptime);
3140 RTMP_Log(RTMP_LOGDEBUG, "%s: Server Uptime : %d", __FUNCTION__, suptime);
3141 RTMP_Log(RTMP_LOGDEBUG, "%s: FMS Version : %d.%d.%d.%d", __FUNCTION__,
3142 serversig[4], serversig[5], serversig[6], serversig[7]);
3144 /* 2nd part of handshake */
3145 if (!WriteN(r, serversig, RTMP_SIG_SIZE))
3146 return FALSE;
3148 if (ReadN(r, serversig, RTMP_SIG_SIZE) != RTMP_SIG_SIZE)
3149 return FALSE;
3151 bMatch = (memcmp(serversig, clientsig, RTMP_SIG_SIZE) == 0);
3152 if (!bMatch)
3154 RTMP_Log(RTMP_LOGWARNING, "%s, client signature does not match!", __FUNCTION__);
3156 return TRUE;
3159 static int
3160 SHandShake(RTMP *r)
3162 int i;
3163 char serverbuf[RTMP_SIG_SIZE + 1], *serversig = serverbuf + 1;
3164 char clientsig[RTMP_SIG_SIZE];
3165 uint32_t uptime;
3166 int bMatch;
3168 if (ReadN(r, serverbuf, 1) != 1) /* 0x03 or 0x06 */
3169 return FALSE;
3171 RTMP_Log(RTMP_LOGDEBUG, "%s: Type Request : %02X", __FUNCTION__, serverbuf[0]);
3173 if (serverbuf[0] != 3)
3175 RTMP_Log(RTMP_LOGERROR, "%s: Type unknown: client sent %02X",
3176 __FUNCTION__, serverbuf[0]);
3177 return FALSE;
3180 uptime = htonl(RTMP_GetTime());
3181 memcpy(serversig, &uptime, 4);
3183 memset(&serversig[4], 0, 4);
3184 #ifdef _DEBUG
3185 for (i = 8; i < RTMP_SIG_SIZE; i++)
3186 serversig[i] = 0xff;
3187 #else
3188 for (i = 8; i < RTMP_SIG_SIZE; i++)
3189 serversig[i] = (char)(rand() % 256);
3190 #endif
3192 if (!WriteN(r, serverbuf, RTMP_SIG_SIZE + 1))
3193 return FALSE;
3195 if (ReadN(r, clientsig, RTMP_SIG_SIZE) != RTMP_SIG_SIZE)
3196 return FALSE;
3198 /* decode client response */
3200 memcpy(&uptime, clientsig, 4);
3201 uptime = ntohl(uptime);
3203 RTMP_Log(RTMP_LOGDEBUG, "%s: Client Uptime : %d", __FUNCTION__, uptime);
3204 RTMP_Log(RTMP_LOGDEBUG, "%s: Player Version: %d.%d.%d.%d", __FUNCTION__,
3205 clientsig[4], clientsig[5], clientsig[6], clientsig[7]);
3207 /* 2nd part of handshake */
3208 if (!WriteN(r, clientsig, RTMP_SIG_SIZE))
3209 return FALSE;
3211 if (ReadN(r, clientsig, RTMP_SIG_SIZE) != RTMP_SIG_SIZE)
3212 return FALSE;
3214 bMatch = (memcmp(serversig, clientsig, RTMP_SIG_SIZE) == 0);
3215 if (!bMatch)
3217 RTMP_Log(RTMP_LOGWARNING, "%s, client signature does not match!", __FUNCTION__);
3219 return TRUE;
3221 #endif
3224 RTMP_SendChunk(RTMP *r, RTMPChunk *chunk)
3226 int wrote;
3227 char hbuf[RTMP_MAX_HEADER_SIZE];
3229 RTMP_Log(RTMP_LOGDEBUG2, "%s: fd=%d, size=%d", __FUNCTION__, r->m_sb.sb_socket,
3230 chunk->c_chunkSize);
3231 RTMP_LogHexString(RTMP_LOGDEBUG2, (uint8_t *)chunk->c_header, chunk->c_headerSize);
3232 if (chunk->c_chunkSize)
3234 char *ptr = chunk->c_chunk - chunk->c_headerSize;
3235 RTMP_LogHexString(RTMP_LOGDEBUG2, (uint8_t *)chunk->c_chunk, chunk->c_chunkSize);
3236 /* save header bytes we're about to overwrite */
3237 memcpy(hbuf, ptr, chunk->c_headerSize);
3238 memcpy(ptr, chunk->c_header, chunk->c_headerSize);
3239 wrote = WriteN(r, ptr, chunk->c_headerSize + chunk->c_chunkSize);
3240 memcpy(ptr, hbuf, chunk->c_headerSize);
3242 else
3243 wrote = WriteN(r, chunk->c_header, chunk->c_headerSize);
3244 return wrote;
3248 RTMP_SendPacket(RTMP *r, RTMPPacket *packet, int queue)
3250 const RTMPPacket *prevPacket = r->m_vecChannelsOut[packet->m_nChannel];
3251 uint32_t last = 0;
3252 int nSize;
3253 int hSize, cSize;
3254 char *header, *hptr, *hend, hbuf[RTMP_MAX_HEADER_SIZE], c;
3255 uint32_t t;
3256 char *buffer, *tbuf = NULL, *toff = NULL;
3257 int nChunkSize;
3258 int tlen;
3260 if (prevPacket && packet->m_headerType != RTMP_PACKET_SIZE_LARGE)
3262 /* compress a bit by using the prev packet's attributes */
3263 if (prevPacket->m_nBodySize == packet->m_nBodySize
3264 && prevPacket->m_packetType == packet->m_packetType
3265 && packet->m_headerType == RTMP_PACKET_SIZE_MEDIUM)
3266 packet->m_headerType = RTMP_PACKET_SIZE_SMALL;
3268 if (prevPacket->m_nTimeStamp == packet->m_nTimeStamp
3269 && packet->m_headerType == RTMP_PACKET_SIZE_SMALL)
3270 packet->m_headerType = RTMP_PACKET_SIZE_MINIMUM;
3271 last = prevPacket->m_nTimeStamp;
3274 if (packet->m_headerType > 3) /* sanity */
3276 RTMP_Log(RTMP_LOGERROR, "sanity failed!! trying to send header of type: 0x%02x.",
3277 (unsigned char)packet->m_headerType);
3278 return FALSE;
3281 nSize = packetSize[packet->m_headerType];
3282 hSize = nSize; cSize = 0;
3283 t = packet->m_nTimeStamp - last;
3285 if (packet->m_body)
3287 header = packet->m_body - nSize;
3288 hend = packet->m_body;
3290 else
3292 header = hbuf + 6;
3293 hend = hbuf + sizeof(hbuf);
3296 if (packet->m_nChannel > 319)
3297 cSize = 2;
3298 else if (packet->m_nChannel > 63)
3299 cSize = 1;
3300 if (cSize)
3302 header -= cSize;
3303 hSize += cSize;
3306 if (nSize > 1 && t >= 0xffffff)
3308 header -= 4;
3309 hSize += 4;
3312 hptr = header;
3313 c = packet->m_headerType << 6;
3314 switch (cSize)
3316 case 0:
3317 c |= packet->m_nChannel;
3318 break;
3319 case 1:
3320 break;
3321 case 2:
3322 c |= 1;
3323 break;
3325 *hptr++ = c;
3326 if (cSize)
3328 int tmp = packet->m_nChannel - 64;
3329 *hptr++ = tmp & 0xff;
3330 if (cSize == 2)
3331 *hptr++ = tmp >> 8;
3334 if (nSize > 1)
3336 hptr = AMF_EncodeInt24(hptr, hend, t > 0xffffff ? 0xffffff : t);
3339 if (nSize > 4)
3341 hptr = AMF_EncodeInt24(hptr, hend, packet->m_nBodySize);
3342 *hptr++ = packet->m_packetType;
3345 if (nSize > 8)
3346 hptr += EncodeInt32LE(hptr, packet->m_nInfoField2);
3348 if (nSize > 1 && t >= 0xffffff)
3349 hptr = AMF_EncodeInt32(hptr, hend, t);
3351 nSize = packet->m_nBodySize;
3352 buffer = packet->m_body;
3353 nChunkSize = r->m_outChunkSize;
3355 RTMP_Log(RTMP_LOGDEBUG2, "%s: fd=%d, size=%d", __FUNCTION__, r->m_sb.sb_socket,
3356 nSize);
3357 /* send all chunks in one HTTP request */
3358 if (r->Link.protocol & RTMP_FEATURE_HTTP)
3360 int chunks = (nSize+nChunkSize-1) / nChunkSize;
3361 if (chunks > 1)
3363 tlen = chunks * (cSize + 1) + nSize + hSize;
3364 tbuf = malloc(tlen);
3365 if (!tbuf)
3366 return FALSE;
3367 toff = tbuf;
3370 while (nSize + hSize)
3372 int wrote;
3374 if (nSize < nChunkSize)
3375 nChunkSize = nSize;
3377 RTMP_LogHexString(RTMP_LOGDEBUG2, (uint8_t *)header, hSize);
3378 RTMP_LogHexString(RTMP_LOGDEBUG2, (uint8_t *)buffer, nChunkSize);
3379 if (tbuf)
3381 memcpy(toff, header, nChunkSize + hSize);
3382 toff += nChunkSize + hSize;
3384 else
3386 wrote = WriteN(r, header, nChunkSize + hSize);
3387 if (!wrote)
3388 return FALSE;
3390 nSize -= nChunkSize;
3391 buffer += nChunkSize;
3392 hSize = 0;
3394 if (nSize > 0)
3396 header = buffer - 1;
3397 hSize = 1;
3398 if (cSize)
3400 header -= cSize;
3401 hSize += cSize;
3403 *header = (0xc0 | c);
3404 if (cSize)
3406 int tmp = packet->m_nChannel - 64;
3407 header[1] = tmp & 0xff;
3408 if (cSize == 2)
3409 header[2] = tmp >> 8;
3413 if (tbuf)
3415 int wrote = WriteN(r, tbuf, toff-tbuf);
3416 free(tbuf);
3417 tbuf = NULL;
3418 if (!wrote)
3419 return FALSE;
3422 /* we invoked a remote method */
3423 if (packet->m_packetType == RTMP_PACKET_TYPE_INVOKE)
3425 AVal method;
3426 char *ptr;
3427 ptr = packet->m_body + 1;
3428 AMF_DecodeString(ptr, &method);
3429 RTMP_Log(RTMP_LOGDEBUG, "Invoking %s", method.av_val);
3430 /* keep it in call queue till result arrives */
3431 if (queue) {
3432 int txn;
3433 ptr += 3 + method.av_len;
3434 txn = (int)AMF_DecodeNumber(ptr);
3435 AV_queue(&r->m_methodCalls, &r->m_numCalls, &method, txn);
3439 if (!r->m_vecChannelsOut[packet->m_nChannel])
3440 r->m_vecChannelsOut[packet->m_nChannel] = malloc(sizeof(RTMPPacket));
3441 memcpy(r->m_vecChannelsOut[packet->m_nChannel], packet, sizeof(RTMPPacket));
3442 return TRUE;
3446 RTMP_Serve(RTMP *r)
3448 return SHandShake(r);
3451 void
3452 RTMP_Close(RTMP *r)
3454 int i;
3456 if (RTMP_IsConnected(r))
3458 if (r->m_stream_id > 0)
3460 i = r->m_stream_id;
3461 r->m_stream_id = 0;
3462 if ((r->Link.protocol & RTMP_FEATURE_WRITE))
3463 SendFCUnpublish(r);
3464 SendDeleteStream(r, i);
3466 if (r->m_clientID.av_val)
3468 HTTP_Post(r, RTMPT_CLOSE, "", 1);
3469 free(r->m_clientID.av_val);
3470 r->m_clientID.av_val = NULL;
3471 r->m_clientID.av_len = 0;
3473 RTMPSockBuf_Close(&r->m_sb);
3476 r->m_stream_id = -1;
3477 r->m_sb.sb_socket = -1;
3478 r->m_nBWCheckCounter = 0;
3479 r->m_nBytesIn = 0;
3480 r->m_nBytesInSent = 0;
3482 if (r->m_read.flags & RTMP_READ_HEADER) {
3483 free(r->m_read.buf);
3484 r->m_read.buf = NULL;
3486 r->m_read.dataType = 0;
3487 r->m_read.flags = 0;
3488 r->m_read.status = 0;
3489 r->m_read.nResumeTS = 0;
3490 r->m_read.nIgnoredFrameCounter = 0;
3491 r->m_read.nIgnoredFlvFrameCounter = 0;
3493 r->m_write.m_nBytesRead = 0;
3494 RTMPPacket_Free(&r->m_write);
3496 for (i = 0; i < RTMP_CHANNELS; i++)
3498 if (r->m_vecChannelsIn[i])
3500 RTMPPacket_Free(r->m_vecChannelsIn[i]);
3501 free(r->m_vecChannelsIn[i]);
3502 r->m_vecChannelsIn[i] = NULL;
3504 if (r->m_vecChannelsOut[i])
3506 free(r->m_vecChannelsOut[i]);
3507 r->m_vecChannelsOut[i] = NULL;
3510 AV_clear(r->m_methodCalls, r->m_numCalls);
3511 r->m_methodCalls = NULL;
3512 r->m_numCalls = 0;
3513 r->m_numInvokes = 0;
3515 r->m_bPlaying = FALSE;
3516 r->m_sb.sb_size = 0;
3518 r->m_msgCounter = 0;
3519 r->m_resplen = 0;
3520 r->m_unackd = 0;
3522 free(r->Link.playpath0.av_val);
3523 r->Link.playpath0.av_val = NULL;
3525 if (r->Link.lFlags & RTMP_LF_FTCU)
3527 free(r->Link.tcUrl.av_val);
3528 r->Link.tcUrl.av_val = NULL;
3529 r->Link.lFlags ^= RTMP_LF_FTCU;
3532 #ifdef CRYPTO
3533 if (r->Link.dh)
3535 MDH_free(r->Link.dh);
3536 r->Link.dh = NULL;
3538 if (r->Link.rc4keyIn)
3540 RC4_free(r->Link.rc4keyIn);
3541 r->Link.rc4keyIn = NULL;
3543 if (r->Link.rc4keyOut)
3545 RC4_free(r->Link.rc4keyOut);
3546 r->Link.rc4keyOut = NULL;
3548 #endif
3552 RTMPSockBuf_Fill(RTMPSockBuf *sb)
3554 int nBytes;
3556 if (!sb->sb_size)
3557 sb->sb_start = sb->sb_buf;
3559 while (1)
3561 nBytes = sizeof(sb->sb_buf) - sb->sb_size - (sb->sb_start - sb->sb_buf);
3562 #if defined(CRYPTO) && !defined(NO_SSL)
3563 if (sb->sb_ssl)
3565 nBytes = TLS_read(sb->sb_ssl, sb->sb_start + sb->sb_size, nBytes);
3567 else
3568 #endif
3570 nBytes = recv(sb->sb_socket, sb->sb_start + sb->sb_size, nBytes, 0);
3572 if (nBytes != -1)
3574 sb->sb_size += nBytes;
3576 else
3578 int sockerr = GetSockError();
3579 RTMP_Log(RTMP_LOGDEBUG, "%s, recv returned %d. GetSockError(): %d (%s)",
3580 __FUNCTION__, nBytes, sockerr, strerror(sockerr));
3581 if (sockerr == EINTR && !RTMP_ctrlC)
3582 continue;
3584 if (sockerr == EWOULDBLOCK || sockerr == EAGAIN)
3586 sb->sb_timedout = TRUE;
3587 nBytes = 0;
3590 break;
3593 return nBytes;
3597 RTMPSockBuf_Send(RTMPSockBuf *sb, const char *buf, int len)
3599 int rc;
3601 #ifdef _DEBUG
3602 fwrite(buf, 1, len, netstackdump);
3603 #endif
3605 #if defined(CRYPTO) && !defined(NO_SSL)
3606 if (sb->sb_ssl)
3608 rc = TLS_write(sb->sb_ssl, buf, len);
3610 else
3611 #endif
3613 rc = send(sb->sb_socket, buf, len, 0);
3615 return rc;
3619 RTMPSockBuf_Close(RTMPSockBuf *sb)
3621 #if defined(CRYPTO) && !defined(NO_SSL)
3622 if (sb->sb_ssl)
3624 TLS_shutdown(sb->sb_ssl);
3625 TLS_close(sb->sb_ssl);
3626 sb->sb_ssl = NULL;
3628 #endif
3629 if (sb->sb_socket != -1)
3630 return closesocket(sb->sb_socket);
3631 return 0;
3634 #define HEX2BIN(a) (((a)&0x40)?((a)&0xf)+9:((a)&0xf))
3636 static void
3637 DecodeTEA(AVal *key, AVal *text)
3639 uint32_t *v, k[4] = { 0 }, u;
3640 uint32_t z, y, sum = 0, e, DELTA = 0x9e3779b9;
3641 int32_t p, q;
3642 int i, n;
3643 unsigned char *ptr, *out;
3645 /* prep key: pack 1st 16 chars into 4 LittleEndian ints */
3646 ptr = (unsigned char *)key->av_val;
3647 u = 0;
3648 n = 0;
3649 v = k;
3650 p = key->av_len > 16 ? 16 : key->av_len;
3651 for (i = 0; i < p; i++)
3653 u |= ptr[i] << (n * 8);
3654 if (n == 3)
3656 *v++ = u;
3657 u = 0;
3658 n = 0;
3660 else
3662 n++;
3665 /* any trailing chars */
3666 if (u)
3667 *v = u;
3669 /* prep text: hex2bin, multiples of 4 */
3670 n = (text->av_len + 7) / 8;
3671 out = malloc(n * 8);
3672 ptr = (unsigned char *)text->av_val;
3673 v = (uint32_t *) out;
3674 for (i = 0; i < n; i++)
3676 u = (HEX2BIN(ptr[0]) << 4) + HEX2BIN(ptr[1]);
3677 u |= ((HEX2BIN(ptr[2]) << 4) + HEX2BIN(ptr[3])) << 8;
3678 u |= ((HEX2BIN(ptr[4]) << 4) + HEX2BIN(ptr[5])) << 16;
3679 u |= ((HEX2BIN(ptr[6]) << 4) + HEX2BIN(ptr[7])) << 24;
3680 *v++ = u;
3681 ptr += 8;
3683 v = (uint32_t *) out;
3685 /* http://www.movable-type.co.uk/scripts/tea-block.html */
3686 #define MX (((z>>5)^(y<<2)) + ((y>>3)^(z<<4))) ^ ((sum^y) + (k[(p&3)^e]^z));
3687 z = v[n - 1];
3688 y = v[0];
3689 q = 6 + 52 / n;
3690 sum = q * DELTA;
3691 while (sum != 0)
3693 e = sum >> 2 & 3;
3694 for (p = n - 1; p > 0; p--)
3695 z = v[p - 1], y = v[p] -= MX;
3696 z = v[n - 1];
3697 y = v[0] -= MX;
3698 sum -= DELTA;
3701 text->av_len /= 2;
3702 memcpy(text->av_val, out, text->av_len);
3703 free(out);
3706 static int
3707 HTTP_Post(RTMP *r, RTMPTCmd cmd, const char *buf, int len)
3709 char hbuf[512];
3710 int hlen = snprintf(hbuf, sizeof(hbuf), "POST /%s%s/%d HTTP/1.1\r\n"
3711 "Host: %.*s:%d\r\n"
3712 "Accept: */*\r\n"
3713 "User-Agent: Shockwave Flash\n"
3714 "Connection: Keep-Alive\n"
3715 "Cache-Control: no-cache\r\n"
3716 "Content-type: application/x-fcs\r\n"
3717 "Content-length: %d\r\n\r\n", RTMPT_cmds[cmd],
3718 r->m_clientID.av_val ? r->m_clientID.av_val : "",
3719 r->m_msgCounter, r->Link.hostname.av_len, r->Link.hostname.av_val,
3720 r->Link.port, len);
3721 RTMPSockBuf_Send(&r->m_sb, hbuf, hlen);
3722 hlen = RTMPSockBuf_Send(&r->m_sb, buf, len);
3723 r->m_msgCounter++;
3724 r->m_unackd++;
3725 return hlen;
3728 static int
3729 HTTP_read(RTMP *r, int fill)
3731 char *ptr;
3732 int hlen;
3734 if (fill)
3735 RTMPSockBuf_Fill(&r->m_sb);
3736 if (r->m_sb.sb_size < 144)
3737 return -2;
3738 if (strncmp(r->m_sb.sb_start, "HTTP/1.1 200 ", 13))
3739 return -1;
3740 ptr = r->m_sb.sb_start + sizeof("HTTP/1.1 200");
3741 while ((ptr = strstr(ptr, "Content-"))) {
3742 if (!strncasecmp(ptr+8, "length:", 7)) break;
3743 ptr += 8;
3745 if (!ptr)
3746 return -1;
3747 hlen = atoi(ptr+16);
3748 ptr = strstr(ptr+16, "\r\n\r\n");
3749 if (!ptr)
3750 return -1;
3751 ptr += 4;
3752 r->m_sb.sb_size -= ptr - r->m_sb.sb_start;
3753 r->m_sb.sb_start = ptr;
3754 r->m_unackd--;
3756 if (!r->m_clientID.av_val)
3758 r->m_clientID.av_len = hlen;
3759 r->m_clientID.av_val = malloc(hlen+1);
3760 if (!r->m_clientID.av_val)
3761 return -1;
3762 r->m_clientID.av_val[0] = '/';
3763 memcpy(r->m_clientID.av_val+1, ptr, hlen-1);
3764 r->m_clientID.av_val[hlen] = 0;
3765 r->m_sb.sb_size = 0;
3767 else
3769 r->m_polling = *ptr++;
3770 r->m_resplen = hlen - 1;
3771 r->m_sb.sb_start++;
3772 r->m_sb.sb_size--;
3774 return 0;
3777 #define MAX_IGNORED_FRAMES 50
3779 /* Read from the stream until we get a media packet.
3780 * Returns -3 if Play.Close/Stop, -2 if fatal error, -1 if no more media
3781 * packets, 0 if ignorable error, >0 if there is a media packet
3783 static int
3784 Read_1_Packet(RTMP *r, char *buf, unsigned int buflen)
3786 uint32_t prevTagSize = 0;
3787 int rtnGetNextMediaPacket = 0, ret = RTMP_READ_EOF;
3788 RTMPPacket packet = { 0 };
3789 int recopy = FALSE;
3790 unsigned int size;
3791 char *ptr, *pend;
3792 uint32_t nTimeStamp = 0;
3793 unsigned int len;
3795 rtnGetNextMediaPacket = RTMP_GetNextMediaPacket(r, &packet);
3796 while (rtnGetNextMediaPacket)
3798 char *packetBody = packet.m_body;
3799 unsigned int nPacketLen = packet.m_nBodySize;
3801 /* Return RTMP_READ_COMPLETE if this was completed nicely with
3802 * invoke message Play.Stop or Play.Complete
3804 if (rtnGetNextMediaPacket == 2)
3806 RTMP_Log(RTMP_LOGDEBUG,
3807 "Got Play.Complete or Play.Stop from server. "
3808 "Assuming stream is complete");
3809 ret = RTMP_READ_COMPLETE;
3810 break;
3813 r->m_read.dataType |= (((packet.m_packetType == RTMP_PACKET_TYPE_AUDIO) << 2) |
3814 (packet.m_packetType == RTMP_PACKET_TYPE_VIDEO));
3816 if (packet.m_packetType == RTMP_PACKET_TYPE_VIDEO && nPacketLen <= 5)
3818 RTMP_Log(RTMP_LOGDEBUG, "ignoring too small video packet: size: %d",
3819 nPacketLen);
3820 ret = RTMP_READ_IGNORE;
3821 break;
3823 if (packet.m_packetType == RTMP_PACKET_TYPE_AUDIO && nPacketLen <= 1)
3825 RTMP_Log(RTMP_LOGDEBUG, "ignoring too small audio packet: size: %d",
3826 nPacketLen);
3827 ret = RTMP_READ_IGNORE;
3828 break;
3831 if (r->m_read.flags & RTMP_READ_SEEKING)
3833 ret = RTMP_READ_IGNORE;
3834 break;
3836 #ifdef _DEBUG
3837 RTMP_Log(RTMP_LOGDEBUG, "type: %02X, size: %d, TS: %d ms, abs TS: %d",
3838 packet.m_packetType, nPacketLen, packet.m_nTimeStamp,
3839 packet.m_hasAbsTimestamp);
3840 if (packet.m_packetType == RTMP_PACKET_TYPE_VIDEO)
3841 RTMP_Log(RTMP_LOGDEBUG, "frametype: %02X", (*packetBody & 0xf0));
3842 #endif
3844 if (r->m_read.flags & RTMP_READ_RESUME)
3846 /* check the header if we get one */
3847 if (packet.m_nTimeStamp == 0)
3849 if (r->m_read.nMetaHeaderSize > 0
3850 && packet.m_packetType == RTMP_PACKET_TYPE_INFO)
3852 AMFObject metaObj;
3853 int nRes =
3854 AMF_Decode(&metaObj, packetBody, nPacketLen, FALSE);
3855 if (nRes >= 0)
3857 AVal metastring;
3858 AMFProp_GetString(AMF_GetProp(&metaObj, NULL, 0),
3859 &metastring);
3861 if (AVMATCH(&metastring, &av_onMetaData))
3863 /* compare */
3864 if ((r->m_read.nMetaHeaderSize != nPacketLen) ||
3865 (memcmp
3866 (r->m_read.metaHeader, packetBody,
3867 r->m_read.nMetaHeaderSize) != 0))
3869 ret = RTMP_READ_ERROR;
3872 AMF_Reset(&metaObj);
3873 if (ret == RTMP_READ_ERROR)
3874 break;
3878 /* check first keyframe to make sure we got the right position
3879 * in the stream! (the first non ignored frame)
3881 if (r->m_read.nInitialFrameSize > 0)
3883 /* video or audio data */
3884 if (packet.m_packetType == r->m_read.initialFrameType
3885 && r->m_read.nInitialFrameSize == nPacketLen)
3887 /* we don't compare the sizes since the packet can
3888 * contain several FLV packets, just make sure the
3889 * first frame is our keyframe (which we are going
3890 * to rewrite)
3892 if (memcmp
3893 (r->m_read.initialFrame, packetBody,
3894 r->m_read.nInitialFrameSize) == 0)
3896 RTMP_Log(RTMP_LOGDEBUG, "Checked keyframe successfully!");
3897 r->m_read.flags |= RTMP_READ_GOTKF;
3898 /* ignore it! (what about audio data after it? it is
3899 * handled by ignoring all 0ms frames, see below)
3901 ret = RTMP_READ_IGNORE;
3902 break;
3906 /* hande FLV streams, even though the server resends the
3907 * keyframe as an extra video packet it is also included
3908 * in the first FLV stream chunk and we have to compare
3909 * it and filter it out !!
3911 if (packet.m_packetType == RTMP_PACKET_TYPE_FLASH_VIDEO)
3913 /* basically we have to find the keyframe with the
3914 * correct TS being nResumeTS
3916 unsigned int pos = 0;
3917 uint32_t ts = 0;
3919 while (pos + 11 < nPacketLen)
3921 /* size without header (11) and prevTagSize (4) */
3922 uint32_t dataSize =
3923 AMF_DecodeInt24(packetBody + pos + 1);
3924 ts = AMF_DecodeInt24(packetBody + pos + 4);
3925 ts |= (packetBody[pos + 7] << 24);
3927 #ifdef _DEBUG
3928 RTMP_Log(RTMP_LOGDEBUG,
3929 "keyframe search: FLV Packet: type %02X, dataSize: %d, timeStamp: %d ms",
3930 packetBody[pos], dataSize, ts);
3931 #endif
3932 /* ok, is it a keyframe?:
3933 * well doesn't work for audio!
3935 if (packetBody[pos /*6928, test 0 */ ] ==
3936 r->m_read.initialFrameType
3937 /* && (packetBody[11]&0xf0) == 0x10 */ )
3939 if (ts == r->m_read.nResumeTS)
3941 RTMP_Log(RTMP_LOGDEBUG,
3942 "Found keyframe with resume-keyframe timestamp!");
3943 if (r->m_read.nInitialFrameSize != dataSize
3944 || memcmp(r->m_read.initialFrame,
3945 packetBody + pos + 11,
3946 r->m_read.
3947 nInitialFrameSize) != 0)
3949 RTMP_Log(RTMP_LOGERROR,
3950 "FLV Stream: Keyframe doesn't match!");
3951 ret = RTMP_READ_ERROR;
3952 break;
3954 r->m_read.flags |= RTMP_READ_GOTFLVK;
3956 /* skip this packet?
3957 * check whether skippable:
3959 if (pos + 11 + dataSize + 4 > nPacketLen)
3961 RTMP_Log(RTMP_LOGWARNING,
3962 "Non skipable packet since it doesn't end with chunk, stream corrupt!");
3963 ret = RTMP_READ_ERROR;
3964 break;
3966 packetBody += (pos + 11 + dataSize + 4);
3967 nPacketLen -= (pos + 11 + dataSize + 4);
3969 goto stopKeyframeSearch;
3972 else if (r->m_read.nResumeTS < ts)
3974 /* the timestamp ts will only increase with
3975 * further packets, wait for seek
3977 goto stopKeyframeSearch;
3980 pos += (11 + dataSize + 4);
3982 if (ts < r->m_read.nResumeTS)
3984 RTMP_Log(RTMP_LOGERROR,
3985 "First packet does not contain keyframe, all "
3986 "timestamps are smaller than the keyframe "
3987 "timestamp; probably the resume seek failed?");
3989 stopKeyframeSearch:
3991 if (!(r->m_read.flags & RTMP_READ_GOTFLVK))
3993 RTMP_Log(RTMP_LOGERROR,
3994 "Couldn't find the seeked keyframe in this chunk!");
3995 ret = RTMP_READ_IGNORE;
3996 break;
4002 if (packet.m_nTimeStamp > 0
4003 && (r->m_read.flags & (RTMP_READ_GOTKF|RTMP_READ_GOTFLVK)))
4005 /* another problem is that the server can actually change from
4006 * 09/08 video/audio packets to an FLV stream or vice versa and
4007 * our keyframe check will prevent us from going along with the
4008 * new stream if we resumed.
4010 * in this case set the 'found keyframe' variables to true.
4011 * We assume that if we found one keyframe somewhere and were
4012 * already beyond TS > 0 we have written data to the output
4013 * which means we can accept all forthcoming data including the
4014 * change between 08/09 <-> FLV packets
4016 r->m_read.flags |= (RTMP_READ_GOTKF|RTMP_READ_GOTFLVK);
4019 /* skip till we find our keyframe
4020 * (seeking might put us somewhere before it)
4022 if (!(r->m_read.flags & RTMP_READ_GOTKF) &&
4023 packet.m_packetType != RTMP_PACKET_TYPE_FLASH_VIDEO)
4025 RTMP_Log(RTMP_LOGWARNING,
4026 "Stream does not start with requested frame, ignoring data... ");
4027 r->m_read.nIgnoredFrameCounter++;
4028 if (r->m_read.nIgnoredFrameCounter > MAX_IGNORED_FRAMES)
4029 ret = RTMP_READ_ERROR; /* fatal error, couldn't continue stream */
4030 else
4031 ret = RTMP_READ_IGNORE;
4032 break;
4034 /* ok, do the same for FLV streams */
4035 if (!(r->m_read.flags & RTMP_READ_GOTFLVK) &&
4036 packet.m_packetType == RTMP_PACKET_TYPE_FLASH_VIDEO)
4038 RTMP_Log(RTMP_LOGWARNING,
4039 "Stream does not start with requested FLV frame, ignoring data... ");
4040 r->m_read.nIgnoredFlvFrameCounter++;
4041 if (r->m_read.nIgnoredFlvFrameCounter > MAX_IGNORED_FRAMES)
4042 ret = RTMP_READ_ERROR;
4043 else
4044 ret = RTMP_READ_IGNORE;
4045 break;
4048 /* we have to ignore the 0ms frames since these are the first
4049 * keyframes; we've got these so don't mess around with multiple
4050 * copies sent by the server to us! (if the keyframe is found at a
4051 * later position there is only one copy and it will be ignored by
4052 * the preceding if clause)
4054 if (!(r->m_read.flags & RTMP_READ_NO_IGNORE) &&
4055 packet.m_packetType != RTMP_PACKET_TYPE_FLASH_VIDEO)
4057 /* exclude type RTMP_PACKET_TYPE_FLASH_VIDEO since it can
4058 * contain several FLV packets
4060 if (packet.m_nTimeStamp == 0)
4062 ret = RTMP_READ_IGNORE;
4063 break;
4065 else
4067 /* stop ignoring packets */
4068 r->m_read.flags |= RTMP_READ_NO_IGNORE;
4073 /* calculate packet size and allocate slop buffer if necessary */
4074 size = nPacketLen +
4075 ((packet.m_packetType == RTMP_PACKET_TYPE_AUDIO
4076 || packet.m_packetType == RTMP_PACKET_TYPE_VIDEO
4077 || packet.m_packetType == RTMP_PACKET_TYPE_INFO) ? 11 : 0) +
4078 (packet.m_packetType != RTMP_PACKET_TYPE_FLASH_VIDEO ? 4 : 0);
4080 if (size + 4 > buflen)
4082 /* the extra 4 is for the case of an FLV stream without a last
4083 * prevTagSize (we need extra 4 bytes to append it) */
4084 r->m_read.buf = malloc(size + 4);
4085 if (r->m_read.buf == 0)
4087 RTMP_Log(RTMP_LOGERROR, "Couldn't allocate memory!");
4088 ret = RTMP_READ_ERROR; /* fatal error */
4089 break;
4091 recopy = TRUE;
4092 ptr = r->m_read.buf;
4094 else
4096 ptr = buf;
4098 pend = ptr + size + 4;
4100 /* use to return timestamp of last processed packet */
4102 /* audio (0x08), video (0x09) or metadata (0x12) packets :
4103 * construct 11 byte header then add rtmp packet's data */
4104 if (packet.m_packetType == RTMP_PACKET_TYPE_AUDIO
4105 || packet.m_packetType == RTMP_PACKET_TYPE_VIDEO
4106 || packet.m_packetType == RTMP_PACKET_TYPE_INFO)
4108 nTimeStamp = r->m_read.nResumeTS + packet.m_nTimeStamp;
4109 prevTagSize = 11 + nPacketLen;
4111 *ptr = packet.m_packetType;
4112 ptr++;
4113 ptr = AMF_EncodeInt24(ptr, pend, nPacketLen);
4115 #if 0
4116 if(packet.m_packetType == RTMP_PACKET_TYPE_VIDEO) {
4118 /* H264 fix: */
4119 if((packetBody[0] & 0x0f) == 7) { /* CodecId = H264 */
4120 uint8_t packetType = *(packetBody+1);
4122 uint32_t ts = AMF_DecodeInt24(packetBody+2); /* composition time */
4123 int32_t cts = (ts+0xff800000)^0xff800000;
4124 RTMP_Log(RTMP_LOGDEBUG, "cts : %d\n", cts);
4126 nTimeStamp -= cts;
4127 /* get rid of the composition time */
4128 CRTMP::EncodeInt24(packetBody+2, 0);
4130 RTMP_Log(RTMP_LOGDEBUG, "VIDEO: nTimeStamp: 0x%08X (%d)\n", nTimeStamp, nTimeStamp);
4132 #endif
4134 ptr = AMF_EncodeInt24(ptr, pend, nTimeStamp);
4135 *ptr = (char)((nTimeStamp & 0xFF000000) >> 24);
4136 ptr++;
4138 /* stream id */
4139 ptr = AMF_EncodeInt24(ptr, pend, 0);
4142 memcpy(ptr, packetBody, nPacketLen);
4143 len = nPacketLen;
4145 /* correct tagSize and obtain timestamp if we have an FLV stream */
4146 if (packet.m_packetType == RTMP_PACKET_TYPE_FLASH_VIDEO)
4148 unsigned int pos = 0;
4149 int delta;
4151 /* grab first timestamp and see if it needs fixing */
4152 nTimeStamp = AMF_DecodeInt24(packetBody + 4);
4153 nTimeStamp |= (packetBody[7] << 24);
4154 delta = packet.m_nTimeStamp - nTimeStamp + r->m_read.nResumeTS;
4156 while (pos + 11 < nPacketLen)
4158 /* size without header (11) and without prevTagSize (4) */
4159 uint32_t dataSize = AMF_DecodeInt24(packetBody + pos + 1);
4160 nTimeStamp = AMF_DecodeInt24(packetBody + pos + 4);
4161 nTimeStamp |= (packetBody[pos + 7] << 24);
4163 if (delta)
4165 nTimeStamp += delta;
4166 AMF_EncodeInt24(ptr+pos+4, pend, nTimeStamp);
4167 ptr[pos+7] = nTimeStamp>>24;
4170 /* set data type */
4171 r->m_read.dataType |= (((*(packetBody + pos) == 0x08) << 2) |
4172 (*(packetBody + pos) == 0x09));
4174 if (pos + 11 + dataSize + 4 > nPacketLen)
4176 if (pos + 11 + dataSize > nPacketLen)
4178 RTMP_Log(RTMP_LOGERROR,
4179 "Wrong data size (%lu), stream corrupted, aborting!",
4180 dataSize);
4181 ret = RTMP_READ_ERROR;
4182 break;
4184 RTMP_Log(RTMP_LOGWARNING, "No tagSize found, appending!");
4186 /* we have to append a last tagSize! */
4187 prevTagSize = dataSize + 11;
4188 AMF_EncodeInt32(ptr + pos + 11 + dataSize, pend,
4189 prevTagSize);
4190 size += 4;
4191 len += 4;
4193 else
4195 prevTagSize =
4196 AMF_DecodeInt32(packetBody + pos + 11 + dataSize);
4198 #ifdef _DEBUG
4199 RTMP_Log(RTMP_LOGDEBUG,
4200 "FLV Packet: type %02X, dataSize: %lu, tagSize: %lu, timeStamp: %lu ms",
4201 (unsigned char)packetBody[pos], dataSize, prevTagSize,
4202 nTimeStamp);
4203 #endif
4205 if (prevTagSize != (dataSize + 11))
4207 #ifdef _DEBUG
4208 RTMP_Log(RTMP_LOGWARNING,
4209 "Tag and data size are not consitent, writing tag size according to dataSize+11: %d",
4210 dataSize + 11);
4211 #endif
4213 prevTagSize = dataSize + 11;
4214 AMF_EncodeInt32(ptr + pos + 11 + dataSize, pend,
4215 prevTagSize);
4219 pos += prevTagSize + 4; /*(11+dataSize+4); */
4222 ptr += len;
4224 if (packet.m_packetType != RTMP_PACKET_TYPE_FLASH_VIDEO)
4226 /* FLV tag packets contain their own prevTagSize */
4227 AMF_EncodeInt32(ptr, pend, prevTagSize);
4230 /* In non-live this nTimeStamp can contain an absolute TS.
4231 * Update ext timestamp with this absolute offset in non-live mode
4232 * otherwise report the relative one
4234 /* RTMP_Log(RTMP_LOGDEBUG, "type: %02X, size: %d, pktTS: %dms, TS: %dms, bLiveStream: %d", packet.m_packetType, nPacketLen, packet.m_nTimeStamp, nTimeStamp, r->Link.lFlags & RTMP_LF_LIVE); */
4235 r->m_read.timestamp = (r->Link.lFlags & RTMP_LF_LIVE) ? packet.m_nTimeStamp : nTimeStamp;
4237 ret = size;
4238 break;
4241 if (rtnGetNextMediaPacket)
4242 RTMPPacket_Free(&packet);
4244 if (recopy)
4246 len = ret > buflen ? buflen : ret;
4247 memcpy(buf, r->m_read.buf, len);
4248 r->m_read.bufpos = r->m_read.buf + len;
4249 r->m_read.buflen = ret - len;
4251 return ret;
4254 static const char flvHeader[] = { 'F', 'L', 'V', 0x01,
4255 0x00, /* 0x04 == audio, 0x01 == video */
4256 0x00, 0x00, 0x00, 0x09,
4257 0x00, 0x00, 0x00, 0x00
4260 #define HEADERBUF (128*1024)
4262 RTMP_Read(RTMP *r, char *buf, int size)
4264 int nRead = 0, total = 0;
4266 /* can't continue */
4267 fail:
4268 switch (r->m_read.status) {
4269 case RTMP_READ_EOF:
4270 case RTMP_READ_COMPLETE:
4271 return 0;
4272 case RTMP_READ_ERROR: /* corrupted stream, resume failed */
4273 SetSockError(EINVAL);
4274 return -1;
4275 default:
4276 break;
4279 /* first time thru */
4280 if (!(r->m_read.flags & RTMP_READ_HEADER))
4282 if (!(r->m_read.flags & RTMP_READ_RESUME))
4284 char *mybuf = malloc(HEADERBUF), *end = mybuf + HEADERBUF;
4285 int cnt = 0;
4286 r->m_read.buf = mybuf;
4287 r->m_read.buflen = HEADERBUF;
4289 memcpy(mybuf, flvHeader, sizeof(flvHeader));
4290 r->m_read.buf += sizeof(flvHeader);
4291 r->m_read.buflen -= sizeof(flvHeader);
4293 while (r->m_read.timestamp == 0)
4295 nRead = Read_1_Packet(r, r->m_read.buf, r->m_read.buflen);
4296 if (nRead < 0)
4298 free(mybuf);
4299 r->m_read.buf = NULL;
4300 r->m_read.buflen = 0;
4301 r->m_read.status = nRead;
4302 goto fail;
4304 /* buffer overflow, fix buffer and give up */
4305 if (r->m_read.buf < mybuf || r->m_read.buf > end) {
4306 mybuf = realloc(mybuf, cnt + nRead);
4307 memcpy(mybuf+cnt, r->m_read.buf, nRead);
4308 r->m_read.buf = mybuf+cnt+nRead;
4309 break;
4311 cnt += nRead;
4312 r->m_read.buf += nRead;
4313 r->m_read.buflen -= nRead;
4314 if (r->m_read.dataType == 5)
4315 break;
4317 mybuf[4] = r->m_read.dataType;
4318 r->m_read.buflen = r->m_read.buf - mybuf;
4319 r->m_read.buf = mybuf;
4320 r->m_read.bufpos = mybuf;
4322 r->m_read.flags |= RTMP_READ_HEADER;
4325 if ((r->m_read.flags & RTMP_READ_SEEKING) && r->m_read.buf)
4327 /* drop whatever's here */
4328 free(r->m_read.buf);
4329 r->m_read.buf = NULL;
4330 r->m_read.bufpos = NULL;
4331 r->m_read.buflen = 0;
4334 /* If there's leftover data buffered, use it up */
4335 if (r->m_read.buf)
4337 nRead = r->m_read.buflen;
4338 if (nRead > size)
4339 nRead = size;
4340 memcpy(buf, r->m_read.bufpos, nRead);
4341 r->m_read.buflen -= nRead;
4342 if (!r->m_read.buflen)
4344 free(r->m_read.buf);
4345 r->m_read.buf = NULL;
4346 r->m_read.bufpos = NULL;
4348 else
4350 r->m_read.bufpos += nRead;
4352 buf += nRead;
4353 total += nRead;
4354 size -= nRead;
4357 while (size > 0 && (nRead = Read_1_Packet(r, buf, size)) >= 0)
4359 if (!nRead) continue;
4360 buf += nRead;
4361 total += nRead;
4362 size -= nRead;
4363 break;
4365 if (nRead < 0)
4366 r->m_read.status = nRead;
4368 if (size < 0)
4369 total += size;
4370 return total;
4373 static const AVal av_setDataFrame = AVC("@setDataFrame");
4376 RTMP_Write(RTMP *r, const char *buf, int size)
4378 RTMPPacket *pkt = &r->m_write;
4379 char *pend, *enc;
4380 int s2 = size, ret, num;
4382 pkt->m_nChannel = 0x04; /* source channel */
4383 pkt->m_nInfoField2 = r->m_stream_id;
4385 while (s2)
4387 if (!pkt->m_nBytesRead)
4389 if (size < 11) {
4390 /* FLV pkt too small */
4391 return 0;
4394 if (buf[0] == 'F' && buf[1] == 'L' && buf[2] == 'V')
4396 buf += 13;
4397 s2 -= 13;
4400 pkt->m_packetType = *buf++;
4401 pkt->m_nBodySize = AMF_DecodeInt24(buf);
4402 buf += 3;
4403 pkt->m_nTimeStamp = AMF_DecodeInt24(buf);
4404 buf += 3;
4405 pkt->m_nTimeStamp |= *buf++ << 24;
4406 buf += 3;
4407 s2 -= 11;
4409 if (((pkt->m_packetType == RTMP_PACKET_TYPE_AUDIO
4410 || pkt->m_packetType == RTMP_PACKET_TYPE_VIDEO) &&
4411 !pkt->m_nTimeStamp) || pkt->m_packetType == RTMP_PACKET_TYPE_INFO)
4413 pkt->m_headerType = RTMP_PACKET_SIZE_LARGE;
4414 if (pkt->m_packetType == RTMP_PACKET_TYPE_INFO)
4415 pkt->m_nBodySize += 16;
4417 else
4419 pkt->m_headerType = RTMP_PACKET_SIZE_MEDIUM;
4422 if (!RTMPPacket_Alloc(pkt, pkt->m_nBodySize))
4424 RTMP_Log(RTMP_LOGDEBUG, "%s, failed to allocate packet", __FUNCTION__);
4425 return FALSE;
4427 enc = pkt->m_body;
4428 pend = enc + pkt->m_nBodySize;
4429 if (pkt->m_packetType == RTMP_PACKET_TYPE_INFO)
4431 enc = AMF_EncodeString(enc, pend, &av_setDataFrame);
4432 pkt->m_nBytesRead = enc - pkt->m_body;
4435 else
4437 enc = pkt->m_body + pkt->m_nBytesRead;
4439 num = pkt->m_nBodySize - pkt->m_nBytesRead;
4440 if (num > s2)
4441 num = s2;
4442 memcpy(enc, buf, num);
4443 pkt->m_nBytesRead += num;
4444 s2 -= num;
4445 buf += num;
4446 if (pkt->m_nBytesRead == pkt->m_nBodySize)
4448 ret = RTMP_SendPacket(r, pkt, FALSE);
4449 RTMPPacket_Free(pkt);
4450 pkt->m_nBytesRead = 0;
4451 if (!ret)
4452 return -1;
4453 buf += 4;
4454 s2 -= 4;
4455 if (s2 < 0)
4456 break;
4459 return size+s2;