Making mod_rtmp compatible with Adobe Media Server

Adobe Media Server connects differently to mod_rtmp than the way
Flash player connects. The RTMP publish handler rtmp_i_publish
message needs to match the RTMP specification, and a new initStream
handler is required.

This patch modifies the rtmp_i_publish handler to send an onStatus
message to Adobe Media Server that includes an object with "level",
"code" and "description" fields.

The initStream message is sent by Adobe Media Server to notify Freeswitch
of the stream ID for the publish stream. This cannot clash with the play
stream ID so the initStream handler can simply increment the next_streamid
field. The initStream message is undocumented in the RTMP specification.

The transaction ID for onStatus messages has been modified to 0 instead
of 1 to match with the RTMP specification.

FS-7924 #resolve
This commit is contained in:
Paul Cuttler 2015-08-14 06:06:43 +10:00
parent 6813d6647b
commit 53c37d2385
3 changed files with 25 additions and 8 deletions

View File

@ -1990,6 +1990,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_rtmp_load)
rtmp_register_invoke_function("connect", rtmp_i_connect);
rtmp_register_invoke_function("createStream", rtmp_i_createStream);
rtmp_register_invoke_function("initStream", rtmp_i_initStream);
rtmp_register_invoke_function("closeStream", rtmp_i_noop);
rtmp_register_invoke_function("deleteStream", rtmp_i_noop);
rtmp_register_invoke_function("play", rtmp_i_play);

View File

@ -596,6 +596,7 @@ typedef enum {
/* Invokable functions from flash */
RTMP_INVOKE_FUNCTION(rtmp_i_connect);
RTMP_INVOKE_FUNCTION(rtmp_i_createStream);
RTMP_INVOKE_FUNCTION(rtmp_i_initStream);
RTMP_INVOKE_FUNCTION(rtmp_i_noop);
RTMP_INVOKE_FUNCTION(rtmp_i_play);
RTMP_INVOKE_FUNCTION(rtmp_i_publish);

View File

@ -126,6 +126,15 @@ RTMP_INVOKE_FUNCTION(rtmp_i_connect)
RTMP_INVOKE_FUNCTION(rtmp_i_createStream)
{
switch_log_printf(SWITCH_CHANNEL_UUID_LOG(rsession->uuid), SWITCH_LOG_INFO, "Replied to createStream (%u)\n", amf0_get_number(argv[1]));
rsession->next_streamid++;
return SWITCH_STATUS_SUCCESS;
}
RTMP_INVOKE_FUNCTION(rtmp_i_initStream)
{
rtmp_send_invoke_free(rsession, amfnumber, 0, 0,
amf0_str("_result"),
@ -134,7 +143,7 @@ RTMP_INVOKE_FUNCTION(rtmp_i_createStream)
amf0_number_new(rsession->next_streamid),
NULL);
switch_log_printf(SWITCH_CHANNEL_UUID_LOG(rsession->uuid), SWITCH_LOG_INFO, "Replied to createStream (%u)\n", rsession->next_streamid);
switch_log_printf(SWITCH_CHANNEL_UUID_LOG(rsession->uuid), SWITCH_LOG_INFO, "Received initStream (%u)\n", rsession->next_streamid);
rsession->next_streamid++;
@ -222,7 +231,7 @@ RTMP_INVOKE_FUNCTION(rtmp_i_play)
rtmp_send_invoke_free(rsession, RTMP_DEFAULT_STREAM_NOTIFY, 0, rsession->media_streamid,
amf0_str("onStatus"),
amf0_number_new(1),
amf0_number_new(0),
amf0_null_new(),
object, NULL);
@ -236,7 +245,7 @@ RTMP_INVOKE_FUNCTION(rtmp_i_play)
rtmp_send_invoke_free(rsession, RTMP_DEFAULT_STREAM_NOTIFY, 0, rsession->media_streamid,
amf0_str("onStatus"),
amf0_number_new(1),
amf0_number_new(0),
amf0_null_new(),
object, NULL);
@ -256,6 +265,7 @@ RTMP_INVOKE_FUNCTION(rtmp_i_play)
RTMP_INVOKE_FUNCTION(rtmp_i_publish)
{
amf0_data *object = amf0_object_new();
unsigned char buf[] = {
INT16(RTMP_CTRL_STREAM_BEGIN),
@ -264,12 +274,17 @@ RTMP_INVOKE_FUNCTION(rtmp_i_publish)
rtmp_send_message(rsession, 2, 0, RTMP_TYPE_USERCTRL, 0, buf, sizeof(buf), 0);
rtmp_send_invoke_free(rsession, amfnumber, 0, 0,
amf0_str("_result"),
amf0_number_new(transaction_id),
amf0_object_add(object, "level", amf0_str("status"));
amf0_object_add(object, "code", amf0_str("NetStream.Publish.Start"));
amf0_object_add(object, "description", amf0_str("description"));
amf0_object_add(object, "details", amf0_str("details"));
amf0_object_add(object, "clientid", amf0_number_new(217834719));
rtmp_send_invoke_free(rsession, RTMP_DEFAULT_STREAM_NOTIFY, 0, state->stream_id,
amf0_str("onStatus"),
amf0_number_new(0),
amf0_null_new(),
amf0_null_new(),
NULL);
object, NULL);
switch_log_printf(SWITCH_CHANNEL_UUID_LOG(rsession->uuid), SWITCH_LOG_INFO, "Got publish on stream %u.\n", state->stream_id);