📄 pjsua_media.c
字号:
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));
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 */
PJSUA_UNLOCK();
pj_assert(0);
return PJ_EBUG;
}
pj_memcpy(path, filename->ptr, filename->slen);
path[filename->slen] = '\0';
if (file_format == FMT_WAV) {
status = pjmedia_wav_writer_port_create(pjsua_var.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) {
status = pjmedia_mp3_writer_port_create(pjsua_var.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,
enc_param, &port);
} else {
port = NULL;
status = PJ_ENOTSUP;
}
if (status != PJ_SUCCESS) {
PJSUA_UNLOCK();
pjsua_perror(THIS_FILE, "Unable to open file for recording", status);
return status;
}
status = pjmedia_conf_add_port(pjsua_var.mconf, pjsua_var.pool,
port, filename, &slot);
if (status != PJ_SUCCESS) {
pjmedia_port_destroy(port);
PJSUA_UNLOCK();
return status;
}
pjsua_var.recorder[file_id].port = port;
pjsua_var.recorder[file_id].slot = slot;
if (p_id) *p_id = file_id;
++pjsua_var.rec_cnt;
PJSUA_UNLOCK();
return PJ_SUCCESS;
}
/*
* Get conference port associated with recorder.
*/
PJ_DEF(pjsua_conf_port_id) pjsua_recorder_get_conf_port(pjsua_recorder_id id)
{
PJ_ASSERT_RETURN(id>=0 && id<PJ_ARRAY_SIZE(pjsua_var.recorder), PJ_EINVAL);
PJ_ASSERT_RETURN(pjsua_var.recorder[id].port != NULL, PJ_EINVAL);
return pjsua_var.recorder[id].slot;
}
/*
* Get the media port for the recorder.
*/
PJ_DEF(pj_status_t) pjsua_recorder_get_port( pjsua_recorder_id id,
pjmedia_port **p_port)
{
PJ_ASSERT_RETURN(id>=0 && id<PJ_ARRAY_SIZE(pjsua_var.recorder), PJ_EINVAL);
PJ_ASSERT_RETURN(pjsua_var.recorder[id].port != NULL, PJ_EINVAL);
PJ_ASSERT_RETURN(p_port != NULL, PJ_EINVAL);
*p_port = pjsua_var.recorder[id].port;
return PJ_SUCCESS;
}
/*
* Destroy recorder (this will complete recording).
*/
PJ_DEF(pj_status_t) pjsua_recorder_destroy(pjsua_recorder_id id)
{
PJ_ASSERT_RETURN(id>=0 && id<PJ_ARRAY_SIZE(pjsua_var.recorder), PJ_EINVAL);
PJ_ASSERT_RETURN(pjsua_var.recorder[id].port != NULL, PJ_EINVAL);
PJSUA_LOCK();
if (pjsua_var.recorder[id].port) {
pjmedia_conf_remove_port(pjsua_var.mconf,
pjsua_var.recorder[id].slot);
pjmedia_port_destroy(pjsua_var.recorder[id].port);
pjsua_var.recorder[id].port = NULL;
pjsua_var.recorder[id].slot = 0xFFFF;
pjsua_var.rec_cnt--;
}
PJSUA_UNLOCK();
return PJ_SUCCESS;
}
/*****************************************************************************
* Sound devices.
*/
/*
* Enum sound devices.
*/
PJ_DEF(pj_status_t) pjsua_enum_snd_devs( pjmedia_snd_dev_info info[],
unsigned *count)
{
unsigned i, dev_count;
dev_count = pjmedia_snd_get_dev_count();
if (dev_count > *count) dev_count = *count;
for (i=0; i<dev_count; ++i) {
const pjmedia_snd_dev_info *ci;
ci = pjmedia_snd_get_dev_info(i);
pj_memcpy(&info[i], ci, sizeof(*ci));
}
*count = dev_count;
return PJ_SUCCESS;
}
/* Close existing sound device */
static void close_snd_dev(void)
{
/* Close sound device */
if (pjsua_var.snd_port) {
const pjmedia_snd_dev_info *cap_info, *play_info;
cap_info = pjmedia_snd_get_dev_info(pjsua_var.cap_dev);
play_info = pjmedia_snd_get_dev_info(pjsua_var.play_dev);
PJ_LOG(4,(THIS_FILE, "Closing %s sound playback device and "
"%s sound capture device",
play_info->name, cap_info->name));
pjmedia_snd_port_disconnect(pjsua_var.snd_port);
pjmedia_snd_port_destroy(pjsua_var.snd_port);
pjsua_var.snd_port = NULL;
}
/* Close null sound device */
if (pjsua_var.null_snd) {
PJ_LOG(4,(THIS_FILE, "Closing null sound device.."));
pjmedia_master_port_destroy(pjsua_var.null_snd, PJ_FALSE);
pjsua_var.null_snd = NULL;
}
}
/*
* Select or change sound device. Application may call this function at
* any time to replace current sound device.
*/
PJ_DEF(pj_status_t) pjsua_set_snd_dev( int capture_dev,
int playback_dev)
{
pjmedia_port *conf_port;
const pjmedia_snd_dev_info *play_info;
unsigned clock_rates[] = { 0, 22050, 44100, 48000, 11025, 32000, 8000};
unsigned selected_clock_rate = 0;
unsigned i;
pjmedia_snd_stream *strm;
pjmedia_snd_stream_info si;
pj_str_t tmp;
pj_status_t status = -1;
/* Close existing sound port */
close_snd_dev();
/* Set default clock rate */
clock_rates[0] = pjsua_var.media_cfg.clock_rate;
/* Attempts to open the sound device with different clock rates */
for (i=0; i<PJ_ARRAY_SIZE(clock_rates); ++i) {
char errmsg[PJ_ERR_MSG_SIZE];
PJ_LOG(4,(THIS_FILE,
"pjsua_set_snd_dev(): attempting to open devices "
"@%d Hz", clock_rates[i]));
/* Create the sound device. Sound port will start immediately. */
status = pjmedia_snd_port_create(pjsua_var.pool, capture_dev,
playback_dev,
clock_rates[i], 1,
clock_rates[i]/FPS,
16, 0, &pjsua_var.snd_port);
if (status == PJ_SUCCESS) {
selected_clock_rate = clock_rates[i];
break;
}
pj_strerror(status, errmsg, sizeof(errmsg));
PJ_LOG(4, (THIS_FILE, "..failed: %s", errmsg));
}
if (status != PJ_SUCCESS) {
pjsua_perror(THIS_FILE, "Unable to open sound device", status);
return status;
}
/* Get the port0 of the conference bridge. */
conf_port = pjmedia_conf_get_master_port(pjsua_var.mconf);
pj_assert(conf_port != NULL);
/* Set AEC */
pjmedia_snd_port_set_ec( pjsua_var.snd_port, pjsua_var.pool,
pjsua_var.media_cfg.ec_tail_len,
pjsua_var.media_cfg.ec_options);
/* If there's mismatch between sound port and conference's port,
* create a resample port to bridge them.
*/
if (selected_clock_rate != pjsua_var.media_cfg.clock_rate) {
pjmedia_port *resample_port;
status = pjmedia_resample_port_create(pjsua_var.pool, conf_port,
selected_clock_rate, 0,
&resample_port);
if (status != PJ_SUCCESS) {
pjsua_perror("Error creating resample port", THIS_FILE, status);
return status;
}
conf_port = resample_port;
}
/* Connect sound port to the bridge */
status = pjmedia_snd_port_connect(pjsua_var.snd_port,
conf_port );
if (status != PJ_SUCCESS) {
pjsua_perror(THIS_FILE, "Unable to connect conference port to "
"sound device", status);
pjmedia_snd_port_destroy(pjsua_var.snd_port);
pjsua_var.snd_port = NULL;
return status;
}
/* Save the device IDs */
pjsua_var.cap_dev = capture_dev;
pjsua_var.play_dev = playback_dev;
/* Update sound device name. */
strm = pjmedia_snd_port_get_snd_stream(pjsua_var.snd_port);
pjmedia_snd_stream_get_info(strm, &si);
play_info = pjmedia_snd_get_dev_info(si.rec_id);
pjmedia_conf_set_port0_name(pjsua_var.mconf,
pj_cstr(&tmp, play_info->name));
return PJ_SUCCESS;
}
/*
* Get currently active sound devices. If sound devices has not been created
* (for example when pjsua_start() is not called), it is possible that
* the function returns PJ_SUCCESS with -1 as device IDs.
*/
PJ_DEF(pj_status_t) pjsua_get_snd_dev(int *capture_dev,
int *playback_dev)
{
if (capture_dev) {
*capture_dev = pjsua_var.cap_dev;
}
if (playback_dev) {
*playback_dev = pjsua_var.play_dev;
}
return PJ_SUCCESS;
}
/*
* Use null sound device.
*/
PJ_DEF(pj_status_t) pjsua_set_null_snd_dev(void)
{
pjmedia_port *conf_port;
pj_status_t status;
/* Close existing sound device */
close_snd_dev();
PJ_LOG(4,(THIS_FILE, "Opening null sound device.."));
/* Get the port0 of the conference bridge. */
conf_port = pjmedia_conf_get_master_port(pjsua_var.mconf);
pj_assert(conf_port != NULL);
/* Create master port, connecting port0 of the conference bridge to
* a null port.
*/
status = pjmedia_master_port_create(pjsua_var.pool, pjsua_var.null_port,
conf_port, 0, &pjsua_var.null_snd);
if (status != PJ_SUCCESS) {
pjsua_perror(THIS_FILE, "Unable to create null sound device",
status);
return status;
}
/* Start the master port */
status = pjmedia_master_port_start(pjsua_var.null_snd);
PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
return PJ_SUCCESS;
}
/*
* Use no device!
*/
PJ_DEF(pjmedia_port*) pjsua_set_no_snd_dev(void)
{
/* Close existing sound device */
close_snd_dev();
pjsua_var.no_snd = PJ_TRUE;
return pjmedia_conf_get_master_port(pjsua_var.mconf);
}
/*
* Configure the AEC settings of the sound port.
*/
PJ_DEF(pj_status_t) pjsua_set_ec(unsigned tail_ms, unsigned options)
{
pjsua_var.media_cfg.ec_tail_len = tail_ms;
if (pjsua_var.snd_port)
return pjmedia_snd_port_set_ec( pjsua_var.snd_port, pjsua_var.pool,
tail_ms, options);
return PJ_SUCCESS;
}
/*
* Get current AEC tail length.
*/
PJ_DEF(pj_status_t) pjsua_get_ec_tail(unsigned *p_tail_ms)
{
*p_tail_ms = pjsua_var.media_cfg.ec_tail_len;
return PJ_SUCCESS;
}
/*****************************************************************************
* Codecs.
*/
/*
* Enum all supported codecs in the system.
*/
PJ_DEF(pj_status_t) pjsua_enum_codecs( pjsua_codec_info id[],
unsigned *p_count )
{
pjmedia_codec_mgr *codec_mgr;
pjmedia_codec_info info[32];
unsigned i, count, prio[32];
pj_status_t status;
codec_mgr = pjmedia_endpt_get_codec_mgr(pjsua_var.med_endpt);
count = PJ_ARRAY_SIZE(info);
status = pjmedia_codec_mgr_enum_codecs( codec_mgr, &count, info, prio);
if (status != PJ_SUCCESS) {
*p_count = 0;
return status;
}
if (count > *p_count) count = *p_count;
for (i=0; i<count; ++i) {
pjmedia_codec_info_to_id(&info[i], id[i].buf_, sizeof(id[i].buf_));
id[i].codec_id = pj_str(id[i].buf_);
id[i].priority = (pj_uint8_t) prio[i];
}
*p_count = count;
return PJ_SUCCESS;
}
/*
* Change codec priority.
*/
PJ_DEF(pj_status_t) pjsua_codec_set_priority( const pj_str_t *codec_id,
pj_uint8_t priority )
{
pjmedia_codec_mgr *codec_mgr;
codec_mgr = pjmedia_endpt_get_codec_mgr(pjsua_var.med_endpt);
return pjmedia_codec_mgr_set_codec_priority(codec_mgr, codec_id,
priority);
}
/*
* Get codec parameters.
*/
PJ_DEF(pj_status_t) pjsua_codec_get_param( const pj_str_t *codec_id,
pjmedia_codec_param *param )
{
const pjmedia_codec_info *info;
pjmedia_codec_mgr *codec_mgr;
unsigned count = 1;
pj_status_t status;
codec_mgr = pjmedia_endpt_get_codec_mgr(pjsua_var.med_endpt);
status = pjmedia_codec_mgr_find_codecs_by_id(codec_mgr, codec_id,
&count, &info, NULL);
if (status != PJ_SUCCESS)
return status;
if (count != 1)
return PJ_ENOTFOUND;
status = pjmedia_codec_mgr_get_default_param( codec_mgr, info, param);
return status;
}
/*
* Set codec parameters.
*/
PJ_DEF(pj_status_t) pjsua_codec_set_param( const pj_str_t *id,
const pjmedia_codec_param *param)
{
PJ_UNUSED_ARG(id);
PJ_UNUSED_ARG(param);
PJ_TODO(set_codec_param);
return PJ_SUCCESS;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -