uuid_media_reneg接口实现流程

uuid_media_reneg接口实现流程

一、实现位置

uuid_media_reneg api接口位于mod_command模块,函数位置定义在mod_command.c大约3741行左右。原型如下:

SWITCH_STANDARD_API(uuid_media_neg_function)
{
    // to do
}

在mod_commands_load函数中注册uuid_media_reneg api接口。位置大约在mod_command.c大约7710行左右。注册方式如下:

SWITCH_ADD_API(commands_api_interface, "uuid_media_reneg", "Media negotiation", uuid_media_neg_function, MEDIA_RENEG_SYNTAX);

同时也在mod_commands_load实现了控制台自动填充uuid功能,位置大约在mod_command.c大约7717行左右:

switch_console_set_complete("add uuid_media_reneg ::console::list_uuid");

 二、内部实现流程

 uuid_media_neg_function内部实现如下:

#define MEDIA_RENEG_SYNTAX "<uuid>[ <codec_string>]"
SWITCH_STANDARD_API(uuid_media_neg_function)
{
    char *mycmd = NULL, *argv[2] = { 0 };
    int argc = 0;
    switch_status_t status = SWITCH_STATUS_FALSE;
    if (!zstr(cmd) && (mycmd = strdup(cmd))) {
        argc = switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
    }
    if (zstr(cmd) || argc < 1 || zstr(argv[0])) {
        stream->write_function(stream, "-USAGE: %s\n", MEDIA_RENEG_SYNTAX);
    } else {
        switch_core_session_message_t msg = { 0 };
        switch_core_session_t *lsession = NULL;
        char *uuid = argv[0];
        msg.message_id = SWITCH_MESSAGE_INDICATE_MEDIA_RENEG;
        msg.string_arg = argv[1];
        msg.from = __FILE__;
        if (*uuid == '+') {
            msg.numeric_arg++;
            uuid++;
        }
        if ((lsession = switch_core_session_locate(uuid))) {
            status = switch_core_session_receive_message(lsession, &msg);
            switch_core_session_rwunlock(lsession);
        }
    }
    if (status == SWITCH_STATUS_SUCCESS) {
        stream->write_function(stream, "+OK Success\n");
    } else {
        stream->write_function(stream, "-ERR Operation Failed\n");
    }
    switch_safe_free(mycmd);
    return SWITCH_STATUS_SUCCESS;
}

其中SWITCH_STANDARD_API为一个宏,原型如下:

#define SWITCH_STANDARD_API(name) static switch_status_t name (
   _In_opt_z_ const char *cmd,
   _In_opt_ switch_core_session_t *session,
   _In_ switch_stream_handle_t *stream
)

说明FreeSWITCH回调uuid_media_neg_function函数接口时,会传三个参数:

  • cmd:音视频编解码格式
  • session:本函数没有使用该参数,通话session,而是通过uuid去查找通话session。
  • stream:可以理解数据回写流,比如函数执行状态(字符串提示信息)回传给调用方或控制台回显等。

进入函数后,首先调用zstr()判断cmd参数是否有值。

zstr(cmd)

重新分配内存,将cmd参数值保存到新分配的内存,且将该内存控制权交给mycmd指针:

mycmd = strdup(cmd)

如果cmd参数不为空,且参数复制成功后,调用switch_separate_string解析cmd传入的参数,同时返回参数数量,argv为长度为2的字符串指针数组,argv[0]指向uuid字符串存放内存,argv[1]指向音视频编码格式存放内存。

argc = switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])));

接下来判断参数是否合法,如果cmd没有值,或者cmd传进字符串数量小于1,则回显操作提示信息:

stream->write_function(stream, "-USAGE: %s\n", MEDIA_RENEG_SYNTAX);

如果参数合法,则创建session消息体:

switch_core_session_message_t msg = { 0 };

初始化消息id,并将音视频编码格式传赋值给消息参数成员:

