使用 MicroSip 源码编译后,在录音配置界面虽然有 mp3 格式选项,但是实际录音后不会生成mp3 文件夹,而选择wav格式却可以正常生成 wav 文件。
经测试发现需要重新编译 pjsip 工程,加入 mp3 编码才可以。
操作步骤大概如下:
//...
#include
#include
#include
//增加mp3编码 [2022-7-28 By Pafey]
#include "../../third_party/mp3/mp3_port.h"
//...
在录音格式判断那里,源码只有处理wav格式,需要多加个mp3格式进去。
需要注意的是第七个参数 pjmedia_mp3_encoder_option param_option;
主要是跟mp3文件的质量有关:
vbr:指定是否应使用可变比特率。可变比特率通常会产生更好的质量,但代价可能是文件更大。
bit_rate:目标比特率,单位为bps。如果启用了VBR,此设置指定请求的平均比特率,并将使编码器忽略质量设置。对于CBR,这指定了实际的比特率,如果该选项为零,它将被设置为采样率乘以通道数量。
quality:编码质量,0-9,以0为最高质量。对于VBR,质量设置只在bit_rate设置为零时生效。
if (file_format == FMT_WAV) {
status = pjmedia_wav_writer_port_create(pool, path,
pjsua_var.media_cfg.clock_rate,
pjsua_var.mconf_cfg.channel_count,
pjsua_var.mconf_cfg.samples_per_frame,
pjsua_var.mconf_cfg.bits_per_sample,
options, 0, &port);
}
else if (file_format == FMT_MP3)
{
//增加mp3编码 [2022-7-28 By Pafey]
pjmedia_mp3_encoder_option param_option;
param_option.vbr = PJ_TRUE;
param_option.bit_rate = 0;
param_option.quality = 6;//0-9,0质量最高,vbr启用时,仅bit_rate为0时有效
status = pjmedia_mp3_writer_port_create(pool, path,
pjsua_var.media_cfg.clock_rate,
pjsua_var.mconf_cfg.channel_count,
pjsua_var.mconf_cfg.samples_per_frame,
pjsua_var.mconf_cfg.bits_per_sample,
¶m_option, &port);
} else {
PJ_UNUSED_ARG(enc_param);
port = NULL;
status = PJ_ENOTSUP;
}
/*
* Create a file recorder, and automatically connect this recorder to
* the conference bridge.
*/
PJ_DEF(pj_status_t) pjsua_recorder_create( const pj_str_t *filename,
unsigned enc_type,
void *enc_param,
pj_ssize_t max_size,
unsigned options,
pjsua_recorder_id *p_id)
{
enum Format
{
FMT_UNKNOWN,
FMT_WAV,
FMT_MP3,
};
unsigned slot, file_id;
char path[PJ_MAXPATH];
pj_str_t ext;
int file_format;
pj_pool_t *pool = NULL;
pjmedia_port *port;
pj_status_t status = PJ_SUCCESS;
/* Filename must present */
PJ_ASSERT_RETURN(filename != NULL, PJ_EINVAL);
/* Don't support max_size at present */
PJ_ASSERT_RETURN(max_size == 0 || max_size == -1, PJ_EINVAL);
/* Don't support encoding type at present */
PJ_ASSERT_RETURN(enc_type == 0, PJ_EINVAL);
if (filename->slen >= PJ_MAXPATH)
return PJ_ENAMETOOLONG;
if (filename->slen < 4)
return PJ_EINVALIDOP;
PJ_LOG(4,(THIS_FILE, "Creating recorder %.*s..",
(int)filename->slen, filename->ptr));
pj_log_push_indent();
if (pjsua_var.rec_cnt >= PJ_ARRAY_SIZE(pjsua_var.recorder)) {
pj_log_pop_indent();
return PJ_ETOOMANY;
}
/* Determine the file format */
ext.ptr = filename->ptr + filename->slen - 4;
ext.slen = 4;
if (pj_stricmp2(&ext, ".wav") == 0)
file_format = FMT_WAV;
else if (pj_stricmp2(&ext, ".mp3") == 0)
file_format = FMT_MP3;
else {
PJ_LOG(1,(THIS_FILE, "pjsua_recorder_create() error: unable to "
"determine file format for %.*s",
(int)filename->slen, filename->ptr));
pj_log_pop_indent();
return PJ_ENOTSUP;
}
PJSUA_LOCK();
for (file_id=0; file_id<PJ_ARRAY_SIZE(pjsua_var.recorder); ++file_id) {
if (pjsua_var.recorder[file_id].port == NULL)
break;
}
if (file_id == PJ_ARRAY_SIZE(pjsua_var.recorder)) {
/* This is unexpected */
pj_assert(0);
status = PJ_EBUG;
goto on_return;
}
pj_memcpy(path, filename->ptr, filename->slen);
path[filename->slen] = '\0';
pool = pjsua_pool_create(get_basename(path, (unsigned)filename->slen), 1000,
1000);
if (!pool) {
status = PJ_ENOMEM;
goto on_return;
}
if (file_format == FMT_WAV) {
status = pjmedia_wav_writer_port_create(pool, path,
pjsua_var.media_cfg.clock_rate,
pjsua_var.mconf_cfg.channel_count,
pjsua_var.mconf_cfg.samples_per_frame,
pjsua_var.mconf_cfg.bits_per_sample,
options, 0, &port);
}else if (file_format == FMT_MP3)
{
pjmedia_mp3_encoder_option param_option;
param_option.vbr = PJ_TRUE;
param_option.bit_rate = 0;
param_option.quality = 6;//0-9,0质量最高,vbr启用时,仅bit_rate为0时有效
//增加mp3编码 [2022-7-28 By Pafey]
status = pjmedia_mp3_writer_port_create(pool, path,
pjsua_var.media_cfg.clock_rate,
pjsua_var.mconf_cfg.channel_count,
pjsua_var.mconf_cfg.samples_per_frame,
pjsua_var.mconf_cfg.bits_per_sample,
¶m_option, &port);
} else {
PJ_UNUSED_ARG(enc_param);
port = NULL;
status = PJ_ENOTSUP;
}
if (status != PJ_SUCCESS) {
pjsua_perror(THIS_FILE, "Unable to open file for recording", status);
goto on_return;
}
status = pjmedia_conf_add_port(pjsua_var.mconf, pool,
port, filename, &slot);
if (status != PJ_SUCCESS) {
pjmedia_port_destroy(port);
goto on_return;
}
pjsua_var.recorder[file_id].port = port;
pjsua_var.recorder[file_id].slot = slot;
pjsua_var.recorder[file_id].pool = pool;
if (p_id) *p_id = file_id;
++pjsua_var.rec_cnt;
PJSUA_UNLOCK();
PJ_LOG(4,(THIS_FILE, "Recorder created, id=%d, slot=%d", file_id, slot));
pj_log_pop_indent();
return PJ_SUCCESS;
on_return:
PJSUA_UNLOCK();
if (pool) pj_pool_release(pool);
pj_log_pop_indent();
return status;
}
生成 libpjproject-i386-Win32-vc14-Release.lib 库文件。就可以被sip软电话引入使用了。我这里用的是MicroSip,在配置界面录音选择 mp3
打个电话就可以生成mp3文件了,搞了一天终于完美收工。
pjsip编译完成后,引入库文件依然不能生成mp3文件,后面调试进
pjmedia_mp3_writer_port_create -> init_blade_dll
这个初始化需要加载 LAME_ENC.DLL
去 microsip 安装文件夹内拷一个出来放到自己编译的microsip exe所在路径就成功了
文末放了下载地址
#include
#define DLL_NAME PJ_T("LAME_ENC.DLL")
/*
* Load BladeEncoder DLL.
*/
static pj_status_t init_blade_dll(void)
{
if (BladeDLL.refCount == 0) {
#define GET_PROC(type, name) \
BladeDLL.name = (type)GetProcAddress(BladeDLL.hModule, PJ_T(#name)); \
if (BladeDLL.name == NULL) { \
PJ_LOG(1,(THIS_FILE, "Unable to find %s in %s", #name, DLL_NAME)); \
return PJ_RETURN_OS_ERROR(GetLastError()); \
}
BE_VERSION beVersion;
BladeDLL.hModule = (void*)LoadLibrary(DLL_NAME);
if (BladeDLL.hModule == NULL) {
pj_status_t status = PJ_RETURN_OS_ERROR(GetLastError());
char errmsg[PJ_ERR_MSG_SIZE];
pj_strerror(status, errmsg, sizeof(errmsg));
PJ_LOG(1,(THIS_FILE, "Unable to load %s: %s", DLL_NAME, errmsg));
return status;
}
//...
}