BIG refactoring in pjsua_media.c:
- switchboard/conf detection is done at run-time, removing #ifdefs - use one function, open_snd_dev() to open device - use one function, create_aud_param() to initialize audio parameters: - get the default from device - override with user settings previously done with pjsua_snd_set_setting() (new API) - added new API to set/get sound device settings. The settings are semi permanent, it will be used for future opening of sound dev: - pjsua_snd_set_setting() - pjsua_snd_get_setting() - snd_auto_close_time default value changed to 1 (from -1) - both pjsua_enum_snd_devs() and pjsua_enum_aud_devs() API are now supported (previously it was done with #ifdef). - make_call() will not open the sound device is switchboard is used git-svn-id: https://svn.pjsip.org/repos/pjproject/branches/projects/aps-direct@2493 74dad513-b988-da41-8d7b-12977e46ad98
This commit is contained in:
parent
7a380009f1
commit
f798e5042e
|
@ -4286,9 +4286,10 @@ struct pjsua_media_config
|
|||
|
||||
/**
|
||||
* Specify idle time of sound device before it is automatically closed,
|
||||
* in seconds.
|
||||
* in seconds. Use value -1 to disable the auto-close feature of sound
|
||||
* device
|
||||
*
|
||||
* Default : -1 (Disable the auto-close feature of sound device)
|
||||
* Default : 1
|
||||
*/
|
||||
int snd_auto_close_time;
|
||||
};
|
||||
|
@ -4801,7 +4802,20 @@ PJ_DECL(pj_status_t) pjsua_recorder_destroy(pjsua_recorder_id id);
|
|||
*/
|
||||
|
||||
/**
|
||||
* Enum all sound devices installed in the system.
|
||||
* Enum all audio devices installed in the system.
|
||||
*
|
||||
* @param info Array of info to be initialized.
|
||||
* @param count On input, specifies max elements in the array.
|
||||
* On return, it contains actual number of elements
|
||||
* that have been initialized.
|
||||
*
|
||||
* @return PJ_SUCCESS on success, or the appropriate error code.
|
||||
*/
|
||||
PJ_DECL(pj_status_t) pjsua_enum_aud_devs(pjmedia_aud_dev_info info[],
|
||||
unsigned *count);
|
||||
|
||||
/**
|
||||
* Enum all sound devices installed in the system (old API).
|
||||
*
|
||||
* @param info Array of info to be initialized.
|
||||
* @param count On input, specifies max elements in the array.
|
||||
|
@ -4818,14 +4832,8 @@ PJ_DECL(pj_status_t) pjsua_recorder_destroy(pjsua_recorder_id id);
|
|||
* \endcode
|
||||
*
|
||||
*/
|
||||
#if PJMEDIA_AUDIO_API==PJMEDIA_AUDIO_API_NEW_ONLY
|
||||
PJ_DECL(pj_status_t) pjsua_enum_snd_devs(pjmedia_aud_dev_info info[],
|
||||
unsigned *count);
|
||||
#else
|
||||
PJ_DECL(pj_status_t) pjsua_enum_snd_devs(pjmedia_snd_dev_info info[],
|
||||
unsigned *count);
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* Get currently active sound devices. If sound devices has not been created
|
||||
|
@ -4897,9 +4905,12 @@ PJ_DECL(pjmedia_port*) pjsua_set_no_snd_dev(void);
|
|||
|
||||
|
||||
/**
|
||||
* Change the echo cancellation settings. The behavior of this function
|
||||
* depends on whether the sound device is currently active, and if it is,
|
||||
* whether device or software AEC is being used.
|
||||
* Change the echo cancellation settings. Application may also use the
|
||||
* #pjsua_snd_set_setting() to retrieve the echo cancellation setting.
|
||||
*
|
||||
* The behavior of this function depends on whether the sound device is
|
||||
* currently active, and if it is, whether device or software AEC is
|
||||
* being used.
|
||||
*
|
||||
* If the sound device is currently active, and if the device supports AEC,
|
||||
* this function will forward the change request to the device and it will
|
||||
|
@ -4928,7 +4939,8 @@ PJ_DECL(pj_status_t) pjsua_set_ec(unsigned tail_ms, unsigned options);
|
|||
|
||||
|
||||
/**
|
||||
* Get current echo canceller tail length.
|
||||
* Get current echo canceller tail length. Application may also use the
|
||||
* #pjsua_snd_set_setting() to retrieve the echo cancellation setting.
|
||||
*
|
||||
* @param p_tail_ms Pointer to receive the tail length, in miliseconds.
|
||||
* If AEC is disabled, the value will be zero.
|
||||
|
@ -4944,12 +4956,61 @@ PJ_DECL(pj_status_t) pjsua_get_ec_tail(unsigned *p_tail_ms);
|
|||
|
||||
|
||||
/**
|
||||
* Get active audio device stream instance.
|
||||
*
|
||||
* @return Audio device stream instance if any, otherwise
|
||||
* NULL will be returned.
|
||||
* Check whether the sound device is currently active. The sound device
|
||||
* may be inactive if the application has set the auto close feature to
|
||||
* non-zero (the snd_auto_close_time setting in #pjsua_media_config), or
|
||||
* if null sound device or no sound device has been configured via the
|
||||
* #pjsua_set_no_snd_dev() function.
|
||||
*/
|
||||
PJ_DECL(pjmedia_aud_stream*) pjsua_get_aud_stream();
|
||||
PJ_DECL(pj_bool_t) pjsua_snd_is_active(void);
|
||||
|
||||
|
||||
/**
|
||||
* Configure sound device setting to the sound device being used. If sound
|
||||
* device is currently active, the function will forward the setting to the
|
||||
* sound device instance to be applied immediately, if it supports it.
|
||||
*
|
||||
* The setting will be saved for future opening of the sound device, if the
|
||||
* "keep" argument is set to non-zero. If the sound device is currently
|
||||
* inactive, and the "keep" argument is false, this function will return
|
||||
* error.
|
||||
*
|
||||
* Note that in case the setting is kept for future use, it will be applied
|
||||
* to any devices, even when application has changed the sound device to be
|
||||
* used.
|
||||
*
|
||||
* See also #pjmedia_aud_stream_set_cap() for more information about setting
|
||||
* an audio device capability.
|
||||
*
|
||||
* @param cap The sound device setting to change.
|
||||
* @param pval Pointer to value. Please see #pjmedia_aud_dev_cap
|
||||
* documentation about the type of value to be
|
||||
* supplied for each setting.
|
||||
* @param keep Specify whether the setting is to be kept for future
|
||||
* use.
|
||||
*
|
||||
* @return PJ_SUCCESS on success or the appropriate error code.
|
||||
*/
|
||||
PJ_DECL(pj_status_t) pjsua_snd_set_setting(pjmedia_aud_dev_cap cap,
|
||||
const void *pval,
|
||||
pj_bool_t keep);
|
||||
|
||||
/**
|
||||
* Retrieve a sound device setting. If sound device is currently active,
|
||||
* the function will forward the request to the sound device. If sound device
|
||||
* is currently inactive, and if application had previously set the setting
|
||||
* and mark the setting as kept, then that setting will be returned.
|
||||
* Otherwise, this function will return error.
|
||||
*
|
||||
* @param cap The sound device setting to retrieve.
|
||||
* @param pval Pointer to receive the value.
|
||||
* Please see #pjmedia_aud_dev_cap documentation about
|
||||
* the type of value to be supplied for each setting.
|
||||
*
|
||||
* @return PJ_SUCCESS on success or the appropriate error code.
|
||||
*/
|
||||
PJ_DECL(pj_status_t) pjsua_snd_get_setting(pjmedia_aud_dev_cap cap,
|
||||
void *pval);
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
|
|
|
@ -272,8 +272,15 @@ struct pjsua_data
|
|||
pjmedia_endpt *med_endpt; /**< Media endpoint. */
|
||||
pjsua_conf_setting mconf_cfg; /**< Additionan conf. bridge. param */
|
||||
pjmedia_conf *mconf; /**< Conference bridge. */
|
||||
int cap_dev; /**< Capture device ID. */
|
||||
int play_dev; /**< Playback device ID. */
|
||||
pj_bool_t is_mswitch;/**< Are we using audio switchboard
|
||||
(a.k.a APS-Direct) */
|
||||
|
||||
/* Sound device */
|
||||
pjmedia_aud_dev_index cap_dev; /**< Capture device ID. */
|
||||
pjmedia_aud_dev_index play_dev; /**< Playback device ID. */
|
||||
pj_uint32_t aud_svmask;/**< Which settings to save */
|
||||
pjmedia_aud_param aud_param; /**< User settings to sound dev */
|
||||
pj_bool_t aud_open_cnt;/**< How many # device is opened */
|
||||
pj_bool_t no_snd; /**< No sound (app will manage it) */
|
||||
pj_pool_t *snd_pool; /**< Sound's private pool. */
|
||||
pjmedia_snd_port *snd_port; /**< Sound port. */
|
||||
|
|
|
@ -370,9 +370,13 @@ PJ_DEF(pj_status_t) pjsua_call_make_call( pjsua_acc_id acc_id,
|
|||
|
||||
PJSUA_LOCK();
|
||||
|
||||
/* Create sound port if none is instantiated */
|
||||
if (pjsua_var.snd_port==NULL && pjsua_var.null_snd==NULL &&
|
||||
!pjsua_var.no_snd)
|
||||
/* Create sound port if none is instantiated, to check if sound device
|
||||
* can be used. But only do this with the conference bridge, as with
|
||||
* audio switchboard (i.e. APS-Direct), we can only open the sound
|
||||
* device once the correct format has been known
|
||||
*/
|
||||
if (!pjsua_var.is_mswitch && pjsua_var.snd_port==NULL &&
|
||||
pjsua_var.null_snd==NULL && !pjsua_var.no_snd)
|
||||
{
|
||||
pj_status_t status;
|
||||
|
||||
|
|
|
@ -180,7 +180,7 @@ PJ_DEF(void) pjsua_media_config_default(pjsua_media_config *cfg)
|
|||
cfg->snd_rec_latency = PJMEDIA_SND_DEFAULT_REC_LATENCY;
|
||||
cfg->snd_play_latency = PJMEDIA_SND_DEFAULT_PLAY_LATENCY;
|
||||
cfg->jb_init = cfg->jb_min_pre = cfg->jb_max_pre = cfg->jb_max = -1;
|
||||
cfg->snd_auto_close_time = -1;
|
||||
cfg->snd_auto_close_time = 1;
|
||||
|
||||
cfg->turn_conn_type = PJ_TURN_TP_UDP;
|
||||
}
|
||||
|
|
|
@ -35,8 +35,18 @@
|
|||
/* Next RTP port to be used */
|
||||
static pj_uint16_t next_rtp_port;
|
||||
|
||||
/* Open sound dev */
|
||||
static pj_status_t open_snd_dev(pjmedia_aud_param *param);
|
||||
/* Close existing sound device */
|
||||
static void close_snd_dev(void);
|
||||
/* Create audio device param */
|
||||
static pj_status_t create_aud_param(pjmedia_aud_param *param,
|
||||
pjmedia_aud_dev_index capture_dev,
|
||||
pjmedia_aud_dev_index playback_dev,
|
||||
unsigned clock_rate,
|
||||
unsigned channel_count,
|
||||
unsigned samples_per_frame,
|
||||
unsigned bits_per_sample);
|
||||
|
||||
|
||||
static void pjsua_media_config_dup(pj_pool_t *pool,
|
||||
|
@ -60,6 +70,13 @@ pj_status_t pjsua_media_subsys_init(const pjsua_media_config *cfg)
|
|||
/* To suppress warning about unused var when all codecs are disabled */
|
||||
PJ_UNUSED_ARG(codec_id);
|
||||
|
||||
/* Specify which audio device settings are save-able */
|
||||
pjsua_var.aud_svmask = 0xFFFFFFFF;
|
||||
/* These are not-settable */
|
||||
pjsua_var.aud_svmask &= ~(PJMEDIA_AUD_DEV_CAP_EXT_FORMAT |
|
||||
PJMEDIA_AUD_DEV_CAP_INPUT_SIGNAL_METER |
|
||||
PJMEDIA_AUD_DEV_CAP_OUTPUT_SIGNAL_METER);
|
||||
|
||||
/* Copy configuration */
|
||||
pjsua_media_config_dup(pjsua_var.pool, &pjsua_var.media_cfg, cfg);
|
||||
|
||||
|
@ -236,6 +253,10 @@ pj_status_t pjsua_media_subsys_init(const pjsua_media_config *cfg)
|
|||
return status;
|
||||
}
|
||||
|
||||
/* Are we using the audio switchboard (a.k.a APS-Direct)? */
|
||||
pjsua_var.is_mswitch = pjmedia_conf_get_master_port(pjsua_var.mconf)
|
||||
->info.signature == PJMEDIA_CONF_SWITCH_SIGNATURE;
|
||||
|
||||
/* Create null port just in case user wants to use null sound. */
|
||||
status = pjmedia_null_port_create(pjsua_var.pool,
|
||||
pjsua_var.media_cfg.clock_rate,
|
||||
|
@ -1509,130 +1530,6 @@ pj_status_t pjsua_media_channel_update(pjsua_call_id call_id,
|
|||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
#if PJMEDIA_CONF_USE_SWITCH_BOARD
|
||||
|
||||
/*
|
||||
* Open sound device with extended setting.
|
||||
*/
|
||||
static pj_status_t open_snd_dev_ext(pjmedia_aud_param *param)
|
||||
{
|
||||
pjmedia_port *conf_port;
|
||||
pj_status_t status;
|
||||
|
||||
PJ_ASSERT_RETURN(param, PJ_EINVAL);
|
||||
|
||||
/* Check if NULL sound device is used */
|
||||
if (NULL_SND_DEV_ID==param->rec_id || NULL_SND_DEV_ID==param->play_id) {
|
||||
return pjsua_set_null_snd_dev();
|
||||
}
|
||||
|
||||
/* Close existing sound port */
|
||||
close_snd_dev();
|
||||
|
||||
/* Create memory pool for sound device. */
|
||||
pjsua_var.snd_pool = pjsua_pool_create("pjsua_snd", 4000, 4000);
|
||||
PJ_ASSERT_RETURN(pjsua_var.snd_pool, PJ_ENOMEM);
|
||||
|
||||
|
||||
/* Get the port0 of the conference bridge. */
|
||||
conf_port = pjmedia_conf_get_master_port(pjsua_var.mconf);
|
||||
pj_assert(conf_port != NULL);
|
||||
|
||||
PJ_LOG(4,(THIS_FILE, "Opening sound device @%d/%d/%s",
|
||||
param->clock_rate, param->channel_count,
|
||||
(param->ext_fmt.id==PJMEDIA_FORMAT_L16?"pcm":"encoded")));
|
||||
|
||||
status = pjmedia_snd_port_create2( pjsua_var.snd_pool,
|
||||
param, &pjsua_var.snd_port);
|
||||
|
||||
/* Update port 0 info when sound dev opened successfully. */
|
||||
if (status == PJ_SUCCESS) {
|
||||
pj_memcpy(&conf_port->info.format, ¶m->ext_fmt,
|
||||
sizeof(conf_port->info.format));
|
||||
conf_port->info.clock_rate = param->clock_rate;
|
||||
conf_port->info.samples_per_frame = param->samples_per_frame;
|
||||
conf_port->info.channel_count = param->channel_count;
|
||||
conf_port->info.bits_per_sample = 16;
|
||||
} else {
|
||||
pjsua_perror(THIS_FILE, "Unable to open sound device", status);
|
||||
return status;
|
||||
}
|
||||
|
||||
/* 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 = param->rec_id;
|
||||
pjsua_var.play_dev = param->play_id;
|
||||
|
||||
/* Update sound device name. */
|
||||
{
|
||||
pjmedia_aud_dev_info play_info;
|
||||
pjmedia_aud_stream *strm;
|
||||
pjmedia_aud_param si;
|
||||
pj_str_t tmp;
|
||||
|
||||
strm = pjmedia_snd_port_get_snd_stream(pjsua_var.snd_port);
|
||||
pjmedia_aud_stream_get_param(strm, &si);
|
||||
if (pjmedia_aud_dev_get_info(si.play_id, &play_info)==PJ_SUCCESS) {
|
||||
pjmedia_conf_set_port0_name(pjsua_var.mconf,
|
||||
pj_cstr(&tmp, play_info.name));
|
||||
}
|
||||
};
|
||||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/* Close existing sound device */
|
||||
static void close_snd_dev(void)
|
||||
{
|
||||
/* Close sound device */
|
||||
if (pjsua_var.snd_port) {
|
||||
pjmedia_aud_dev_info cap_info, play_info;
|
||||
pjmedia_aud_stream *strm;
|
||||
pjmedia_aud_param param;
|
||||
|
||||
strm = pjmedia_snd_port_get_snd_stream(pjsua_var.snd_port);
|
||||
pjmedia_aud_stream_get_param(strm, ¶m);
|
||||
|
||||
if (pjmedia_aud_dev_get_info(param.rec_id, &cap_info) != PJ_SUCCESS)
|
||||
cap_info.name[0] = '\0';
|
||||
if (pjmedia_aud_dev_get_info(param.play_id, &play_info) != PJ_SUCCESS)
|
||||
play_info.name[0] = '\0';
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (pjsua_var.snd_pool)
|
||||
pj_pool_release(pjsua_var.snd_pool);
|
||||
pjsua_var.snd_pool = NULL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Get maxinum number of conference ports.
|
||||
*/
|
||||
|
@ -1747,14 +1644,14 @@ PJ_DEF(pj_status_t) pjsua_conf_connect( pjsua_conf_port_id source,
|
|||
pjsua_var.snd_idle_timer.id = PJ_FALSE;
|
||||
}
|
||||
|
||||
#if PJMEDIA_CONF_USE_SWITCH_BOARD
|
||||
|
||||
/* Check if sound device need to be reopened, i.e: its attributes
|
||||
/* For audio switchboard (i.e. APS-Direct):
|
||||
* Check if sound device need to be reopened, i.e: its attributes
|
||||
* (format, clock rate, channel count) must match to peer's.
|
||||
* Note that sound device can be reopened only if it doesn't have
|
||||
* any connection.
|
||||
*/
|
||||
do {
|
||||
if (pjsua_var.is_mswitch) {
|
||||
pjmedia_conf_port_info port0_info;
|
||||
pjmedia_conf_port_info peer_info;
|
||||
unsigned peer_id;
|
||||
|
@ -1789,64 +1686,44 @@ PJ_DEF(pj_status_t) pjsua_conf_connect( pjsua_conf_port_id source,
|
|||
if (need_reopen) {
|
||||
pjmedia_aud_param param;
|
||||
|
||||
status = pjmedia_aud_dev_default_param(pjsua_var.cap_dev, ¶m);
|
||||
if (status != PJ_SUCCESS) {
|
||||
pjsua_perror(THIS_FILE, "Error retrieving default audio "
|
||||
"device parameters", status);
|
||||
return status;
|
||||
/* Create parameter based on peer info */
|
||||
status = create_aud_param(¶m, pjsua_var.cap_dev,
|
||||
pjsua_var.play_dev,
|
||||
peer_info.clock_rate,
|
||||
peer_info.channel_count,
|
||||
peer_info.samples_per_frame,
|
||||
peer_info.bits_per_sample);
|
||||
|
||||
/* And peer format */
|
||||
if (peer_info.format.id != PJMEDIA_FORMAT_PCM) {
|
||||
param.flags |= PJMEDIA_AUD_DEV_CAP_EXT_FORMAT;
|
||||
param.ext_fmt = peer_info.format;
|
||||
}
|
||||
|
||||
param.dir = PJMEDIA_DIR_CAPTURE_PLAYBACK;
|
||||
param.rec_id = pjsua_var.cap_dev;
|
||||
param.play_id = pjsua_var.play_dev;
|
||||
param.clock_rate = peer_info.clock_rate;
|
||||
param.samples_per_frame = peer_info.samples_per_frame;
|
||||
param.channel_count = peer_info.channel_count;
|
||||
param.bits_per_sample = peer_info.bits_per_sample;
|
||||
/* Latency setting */
|
||||
param.flags |= (PJMEDIA_AUD_DEV_CAP_INPUT_LATENCY |
|
||||
PJMEDIA_AUD_DEV_CAP_OUTPUT_LATENCY);
|
||||
param.input_latency_ms = pjsua_var.media_cfg.snd_rec_latency;
|
||||
param.output_latency_ms = pjsua_var.media_cfg.snd_play_latency;
|
||||
/* EC settings */
|
||||
if (pjsua_var.media_cfg.ec_tail_len) {
|
||||
param.flags |= (PJMEDIA_AUD_DEV_CAP_EC | PJMEDIA_AUD_DEV_CAP_EC_TAIL);
|
||||
param.ec_enabled = PJ_TRUE;
|
||||
param.ec_tail_ms = pjsua_var.media_cfg.ec_tail_len;
|
||||
} else {
|
||||
param.flags &= ~(PJMEDIA_AUD_DEV_CAP_EC | PJMEDIA_AUD_DEV_CAP_EC_TAIL);
|
||||
}
|
||||
/* Format */
|
||||
param.flags |= (PJMEDIA_AUD_DEV_CAP_EXT_FORMAT |
|
||||
PJMEDIA_AUD_DEV_CAP_OUTPUT_ROUTE);
|
||||
param.ext_fmt = peer_info.format;
|
||||
//param.plc = PJ_FALSE;
|
||||
param.out_route = PJMEDIA_AUD_DEV_ROUTE_DEFAULT;
|
||||
|
||||
status = open_snd_dev_ext(¶m);
|
||||
status = open_snd_dev(¶m);
|
||||
if (status != PJ_SUCCESS) {
|
||||
pjsua_perror(THIS_FILE, "Error opening sound device", status);
|
||||
return status;
|
||||
}
|
||||
}
|
||||
} while(0);
|
||||
|
||||
#else
|
||||
} else {
|
||||
/* The bridge version */
|
||||
|
||||
/* Create sound port if none is instantiated */
|
||||
if (pjsua_var.snd_port==NULL && pjsua_var.null_snd==NULL &&
|
||||
!pjsua_var.no_snd)
|
||||
{
|
||||
pj_status_t status;
|
||||
/* Create sound port if none is instantiated */
|
||||
if (pjsua_var.snd_port==NULL && pjsua_var.null_snd==NULL &&
|
||||
!pjsua_var.no_snd)
|
||||
{
|
||||
pj_status_t status;
|
||||
|
||||
status = pjsua_set_snd_dev(pjsua_var.cap_dev, pjsua_var.play_dev);
|
||||
if (status != PJ_SUCCESS) {
|
||||
pjsua_perror(THIS_FILE, "Error opening sound device", status);
|
||||
return status;
|
||||
status = pjsua_set_snd_dev(pjsua_var.cap_dev, pjsua_var.play_dev);
|
||||
if (status != PJ_SUCCESS) {
|
||||
pjsua_perror(THIS_FILE, "Error opening sound device", status);
|
||||
return status;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
return pjmedia_conf_connect_port(pjsua_var.mconf, source, sink, 0);
|
||||
}
|
||||
|
@ -2322,8 +2199,8 @@ PJ_DEF(pj_status_t) pjsua_recorder_destroy(pjsua_recorder_id id)
|
|||
/*
|
||||
* Enum sound devices.
|
||||
*/
|
||||
#if PJMEDIA_AUDIO_API==PJMEDIA_AUDIO_API_NEW_ONLY
|
||||
PJ_DEF(pj_status_t) pjsua_enum_snd_devs( pjmedia_aud_dev_info info[],
|
||||
|
||||
PJ_DEF(pj_status_t) pjsua_enum_aud_devs( pjmedia_aud_dev_info info[],
|
||||
unsigned *count)
|
||||
{
|
||||
unsigned i, dev_count;
|
||||
|
@ -2344,7 +2221,8 @@ PJ_DEF(pj_status_t) pjsua_enum_snd_devs( pjmedia_aud_dev_info info[],
|
|||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
#else /* PJMEDIA_AUDIO_API */
|
||||
|
||||
|
||||
PJ_DEF(pj_status_t) pjsua_enum_snd_devs( pjmedia_snd_dev_info info[],
|
||||
unsigned *count)
|
||||
{
|
||||
|
@ -2374,180 +2252,201 @@ PJ_DEF(pj_status_t) pjsua_enum_snd_devs( pjmedia_snd_dev_info info[],
|
|||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* 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)
|
||||
/* Create audio device parameter to open the device */
|
||||
static pj_status_t create_aud_param(pjmedia_aud_param *param,
|
||||
pjmedia_aud_dev_index capture_dev,
|
||||
pjmedia_aud_dev_index playback_dev,
|
||||
unsigned clock_rate,
|
||||
unsigned channel_count,
|
||||
unsigned samples_per_frame,
|
||||
unsigned bits_per_sample)
|
||||
{
|
||||
#if PJMEDIA_CONF_USE_SWITCH_BOARD
|
||||
|
||||
pjmedia_aud_param param;
|
||||
pj_status_t status;
|
||||
|
||||
/* Create default parameters for the device */
|
||||
status = pjmedia_aud_dev_default_param(capture_dev, ¶m);
|
||||
if (status != PJ_SUCCESS) {
|
||||
pjsua_perror(THIS_FILE, "Error retrieving default audio "
|
||||
"device parameters", status);
|
||||
return status;
|
||||
}
|
||||
param.dir = PJMEDIA_DIR_CAPTURE_PLAYBACK;
|
||||
param.rec_id = capture_dev;
|
||||
param.play_id = playback_dev;
|
||||
param.channel_count = pjsua_var.media_cfg.channel_count;
|
||||
/* Latency settings */
|
||||
param.flags |= (PJMEDIA_AUD_DEV_CAP_INPUT_LATENCY |
|
||||
PJMEDIA_AUD_DEV_CAP_OUTPUT_LATENCY);
|
||||
param.input_latency_ms = pjsua_var.media_cfg.snd_rec_latency;
|
||||
param.output_latency_ms = pjsua_var.media_cfg.snd_play_latency;
|
||||
/* EC settings */
|
||||
if (pjsua_var.media_cfg.ec_tail_len) {
|
||||
param.flags |= (PJMEDIA_AUD_DEV_CAP_EC | PJMEDIA_AUD_DEV_CAP_EC_TAIL);
|
||||
param.ec_enabled = PJ_TRUE;
|
||||
param.ec_tail_ms = pjsua_var.media_cfg.ec_tail_len;
|
||||
} else {
|
||||
param.flags &= ~(PJMEDIA_AUD_DEV_CAP_EC | PJMEDIA_AUD_DEV_CAP_EC_TAIL);
|
||||
}
|
||||
|
||||
return open_snd_dev_ext(¶m);
|
||||
|
||||
#else
|
||||
|
||||
pjmedia_port *conf_port;
|
||||
pjmedia_aud_dev_info play_info;
|
||||
pjmedia_aud_param param;
|
||||
unsigned clock_rates[] = {0, 44100, 48000, 32000, 16000, 8000};
|
||||
unsigned selected_clock_rate = 0;
|
||||
unsigned i;
|
||||
pjmedia_aud_stream *strm;
|
||||
pj_str_t tmp;
|
||||
pj_status_t status = -1;
|
||||
|
||||
/* Check if NULL sound device is used */
|
||||
if (NULL_SND_DEV_ID == capture_dev || NULL_SND_DEV_ID == playback_dev) {
|
||||
return pjsua_set_null_snd_dev();
|
||||
}
|
||||
|
||||
/* Normalize device ID with new convention about default device ID */
|
||||
if (playback_dev == PJMEDIA_AUD_DEFAULT_CAPTURE_DEV)
|
||||
playback_dev = PJMEDIA_AUD_DEFAULT_PLAYBACK_DEV;
|
||||
|
||||
/* Close existing sound port */
|
||||
close_snd_dev();
|
||||
|
||||
/* Create memory pool for sound device. */
|
||||
pjsua_var.snd_pool = pjsua_pool_create("pjsua_snd", 1000, 1000);
|
||||
PJ_ASSERT_RETURN(pjsua_var.snd_pool, PJ_ENOMEM);
|
||||
|
||||
/* Set default clock rate */
|
||||
clock_rates[0] = pjsua_var.media_cfg.snd_clock_rate;
|
||||
if (clock_rates[0] == 0)
|
||||
clock_rates[0] = pjsua_var.media_cfg.clock_rate;
|
||||
|
||||
/* Get the port0 of the conference bridge. */
|
||||
conf_port = pjmedia_conf_get_master_port(pjsua_var.mconf);
|
||||
pj_assert(conf_port != NULL);
|
||||
|
||||
/* Create default parameters for the device */
|
||||
status = pjmedia_aud_dev_default_param(capture_dev, ¶m);
|
||||
status = pjmedia_aud_dev_default_param(capture_dev, param);
|
||||
if (status != PJ_SUCCESS) {
|
||||
pjsua_perror(THIS_FILE, "Error retrieving default audio "
|
||||
"device parameters", status);
|
||||
return status;
|
||||
}
|
||||
param.dir = PJMEDIA_DIR_CAPTURE_PLAYBACK;
|
||||
param.rec_id = capture_dev;
|
||||
param.play_id = playback_dev;
|
||||
param.channel_count = pjsua_var.media_cfg.channel_count;
|
||||
param->dir = PJMEDIA_DIR_CAPTURE_PLAYBACK;
|
||||
param->rec_id = capture_dev;
|
||||
param->play_id = playback_dev;
|
||||
param->clock_rate = clock_rate;
|
||||
param->channel_count = channel_count;
|
||||
param->samples_per_frame = samples_per_frame;
|
||||
param->bits_per_sample = bits_per_sample;
|
||||
|
||||
/* Update the setting with user preference */
|
||||
#define update_param(cap, field) \
|
||||
if (pjsua_var.aud_param.flags & cap) { \
|
||||
param->flags |= cap; \
|
||||
param->field = pjsua_var.aud_param.field; \
|
||||
}
|
||||
update_param( PJMEDIA_AUD_DEV_CAP_INPUT_VOLUME_SETTING, input_vol);
|
||||
update_param( PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING, output_vol);
|
||||
update_param( PJMEDIA_AUD_DEV_CAP_INPUT_ROUTE, input_route);
|
||||
update_param( PJMEDIA_AUD_DEV_CAP_OUTPUT_ROUTE, output_route);
|
||||
#undef update_param
|
||||
|
||||
/* Latency settings */
|
||||
param.flags |= (PJMEDIA_AUD_DEV_CAP_INPUT_LATENCY |
|
||||
PJMEDIA_AUD_DEV_CAP_OUTPUT_LATENCY);
|
||||
param.input_latency_ms = pjsua_var.media_cfg.snd_rec_latency;
|
||||
param.output_latency_ms = pjsua_var.media_cfg.snd_play_latency;
|
||||
param->flags |= (PJMEDIA_AUD_DEV_CAP_INPUT_LATENCY |
|
||||
PJMEDIA_AUD_DEV_CAP_OUTPUT_LATENCY);
|
||||
param->input_latency_ms = pjsua_var.media_cfg.snd_rec_latency;
|
||||
param->output_latency_ms = pjsua_var.media_cfg.snd_play_latency;
|
||||
|
||||
/* EC settings */
|
||||
if (pjsua_var.media_cfg.ec_tail_len) {
|
||||
param.flags |= (PJMEDIA_AUD_DEV_CAP_EC | PJMEDIA_AUD_DEV_CAP_EC_TAIL);
|
||||
param.ec_enabled = PJ_TRUE;
|
||||
param.ec_tail_ms = pjsua_var.media_cfg.ec_tail_len;
|
||||
param->flags |= (PJMEDIA_AUD_DEV_CAP_EC | PJMEDIA_AUD_DEV_CAP_EC_TAIL);
|
||||
param->ec_enabled = PJ_TRUE;
|
||||
param->ec_tail_ms = pjsua_var.media_cfg.ec_tail_len;
|
||||
} else {
|
||||
param.flags &= ~(PJMEDIA_AUD_DEV_CAP_EC | PJMEDIA_AUD_DEV_CAP_EC_TAIL);
|
||||
param->flags &= ~(PJMEDIA_AUD_DEV_CAP_EC|PJMEDIA_AUD_DEV_CAP_EC_TAIL);
|
||||
}
|
||||
|
||||
/* 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];
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
PJ_LOG(4,(THIS_FILE,
|
||||
"pjsua_set_snd_dev(): attempting to open devices "
|
||||
"@%d Hz", clock_rates[i]));
|
||||
/* Internal: the first time the audio device is opened (during app
|
||||
* startup), retrieve the audio settings such as volume level
|
||||
* so that aud_get_settings() will work.
|
||||
*/
|
||||
static pj_status_t update_initial_aud_param()
|
||||
{
|
||||
pjmedia_aud_stream *strm;
|
||||
pjmedia_aud_param param;
|
||||
pj_status_t status;
|
||||
|
||||
param.clock_rate = clock_rates[i];
|
||||
param.samples_per_frame = clock_rates[i] *
|
||||
pjsua_var.media_cfg.audio_frame_ptime *
|
||||
pjsua_var.media_cfg.channel_count / 1000;
|
||||
PJ_ASSERT_RETURN(pjsua_var.snd_port != NULL, PJ_EBUG);
|
||||
|
||||
/* Create the sound device. Sound port will start immediately. */
|
||||
status = pjmedia_snd_port_create2(pjsua_var.snd_pool, ¶m,
|
||||
&pjsua_var.snd_port);
|
||||
|
||||
if (status == PJ_SUCCESS) {
|
||||
selected_clock_rate = clock_rates[i];
|
||||
|
||||
/* 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;
|
||||
unsigned resample_opt = 0;
|
||||
|
||||
if (pjsua_var.media_cfg.quality >= 3 &&
|
||||
pjsua_var.media_cfg.quality <= 4)
|
||||
{
|
||||
resample_opt |= PJMEDIA_RESAMPLE_USE_SMALL_FILTER;
|
||||
}
|
||||
else if (pjsua_var.media_cfg.quality < 3) {
|
||||
resample_opt |= PJMEDIA_RESAMPLE_USE_LINEAR;
|
||||
}
|
||||
|
||||
status = pjmedia_resample_port_create(pjsua_var.snd_pool,
|
||||
conf_port,
|
||||
selected_clock_rate,
|
||||
resample_opt,
|
||||
&resample_port);
|
||||
if (status != PJ_SUCCESS) {
|
||||
pj_strerror(status, errmsg, sizeof(errmsg));
|
||||
PJ_LOG(4, (THIS_FILE,
|
||||
"Error creating resample port, trying next "
|
||||
"clock rate",
|
||||
errmsg));
|
||||
pjmedia_snd_port_destroy(pjsua_var.snd_port);
|
||||
pjsua_var.snd_port = NULL;
|
||||
continue;
|
||||
} else {
|
||||
conf_port = resample_port;
|
||||
break;
|
||||
}
|
||||
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
pj_strerror(status, errmsg, sizeof(errmsg));
|
||||
PJ_LOG(4, (THIS_FILE, "..failed: %s", errmsg));
|
||||
}
|
||||
strm = pjmedia_snd_port_get_snd_stream(pjsua_var.snd_port);
|
||||
|
||||
status = pjmedia_aud_stream_get_param(strm, ¶m);
|
||||
if (status != PJ_SUCCESS) {
|
||||
pjsua_perror(THIS_FILE, "Unable to open sound device", status);
|
||||
pjsua_perror(THIS_FILE, "Error audio stream "
|
||||
"device parameters", status);
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Connect sound port to the bridge */
|
||||
#define update_saved_param(cap, field) \
|
||||
if (param.flags & cap) { \
|
||||
pjsua_var.aud_param.flags |= cap; \
|
||||
pjsua_var.aud_param.field = param.field; \
|
||||
}
|
||||
|
||||
update_saved_param(PJMEDIA_AUD_DEV_CAP_INPUT_VOLUME_SETTING, input_vol);
|
||||
update_saved_param(PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING, output_vol);
|
||||
update_saved_param(PJMEDIA_AUD_DEV_CAP_INPUT_ROUTE, input_route);
|
||||
update_saved_param(PJMEDIA_AUD_DEV_CAP_OUTPUT_ROUTE, output_route);
|
||||
#undef update_saved_param
|
||||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
/* Get format name */
|
||||
static const char *get_fmt_name(pj_uint32_t id)
|
||||
{
|
||||
static char name[8];
|
||||
|
||||
if (id == PJMEDIA_FORMAT_L16)
|
||||
return "PCM";
|
||||
pj_memcpy(name, &id, 4);
|
||||
name[4] = '\0';
|
||||
return name;
|
||||
}
|
||||
|
||||
/* Open sound device with the setting. */
|
||||
static pj_status_t open_snd_dev(pjmedia_aud_param *param)
|
||||
{
|
||||
pjmedia_port *conf_port;
|
||||
pj_status_t status;
|
||||
|
||||
PJ_ASSERT_RETURN(param, PJ_EINVAL);
|
||||
|
||||
/* Check if NULL sound device is used */
|
||||
if (NULL_SND_DEV_ID==param->rec_id || NULL_SND_DEV_ID==param->play_id) {
|
||||
return pjsua_set_null_snd_dev();
|
||||
}
|
||||
|
||||
/* Close existing sound port */
|
||||
close_snd_dev();
|
||||
|
||||
/* Create memory pool for sound device. */
|
||||
pjsua_var.snd_pool = pjsua_pool_create("pjsua_snd", 4000, 4000);
|
||||
PJ_ASSERT_RETURN(pjsua_var.snd_pool, PJ_ENOMEM);
|
||||
|
||||
|
||||
PJ_LOG(4,(THIS_FILE, "Opening sound device %s@%d/%d/%dms",
|
||||
get_fmt_name(param->ext_fmt.id),
|
||||
param->clock_rate, param->channel_count,
|
||||
param->samples_per_frame / param->channel_count * 1000 /
|
||||
param->clock_rate));
|
||||
|
||||
status = pjmedia_snd_port_create2( pjsua_var.snd_pool,
|
||||
param, &pjsua_var.snd_port);
|
||||
if (status != PJ_SUCCESS)
|
||||
return status;
|
||||
|
||||
/* Get the port0 of the conference bridge. */
|
||||
conf_port = pjmedia_conf_get_master_port(pjsua_var.mconf);
|
||||
pj_assert(conf_port != NULL);
|
||||
|
||||
/* For conference bridge, resample if necessary if the bridge's
|
||||
* clock rate is different than the sound device's clock rate.
|
||||
*/
|
||||
if (!pjsua_var.is_mswitch &&
|
||||
param->ext_fmt.id == PJMEDIA_FORMAT_PCM &&
|
||||
conf_port->info.clock_rate != param->clock_rate)
|
||||
{
|
||||
pjmedia_port *resample_port;
|
||||
unsigned resample_opt = 0;
|
||||
|
||||
if (pjsua_var.media_cfg.quality >= 3 &&
|
||||
pjsua_var.media_cfg.quality <= 4)
|
||||
{
|
||||
resample_opt |= PJMEDIA_RESAMPLE_USE_SMALL_FILTER;
|
||||
}
|
||||
else if (pjsua_var.media_cfg.quality < 3) {
|
||||
resample_opt |= PJMEDIA_RESAMPLE_USE_LINEAR;
|
||||
}
|
||||
|
||||
status = pjmedia_resample_port_create(pjsua_var.snd_pool,
|
||||
conf_port,
|
||||
param->clock_rate,
|
||||
resample_opt,
|
||||
&resample_port);
|
||||
if (status != PJ_SUCCESS) {
|
||||
char errmsg[PJ_ERR_MSG_SIZE];
|
||||
pj_strerror(status, errmsg, sizeof(errmsg));
|
||||
PJ_LOG(4, (THIS_FILE,
|
||||
"Error creating resample port: %s",
|
||||
errmsg));
|
||||
close_snd_dev();
|
||||
return status;
|
||||
}
|
||||
|
||||
conf_port = resample_port;
|
||||
}
|
||||
|
||||
/* Otherwise for audio switchboard, the switch's port0 setting is
|
||||
* derived from the sound device setting, so update the setting.
|
||||
*/
|
||||
if (pjsua_var.is_mswitch) {
|
||||
pj_memcpy(&conf_port->info.format, ¶m->ext_fmt,
|
||||
sizeof(conf_port->info.format));
|
||||
conf_port->info.clock_rate = param->clock_rate;
|
||||
conf_port->info.samples_per_frame = param->samples_per_frame;
|
||||
conf_port->info.channel_count = param->channel_count;
|
||||
conf_port->info.bits_per_sample = 16;
|
||||
}
|
||||
|
||||
/* Connect sound port to the bridge */
|
||||
status = pjmedia_snd_port_connect(pjsua_var.snd_port,
|
||||
conf_port );
|
||||
if (status != PJ_SUCCESS) {
|
||||
|
@ -2559,31 +2458,148 @@ PJ_DEF(pj_status_t) pjsua_set_snd_dev( int capture_dev,
|
|||
}
|
||||
|
||||
/* Save the device IDs */
|
||||
pjsua_var.cap_dev = capture_dev;
|
||||
pjsua_var.play_dev = playback_dev;
|
||||
pjsua_var.cap_dev = param->rec_id;
|
||||
pjsua_var.play_dev = param->play_id;
|
||||
|
||||
/* Update sound device name. */
|
||||
strm = pjmedia_snd_port_get_snd_stream(pjsua_var.snd_port);
|
||||
pjmedia_aud_stream_get_param(strm, ¶m);
|
||||
pjmedia_aud_dev_get_info(param.play_id, &play_info);
|
||||
{
|
||||
pjmedia_aud_dev_info rec_info;
|
||||
pjmedia_aud_stream *strm;
|
||||
pjmedia_aud_param si;
|
||||
pj_str_t tmp;
|
||||
|
||||
if (param.clock_rate != pjsua_var.media_cfg.clock_rate) {
|
||||
char tmp_buf[128];
|
||||
int tmp_buf_len = sizeof(tmp_buf);
|
||||
strm = pjmedia_snd_port_get_snd_stream(pjsua_var.snd_port);
|
||||
status = pjmedia_aud_stream_get_param(strm, &si);
|
||||
if (status == PJ_SUCCESS)
|
||||
status = pjmedia_aud_dev_get_info(si.rec_id, &rec_info);
|
||||
|
||||
tmp_buf_len = pj_ansi_snprintf(tmp_buf, sizeof(tmp_buf)-1, "%s (%dKHz)",
|
||||
play_info.name, param.clock_rate/1000);
|
||||
pj_strset(&tmp, tmp_buf, tmp_buf_len);
|
||||
pjmedia_conf_set_port0_name(pjsua_var.mconf, &tmp);
|
||||
} else {
|
||||
pjmedia_conf_set_port0_name(pjsua_var.mconf,
|
||||
pj_cstr(&tmp, play_info.name));
|
||||
if (status==PJ_SUCCESS) {
|
||||
if (param->clock_rate != pjsua_var.media_cfg.clock_rate) {
|
||||
char tmp_buf[128];
|
||||
int tmp_buf_len = sizeof(tmp_buf);
|
||||
|
||||
tmp_buf_len = pj_ansi_snprintf(tmp_buf, sizeof(tmp_buf)-1,
|
||||
"%s (%dKHz)",
|
||||
rec_info.name,
|
||||
param->clock_rate/1000);
|
||||
pj_strset(&tmp, tmp_buf, tmp_buf_len);
|
||||
pjmedia_conf_set_port0_name(pjsua_var.mconf, &tmp);
|
||||
} else {
|
||||
pjmedia_conf_set_port0_name(pjsua_var.mconf,
|
||||
pj_cstr(&tmp, rec_info.name));
|
||||
}
|
||||
}
|
||||
|
||||
/* Any error is not major, let it through */
|
||||
status = PJ_SUCCESS;
|
||||
};
|
||||
|
||||
/* If this is the first time the audio device is open, retrieve some
|
||||
* settings from the device (such as volume settings) so that the
|
||||
* pjsua_snd_get_setting() work.
|
||||
*/
|
||||
if (pjsua_var.aud_open_cnt == 0) {
|
||||
update_initial_aud_param();
|
||||
++pjsua_var.aud_open_cnt;
|
||||
}
|
||||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
#endif /* PJMEDIA_CONF_USE_SWITCH_BOARD */
|
||||
|
||||
/* Close existing sound device */
|
||||
static void close_snd_dev(void)
|
||||
{
|
||||
/* Close sound device */
|
||||
if (pjsua_var.snd_port) {
|
||||
pjmedia_aud_dev_info cap_info, play_info;
|
||||
pjmedia_aud_stream *strm;
|
||||
pjmedia_aud_param param;
|
||||
|
||||
strm = pjmedia_snd_port_get_snd_stream(pjsua_var.snd_port);
|
||||
pjmedia_aud_stream_get_param(strm, ¶m);
|
||||
|
||||
if (pjmedia_aud_dev_get_info(param.rec_id, &cap_info) != PJ_SUCCESS)
|
||||
cap_info.name[0] = '\0';
|
||||
if (pjmedia_aud_dev_get_info(param.play_id, &play_info) != PJ_SUCCESS)
|
||||
play_info.name[0] = '\0';
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (pjsua_var.snd_pool)
|
||||
pj_pool_release(pjsua_var.snd_pool);
|
||||
pjsua_var.snd_pool = 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)
|
||||
{
|
||||
unsigned alt_cr_cnt = 1;
|
||||
unsigned alt_cr[] = {0, 44100, 48000, 32000, 16000, 8000};
|
||||
unsigned i;
|
||||
pj_status_t status = -1;
|
||||
|
||||
/* Set default clock rate */
|
||||
alt_cr[0] = pjsua_var.media_cfg.snd_clock_rate;
|
||||
if (alt_cr[0] == 0)
|
||||
alt_cr[0] = pjsua_var.media_cfg.clock_rate;
|
||||
|
||||
/* Allow retrying of different clock rate if we're using conference
|
||||
* bridge (meaning audio format is always PCM), otherwise lock on
|
||||
* to one clock rate.
|
||||
*/
|
||||
if (pjsua_var.is_mswitch) {
|
||||
alt_cr_cnt = 1;
|
||||
} else {
|
||||
alt_cr_cnt = PJ_ARRAY_SIZE(alt_cr);
|
||||
}
|
||||
|
||||
/* Attempts to open the sound device with different clock rates */
|
||||
for (i=0; i<alt_cr_cnt; ++i) {
|
||||
pjmedia_aud_param param;
|
||||
unsigned samples_per_frame;
|
||||
|
||||
/* Create the default audio param */
|
||||
samples_per_frame = alt_cr[i] *
|
||||
pjsua_var.media_cfg.audio_frame_ptime *
|
||||
pjsua_var.media_cfg.channel_count / 1000;
|
||||
status = create_aud_param(¶m, capture_dev, playback_dev,
|
||||
alt_cr[i], pjsua_var.media_cfg.channel_count,
|
||||
samples_per_frame, 16);
|
||||
if (status != PJ_SUCCESS)
|
||||
return status;
|
||||
|
||||
/* Open! */
|
||||
status = open_snd_dev(¶m);
|
||||
if (status == PJ_SUCCESS)
|
||||
break;
|
||||
}
|
||||
|
||||
if (status != PJ_SUCCESS) {
|
||||
pjsua_perror(THIS_FILE, "Unable to open sound device", status);
|
||||
return status;
|
||||
}
|
||||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
|
@ -2689,16 +2705,71 @@ PJ_DEF(pj_status_t) pjsua_get_ec_tail(unsigned *p_tail_ms)
|
|||
|
||||
|
||||
/*
|
||||
* Get active sound port instance.
|
||||
* Check whether the sound device is currently active.
|
||||
*/
|
||||
PJ_DEF(pjmedia_aud_stream*) pjsua_get_aud_stream()
|
||||
PJ_DEF(pj_bool_t) pjsua_snd_is_active(void)
|
||||
{
|
||||
pjmedia_aud_stream *aud_stream = NULL;
|
||||
return pjsua_var.snd_port != NULL;
|
||||
}
|
||||
|
||||
if (pjsua_var.snd_port)
|
||||
aud_stream = pjmedia_snd_port_get_snd_stream(pjsua_var.snd_port);
|
||||
|
||||
return aud_stream;
|
||||
/*
|
||||
* Configure sound device setting to the sound device being used.
|
||||
*/
|
||||
PJ_DEF(pj_status_t) pjsua_snd_set_setting( pjmedia_aud_dev_cap cap,
|
||||
const void *pval,
|
||||
pj_bool_t keep)
|
||||
{
|
||||
/* Check if we are allowed to set the cap */
|
||||
if (cap & pjsua_var.aud_svmask) {
|
||||
return PJMEDIA_EAUD_INVCAP;
|
||||
}
|
||||
|
||||
if (keep) {
|
||||
/* Save in internal param for later device open */
|
||||
pj_status_t status;
|
||||
|
||||
status = pjmedia_aud_param_set_cap(&pjsua_var.aud_param,
|
||||
cap, pval);
|
||||
if (status != PJ_SUCCESS)
|
||||
return status;
|
||||
}
|
||||
|
||||
if (pjsua_snd_is_active()) {
|
||||
/* Sound is active, set it immediately */
|
||||
pjmedia_aud_stream *strm;
|
||||
|
||||
strm = pjmedia_snd_port_get_snd_stream(pjsua_var.snd_port);
|
||||
return pjmedia_aud_stream_set_cap(strm, cap, pval);
|
||||
} else {
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Retrieve a sound device setting.
|
||||
*/
|
||||
PJ_DEF(pj_status_t) pjsua_snd_get_setting( pjmedia_aud_dev_cap cap,
|
||||
void *pval)
|
||||
{
|
||||
/* If sound device has never been opened before, open it to
|
||||
* retrieve the initial setting from the device (e.g. audio
|
||||
* volume)
|
||||
*/
|
||||
if (pjsua_var.aud_open_cnt==0)
|
||||
pjsua_set_snd_dev(pjsua_var.cap_dev, pjsua_var.play_dev);
|
||||
|
||||
if (pjsua_snd_is_active()) {
|
||||
/* Sound is active, retrieve from device directly */
|
||||
pjmedia_aud_stream *strm;
|
||||
|
||||
strm = pjmedia_snd_port_get_snd_stream(pjsua_var.snd_port);
|
||||
return pjmedia_aud_stream_get_cap(strm, cap, pval);
|
||||
} else {
|
||||
/* Otherwise retrieve from internal param */
|
||||
return pjmedia_aud_param_get_cap(&pjsua_var.aud_param,
|
||||
cap, pval);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue