FreeSwitch双轨录音

本文介绍了两种在FreeSwitch中实现双轨录音的方法。方法一是通过diaplan配置APP,利用'record_session'应用和'set'应用设置双轨录音。方法二是使用ESL模式的API,结合'uuid_record'和'uuid_setvar'命令来控制录音并启用双轨功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

方法一:diaplan配置APP

打开会话录音:

action application=“record_session” data=“xxx.wav”
app源码

SWITCH_STANDARD_APP(record_session_function)
{
    char *path = NULL;
    char *path_end;
    uint32_t limit = 0;

    if (zstr(data)) {
        return;
    }

    path = switch_core_session_strdup(session, data);

    /* Search for a space then a plus followed by only numbers at the end of the path, 
       if found trim any spaces to the left/right of the plus use the left side as the
       path and right side as a time limit on the recording
     */

    /* if we find a + and the character before it is a space */
    if ((path_end = strrchr(path, '+')) && path_end > path && *(path_end - 1) == ' ') {
        char *limit_start = path_end + 1;

        /* not at the end and the rest is numbers lets parse out the limit and fix up the path */
        if (*limit_start != '\0' && switch_is_number(limit_start) == SWITCH_TRUE) {
            limit = atoi(limit_start);
            /* back it off by one character to the char before the + */
            path_end--;

            /* trim spaces to the left of the plus */
            while (path_end > path && *path_end == ' ') {
                path_end--;
            }

            *(path_end + 1) = '\0';
        }
    }
    switch_ivr_record_session(session, path, limit, NULL);
}

可以看到次app调用的是switch_ivr_record_session函数,继续看switch_ivr_record_session函数,此函数核心逻辑是添加了一个回调函数

     if ((status = switch_core_media_bug_add(session, "session_record", file,
                                             record_callback, rh, to, flags, &bug)) != SWITCH_STATUS_SUCCESS) {
         switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Error adding media bug for file %s\n", file);
         if (rh->native) {
             switch_core_file_close(&rh->in_fh);
             switch_core_file_close(&rh->out_fh);
         } else {
             switch_core_file_close(fh);
         }
         return status;
     }

然后通话过程中每一帧处理都会调用此回调函数,调用处:
switch_core_io.c:

if (session->bugs && !((*frame)->flags & SFF_CNG) && !((*frame)->flags & SFF_NOT_AUDIO)) {
    switch_media_bug_t *bp;
    switch_bool_t ok = SWITCH_TRUE;
    int prune = 0;

    switch_thread_rwlock_rdlock(session->bug_rwlock);

    for (bp = session->bugs; bp; bp = bp->next) {
        ok = SWITCH_TRUE;

        if (switch_channel_test_flag(session->channel, CF_PAUSE_BUGS) && !switch_core_media_bug_test_flag(bp, SMBF_NO_PAUSE)) {
            continue;
        }

        if (!switch_channel_test_flag(session->channel, CF_ANSWERED) && switch_core_media_bug_test_flag(bp, SMBF_ANSWER_REQ)) {
            continue;
        }
        if (switch_test_flag(bp, SMBF_PRUNE)) {
            prune++;
            continue;
        }

        if (bp->ready) {
            if (switch_test_flag(bp, SMBF_TAP_NATIVE_READ)) {
                if ((*frame)->codec && (*frame)->codec->implementation &&
                    (*frame)->codec->implementation->encoded_bytes_per_packet &&
                    (*frame)->datalen != (*frame)->codec->implementation->encoded_bytes_per_packet) {
                    switch_set_flag((*frame), SFF_CNG);
                    break;
                }
                if (bp->callback) {
                    bp->native_read_frame = *frame;
                    ok = bp->callback(bp, bp->user_data, SWITCH_ABC_TYPE_TAP_NATIVE_READ);
                    bp->native_read_frame = NULL;
                }
            }
        }

        if ((bp->stop_time && bp->stop_time <= switch_epoch_time_now(NULL)) || ok == SWITCH_FALSE) {
            switch_set_flag(bp, SMBF_PRUNE);
            prune++;
        }
    }
    switch_thread_rwlock_unlock(session->bug_rwlock);

    if (prune) {
        switch_core_media_bug_prune(session);
    }
}

设置双轨录音

action application=“set” data=“RECORD_STEREO=true”/
源码switch_ivr_async.c:检测RECORD_STEREO字段,设置channels为2

if (channels == 1) { /* if leg is already stereo this feature is not available */
    if ((p = switch_channel_get_variable(channel, "RECORD_STEREO")) && switch_true(p)) {
        flags |= SMBF_STEREO;
        flags &= ~SMBF_STEREO_SWAP;
        channels = 2;
    }

    if ((p = switch_channel_get_variable(channel, "RECORD_STEREO_SWAP")) && switch_true(p)) {
        flags |= SMBF_STEREO;
        flags |= SMBF_STEREO_SWAP;
        channels = 2;
    }
}

方法二:ESL 模式API

开始录音API:
uuid_record < uuid> [start|stop|mask|unmask] < path> [< limit>]
分析源码可见,其调用的也是switch_ivr_record_session函数,所以再在开始录音前设置RECORD_STEREO即可实现双规录音。

if (!strcasecmp(action, "start")) {
    if (switch_ivr_record_session(rsession, path, limit, NULL) != SWITCH_STATUS_SUCCESS) {
        stream->write_function(stream, "-ERR Cannot record session!\n");
    } else {
        stream->write_function(stream, "+OK Success\n");
    }
} else if (!strcasecmp(action, "stop")) {

设置参数API:
uuid_setvar < uuid> < var> [value]

### FreeSWITCH 录音配置与实现方法 #### 配置录音功能的基础设置 为了启用FreeSWITCH录音功能,需编辑`/usr/local/freeswitch/conf/dialplan/default`下的配置文件,在此位置添加必要的配置项来激活录音能力[^2]。 #### 修改拨号计划以支持录音操作 在拨号计划 `dialplan.xml` 中加入特定的动作标签 `<action>` 来定义录音行为。具体来说,可以通过如下方式指定录音路径以及命名规则: ```xml <action application="record_session" data="/tmp/${strftime(%Y-%m-%d)}/${caller_id_number}_${destination_number}.wav"/> <!-- 设置两个变量,用于将通话记录保存到数据库 --> <action application="set" data="recordfile=/tmp/${strftime(%Y-%m-%d)}/${caller_id_number}_${destination_number}.wav"/> <action application="set" data="recordname=${caller_id_number}_${destination_number}.wav"/> ``` 上述XML片段展示了如何利用内置的应用程序指令完成录音会话,并设置了相应的环境变量以便后续处理[^4]。 #### 调整CTI模块参数控制录音时机 对于希望在呼叫建立之前就开始录制的情况,则可以在CCAdmin界面内调整mod_cti的相关选项。“RECORD_ANSWER_REQ=false”的设定决定了是否允许未接通状态下的录音活动发生[^3]。 #### 关键组件协作机制概述 整个录音流程的成功执行离不开几个核心模块之间的紧密配合——包括但不限于负责SIP协议栈管理的`mod_sofia`、提供JSON接口服务的`mod_fs_json`,当然还有专门用来捕捉语音流并将其持久化的`mod_record`。这些组成部分共同作用确保了从初始化至最终存档各阶段工作的顺利开展[^1]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值