You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

593 lines
18KB

  1. /* Adobe's Real Time Messaging Protocol
  2. 1. handshake (p10)
  3. C -> S: C0/C1
  4. S -> C: S0/S1/S2
  5. C -> S: C2
  6. 2. connect (p34)
  7. C -> S: connect
  8. S -> C: Window Acknowledgement Size
  9. S -> C: Set Peer Bandwidth
  10. C -> S: Window Acknowledgement Size
  11. S -> C: User Control Message (StreamBegin)
  12. S -> C: _result(connect response)
  13. 3. play (p41)
  14. C -> S: createStream
  15. S -> C: _result(createStream response)
  16. C -> S: play
  17. C -> S: SetBufferLength (optional)
  18. S -> C: SetChunkSize
  19. S -> C: User Control (StreamIsRecorded)
  20. S -> C: User Control (StreamBegin)
  21. S -> C: onStatus (play reset) (only play set reset flag)
  22. S -> C: onStatus (play start)
  23. S -> C: Audio
  24. S -> C: Video
  25. 4. publish (p49)
  26. C -> S: createStream
  27. S -> C: _result(createStream response)
  28. C -> S: publish
  29. S -> C: User Control (StreamBegin)
  30. C -> S: Metadata
  31. C -> S: Audio
  32. C -> S: SetChunkSize
  33. S -> C: onStatus(publish result)
  34. C -> S: Video
  35. */
  36. #include "rtmp-client.h"
  37. #include "rtmp-internal.h"
  38. #include "rtmp-msgtypeid.h"
  39. #include "rtmp-handshake.h"
  40. #include "rtmp-control-message.h"
  41. #include "rtmp-netconnection.h"
  42. #include "rtmp-netstream.h"
  43. #include "rtmp-event.h"
  44. #include <stdio.h>
  45. #include <stdlib.h>
  46. #include <string.h>
  47. #include <assert.h>
  48. #include <errno.h>
  49. #include <time.h>
  50. #define FLASHVER "LNX 9,0,124,2"
  51. #define RTMP_PUBLISH_CHUNK_SIZE 4000
  52. struct rtmp_client_t
  53. {
  54. struct rtmp_t rtmp;
  55. struct rtmp_connect_t connect;
  56. uint32_t stream_id; // createStream/deleteStream
  57. char stream_name[256]; // Play/Publishing stream name, flv:sample, mp3:sample, H.264/AAC: mp4:sample.m4v
  58. enum rtmp_state_t state;
  59. uint32_t recv_bytes[2]; // for rtmp_acknowledgement
  60. struct rtmp_client_handler_t handler;
  61. void* param;
  62. uint8_t payload[2*1024];
  63. //uint8_t handshake[RTMP_HANDSHAKE_SIZE + 1]; // only for handshake
  64. size_t handshake_bytes;
  65. int handshake_state; // RTMP_HANDSHAKE_XXX
  66. int publish; // 0-publish, 1-live/vod, 2-live only, 3-vod only
  67. };
  68. static int rtmp_client_send_control(struct rtmp_t* rtmp, const uint8_t* payload, uint32_t bytes, uint32_t stream_id)
  69. {
  70. struct rtmp_chunk_header_t header;
  71. header.fmt = RTMP_CHUNK_TYPE_0; // disable compact header
  72. header.cid = RTMP_CHANNEL_INVOKE;
  73. header.timestamp = 0;
  74. header.length = bytes;
  75. header.type = RTMP_TYPE_INVOKE;
  76. header.stream_id = stream_id; /* default 0 */
  77. return rtmp_chunk_write(rtmp, &header, payload);
  78. }
  79. // C2
  80. static int rtmp_client_send_c2(struct rtmp_client_t* ctx)
  81. {
  82. int r;
  83. rtmp_handshake_c2(ctx->payload, (uint32_t)time(NULL), ctx->payload, RTMP_HANDSHAKE_SIZE);
  84. r = ctx->handler.send(ctx->param, ctx->payload, RTMP_HANDSHAKE_SIZE, NULL, 0);
  85. return RTMP_HANDSHAKE_SIZE == r ? 0 : -1;
  86. }
  87. // Connect
  88. static int rtmp_client_send_connect(struct rtmp_client_t* ctx)
  89. {
  90. int r;
  91. r = (int)(rtmp_netconnection_connect(ctx->payload, sizeof(ctx->payload), RTMP_TRANSACTION_CONNECT, &ctx->connect) - ctx->payload);
  92. return rtmp_client_send_control(&ctx->rtmp, ctx->payload, r, 0);
  93. }
  94. // ReleaseStream
  95. static int rmtp_client_send_release_stream(struct rtmp_client_t* ctx)
  96. {
  97. int r;
  98. r = (int)(rtmp_netstream_release_stream(ctx->payload, sizeof(ctx->payload), 0, ctx->stream_name) - ctx->payload);
  99. return rtmp_client_send_control(&ctx->rtmp, ctx->payload, r, ctx->stream_id);
  100. }
  101. // FCPublish
  102. static int rtmp_client_send_fcpublish(struct rtmp_client_t* ctx)
  103. {
  104. int r;
  105. r = (int)(rtmp_netstream_fcpublish(ctx->payload, sizeof(ctx->payload), 0, ctx->stream_name) - ctx->payload);
  106. return rtmp_client_send_control(&ctx->rtmp, ctx->payload, r, 0);
  107. }
  108. // FCUnpublish
  109. static int rtmp_client_send_fcunpublish(struct rtmp_client_t* ctx)
  110. {
  111. int r;
  112. r = (int)(rtmp_netstream_fcunpublish(ctx->payload, sizeof(ctx->payload), 0, ctx->stream_name) - ctx->payload);
  113. return rtmp_client_send_control(&ctx->rtmp, ctx->payload, r, ctx->stream_id);
  114. }
  115. // createStream
  116. static int rtmp_client_send_create_stream(struct rtmp_client_t* ctx)
  117. {
  118. int r;
  119. assert(0 == ctx->stream_id);
  120. r = (int)(rtmp_netconnection_create_stream(ctx->payload, sizeof(ctx->payload), RTMP_TRANSACTION_CREATE_STREAM) - ctx->payload);
  121. return rtmp_client_send_control(&ctx->rtmp, ctx->payload, r, 0);
  122. }
  123. // deleteStream
  124. static int rtmp_client_send_delete_stream(struct rtmp_client_t* ctx)
  125. {
  126. int r;
  127. assert(0 != ctx->stream_id);
  128. r = (int)(rtmp_netstream_delete_stream(ctx->payload, sizeof(ctx->payload), 0, ctx->stream_id) - ctx->payload);
  129. return rtmp_client_send_control(&ctx->rtmp, ctx->payload, r, ctx->stream_id);
  130. }
  131. // publish
  132. static int rtmp_client_send_publish(struct rtmp_client_t* ctx)
  133. {
  134. int r;
  135. assert(0 != ctx->stream_id);
  136. r = (int)(rtmp_netstream_publish(ctx->payload, sizeof(ctx->payload), 0, ctx->stream_name, RTMP_STREAM_LIVE) - ctx->payload);
  137. return rtmp_client_send_control(&ctx->rtmp, ctx->payload, r, ctx->stream_id);
  138. }
  139. // play
  140. static int rtmp_client_send_play(struct rtmp_client_t* ctx)
  141. {
  142. int r;
  143. assert(0 != ctx->stream_id);
  144. r = (int)(rtmp_netstream_play(ctx->payload, sizeof(ctx->payload), 0, ctx->stream_name, -2, -1, 1) - ctx->payload);
  145. // rtmp_client_chunk_header_default(&header, RTMP_CHANNEL_CONTROL, (uint32_t)time(NULL), r, RTMP_TYPE_INVOKE, ctx->stream_id);
  146. return rtmp_client_send_control(&ctx->rtmp, ctx->payload, r, ctx->stream_id);
  147. }
  148. /// 5.4.1. Set Chunk Size (1)
  149. static int rtmp_client_send_set_chunk_size(struct rtmp_client_t* ctx, size_t size)
  150. {
  151. int n, r;
  152. assert(0 == ctx->publish);
  153. n = rtmp_set_chunk_size(ctx->payload, sizeof(ctx->payload), (uint32_t)size);
  154. r = ctx->handler.send(ctx->param, ctx->payload, n, NULL, 0);
  155. return n == r ? 0 : r;
  156. }
  157. /// 5.4.3. Acknowledgement (3)
  158. static int rtmp_client_send_acknowledgement(struct rtmp_client_t* ctx, size_t size)
  159. {
  160. int n, r;
  161. ctx->recv_bytes[0] += (uint32_t)size;
  162. if (ctx->rtmp.window_size && ctx->recv_bytes[0] - ctx->recv_bytes[1] > ctx->rtmp.window_size)
  163. {
  164. n = rtmp_acknowledgement(ctx->payload, sizeof(ctx->payload), ctx->recv_bytes[0]);
  165. r = ctx->handler.send(ctx->param, ctx->payload, n, NULL, 0);
  166. ctx->recv_bytes[1] = ctx->recv_bytes[0];
  167. return n == r ? 0 : r;
  168. }
  169. return 0;
  170. }
  171. // Window Acknowledgement Size (5)
  172. static int rtmp_client_send_server_bandwidth(struct rtmp_client_t* ctx)
  173. {
  174. int n, r;
  175. n = rtmp_window_acknowledgement_size(ctx->payload, sizeof(ctx->payload), ctx->rtmp.window_size);
  176. r = ctx->handler.send(ctx->param, ctx->payload, n, NULL, 0);
  177. return n == r ? 0 : r;
  178. }
  179. static int rtmp_client_send_set_buffer_length(struct rtmp_client_t* ctx)
  180. {
  181. int n, r;
  182. n = rtmp_event_set_buffer_length(ctx->payload, sizeof(ctx->payload), ctx->stream_id, ctx->rtmp.buffer_length_ms);
  183. r = ctx->handler.send(ctx->param, ctx->payload, n, NULL, 0);
  184. return n == r ? 0 : r;
  185. }
  186. static int rtmp_client_send_get_stream_length(struct rtmp_client_t* ctx)
  187. {
  188. int r;
  189. r = (int)(rtmp_netconnection_get_stream_length(ctx->payload, sizeof(ctx->payload), RTMP_TRANSACTION_GET_STREAM_LENGTH, ctx->stream_name) - ctx->payload);
  190. return rtmp_client_send_control(&ctx->rtmp, ctx->payload, r, ctx->stream_id);
  191. }
  192. static int rtmp_client_onconnect(void* param)
  193. {
  194. int r = 0;
  195. struct rtmp_client_t* ctx;
  196. ctx = (struct rtmp_client_t*)param;
  197. ctx->state = RTMP_STATE_CONNECTED;
  198. if (0 == ctx->publish)
  199. {
  200. // publish only
  201. r = rmtp_client_send_release_stream(ctx);
  202. r = 0 == r ? rtmp_client_send_fcpublish(ctx) : r;
  203. }
  204. else
  205. {
  206. // send by rtmp_client_onbandwidth
  207. //r = rtmp_client_send_server_bandwidth(ctx);
  208. }
  209. return 0 == r ? rtmp_client_send_create_stream(ctx) : r;
  210. }
  211. static int rtmp_client_oncreate_stream(void* param, double stream_id)
  212. {
  213. int r = 0;
  214. struct rtmp_client_t* ctx;
  215. ctx = (struct rtmp_client_t*)param;
  216. ctx->state = RTMP_STATE_CREATE_STREAM;
  217. ctx->stream_id = (uint32_t)stream_id;
  218. if (0 == ctx->publish)
  219. {
  220. r = rtmp_client_send_publish(ctx);
  221. r = 0 == r ? rtmp_client_send_set_chunk_size(ctx, RTMP_PUBLISH_CHUNK_SIZE) : r;
  222. if (0 == r) ctx->rtmp.out_chunk_size = RTMP_PUBLISH_CHUNK_SIZE; // update output chunk size
  223. }
  224. else
  225. {
  226. if (3 == ctx->publish)
  227. r = rtmp_client_send_get_stream_length(ctx);
  228. r = 0 == r ? rtmp_client_send_play(ctx) : r;
  229. r = 0 == r ? rtmp_client_send_set_buffer_length(ctx) : r;
  230. }
  231. return r;
  232. }
  233. static int rtmp_client_onnotify(void* param, enum rtmp_notify_t notify)
  234. {
  235. struct rtmp_client_t* ctx;
  236. ctx = (struct rtmp_client_t*)param;
  237. switch (notify)
  238. {
  239. case RTMP_NOTIFY_START:
  240. ctx->state = RTMP_STATE_START;
  241. break;
  242. case RTMP_NOTIFY_STOP:
  243. ctx->state = RTMP_STATE_STOP;
  244. break;
  245. case RTMP_NOTIFY_PAUSE:
  246. case RTMP_NOTIFY_SEEK:
  247. default:
  248. break;
  249. }
  250. return 0;
  251. }
  252. static int rtmp_client_oneof(void* param, uint32_t streamId)
  253. {
  254. (void)streamId;
  255. return rtmp_client_onnotify(param, RTMP_NOTIFY_STOP);
  256. }
  257. static int rtmp_client_onping(void* param, uint32_t seqNo)
  258. {
  259. int n, r;
  260. struct rtmp_client_t* ctx;
  261. ctx = (struct rtmp_client_t*)param;
  262. n = rtmp_event_pong(ctx->payload, sizeof(ctx->payload), seqNo);
  263. r = ctx->handler.send(ctx->param, ctx->payload, n, NULL, 0);
  264. return n == r ? 0 : r;
  265. }
  266. static int rtmp_client_onbandwidth(void* param)
  267. {
  268. struct rtmp_client_t* ctx;
  269. ctx = (struct rtmp_client_t*)param;
  270. return rtmp_client_send_server_bandwidth(ctx);
  271. }
  272. static void rtmp_client_onabort(void* param, uint32_t chunk_stream_id)
  273. {
  274. struct rtmp_client_t* ctx;
  275. ctx = (struct rtmp_client_t*)param;
  276. (void)ctx, (void)chunk_stream_id;
  277. }
  278. static int rtmp_client_onaudio(void* param, const uint8_t* data, size_t bytes, uint32_t timestamp)
  279. {
  280. struct rtmp_client_t* ctx;
  281. ctx = (struct rtmp_client_t*)param;
  282. return ctx->handler.onaudio(ctx->param, data, bytes, timestamp);
  283. }
  284. static int rtmp_client_onvideo(void* param, const uint8_t* data, size_t bytes, uint32_t timestamp)
  285. {
  286. struct rtmp_client_t* ctx;
  287. ctx = (struct rtmp_client_t*)param;
  288. return ctx->handler.onvideo(ctx->param, data, bytes, timestamp);
  289. }
  290. static int rtmp_client_onscript(void* param, const uint8_t* data, size_t bytes, uint32_t timestamp)
  291. {
  292. struct rtmp_client_t* ctx;
  293. ctx = (struct rtmp_client_t*)param;
  294. return ctx->handler.onscript(ctx->param, data, bytes, timestamp);
  295. }
  296. static int rtmp_client_send(void* param, const uint8_t* header, uint32_t headerBytes, const uint8_t* payload, uint32_t payloadBytes)
  297. {
  298. int r;
  299. struct rtmp_client_t* ctx;
  300. ctx = (struct rtmp_client_t*)param;
  301. r = ctx->handler.send(ctx->param, header, headerBytes, payload, payloadBytes);
  302. return (r == (int)(payloadBytes + headerBytes)) ? 0 : -1;
  303. }
  304. struct rtmp_client_t* rtmp_client_create(const char* appname, const char* playpath, const char* tcurl, void* param, const struct rtmp_client_handler_t* handler)
  305. {
  306. struct rtmp_client_t* ctx;
  307. assert(appname && *appname && playpath && *playpath && handler);
  308. ctx = (struct rtmp_client_t*)calloc(1, sizeof(struct rtmp_client_t));
  309. if (!ctx) return NULL;
  310. memcpy(&ctx->handler, handler, sizeof(ctx->handler));
  311. snprintf(ctx->stream_name, sizeof(ctx->stream_name) - 1, "%s", playpath);
  312. ctx->stream_id = 0;
  313. ctx->param = param;
  314. ctx->state = RTMP_STATE_UNINIT;
  315. ctx->rtmp.parser.state = RTMP_PARSE_INIT;
  316. ctx->rtmp.in_chunk_size = RTMP_CHUNK_SIZE;
  317. ctx->rtmp.out_chunk_size = RTMP_CHUNK_SIZE;
  318. ctx->rtmp.window_size = 2500000;
  319. ctx->rtmp.peer_bandwidth = 2500000;
  320. ctx->rtmp.buffer_length_ms = 30000;
  321. ctx->rtmp.param = ctx;
  322. ctx->rtmp.send = rtmp_client_send;
  323. ctx->rtmp.onaudio = rtmp_client_onaudio;
  324. ctx->rtmp.onvideo = rtmp_client_onvideo;
  325. ctx->rtmp.onabort = rtmp_client_onabort;
  326. ctx->rtmp.onscript = rtmp_client_onscript;
  327. ctx->rtmp.client.onconnect = rtmp_client_onconnect;
  328. ctx->rtmp.client.oncreate_stream = rtmp_client_oncreate_stream;
  329. ctx->rtmp.client.onnotify = rtmp_client_onnotify;
  330. ctx->rtmp.client.onping = rtmp_client_onping;
  331. ctx->rtmp.client.oneof = rtmp_client_oneof;
  332. ctx->rtmp.client.onbandwidth = rtmp_client_onbandwidth;
  333. snprintf(ctx->connect.app, sizeof(ctx->connect.app) - 1, "%s", appname);
  334. if (tcurl) snprintf(ctx->connect.tcUrl, sizeof(ctx->connect.tcUrl) - 1, "%s", tcurl);
  335. //snprintf(ctx->connect.swfUrl, sizeof(ctx->connect.swfUrl) - 1, "%s", tcurl ? tcurl : url);
  336. //snprintf(ctx->connect.pageUrl, sizeof(ctx->connect.pageUrl) - 1, "%s", tcurl ? tcurl : url);
  337. snprintf(ctx->connect.flashver, sizeof(ctx->connect.flashver) - 1, "%s", FLASHVER);
  338. ctx->connect.fpad = 0;
  339. ctx->connect.capabilities = 15;
  340. ctx->connect.audioCodecs = 3191; //SUPPORT_SND_AAC;
  341. ctx->connect.videoCodecs = 252; // SUPPORT_VID_H264;
  342. ctx->connect.videoFunction = SUPPORT_VID_CLIENT_SEEK;
  343. ctx->connect.encoding = RTMP_ENCODING_AMF_0;
  344. ctx->rtmp.out_packets[RTMP_CHANNEL_PROTOCOL].header.cid = RTMP_CHANNEL_PROTOCOL;
  345. ctx->rtmp.out_packets[RTMP_CHANNEL_INVOKE].header.cid = RTMP_CHANNEL_INVOKE;
  346. ctx->rtmp.out_packets[RTMP_CHANNEL_AUDIO].header.cid = RTMP_CHANNEL_AUDIO;
  347. ctx->rtmp.out_packets[RTMP_CHANNEL_VIDEO].header.cid = RTMP_CHANNEL_VIDEO;
  348. ctx->rtmp.out_packets[RTMP_CHANNEL_DATA].header.cid = RTMP_CHANNEL_DATA;
  349. return ctx;
  350. }
  351. void rtmp_client_destroy(struct rtmp_client_t* ctx)
  352. {
  353. size_t i;
  354. assert(sizeof(ctx->rtmp.in_packets) == sizeof(ctx->rtmp.out_packets));
  355. for (i = 0; i < N_CHUNK_STREAM; i++)
  356. {
  357. assert(NULL == ctx->rtmp.out_packets[i].payload);
  358. if (ctx->rtmp.in_packets[i].payload)
  359. {
  360. #if defined(DEBUG) || defined(_DEBUG)
  361. memset(ctx->rtmp.in_packets[i].payload, 0xCC, ctx->rtmp.in_packets[i].capacity);
  362. #endif
  363. free(ctx->rtmp.in_packets[i].payload);
  364. ctx->rtmp.in_packets[i].payload = NULL;
  365. }
  366. }
  367. #if defined(DEBUG) || defined(_DEBUG)
  368. memset(ctx, 0xCC, sizeof(*ctx));
  369. #endif
  370. free(ctx);
  371. }
  372. int rtmp_client_input(struct rtmp_client_t* ctx, const void* data, size_t bytes)
  373. {
  374. int r;
  375. const uint8_t* p;
  376. p = data;
  377. while (bytes > 0)
  378. {
  379. switch (ctx->handshake_state)
  380. {
  381. case RTMP_HANDSHAKE_UNINIT: // S0: version
  382. ctx->handshake_state = RTMP_HANDSHAKE_0;
  383. ctx->handshake_bytes = 0; // clear buffer
  384. assert(*p <= RTMP_VERSION);
  385. bytes -= 1;
  386. p += 1;
  387. break;
  388. case RTMP_HANDSHAKE_0: // S1: 4-time + 4-zero + 1528-random
  389. if (bytes + ctx->handshake_bytes < RTMP_HANDSHAKE_SIZE)
  390. {
  391. memcpy(ctx->payload + ctx->handshake_bytes, p, bytes);
  392. ctx->handshake_bytes += bytes;
  393. p += bytes;
  394. bytes = 0; // 0
  395. }
  396. else
  397. {
  398. memcpy(ctx->payload + ctx->handshake_bytes, p, RTMP_HANDSHAKE_SIZE - ctx->handshake_bytes);
  399. bytes -= RTMP_HANDSHAKE_SIZE - ctx->handshake_bytes;
  400. p += RTMP_HANDSHAKE_SIZE - ctx->handshake_bytes;
  401. ctx->handshake_state = RTMP_HANDSHAKE_1;
  402. ctx->handshake_bytes = 0; // clear buffer
  403. r = rtmp_client_send_c2(ctx);
  404. if(0 != r) return r;
  405. }
  406. break;
  407. case RTMP_HANDSHAKE_1: // S2: 4-time + 4-time2 + 1528-echo
  408. if (bytes + ctx->handshake_bytes < RTMP_HANDSHAKE_SIZE)
  409. {
  410. memcpy(ctx->payload + ctx->handshake_bytes, p, bytes);
  411. ctx->handshake_bytes += bytes;
  412. p += bytes;
  413. bytes = 0; // 0
  414. }
  415. else
  416. {
  417. memcpy(ctx->payload + ctx->handshake_bytes, p, RTMP_HANDSHAKE_SIZE - ctx->handshake_bytes);
  418. bytes -= RTMP_HANDSHAKE_SIZE - ctx->handshake_bytes;
  419. p += RTMP_HANDSHAKE_SIZE - ctx->handshake_bytes;
  420. ctx->handshake_state = RTMP_HANDSHAKE_2;
  421. ctx->handshake_bytes = 0; // clear buffer
  422. ctx->state = RTMP_STATE_HANDSHAKE;
  423. r = rtmp_client_send_connect(ctx);
  424. if (0 != r) return r;
  425. }
  426. break;
  427. default:
  428. rtmp_client_send_acknowledgement(ctx, bytes);
  429. return rtmp_chunk_read(&ctx->rtmp, (const uint8_t*)p, bytes);
  430. }
  431. }
  432. return 0; // need more data
  433. }
  434. int rtmp_client_start(struct rtmp_client_t* ctx, int publish)
  435. {
  436. int n;
  437. ctx->publish = publish;
  438. // handshake C0/C1
  439. ctx->handshake_state = RTMP_HANDSHAKE_UNINIT;
  440. n = rtmp_handshake_c0(ctx->payload, RTMP_VERSION);
  441. n += rtmp_handshake_c1(ctx->payload + n, (uint32_t)time(NULL));
  442. assert(n == RTMP_HANDSHAKE_SIZE + 1);
  443. return n == ctx->handler.send(ctx->param, ctx->payload, n, NULL, 0) ? 0 : -1;
  444. }
  445. int rtmp_client_stop(struct rtmp_client_t* ctx)
  446. {
  447. int r = 0;
  448. if (0 == ctx->publish)
  449. {
  450. r = rtmp_client_send_fcunpublish(ctx);
  451. }
  452. return 0 == r ? rtmp_client_send_delete_stream(ctx) : r;
  453. }
  454. int rtmp_client_pause(struct rtmp_client_t* ctx, int pause)
  455. {
  456. int r, i;
  457. uint32_t timestamp = 0;
  458. for (i = 0; i < N_CHUNK_STREAM; i++)
  459. {
  460. if(0 == ctx->rtmp.in_packets[i].header.cid)
  461. continue;
  462. if (timestamp < ctx->rtmp.in_packets[i].header.timestamp)
  463. timestamp = ctx->rtmp.in_packets[i].header.timestamp;
  464. }
  465. r = (int)(rtmp_netstream_pause(ctx->payload, sizeof(ctx->payload), 0, pause, timestamp) - ctx->payload);
  466. return rtmp_client_send_control(&ctx->rtmp, ctx->payload, r, ctx->stream_id);
  467. }
  468. int rtmp_client_seek(struct rtmp_client_t* ctx, double timestamp)
  469. {
  470. int r;
  471. r = (int)(rtmp_netstream_seek(ctx->payload, sizeof(ctx->payload), 0, timestamp) - ctx->payload);
  472. return rtmp_client_send_control(&ctx->rtmp, ctx->payload, r, ctx->stream_id);
  473. }
  474. int rtmp_client_getstate(struct rtmp_client_t* ctx)
  475. {
  476. return ctx->state;
  477. }
  478. int rtmp_client_push_video(struct rtmp_client_t* ctx, const void* video, size_t bytes, uint32_t timestamp)
  479. {
  480. struct rtmp_chunk_header_t header;
  481. assert(0 != ctx->stream_id);
  482. header.fmt = RTMP_CHUNK_TYPE_1; // enable compact header
  483. header.cid = RTMP_CHANNEL_VIDEO;
  484. header.timestamp = timestamp;
  485. header.length = (uint32_t)bytes;
  486. header.type = RTMP_TYPE_VIDEO;
  487. header.stream_id = ctx->stream_id;
  488. return rtmp_chunk_write(&ctx->rtmp, &header, (const uint8_t*)video);
  489. }
  490. int rtmp_client_push_audio(struct rtmp_client_t* ctx, const void* audio, size_t bytes, uint32_t timestamp)
  491. {
  492. struct rtmp_chunk_header_t header;
  493. assert(0 != ctx->stream_id);
  494. header.fmt = RTMP_CHUNK_TYPE_1; // enable compact header
  495. header.cid = RTMP_CHANNEL_AUDIO;
  496. header.timestamp = timestamp;
  497. header.length = (uint32_t)bytes;
  498. header.type = RTMP_TYPE_AUDIO;
  499. header.stream_id = ctx->stream_id;
  500. return rtmp_chunk_write(&ctx->rtmp, &header, (const uint8_t*)audio);
  501. }
  502. int rtmp_client_push_script(struct rtmp_client_t* ctx, const void* data, size_t bytes, uint32_t timestamp)
  503. {
  504. struct rtmp_chunk_header_t header;
  505. assert(0 != ctx->stream_id);
  506. header.fmt = RTMP_CHUNK_TYPE_1; // enable compact header
  507. header.cid = RTMP_CHANNEL_INVOKE;
  508. header.timestamp = timestamp;
  509. header.length = (uint32_t)bytes;
  510. header.type = RTMP_TYPE_DATA;
  511. header.stream_id = ctx->stream_id;
  512. return rtmp_chunk_write(&ctx->rtmp, &header, (const uint8_t*)data);
  513. }