stream-deploy/ZLM/3rdpart/media-server/librtmp/source/rtmp-client-invoke-handler.h

255 lines
9.3 KiB
C++
Raw Normal View History

#include "rtmp-internal.h"
#include "amf0.h"
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#if defined(_WIN32) || defined(_WIN64)
#define strcasecmp _stricmp
#endif
struct rtmp_result_t
{
char code[64]; // NetStream.Play.Start
char level[8]; // warning/status/error
char description[256];
};
//static const char* s_rtmp_command_code[] = {
// "NetConnection.Connect.Success",
// "NetConnection.Connect.Closed",
// "NetConnection.Connect.Failed",
// "NetConnection.Connect.AppShutdown",
// "NetConnection.Connect.InvalidApp",
// "NetConnection.Connect.Rejected",
//
// "NetConnection.Connect.ReconnectRequest" // enhanced rtmp v2
//
// "NetStream.Failed",
// "NetStream.Play.Failed",
// "NetStream.Play.StreamNotFound",
// "NetStream.Play.Start",
// "NetStream.Play.Stop",
// "NetStream.Play.Complete",
// "NetStream.Play.PublishNotify",
// "NetStream.Play.UnpublishNotify",
// "NetStream.Seek.Notify",
// "NetStream.Seek.Failed",
// "NetStream.Pause.Notify",
// "NetStream.Unpause.Notify",
// "NetStream.Publish.Start",
// "NetStream.Publish.BadName",
// "NetStream.Unpublish.Success",
// "NetStream.Record.Failed",
// "NetStream.Record.NoAccess",
// "NetStream.Record.Start",
// "NetStream.Record.Stop",
//};
#define AMF_OBJECT_ITEM_VALUE(v, amf_type, amf_name, amf_value, amf_size) { v.type=amf_type; v.name=amf_name; v.value=amf_value; v.size=amf_size; }
// s -> c
static int rtmp_command_onconnect_reply(struct rtmp_result_t* result, const uint8_t* data, uint32_t bytes)
{
char fmsver[64] = { 0 };
double capabilities = 0;
struct amf_object_item_t prop[2];
struct amf_object_item_t info[3];
struct amf_object_item_t items[2];
AMF_OBJECT_ITEM_VALUE(prop[0], AMF_STRING, "fmsVer", fmsver, sizeof(fmsver));
AMF_OBJECT_ITEM_VALUE(prop[1], AMF_NUMBER, "capabilities", &capabilities, sizeof(capabilities));
AMF_OBJECT_ITEM_VALUE(info[0], AMF_STRING, "code", result->code, sizeof(result->code));
AMF_OBJECT_ITEM_VALUE(info[1], AMF_STRING, "level", result->level, sizeof(result->level));
AMF_OBJECT_ITEM_VALUE(info[2], AMF_STRING, "description", result->description, sizeof(result->description));
AMF_OBJECT_ITEM_VALUE(items[0], AMF_OBJECT, "Properties", prop, sizeof(prop) / sizeof(prop[0]));
AMF_OBJECT_ITEM_VALUE(items[1], AMF_OBJECT, "Information", info, sizeof(info) / sizeof(info[0]));
//rtmp->onstatus();
return amf_read_items(data, data + bytes, items, sizeof(items) / sizeof(items[0])) ? 0 : EINVAL;
}
// s -> c
static int rtmp_command_oncreate_stream_reply(const uint8_t* data, uint32_t bytes, double *stream_id)
{
struct amf_object_item_t items[2];
AMF_OBJECT_ITEM_VALUE(items[0], AMF_OBJECT, "command", NULL, 0);
AMF_OBJECT_ITEM_VALUE(items[1], AMF_NUMBER, "streamId", stream_id, 8);
//rtmp->onstatus();
return amf_read_items(data, data + bytes, items, sizeof(items) / sizeof(items[0])) ? 0 : EINVAL;
}
// s -> c
static int rtmp_command_onresult(struct rtmp_t* rtmp, double transaction, const uint8_t* data, uint32_t bytes)
{
int r;
double stream_id = 0;
double duration = 0;
struct rtmp_result_t result;
memset(&result, 0, sizeof(result));
switch ((uint32_t)transaction)
{
case RTMP_TRANSACTION_CONNECT:
// next:
// 1. releaseStream/FCPublish or serverBW/user control message event buffer time
// 2. createStream
// 3. FCSubscribe
r = rtmp_command_onconnect_reply(&result, data, bytes);
return 0 == r ? (rtmp->client.onconnect ? rtmp->client.onconnect(rtmp->param) : -1) : r;
case RTMP_TRANSACTION_CREATE_STREAM:
// next:
// publish
// or play/user control message event buffer time
r = rtmp_command_oncreate_stream_reply(data, bytes, &stream_id);
return 0 == r ? (rtmp->client.oncreate_stream ? rtmp->client.oncreate_stream(rtmp->param, stream_id) : -1) : r;
case RTMP_TRANSACTION_GET_STREAM_LENGTH:
return rtmp_command_oncreate_stream_reply(data, bytes, &duration);
default:
return 0;
}
}
// s -> c
//static int rtmp_command_onerror(struct rtmp_t* rtmp, double transaction, const uint8_t* data, uint32_t bytes)
//{
// struct rtmp_result_t result;
// struct amf_object_item_t info[3];
// struct amf_object_item_t items[2];
//
// memset(&result, 0, sizeof(result));
// AMF_OBJECT_ITEM_VALUE(info[0], AMF_STRING, "code", result.code, sizeof(result.code));
// AMF_OBJECT_ITEM_VALUE(info[1], AMF_STRING, "level", result.level, sizeof(result.level));
// AMF_OBJECT_ITEM_VALUE(info[2], AMF_STRING, "description", result.description, sizeof(result.description));
//
// AMF_OBJECT_ITEM_VALUE(items[0], AMF_OBJECT, "command", NULL, 0);
// AMF_OBJECT_ITEM_VALUE(items[1], AMF_OBJECT, "Information", info, sizeof(info) / sizeof(info[0]));
//
// if (NULL == amf_read_items(data, data + bytes, items, sizeof(items) / sizeof(items[0])))
// {
// return -EINVAL; // format error
// }
//
// //rtmp->onerror(rtmp->param, -1, result.code);
// (void)transaction;
// (void)rtmp;
// return -1;
//}
// s -> c
static int rtmp_command_onstatus(struct rtmp_t* rtmp, double transaction, const uint8_t* data, uint32_t bytes)
{
double code = 0.0;
char tcurl[256] = { 0 };
struct rtmp_result_t result;
struct amf_object_item_t info[5];
struct amf_object_item_t items[2];
struct amf_object_item_t redirect[2];
memset(&result, 0, sizeof(result));
AMF_OBJECT_ITEM_VALUE(redirect[0], AMF_NUMBER, "code", &code, sizeof(code));
AMF_OBJECT_ITEM_VALUE(redirect[1], AMF_STRING, "redirect", tcurl, sizeof(tcurl));
AMF_OBJECT_ITEM_VALUE(info[0], AMF_STRING, "code", result.code, sizeof(result.code));
AMF_OBJECT_ITEM_VALUE(info[1], AMF_STRING, "level", result.level, sizeof(result.level));
AMF_OBJECT_ITEM_VALUE(info[2], AMF_STRING, "description", result.description, sizeof(result.description));
AMF_OBJECT_ITEM_VALUE(info[3], AMF_STRING, "tcUrl", tcurl, sizeof(tcurl)); // enhanced rtmp v2
AMF_OBJECT_ITEM_VALUE(info[4], AMF_OBJECT, "ex", redirect, sizeof(redirect)); // AMS(adoble media server) serverside redirect
AMF_OBJECT_ITEM_VALUE(items[0], AMF_OBJECT, "command", NULL, 0); // Command object
AMF_OBJECT_ITEM_VALUE(items[1], AMF_OBJECT, "information", info, sizeof(info) / sizeof(info[0])); // Information object
if (NULL == amf_read_items(data, data + bytes, items, sizeof(items) / sizeof(items[0])))
{
return -EINVAL;
}
assert(0 == strcmp(RTMP_LEVEL_ERROR, result.level)
|| 0 == strcmp(RTMP_LEVEL_STATUS, result.level)
|| 0 == strcmp(RTMP_LEVEL_WARNING, result.level)
|| 0 == strcmp(RTMP_LEVEL_FINISH, result.level));
if (0 == strcasecmp(result.code, "NetStream.Play.Start")
|| 0 == strcasecmp(result.code, "NetStream.Record.Start")
|| 0 == strcasecmp(result.code, "NetStream.Publish.Start"))
{
rtmp->client.onnotify ? rtmp->client.onnotify(rtmp->param, RTMP_NOTIFY_START) : 0;
}
else if (0 == strcasecmp(result.code, "NetStream.Seek.Notify"))
{
rtmp->client.onnotify ? rtmp->client.onnotify(rtmp->param, RTMP_NOTIFY_SEEK) : 0;
}
else if (0 == strcasecmp(result.code, "NetStream.Pause.Notify"))
{
rtmp->client.onnotify ? rtmp->client.onnotify(rtmp->param, RTMP_NOTIFY_PAUSE) : 0;
}
else if (0 == strcasecmp(result.code, "NetStream.Unpause.Notify"))
{
rtmp->client.onnotify ? rtmp->client.onnotify(rtmp->param, RTMP_NOTIFY_START) : 0;
}
else if (0 == strcasecmp(result.code, "NetStream.Play.Reset"))
{
//rtmp->u.client.onnotify(rtmp->param, RTMP_NOTIFY_RESET);
}
else if (0 == strcasecmp(result.code, "NetStream.Play.Stop")
|| 0 == strcasecmp(result.code, "NetStream.Record.Stop")
|| 0 == strcasecmp(result.code, "NetStream.Play.Complete"))
{
rtmp->client.onnotify ? rtmp->client.onnotify(rtmp->param, RTMP_NOTIFY_STOP) : 0;
}
else if (0 == strcasecmp(result.code, "NetStream.Play.PublishNotify")
|| 0 == strcasecmp(result.code, "NetStream.Play.UnpublishNotify"))
{
}
else if (0 == strcasecmp(result.code, "NetConnection.Connect.InvalidApp")
|| 0 == strcasecmp(result.code, "NetStream.Connect.IllegalApplication") // ksyun cdn: level finish, auth failed
|| 0 == strcasecmp(result.code, "NetStream.Publish.AlreadyExistStream") // ksyun cdn: level finish, description Already exist stream!
|| 0 == strcasecmp(result.code, "NetStream.Failed")
|| 0 == strcasecmp(result.code, "NetStream.Play.Failed")
|| 0 == strcasecmp(result.code, "NetStream.Play.StreamNotFound"))
{
//rtmp->onerror(rtmp->param, -1, result.code);
return -1;
}
else if (0 == strcasecmp(result.code, "NetConnection.Connect.ReconnectRequest") // enhanced rtmp v2
|| (302 == (int)code && 0 == strcasecmp(result.code, "NetConnection.Connect.Rejected"))) // AMS(adoble media server) server-side redirect
{
return rtmp->client.onreconnect ? rtmp->client.onreconnect(rtmp->param, tcurl, result.description) : 0;
}
else
{
assert(0);
printf("%s: level: %s, code: %s, description: %s\n", __FUNCTION__, result.level, result.code, result.description);
return 0;
}
(void)transaction;
return strcmp(RTMP_LEVEL_ERROR, result.level) ? 0 : -1;
}
/*
static int rtmp_command_onbwdone(struct rtmp_t* rtmp, double transaction, const uint8_t* data, uint32_t bytes)
{
struct amf_object_item_t items[1];
AMF_OBJECT_ITEM_VALUE(items[0], AMF_OBJECT, "command", NULL, 0);
return amf_read_items(data, data + bytes, items, sizeof(items) / sizeof(items[0])) ? 0 : -1;
}
static int rtmp_command_onbwcheck(struct rtmp_t* rtmp, double transaction, const uint8_t* data, uint32_t bytes)
{
struct amf_object_item_t items[1];
AMF_OBJECT_ITEM_VALUE(items[0], AMF_OBJECT, "command", NULL, 0);
return amf_read_items(data, data + bytes, items, sizeof(items) / sizeof(items[0])) ? 0 : -1;
}
*/