#include "sys/sock.h" #include "sys/thread.h" #include "sys/system.h" #include "sys/sync.hpp" #include "aio-connect.h" #include "aio-timeout.h" #include "aio-rtmp-client.h" #include "flv-reader.h" #include "flv-proto.h" #include #include #include static struct { int code; // rtmp error code const char* file; char tcurl[4 * 1024]; const char* app; const char* stream; aio_rtmp_client_t* rtmp; } s_param; static int STDCALL rtmp_client_push(void* flv) { int r, type; size_t taglen; uint32_t timestamp; uint32_t clock0 = system_clock(); void* f = flv_reader_create((const char*)flv); static char packet[2 * 1024 * 1024]; while (0 == s_param.code && 1 == flv_reader_read(f, &type, ×tamp, &taglen, packet, sizeof(packet))) { uint32_t t = system_clock(); if(clock0 + timestamp > t && clock0 + timestamp < t + 3 * 1000) system_sleep(clock0 + timestamp - t); else if (t + timestamp > t + 3 * 1000) t = t - timestamp; while (s_param.rtmp && aio_rtmp_client_get_unsend(s_param.rtmp) > 8 * 1024 * 1024) system_sleep(1000); // can't send? switch (type) { case FLV_TYPE_AUDIO: r = aio_rtmp_client_send_audio(s_param.rtmp, packet, taglen, timestamp); break; case FLV_TYPE_VIDEO: r = aio_rtmp_client_send_video(s_param.rtmp, packet, taglen, timestamp); break; case FLV_TYPE_SCRIPT: r = aio_rtmp_client_send_script(s_param.rtmp, packet, taglen, timestamp); break; default: r = 0; break; } if (0 != r) { assert(0); break; // TODO: handle send failed } } aio_rtmp_client_destroy(s_param.rtmp); flv_reader_destroy(f); s_param.file = NULL; s_param.rtmp = NULL; return 0; } static void rtmp_client_publish_onsend(void*, size_t) { } static void rtmp_client_publish_onready(void*) { pthread_t thread; thread_create(&thread, rtmp_client_push, (void*)s_param.file); thread_detach(thread); } static void rtmp_client_publish_onerror(void* /*param*/, int code) { // exit publish thread s_param.code = code; } static void rtmp_onconnect(void*, int code, socket_t tcp, aio_socket_t aio) { assert(0 == code); struct aio_rtmp_client_handler_t handler; memset(&handler, 0, sizeof(handler)); handler.onerror = rtmp_client_publish_onerror; handler.onready = rtmp_client_publish_onready; handler.onsend = rtmp_client_publish_onsend; s_param.code = 0; s_param.rtmp = aio_rtmp_client_create(aio, s_param.app, s_param.stream, s_param.tcurl, &handler, NULL); assert(0 == aio_rtmp_client_start(s_param.rtmp, 0)); } // rtmp://video-center.alivecdn.com/live/hello?vhost=your.domain // rtmp_publish_aio_test("video-center.alivecdn.com", "live", "hello?vhost=your.domain", local-flv-file-name) void rtmp_publish_aio_test(const char* host, const char* app, const char* stream, const char* file) { s_param.file = file; s_param.app = app; s_param.stream = stream; snprintf(s_param.tcurl, sizeof(s_param.tcurl), "rtmp://%s/%s", host, app); // tcurl aio_socket_init(1); aio_connect(host, 1935, 3000, rtmp_onconnect, NULL); while (aio_socket_process(5000) > 0) { aio_timeout_process(); } aio_socket_clean(); }