- Timestamp:
- Mar 9, 2009 1:08:16 PM (16 years ago)
- Location:
- pjproject/branches/projects/aps-direct/pjsip
- Files:
-
- 5 edited
Legend:
- Unmodified
- Added
- Removed
-
pjproject/branches/projects/aps-direct/pjsip/include/pjsua-lib/pjsua.h
r2480 r2493 4287 4287 /** 4288 4288 * Specify idle time of sound device before it is automatically closed, 4289 * in seconds. 4290 * 4291 * Default : -1 (Disable the auto-close feature of sound device) 4289 * in seconds. Use value -1 to disable the auto-close feature of sound 4290 * device 4291 * 4292 * Default : 1 4292 4293 */ 4293 4294 int snd_auto_close_time; … … 4802 4803 4803 4804 /** 4804 * Enum all sounddevices installed in the system.4805 * Enum all audio devices installed in the system. 4805 4806 * 4806 4807 * @param info Array of info to be initialized. … … 4810 4811 * 4811 4812 * @return PJ_SUCCESS on success, or the appropriate error code. 4813 */ 4814 PJ_DECL(pj_status_t) pjsua_enum_aud_devs(pjmedia_aud_dev_info info[], 4815 unsigned *count); 4816 4817 /** 4818 * Enum all sound devices installed in the system (old API). 4819 * 4820 * @param info Array of info to be initialized. 4821 * @param count On input, specifies max elements in the array. 4822 * On return, it contains actual number of elements 4823 * that have been initialized. 4824 * 4825 * @return PJ_SUCCESS on success, or the appropriate error code. 4812 4826 * 4813 4827 * … … 4819 4833 * 4820 4834 */ 4821 #if PJMEDIA_AUDIO_API==PJMEDIA_AUDIO_API_NEW_ONLY4822 PJ_DECL(pj_status_t) pjsua_enum_snd_devs(pjmedia_aud_dev_info info[],4823 unsigned *count);4824 #else4825 4835 PJ_DECL(pj_status_t) pjsua_enum_snd_devs(pjmedia_snd_dev_info info[], 4826 4836 unsigned *count); 4827 #endif4828 4829 4837 4830 4838 /** … … 4898 4906 4899 4907 /** 4900 * Change the echo cancellation settings. The behavior of this function 4901 * depends on whether the sound device is currently active, and if it is, 4902 * whether device or software AEC is being used. 4908 * Change the echo cancellation settings. Application may also use the 4909 * #pjsua_snd_set_setting() to retrieve the echo cancellation setting. 4910 * 4911 * The behavior of this function depends on whether the sound device is 4912 * currently active, and if it is, whether device or software AEC is 4913 * being used. 4903 4914 * 4904 4915 * If the sound device is currently active, and if the device supports AEC, … … 4929 4940 4930 4941 /** 4931 * Get current echo canceller tail length. 4942 * Get current echo canceller tail length. Application may also use the 4943 * #pjsua_snd_set_setting() to retrieve the echo cancellation setting. 4932 4944 * 4933 4945 * @param p_tail_ms Pointer to receive the tail length, in miliseconds. … … 4945 4957 4946 4958 /** 4947 * Get active audio device stream instance. 4948 * 4949 * @return Audio device stream instance if any, otherwise 4950 * NULL will be returned. 4951 */ 4952 PJ_DECL(pjmedia_aud_stream*) pjsua_get_aud_stream(); 4959 * Check whether the sound device is currently active. The sound device 4960 * may be inactive if the application has set the auto close feature to 4961 * non-zero (the snd_auto_close_time setting in #pjsua_media_config), or 4962 * if null sound device or no sound device has been configured via the 4963 * #pjsua_set_no_snd_dev() function. 4964 */ 4965 PJ_DECL(pj_bool_t) pjsua_snd_is_active(void); 4966 4967 4968 /** 4969 * Configure sound device setting to the sound device being used. If sound 4970 * device is currently active, the function will forward the setting to the 4971 * sound device instance to be applied immediately, if it supports it. 4972 * 4973 * The setting will be saved for future opening of the sound device, if the 4974 * "keep" argument is set to non-zero. If the sound device is currently 4975 * inactive, and the "keep" argument is false, this function will return 4976 * error. 4977 * 4978 * Note that in case the setting is kept for future use, it will be applied 4979 * to any devices, even when application has changed the sound device to be 4980 * used. 4981 * 4982 * See also #pjmedia_aud_stream_set_cap() for more information about setting 4983 * an audio device capability. 4984 * 4985 * @param cap The sound device setting to change. 4986 * @param pval Pointer to value. Please see #pjmedia_aud_dev_cap 4987 * documentation about the type of value to be 4988 * supplied for each setting. 4989 * @param keep Specify whether the setting is to be kept for future 4990 * use. 4991 * 4992 * @return PJ_SUCCESS on success or the appropriate error code. 4993 */ 4994 PJ_DECL(pj_status_t) pjsua_snd_set_setting(pjmedia_aud_dev_cap cap, 4995 const void *pval, 4996 pj_bool_t keep); 4997 4998 /** 4999 * Retrieve a sound device setting. If sound device is currently active, 5000 * the function will forward the request to the sound device. If sound device 5001 * is currently inactive, and if application had previously set the setting 5002 * and mark the setting as kept, then that setting will be returned. 5003 * Otherwise, this function will return error. 5004 * 5005 * @param cap The sound device setting to retrieve. 5006 * @param pval Pointer to receive the value. 5007 * Please see #pjmedia_aud_dev_cap documentation about 5008 * the type of value to be supplied for each setting. 5009 * 5010 * @return PJ_SUCCESS on success or the appropriate error code. 5011 */ 5012 PJ_DECL(pj_status_t) pjsua_snd_get_setting(pjmedia_aud_dev_cap cap, 5013 void *pval); 4953 5014 4954 5015 -
pjproject/branches/projects/aps-direct/pjsip/include/pjsua-lib/pjsua_internal.h
r2394 r2493 273 273 pjsua_conf_setting mconf_cfg; /**< Additionan conf. bridge. param */ 274 274 pjmedia_conf *mconf; /**< Conference bridge. */ 275 int cap_dev; /**< Capture device ID. */ 276 int play_dev; /**< Playback device ID. */ 275 pj_bool_t is_mswitch;/**< Are we using audio switchboard 276 (a.k.a APS-Direct) */ 277 278 /* Sound device */ 279 pjmedia_aud_dev_index cap_dev; /**< Capture device ID. */ 280 pjmedia_aud_dev_index play_dev; /**< Playback device ID. */ 281 pj_uint32_t aud_svmask;/**< Which settings to save */ 282 pjmedia_aud_param aud_param; /**< User settings to sound dev */ 283 pj_bool_t aud_open_cnt;/**< How many # device is opened */ 277 284 pj_bool_t no_snd; /**< No sound (app will manage it) */ 278 285 pj_pool_t *snd_pool; /**< Sound's private pool. */ -
pjproject/branches/projects/aps-direct/pjsip/src/pjsua-lib/pjsua_call.c
r2394 r2493 371 371 PJSUA_LOCK(); 372 372 373 /* Create sound port if none is instantiated */ 374 if (pjsua_var.snd_port==NULL && pjsua_var.null_snd==NULL && 375 !pjsua_var.no_snd) 373 /* Create sound port if none is instantiated, to check if sound device 374 * can be used. But only do this with the conference bridge, as with 375 * audio switchboard (i.e. APS-Direct), we can only open the sound 376 * device once the correct format has been known 377 */ 378 if (!pjsua_var.is_mswitch && pjsua_var.snd_port==NULL && 379 pjsua_var.null_snd==NULL && !pjsua_var.no_snd) 376 380 { 377 381 pj_status_t status; -
pjproject/branches/projects/aps-direct/pjsip/src/pjsua-lib/pjsua_core.c
r2469 r2493 181 181 cfg->snd_play_latency = PJMEDIA_SND_DEFAULT_PLAY_LATENCY; 182 182 cfg->jb_init = cfg->jb_min_pre = cfg->jb_max_pre = cfg->jb_max = -1; 183 cfg->snd_auto_close_time = -1;183 cfg->snd_auto_close_time = 1; 184 184 185 185 cfg->turn_conn_type = PJ_TURN_TP_UDP; -
pjproject/branches/projects/aps-direct/pjsip/src/pjsua-lib/pjsua_media.c
r2486 r2493 36 36 static pj_uint16_t next_rtp_port; 37 37 38 /* Open sound dev */ 39 static pj_status_t open_snd_dev(pjmedia_aud_param *param); 38 40 /* Close existing sound device */ 39 41 static void close_snd_dev(void); 42 /* Create audio device param */ 43 static pj_status_t create_aud_param(pjmedia_aud_param *param, 44 pjmedia_aud_dev_index capture_dev, 45 pjmedia_aud_dev_index playback_dev, 46 unsigned clock_rate, 47 unsigned channel_count, 48 unsigned samples_per_frame, 49 unsigned bits_per_sample); 40 50 41 51 … … 60 70 /* To suppress warning about unused var when all codecs are disabled */ 61 71 PJ_UNUSED_ARG(codec_id); 72 73 /* Specify which audio device settings are save-able */ 74 pjsua_var.aud_svmask = 0xFFFFFFFF; 75 /* These are not-settable */ 76 pjsua_var.aud_svmask &= ~(PJMEDIA_AUD_DEV_CAP_EXT_FORMAT | 77 PJMEDIA_AUD_DEV_CAP_INPUT_SIGNAL_METER | 78 PJMEDIA_AUD_DEV_CAP_OUTPUT_SIGNAL_METER); 62 79 63 80 /* Copy configuration */ … … 236 253 return status; 237 254 } 255 256 /* Are we using the audio switchboard (a.k.a APS-Direct)? */ 257 pjsua_var.is_mswitch = pjmedia_conf_get_master_port(pjsua_var.mconf) 258 ->info.signature == PJMEDIA_CONF_SWITCH_SIGNATURE; 238 259 239 260 /* Create null port just in case user wants to use null sound. */ … … 1510 1531 } 1511 1532 1512 #if PJMEDIA_CONF_USE_SWITCH_BOARD1513 1514 /*1515 * Open sound device with extended setting.1516 */1517 static pj_status_t open_snd_dev_ext(pjmedia_aud_param *param)1518 {1519 pjmedia_port *conf_port;1520 pj_status_t status;1521 1522 PJ_ASSERT_RETURN(param, PJ_EINVAL);1523 1524 /* Check if NULL sound device is used */1525 if (NULL_SND_DEV_ID==param->rec_id || NULL_SND_DEV_ID==param->play_id) {1526 return pjsua_set_null_snd_dev();1527 }1528 1529 /* Close existing sound port */1530 close_snd_dev();1531 1532 /* Create memory pool for sound device. */1533 pjsua_var.snd_pool = pjsua_pool_create("pjsua_snd", 4000, 4000);1534 PJ_ASSERT_RETURN(pjsua_var.snd_pool, PJ_ENOMEM);1535 1536 1537 /* Get the port0 of the conference bridge. */1538 conf_port = pjmedia_conf_get_master_port(pjsua_var.mconf);1539 pj_assert(conf_port != NULL);1540 1541 PJ_LOG(4,(THIS_FILE, "Opening sound device @%d/%d/%s",1542 param->clock_rate, param->channel_count,1543 (param->ext_fmt.id==PJMEDIA_FORMAT_L16?"pcm":"encoded")));1544 1545 status = pjmedia_snd_port_create2( pjsua_var.snd_pool,1546 param, &pjsua_var.snd_port);1547 1548 /* Update port 0 info when sound dev opened successfully. */1549 if (status == PJ_SUCCESS) {1550 pj_memcpy(&conf_port->info.format, ¶m->ext_fmt,1551 sizeof(conf_port->info.format));1552 conf_port->info.clock_rate = param->clock_rate;1553 conf_port->info.samples_per_frame = param->samples_per_frame;1554 conf_port->info.channel_count = param->channel_count;1555 conf_port->info.bits_per_sample = 16;1556 } else {1557 pjsua_perror(THIS_FILE, "Unable to open sound device", status);1558 return status;1559 }1560 1561 /* Connect sound port to the bridge */1562 status = pjmedia_snd_port_connect(pjsua_var.snd_port,1563 conf_port );1564 if (status != PJ_SUCCESS) {1565 pjsua_perror(THIS_FILE, "Unable to connect conference port to "1566 "sound device", status);1567 pjmedia_snd_port_destroy(pjsua_var.snd_port);1568 pjsua_var.snd_port = NULL;1569 return status;1570 }1571 1572 /* Save the device IDs */1573 pjsua_var.cap_dev = param->rec_id;1574 pjsua_var.play_dev = param->play_id;1575 1576 /* Update sound device name. */1577 {1578 pjmedia_aud_dev_info play_info;1579 pjmedia_aud_stream *strm;1580 pjmedia_aud_param si;1581 pj_str_t tmp;1582 1583 strm = pjmedia_snd_port_get_snd_stream(pjsua_var.snd_port);1584 pjmedia_aud_stream_get_param(strm, &si);1585 if (pjmedia_aud_dev_get_info(si.play_id, &play_info)==PJ_SUCCESS) {1586 pjmedia_conf_set_port0_name(pjsua_var.mconf,1587 pj_cstr(&tmp, play_info.name));1588 }1589 };1590 1591 return PJ_SUCCESS;1592 }1593 1594 #endif1595 1596 1597 /* Close existing sound device */1598 static void close_snd_dev(void)1599 {1600 /* Close sound device */1601 if (pjsua_var.snd_port) {1602 pjmedia_aud_dev_info cap_info, play_info;1603 pjmedia_aud_stream *strm;1604 pjmedia_aud_param param;1605 1606 strm = pjmedia_snd_port_get_snd_stream(pjsua_var.snd_port);1607 pjmedia_aud_stream_get_param(strm, ¶m);1608 1609 if (pjmedia_aud_dev_get_info(param.rec_id, &cap_info) != PJ_SUCCESS)1610 cap_info.name[0] = '\0';1611 if (pjmedia_aud_dev_get_info(param.play_id, &play_info) != PJ_SUCCESS)1612 play_info.name[0] = '\0';1613 1614 PJ_LOG(4,(THIS_FILE, "Closing %s sound playback device and "1615 "%s sound capture device",1616 play_info.name, cap_info.name));1617 1618 pjmedia_snd_port_disconnect(pjsua_var.snd_port);1619 pjmedia_snd_port_destroy(pjsua_var.snd_port);1620 pjsua_var.snd_port = NULL;1621 }1622 1623 /* Close null sound device */1624 if (pjsua_var.null_snd) {1625 PJ_LOG(4,(THIS_FILE, "Closing null sound device.."));1626 pjmedia_master_port_destroy(pjsua_var.null_snd, PJ_FALSE);1627 pjsua_var.null_snd = NULL;1628 }1629 1630 if (pjsua_var.snd_pool)1631 pj_pool_release(pjsua_var.snd_pool);1632 pjsua_var.snd_pool = NULL;1633 }1634 1635 1636 1533 /* 1637 1534 * Get maxinum number of conference ports. … … 1748 1645 } 1749 1646 1750 #if PJMEDIA_CONF_USE_SWITCH_BOARD 1751 1752 /* Check if sound device need to be reopened, i.e: its attributes1647 1648 /* For audio switchboard (i.e. APS-Direct): 1649 * Check if sound device need to be reopened, i.e: its attributes 1753 1650 * (format, clock rate, channel count) must match to peer's. 1754 1651 * Note that sound device can be reopened only if it doesn't have 1755 1652 * any connection. 1756 1653 */ 1757 do{1654 if (pjsua_var.is_mswitch) { 1758 1655 pjmedia_conf_port_info port0_info; 1759 1656 pjmedia_conf_port_info peer_info; … … 1790 1687 pjmedia_aud_param param; 1791 1688 1792 status = pjmedia_aud_dev_default_param(pjsua_var.cap_dev, ¶m); 1793 if (status != PJ_SUCCESS) { 1794 pjsua_perror(THIS_FILE, "Error retrieving default audio " 1795 "device parameters", status); 1796 return status; 1689 /* Create parameter based on peer info */ 1690 status = create_aud_param(¶m, pjsua_var.cap_dev, 1691 pjsua_var.play_dev, 1692 peer_info.clock_rate, 1693 peer_info.channel_count, 1694 peer_info.samples_per_frame, 1695 peer_info.bits_per_sample); 1696 1697 /* And peer format */ 1698 if (peer_info.format.id != PJMEDIA_FORMAT_PCM) { 1699 param.flags |= PJMEDIA_AUD_DEV_CAP_EXT_FORMAT; 1700 param.ext_fmt = peer_info.format; 1797 1701 } 1798 1702 1799 param.dir = PJMEDIA_DIR_CAPTURE_PLAYBACK; 1800 param.rec_id = pjsua_var.cap_dev; 1801 param.play_id = pjsua_var.play_dev; 1802 param.clock_rate = peer_info.clock_rate; 1803 param.samples_per_frame = peer_info.samples_per_frame; 1804 param.channel_count = peer_info.channel_count; 1805 param.bits_per_sample = peer_info.bits_per_sample; 1806 /* Latency setting */ 1807 param.flags |= (PJMEDIA_AUD_DEV_CAP_INPUT_LATENCY | 1808 PJMEDIA_AUD_DEV_CAP_OUTPUT_LATENCY); 1809 param.input_latency_ms = pjsua_var.media_cfg.snd_rec_latency; 1810 param.output_latency_ms = pjsua_var.media_cfg.snd_play_latency; 1811 /* EC settings */ 1812 if (pjsua_var.media_cfg.ec_tail_len) { 1813 param.flags |= (PJMEDIA_AUD_DEV_CAP_EC | PJMEDIA_AUD_DEV_CAP_EC_TAIL); 1814 param.ec_enabled = PJ_TRUE; 1815 param.ec_tail_ms = pjsua_var.media_cfg.ec_tail_len; 1816 } else { 1817 param.flags &= ~(PJMEDIA_AUD_DEV_CAP_EC | PJMEDIA_AUD_DEV_CAP_EC_TAIL); 1818 } 1819 /* Format */ 1820 param.flags |= (PJMEDIA_AUD_DEV_CAP_EXT_FORMAT | 1821 PJMEDIA_AUD_DEV_CAP_OUTPUT_ROUTE); 1822 param.ext_fmt = peer_info.format; 1823 //param.plc = PJ_FALSE; 1824 param.out_route = PJMEDIA_AUD_DEV_ROUTE_DEFAULT; 1825 1826 status = open_snd_dev_ext(¶m); 1703 status = open_snd_dev(¶m); 1827 1704 if (status != PJ_SUCCESS) { 1828 1705 pjsua_perror(THIS_FILE, "Error opening sound device", status); … … 1830 1707 } 1831 1708 } 1832 } while(0); 1833 1834 #else 1835 1836 1837 1838 !pjsua_var.no_snd)1839 1840 pj_status_t status;1841 1842 status = pjsua_set_snd_dev(pjsua_var.cap_dev, pjsua_var.play_dev);1843 if (status != PJ_SUCCESS) {1844 1845 1846 }1847 1848 1849 #endif 1709 1710 } else { 1711 /* The bridge version */ 1712 1713 /* Create sound port if none is instantiated */ 1714 if (pjsua_var.snd_port==NULL && pjsua_var.null_snd==NULL && 1715 !pjsua_var.no_snd) 1716 { 1717 pj_status_t status; 1718 1719 status = pjsua_set_snd_dev(pjsua_var.cap_dev, pjsua_var.play_dev); 1720 if (status != PJ_SUCCESS) { 1721 pjsua_perror(THIS_FILE, "Error opening sound device", status); 1722 return status; 1723 } 1724 } 1725 1726 } 1850 1727 1851 1728 return pjmedia_conf_connect_port(pjsua_var.mconf, source, sink, 0); … … 2323 2200 * Enum sound devices. 2324 2201 */ 2325 #if PJMEDIA_AUDIO_API==PJMEDIA_AUDIO_API_NEW_ONLY 2326 PJ_DEF(pj_status_t) pjsua_enum_ snd_devs( pjmedia_aud_dev_info info[],2202 2203 PJ_DEF(pj_status_t) pjsua_enum_aud_devs( pjmedia_aud_dev_info info[], 2327 2204 unsigned *count) 2328 2205 { … … 2345 2222 return PJ_SUCCESS; 2346 2223 } 2347 #else /* PJMEDIA_AUDIO_API */ 2224 2225 2348 2226 PJ_DEF(pj_status_t) pjsua_enum_snd_devs( pjmedia_snd_dev_info info[], 2349 2227 unsigned *count) … … 2375 2253 return PJ_SUCCESS; 2376 2254 } 2377 #endif 2378 2379 2380 /* 2381 * Select or change sound device. Application may call this function at 2382 * any time to replace current sound device. 2383 */ 2384 PJ_DEF(pj_status_t) pjsua_set_snd_dev( int capture_dev, 2385 int playback_dev) 2386 { 2387 #if PJMEDIA_CONF_USE_SWITCH_BOARD 2388 2389 pjmedia_aud_param param; 2255 2256 /* Create audio device parameter to open the device */ 2257 static pj_status_t create_aud_param(pjmedia_aud_param *param, 2258 pjmedia_aud_dev_index capture_dev, 2259 pjmedia_aud_dev_index playback_dev, 2260 unsigned clock_rate, 2261 unsigned channel_count, 2262 unsigned samples_per_frame, 2263 unsigned bits_per_sample) 2264 { 2390 2265 pj_status_t status; 2391 2266 2267 /* Normalize device ID with new convention about default device ID */ 2268 if (playback_dev == PJMEDIA_AUD_DEFAULT_CAPTURE_DEV) 2269 playback_dev = PJMEDIA_AUD_DEFAULT_PLAYBACK_DEV; 2270 2392 2271 /* Create default parameters for the device */ 2393 status = pjmedia_aud_dev_default_param(capture_dev, ¶m);2272 status = pjmedia_aud_dev_default_param(capture_dev, param); 2394 2273 if (status != PJ_SUCCESS) { 2395 2274 pjsua_perror(THIS_FILE, "Error retrieving default audio " … … 2397 2276 return status; 2398 2277 } 2399 param.dir = PJMEDIA_DIR_CAPTURE_PLAYBACK; 2400 param.rec_id = capture_dev; 2401 param.play_id = playback_dev; 2402 param.channel_count = pjsua_var.media_cfg.channel_count; 2278 param->dir = PJMEDIA_DIR_CAPTURE_PLAYBACK; 2279 param->rec_id = capture_dev; 2280 param->play_id = playback_dev; 2281 param->clock_rate = clock_rate; 2282 param->channel_count = channel_count; 2283 param->samples_per_frame = samples_per_frame; 2284 param->bits_per_sample = bits_per_sample; 2285 2286 /* Update the setting with user preference */ 2287 #define update_param(cap, field) \ 2288 if (pjsua_var.aud_param.flags & cap) { \ 2289 param->flags |= cap; \ 2290 param->field = pjsua_var.aud_param.field; \ 2291 } 2292 update_param( PJMEDIA_AUD_DEV_CAP_INPUT_VOLUME_SETTING, input_vol); 2293 update_param( PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING, output_vol); 2294 update_param( PJMEDIA_AUD_DEV_CAP_INPUT_ROUTE, input_route); 2295 update_param( PJMEDIA_AUD_DEV_CAP_OUTPUT_ROUTE, output_route); 2296 #undef update_param 2297 2403 2298 /* Latency settings */ 2404 param.flags |= (PJMEDIA_AUD_DEV_CAP_INPUT_LATENCY | 2405 PJMEDIA_AUD_DEV_CAP_OUTPUT_LATENCY); 2406 param.input_latency_ms = pjsua_var.media_cfg.snd_rec_latency; 2407 param.output_latency_ms = pjsua_var.media_cfg.snd_play_latency; 2299 param->flags |= (PJMEDIA_AUD_DEV_CAP_INPUT_LATENCY | 2300 PJMEDIA_AUD_DEV_CAP_OUTPUT_LATENCY); 2301 param->input_latency_ms = pjsua_var.media_cfg.snd_rec_latency; 2302 param->output_latency_ms = pjsua_var.media_cfg.snd_play_latency; 2303 2408 2304 /* EC settings */ 2409 2305 if (pjsua_var.media_cfg.ec_tail_len) { 2410 param .flags |= (PJMEDIA_AUD_DEV_CAP_EC | PJMEDIA_AUD_DEV_CAP_EC_TAIL);2411 param .ec_enabled = PJ_TRUE;2412 param .ec_tail_ms = pjsua_var.media_cfg.ec_tail_len;2306 param->flags |= (PJMEDIA_AUD_DEV_CAP_EC | PJMEDIA_AUD_DEV_CAP_EC_TAIL); 2307 param->ec_enabled = PJ_TRUE; 2308 param->ec_tail_ms = pjsua_var.media_cfg.ec_tail_len; 2413 2309 } else { 2414 param.flags &= ~(PJMEDIA_AUD_DEV_CAP_EC | PJMEDIA_AUD_DEV_CAP_EC_TAIL); 2415 } 2416 2417 return open_snd_dev_ext(¶m); 2418 2419 #else 2420 2310 param->flags &= ~(PJMEDIA_AUD_DEV_CAP_EC|PJMEDIA_AUD_DEV_CAP_EC_TAIL); 2311 } 2312 2313 return PJ_SUCCESS; 2314 } 2315 2316 /* Internal: the first time the audio device is opened (during app 2317 * startup), retrieve the audio settings such as volume level 2318 * so that aud_get_settings() will work. 2319 */ 2320 static pj_status_t update_initial_aud_param() 2321 { 2322 pjmedia_aud_stream *strm; 2323 pjmedia_aud_param param; 2324 pj_status_t status; 2325 2326 PJ_ASSERT_RETURN(pjsua_var.snd_port != NULL, PJ_EBUG); 2327 2328 strm = pjmedia_snd_port_get_snd_stream(pjsua_var.snd_port); 2329 2330 status = pjmedia_aud_stream_get_param(strm, ¶m); 2331 if (status != PJ_SUCCESS) { 2332 pjsua_perror(THIS_FILE, "Error audio stream " 2333 "device parameters", status); 2334 return status; 2335 } 2336 2337 #define update_saved_param(cap, field) \ 2338 if (param.flags & cap) { \ 2339 pjsua_var.aud_param.flags |= cap; \ 2340 pjsua_var.aud_param.field = param.field; \ 2341 } 2342 2343 update_saved_param(PJMEDIA_AUD_DEV_CAP_INPUT_VOLUME_SETTING, input_vol); 2344 update_saved_param(PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING, output_vol); 2345 update_saved_param(PJMEDIA_AUD_DEV_CAP_INPUT_ROUTE, input_route); 2346 update_saved_param(PJMEDIA_AUD_DEV_CAP_OUTPUT_ROUTE, output_route); 2347 #undef update_saved_param 2348 2349 return PJ_SUCCESS; 2350 } 2351 2352 /* Get format name */ 2353 static const char *get_fmt_name(pj_uint32_t id) 2354 { 2355 static char name[8]; 2356 2357 if (id == PJMEDIA_FORMAT_L16) 2358 return "PCM"; 2359 pj_memcpy(name, &id, 4); 2360 name[4] = '\0'; 2361 return name; 2362 } 2363 2364 /* Open sound device with the setting. */ 2365 static pj_status_t open_snd_dev(pjmedia_aud_param *param) 2366 { 2421 2367 pjmedia_port *conf_port; 2422 pjmedia_aud_dev_info play_info; 2423 pjmedia_aud_param param; 2424 unsigned clock_rates[] = {0, 44100, 48000, 32000, 16000, 8000}; 2425 unsigned selected_clock_rate = 0; 2426 unsigned i; 2427 pjmedia_aud_stream *strm; 2428 pj_str_t tmp; 2429 pj_status_t status = -1; 2368 pj_status_t status; 2369 2370 PJ_ASSERT_RETURN(param, PJ_EINVAL); 2430 2371 2431 2372 /* Check if NULL sound device is used */ 2432 if (NULL_SND_DEV_ID == capture_dev || NULL_SND_DEV_ID == playback_dev) {2373 if (NULL_SND_DEV_ID==param->rec_id || NULL_SND_DEV_ID==param->play_id) { 2433 2374 return pjsua_set_null_snd_dev(); 2434 2375 } 2435 2436 /* Normalize device ID with new convention about default device ID */2437 if (playback_dev == PJMEDIA_AUD_DEFAULT_CAPTURE_DEV)2438 playback_dev = PJMEDIA_AUD_DEFAULT_PLAYBACK_DEV;2439 2376 2440 2377 /* Close existing sound port */ … … 2442 2379 2443 2380 /* Create memory pool for sound device. */ 2444 pjsua_var.snd_pool = pjsua_pool_create("pjsua_snd", 1000, 1000);2381 pjsua_var.snd_pool = pjsua_pool_create("pjsua_snd", 4000, 4000); 2445 2382 PJ_ASSERT_RETURN(pjsua_var.snd_pool, PJ_ENOMEM); 2446 2383 2447 /* Set default clock rate */ 2448 clock_rates[0] = pjsua_var.media_cfg.snd_clock_rate; 2449 if (clock_rates[0] == 0) 2450 clock_rates[0] = pjsua_var.media_cfg.clock_rate; 2384 2385 PJ_LOG(4,(THIS_FILE, "Opening sound device %s@%d/%d/%dms", 2386 get_fmt_name(param->ext_fmt.id), 2387 param->clock_rate, param->channel_count, 2388 param->samples_per_frame / param->channel_count * 1000 / 2389 param->clock_rate)); 2390 2391 status = pjmedia_snd_port_create2( pjsua_var.snd_pool, 2392 param, &pjsua_var.snd_port); 2393 if (status != PJ_SUCCESS) 2394 return status; 2451 2395 2452 2396 /* Get the port0 of the conference bridge. */ … … 2454 2398 pj_assert(conf_port != NULL); 2455 2399 2456 /* Create default parameters for the device */ 2457 status = pjmedia_aud_dev_default_param(capture_dev, ¶m); 2458 if (status != PJ_SUCCESS) { 2459 pjsua_perror(THIS_FILE, "Error retrieving default audio " 2460 "device parameters", status); 2461 return status; 2462 } 2463 param.dir = PJMEDIA_DIR_CAPTURE_PLAYBACK; 2464 param.rec_id = capture_dev; 2465 param.play_id = playback_dev; 2466 param.channel_count = pjsua_var.media_cfg.channel_count; 2467 /* Latency settings */ 2468 param.flags |= (PJMEDIA_AUD_DEV_CAP_INPUT_LATENCY | 2469 PJMEDIA_AUD_DEV_CAP_OUTPUT_LATENCY); 2470 param.input_latency_ms = pjsua_var.media_cfg.snd_rec_latency; 2471 param.output_latency_ms = pjsua_var.media_cfg.snd_play_latency; 2472 /* EC settings */ 2473 if (pjsua_var.media_cfg.ec_tail_len) { 2474 param.flags |= (PJMEDIA_AUD_DEV_CAP_EC | PJMEDIA_AUD_DEV_CAP_EC_TAIL); 2475 param.ec_enabled = PJ_TRUE; 2476 param.ec_tail_ms = pjsua_var.media_cfg.ec_tail_len; 2477 } else { 2478 param.flags &= ~(PJMEDIA_AUD_DEV_CAP_EC | PJMEDIA_AUD_DEV_CAP_EC_TAIL); 2479 } 2480 2481 /* Attempts to open the sound device with different clock rates */ 2482 for (i=0; i<PJ_ARRAY_SIZE(clock_rates); ++i) { 2483 char errmsg[PJ_ERR_MSG_SIZE]; 2484 2485 PJ_LOG(4,(THIS_FILE, 2486 "pjsua_set_snd_dev(): attempting to open devices " 2487 "@%d Hz", clock_rates[i])); 2488 2489 param.clock_rate = clock_rates[i]; 2490 param.samples_per_frame = clock_rates[i] * 2491 pjsua_var.media_cfg.audio_frame_ptime * 2492 pjsua_var.media_cfg.channel_count / 1000; 2493 2494 /* Create the sound device. Sound port will start immediately. */ 2495 status = pjmedia_snd_port_create2(pjsua_var.snd_pool, ¶m, 2496 &pjsua_var.snd_port); 2497 2498 if (status == PJ_SUCCESS) { 2499 selected_clock_rate = clock_rates[i]; 2500 2501 /* If there's mismatch between sound port and conference's port, 2502 * create a resample port to bridge them. 2503 */ 2504 if (selected_clock_rate != pjsua_var.media_cfg.clock_rate) { 2505 pjmedia_port *resample_port; 2506 unsigned resample_opt = 0; 2507 2508 if (pjsua_var.media_cfg.quality >= 3 && 2509 pjsua_var.media_cfg.quality <= 4) 2510 { 2511 resample_opt |= PJMEDIA_RESAMPLE_USE_SMALL_FILTER; 2512 } 2513 else if (pjsua_var.media_cfg.quality < 3) { 2514 resample_opt |= PJMEDIA_RESAMPLE_USE_LINEAR; 2515 } 2516 2517 status = pjmedia_resample_port_create(pjsua_var.snd_pool, 2518 conf_port, 2519 selected_clock_rate, 2520 resample_opt, 2521 &resample_port); 2522 if (status != PJ_SUCCESS) { 2523 pj_strerror(status, errmsg, sizeof(errmsg)); 2524 PJ_LOG(4, (THIS_FILE, 2525 "Error creating resample port, trying next " 2526 "clock rate", 2527 errmsg)); 2528 pjmedia_snd_port_destroy(pjsua_var.snd_port); 2529 pjsua_var.snd_port = NULL; 2530 continue; 2531 } else { 2532 conf_port = resample_port; 2533 break; 2534 } 2535 2536 } else { 2537 break; 2538 } 2539 } 2540 2541 pj_strerror(status, errmsg, sizeof(errmsg)); 2542 PJ_LOG(4, (THIS_FILE, "..failed: %s", errmsg)); 2543 } 2544 2545 if (status != PJ_SUCCESS) { 2546 pjsua_perror(THIS_FILE, "Unable to open sound device", status); 2547 return status; 2548 } 2549 2550 /* Connect sound port to the bridge */ 2400 /* For conference bridge, resample if necessary if the bridge's 2401 * clock rate is different than the sound device's clock rate. 2402 */ 2403 if (!pjsua_var.is_mswitch && 2404 param->ext_fmt.id == PJMEDIA_FORMAT_PCM && 2405 conf_port->info.clock_rate != param->clock_rate) 2406 { 2407 pjmedia_port *resample_port; 2408 unsigned resample_opt = 0; 2409 2410 if (pjsua_var.media_cfg.quality >= 3 && 2411 pjsua_var.media_cfg.quality <= 4) 2412 { 2413 resample_opt |= PJMEDIA_RESAMPLE_USE_SMALL_FILTER; 2414 } 2415 else if (pjsua_var.media_cfg.quality < 3) { 2416 resample_opt |= PJMEDIA_RESAMPLE_USE_LINEAR; 2417 } 2418 2419 status = pjmedia_resample_port_create(pjsua_var.snd_pool, 2420 conf_port, 2421 param->clock_rate, 2422 resample_opt, 2423 &resample_port); 2424 if (status != PJ_SUCCESS) { 2425 char errmsg[PJ_ERR_MSG_SIZE]; 2426 pj_strerror(status, errmsg, sizeof(errmsg)); 2427 PJ_LOG(4, (THIS_FILE, 2428 "Error creating resample port: %s", 2429 errmsg)); 2430 close_snd_dev(); 2431 return status; 2432 } 2433 2434 conf_port = resample_port; 2435 } 2436 2437 /* Otherwise for audio switchboard, the switch's port0 setting is 2438 * derived from the sound device setting, so update the setting. 2439 */ 2440 if (pjsua_var.is_mswitch) { 2441 pj_memcpy(&conf_port->info.format, ¶m->ext_fmt, 2442 sizeof(conf_port->info.format)); 2443 conf_port->info.clock_rate = param->clock_rate; 2444 conf_port->info.samples_per_frame = param->samples_per_frame; 2445 conf_port->info.channel_count = param->channel_count; 2446 conf_port->info.bits_per_sample = 16; 2447 } 2448 2449 /* Connect sound port to the bridge */ 2551 2450 status = pjmedia_snd_port_connect(pjsua_var.snd_port, 2552 2451 conf_port ); … … 2560 2459 2561 2460 /* Save the device IDs */ 2562 pjsua_var.cap_dev = capture_dev;2563 pjsua_var.play_dev = p layback_dev;2461 pjsua_var.cap_dev = param->rec_id; 2462 pjsua_var.play_dev = param->play_id; 2564 2463 2565 2464 /* Update sound device name. */ 2566 strm = pjmedia_snd_port_get_snd_stream(pjsua_var.snd_port); 2567 pjmedia_aud_stream_get_param(strm, ¶m); 2568 pjmedia_aud_dev_get_info(param.play_id, &play_info); 2569 2570 if (param.clock_rate != pjsua_var.media_cfg.clock_rate) { 2571 char tmp_buf[128]; 2572 int tmp_buf_len = sizeof(tmp_buf); 2573 2574 tmp_buf_len = pj_ansi_snprintf(tmp_buf, sizeof(tmp_buf)-1, "%s (%dKHz)", 2575 play_info.name, param.clock_rate/1000); 2576 pj_strset(&tmp, tmp_buf, tmp_buf_len); 2577 pjmedia_conf_set_port0_name(pjsua_var.mconf, &tmp); 2465 { 2466 pjmedia_aud_dev_info rec_info; 2467 pjmedia_aud_stream *strm; 2468 pjmedia_aud_param si; 2469 pj_str_t tmp; 2470 2471 strm = pjmedia_snd_port_get_snd_stream(pjsua_var.snd_port); 2472 status = pjmedia_aud_stream_get_param(strm, &si); 2473 if (status == PJ_SUCCESS) 2474 status = pjmedia_aud_dev_get_info(si.rec_id, &rec_info); 2475 2476 if (status==PJ_SUCCESS) { 2477 if (param->clock_rate != pjsua_var.media_cfg.clock_rate) { 2478 char tmp_buf[128]; 2479 int tmp_buf_len = sizeof(tmp_buf); 2480 2481 tmp_buf_len = pj_ansi_snprintf(tmp_buf, sizeof(tmp_buf)-1, 2482 "%s (%dKHz)", 2483 rec_info.name, 2484 param->clock_rate/1000); 2485 pj_strset(&tmp, tmp_buf, tmp_buf_len); 2486 pjmedia_conf_set_port0_name(pjsua_var.mconf, &tmp); 2487 } else { 2488 pjmedia_conf_set_port0_name(pjsua_var.mconf, 2489 pj_cstr(&tmp, rec_info.name)); 2490 } 2491 } 2492 2493 /* Any error is not major, let it through */ 2494 status = PJ_SUCCESS; 2495 }; 2496 2497 /* If this is the first time the audio device is open, retrieve some 2498 * settings from the device (such as volume settings) so that the 2499 * pjsua_snd_get_setting() work. 2500 */ 2501 if (pjsua_var.aud_open_cnt == 0) { 2502 update_initial_aud_param(); 2503 ++pjsua_var.aud_open_cnt; 2504 } 2505 2506 return PJ_SUCCESS; 2507 } 2508 2509 2510 /* Close existing sound device */ 2511 static void close_snd_dev(void) 2512 { 2513 /* Close sound device */ 2514 if (pjsua_var.snd_port) { 2515 pjmedia_aud_dev_info cap_info, play_info; 2516 pjmedia_aud_stream *strm; 2517 pjmedia_aud_param param; 2518 2519 strm = pjmedia_snd_port_get_snd_stream(pjsua_var.snd_port); 2520 pjmedia_aud_stream_get_param(strm, ¶m); 2521 2522 if (pjmedia_aud_dev_get_info(param.rec_id, &cap_info) != PJ_SUCCESS) 2523 cap_info.name[0] = '\0'; 2524 if (pjmedia_aud_dev_get_info(param.play_id, &play_info) != PJ_SUCCESS) 2525 play_info.name[0] = '\0'; 2526 2527 PJ_LOG(4,(THIS_FILE, "Closing %s sound playback device and " 2528 "%s sound capture device", 2529 play_info.name, cap_info.name)); 2530 2531 pjmedia_snd_port_disconnect(pjsua_var.snd_port); 2532 pjmedia_snd_port_destroy(pjsua_var.snd_port); 2533 pjsua_var.snd_port = NULL; 2534 } 2535 2536 /* Close null sound device */ 2537 if (pjsua_var.null_snd) { 2538 PJ_LOG(4,(THIS_FILE, "Closing null sound device..")); 2539 pjmedia_master_port_destroy(pjsua_var.null_snd, PJ_FALSE); 2540 pjsua_var.null_snd = NULL; 2541 } 2542 2543 if (pjsua_var.snd_pool) 2544 pj_pool_release(pjsua_var.snd_pool); 2545 pjsua_var.snd_pool = NULL; 2546 } 2547 2548 2549 /* 2550 * Select or change sound device. Application may call this function at 2551 * any time to replace current sound device. 2552 */ 2553 PJ_DEF(pj_status_t) pjsua_set_snd_dev( int capture_dev, 2554 int playback_dev) 2555 { 2556 unsigned alt_cr_cnt = 1; 2557 unsigned alt_cr[] = {0, 44100, 48000, 32000, 16000, 8000}; 2558 unsigned i; 2559 pj_status_t status = -1; 2560 2561 /* Set default clock rate */ 2562 alt_cr[0] = pjsua_var.media_cfg.snd_clock_rate; 2563 if (alt_cr[0] == 0) 2564 alt_cr[0] = pjsua_var.media_cfg.clock_rate; 2565 2566 /* Allow retrying of different clock rate if we're using conference 2567 * bridge (meaning audio format is always PCM), otherwise lock on 2568 * to one clock rate. 2569 */ 2570 if (pjsua_var.is_mswitch) { 2571 alt_cr_cnt = 1; 2578 2572 } else { 2579 pjmedia_conf_set_port0_name(pjsua_var.mconf, 2580 pj_cstr(&tmp, play_info.name)); 2581 } 2582 2583 return PJ_SUCCESS; 2584 2585 #endif /* PJMEDIA_CONF_USE_SWITCH_BOARD */ 2586 2573 alt_cr_cnt = PJ_ARRAY_SIZE(alt_cr); 2574 } 2575 2576 /* Attempts to open the sound device with different clock rates */ 2577 for (i=0; i<alt_cr_cnt; ++i) { 2578 pjmedia_aud_param param; 2579 unsigned samples_per_frame; 2580 2581 /* Create the default audio param */ 2582 samples_per_frame = alt_cr[i] * 2583 pjsua_var.media_cfg.audio_frame_ptime * 2584 pjsua_var.media_cfg.channel_count / 1000; 2585 status = create_aud_param(¶m, capture_dev, playback_dev, 2586 alt_cr[i], pjsua_var.media_cfg.channel_count, 2587 samples_per_frame, 16); 2588 if (status != PJ_SUCCESS) 2589 return status; 2590 2591 /* Open! */ 2592 status = open_snd_dev(¶m); 2593 if (status == PJ_SUCCESS) 2594 break; 2595 } 2596 2597 if (status != PJ_SUCCESS) { 2598 pjsua_perror(THIS_FILE, "Unable to open sound device", status); 2599 return status; 2600 } 2601 2602 return PJ_SUCCESS; 2587 2603 } 2588 2604 … … 2690 2706 2691 2707 /* 2692 * Get active sound port instance. 2693 */ 2694 PJ_DEF(pjmedia_aud_stream*) pjsua_get_aud_stream() 2695 { 2696 pjmedia_aud_stream *aud_stream = NULL; 2697 2698 if (pjsua_var.snd_port) 2699 aud_stream = pjmedia_snd_port_get_snd_stream(pjsua_var.snd_port); 2700 2701 return aud_stream; 2708 * Check whether the sound device is currently active. 2709 */ 2710 PJ_DEF(pj_bool_t) pjsua_snd_is_active(void) 2711 { 2712 return pjsua_var.snd_port != NULL; 2713 } 2714 2715 2716 /* 2717 * Configure sound device setting to the sound device being used. 2718 */ 2719 PJ_DEF(pj_status_t) pjsua_snd_set_setting( pjmedia_aud_dev_cap cap, 2720 const void *pval, 2721 pj_bool_t keep) 2722 { 2723 /* Check if we are allowed to set the cap */ 2724 if (cap & pjsua_var.aud_svmask) { 2725 return PJMEDIA_EAUD_INVCAP; 2726 } 2727 2728 if (keep) { 2729 /* Save in internal param for later device open */ 2730 pj_status_t status; 2731 2732 status = pjmedia_aud_param_set_cap(&pjsua_var.aud_param, 2733 cap, pval); 2734 if (status != PJ_SUCCESS) 2735 return status; 2736 } 2737 2738 if (pjsua_snd_is_active()) { 2739 /* Sound is active, set it immediately */ 2740 pjmedia_aud_stream *strm; 2741 2742 strm = pjmedia_snd_port_get_snd_stream(pjsua_var.snd_port); 2743 return pjmedia_aud_stream_set_cap(strm, cap, pval); 2744 } else { 2745 return PJ_SUCCESS; 2746 } 2747 } 2748 2749 /* 2750 * Retrieve a sound device setting. 2751 */ 2752 PJ_DEF(pj_status_t) pjsua_snd_get_setting( pjmedia_aud_dev_cap cap, 2753 void *pval) 2754 { 2755 /* If sound device has never been opened before, open it to 2756 * retrieve the initial setting from the device (e.g. audio 2757 * volume) 2758 */ 2759 if (pjsua_var.aud_open_cnt==0) 2760 pjsua_set_snd_dev(pjsua_var.cap_dev, pjsua_var.play_dev); 2761 2762 if (pjsua_snd_is_active()) { 2763 /* Sound is active, retrieve from device directly */ 2764 pjmedia_aud_stream *strm; 2765 2766 strm = pjmedia_snd_port_get_snd_stream(pjsua_var.snd_port); 2767 return pjmedia_aud_stream_get_cap(strm, cap, pval); 2768 } else { 2769 /* Otherwise retrieve from internal param */ 2770 return pjmedia_aud_param_get_cap(&pjsua_var.aud_param, 2771 cap, pval); 2772 } 2702 2773 } 2703 2774
Note: See TracChangeset
for help on using the changeset viewer.