9.24. virtual_enc虚拟源编码

概述

pcm数据通过虚拟源编码成想要的格式(例如:mp3、amr、ogg、opus、jla、spx、aac等)数据

9.24.1. 应用示例

  • apps/demo/demo_DevKitBoard/include/demo_config.h 打开 #define USE_VIRTUAL_ENC_TEST 宏使用,例程文件为 apps/common/example/audio/virtual_enc/main.c

  • 该例子中以文件 4.pcm 作为输入数据,进行virtual_enc, 输出mp3数据到 out_file.mp3 文件保存

9.24.2. 例子流程

  1. 开启编码服务和注册编码服务事件回调函数

  2. 等待SD卡挂载,打开输入文件和创建输出文件

  3. 设置编码参数,请求打开编码器

  4. 编码结束,关闭编码器和编码服务

9.24.3. 关键过程说明

  • 1.注册编码服务事件回调函数

//线程接收编码服务回调消息队列方式
/*static void server_back()
{
        while(1){
        int msg[32];
        os_time_dly(2);
        os_taskq_pend("taskq",msg,ARRAY_SIZE(msg));
        }
}*/

//2.开启编码服务和注册编码服务回调
if (!__this->enc_server) {
    __this->enc_server = server_open("audio_server", "enc");
    if (!__this->enc_server) {
        return -1;
    }
    //a.将编码服务回调函数注册到“app_core”消息队列  常用方式
    server_register_event_handler_to_task(__this->enc_server, NULL, enc_server_server_event_handler, "app_core");
    //b.将编码服务回调函数注册到创建的线程中接收消息队列
    /* thread_fork("server_back", 10, 1024, 32, NULL, server_back, NULL); */
    /* server_register_event_handler_to_task(__this->enc_server, NULL, enc_server_server_event_handler,"server_back"); */
} else {
    return -1;
}
  • 2.设置编码参数,请求打开编码器

  • req.enc.read_input = enc_server_read_input; //用于虚拟采样源”virtual”编码时的数据读取操作读输入buf及其长度,返回负值自动停止编码并回调编码结束的事件

  • req.enc.vfs_ops = &enc_server_vfs_ops; //编码后数据在fwrite回调中输出

  • req.enc.vir_data_wait = 1; //等待数据编码完成才进行下一帧数据编码,数据完整

//3.设置编码参数,请求打开编码器
union audio_req req = {0};
req.enc.cmd = AUDIO_ENC_OPEN;
req.enc.channel = 2;
req.enc.volume = 100;
req.enc.output_buf = NULL;
req.enc.output_buf_len = 3200 * 8;
req.enc.sample_rate = 16000;
req.enc.format = "mp3";
req.enc.frame_size = 3200;   //frame_size为read_input的len
req.enc.sample_source = "virtual";
req.enc.read_input = enc_server_read_input;    //用于虚拟采样源"virtual"编码时的数据读取操作读输入buf及其长度,返回负值自动停止编码并回调编码结束的事件
req.enc.vfs_ops = &enc_server_vfs_ops;  //编码后数据在fwrite回调中输出
req.enc.vir_data_wait = 1;  //等待数据编码完成才进行下一帧数据编码,数据完整
/* req.enc.no_header = 1; */
/* req.enc.bitrate = 16000;  */

err = server_request(__this->enc_server, AUDIO_REQ_ENC, &req); //请求编码器

//编码虚拟源输入
static u32 enc_server_read_input(u8 *buf, u32 len)
{
    int rlen;
    if (__this->in_file) {
        rlen = fread(buf, len, 1, __this->in_file);
        if (rlen == len) {
            return rlen;
        } else {
            fclose(__this->in_file);
            __this->in_file = NULL;
            return rlen;
        }
    } else {
        return -1;   //read_input返回-1表示输入数据完成,没有数据输入,让编码服务发结束消息出来AUDIO_SERVER_EVENT_END去进行结束编码的操作
    }
}
  • 开启编码请求后会自动调用enc_server_read_input输入函数,其中参数len为编码参数中设置的frame_size为设置的需要输入的数据长度,buf为需要输入给编码器的数据,返回值为实际输入数据长度,当设置返回负数时,virtual_enc获取到编码结束事件

  • 除了在read_input数据输入获取编码结束事件,也可以在编码参数中增加req.enc.msec 设置编码时长(单位ms)

  • 上述两种方式的去获取到编码结束编码 AUDIO_SERVER_EVENT_END,在事件中调用去结束编码服务一系列操作

  • 想要获取到编码结束事件,一定要在上面注册编码服务回调中将编码服务回调函数enc_server_server_event_handler注册

//关闭virtual编码操作
static enc_server_test_close(void)
{
    puts("--------enc_server_test_close---------");

    union audio_req req = {0};

    if (__this->enc_server) {
        req.enc.cmd = AUDIO_ENC_CLOSE;
        server_request(__this->enc_server, AUDIO_REQ_ENC, &req);
        server_close(__this->enc_server);
        __this->enc_server = NULL;
    }

    if (__this->out_file) {
        fclose(__this->out_file);
        __this->out_file = NULL;
    }
}

//编码服务注册的回调函数
static void enc_server_server_event_handler(void *priv, int argc, int *argv)
{
    switch (argv[0]) {
    case AUDIO_SERVER_EVENT_ERR:
    case AUDIO_SERVER_EVENT_END:
        printf("VIRTUAL_AUDIO_SERVER_EVENT_END");
        enc_server_test_close();
        break;
    case AUDIO_SERVER_EVENT_SPEAK_START:
        printf("speak start ! \n");
        break;
    case AUDIO_SERVER_EVENT_SPEAK_STOP:
        printf("speak stop ! \n");
        break;
    default:
        break;
    }
}