msg.message_id = SWITCH_MESSAGE_INDICATE_MEDIA_RENEG;
msg.string_arg = argv[1];

调用switch_core_session_locate函数通过uuid查找通话的session:

switch_core_session_locate(uuid)

如果session存在,则调用switch_core_session_receive_message发起re-invite进行媒体协商。

调用switch_core_session_receive_message发起消息后,需要使用switch_core_session_rwunlock释放锁。

switch_core_session_rwunlock(lsession);

判断操作是否成功,回写函数执行状态信息:

    if (status == SWITCH_STATUS_SUCCESS) {
        stream->write_function(stream, "+OK Success\n");
    } else {
        stream->write_function(stream, "-ERR Operation Failed\n");
    }

调用switch_safe_free()释放mycmd指向的内存。

switch_safe_free(mycmd);

最后返回函数执行状态。

 三、switch_core_session_receive_message函数解析

switch_core_session_receive_message其实是一个宏,定义在switch_core.h文件中,原型如下:

#define switch_core_session_receive_message(_session, _message) \
switch_core_session_perform_receive_message(_session, _message, \ 
__FILE__, __SWITCH_FUNC__, __LINE__)

 switch_core_session_perform_receive_message()函数在switch_core_session.c进行实现。在此函数体中有许多执行分支,我们只看与消息id为SWITCH_MESSAGE_INDICATE_MEDIA_RENEG相关的执行路径。所在可以直接跳到switch_core_session.c文件920行,判断channel是否存在,如果不存在则打印消息,提示channel is hungup already。如果channel存在则调用switch_core_media_receive_message函数。

    if (switch_channel_down_nosig(session->channel)) {
        switch_log_printf(SWITCH_CHANNEL_ID_LOG, message->_file, message->_func, message->_line,
        switch_core_session_get_uuid(session), SWITCH_LOG_DEBUG, "%s skip receive message [%s] (channel is hungup already)\n",
        switch_channel_get_name(session->channel), message_names[message->message_id]);

    } else {
        if (session->media_handle) {
            status = switch_core_media_receive_message(session, message);
        }
        if (status == SWITCH_STATUS_SUCCESS) {
            if (session->endpoint_interface->io_routines->receive_message) {
                status = session->endpoint_interface->io_routines->receive_message(session, message);
            }
        }
    }

可以看到在这里,调用了switch_core_media_receive_message()函数,并在这个函数中更新channel中相关音视频编码格式,同时更新sdp信息:

case SWITCH_MESSAGE_INDICATE_MEDIA_RENEG:
        {
            switch_core_session_t *nsession;

            if (msg->string_arg) {
                switch_channel_set_variable(session->channel, "absolute_codec_string", NULL);

                if (*msg->string_arg == '=') {
                    switch_channel_set_variable(session->channel, "codec_string", msg->string_arg);
                } else {
                    switch_channel_set_variable_printf(session->channel,
                        "codec_string", "=%s", switch_channel_get_variable(session->channel, "ep_codec_string"));
                }
                
                a_engine->codec_negotiated = 0;
                v_engine->codec_negotiated = 0;
                smh->num_negotiated_codecs = 0;
                switch_channel_clear_flag(session->channel, CF_VIDEO_POSSIBLE);
                switch_core_media_prepare_codecs(session, SWITCH_TRUE);
                switch_core_media_check_video_codecs(session);
                
                switch_core_media_gen_local_sdp(session, SDP_TYPE_REQUEST, NULL, 0, NULL, 1);
            }

            if (msg->numeric_arg && switch_core_session_get_partner(session, &nsession) == SWITCH_STATUS_SUCCESS) {
                msg->numeric_arg = 0;
                switch_core_session_receive_message(nsession, msg);
                switch_core_session_rwunlock(nsession);
            }

        }
        break;

 

posted @ 2023-11-21 11:33  钟齐峰  阅读(170)  评论(0编辑  收藏  举报