Changeset 2506 for pjproject/trunk/pjsip/src/pjsua-lib/pjsua_media.c
- Timestamp:
- Mar 12, 2009 6:11:37 PM (14 years ago)
- Location:
- pjproject/trunk
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
pjproject/trunk
-
Property
svn:mergeinfo
set to
False
/pjproject/branches/projects/aps-direct merged eligible
-
Property
svn:mergeinfo
set to
False
-
pjproject/trunk/pjsip/src/pjsua-lib/pjsua_media.c
r2425 r2506 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); 79 /* EC settings use different API */ 80 pjsua_var.aud_svmask &= ~(PJMEDIA_AUD_DEV_CAP_EC | 81 PJMEDIA_AUD_DEV_CAP_EC_TAIL); 62 82 63 83 /* Copy configuration */ … … 172 192 173 193 #endif /* PJMEDIA_HAS_INTEL_IPP */ 194 195 #if PJMEDIA_HAS_PASSTHROUGH_CODECS 196 /* Register passthrough codecs */ 197 status = pjmedia_codec_passthrough_init(pjsua_var.med_endpt); 198 if (status != PJ_SUCCESS) { 199 pjsua_perror(THIS_FILE, "Error initializing passthrough codecs", 200 status); 201 return status; 202 } 203 #endif /* PJMEDIA_HAS_PASSTHROUGH_CODECS */ 174 204 175 205 #if PJMEDIA_HAS_L16_CODEC … … 226 256 return status; 227 257 } 258 259 /* Are we using the audio switchboard (a.k.a APS-Direct)? */ 260 pjsua_var.is_mswitch = pjmedia_conf_get_master_port(pjsua_var.mconf) 261 ->info.signature == PJMEDIA_CONF_SWITCH_SIGNATURE; 228 262 229 263 /* Create null port just in case user wants to use null sound. */ … … 574 608 pjmedia_codec_ipp_deinit(); 575 609 # endif /* PJMEDIA_HAS_INTEL_IPP */ 610 611 # if PJMEDIA_HAS_PASSTHROUGH_CODECS 612 pjmedia_codec_passthrough_deinit(); 613 # endif /* PJMEDIA_HAS_PASSTHROUGH_CODECS */ 576 614 577 615 # if PJMEDIA_HAS_L16_CODEC … … 1496 1534 } 1497 1535 1498 1499 1536 /* 1500 1537 * Get maxinum number of conference ports. … … 1611 1648 } 1612 1649 1613 /* Create sound port if none is instantiated */ 1614 if (pjsua_var.snd_port==NULL && pjsua_var.null_snd==NULL && 1615 !pjsua_var.no_snd) 1616 { 1650 1651 /* For audio switchboard (i.e. APS-Direct): 1652 * Check if sound device need to be reopened, i.e: its attributes 1653 * (format, clock rate, channel count) must match to peer's. 1654 * Note that sound device can be reopened only if it doesn't have 1655 * any connection. 1656 */ 1657 if (pjsua_var.is_mswitch) { 1658 pjmedia_conf_port_info port0_info; 1659 pjmedia_conf_port_info peer_info; 1660 unsigned peer_id; 1661 pj_bool_t need_reopen = PJ_FALSE; 1617 1662 pj_status_t status; 1618 1663 1619 status = pjsua_set_snd_dev(pjsua_var.cap_dev, pjsua_var.play_dev); 1620 if (status != PJ_SUCCESS) { 1621 pjsua_perror(THIS_FILE, "Error opening sound device", status); 1622 return status; 1623 } 1664 peer_id = (source!=0)? source : sink; 1665 status = pjmedia_conf_get_port_info(pjsua_var.mconf, peer_id, 1666 &peer_info); 1667 pj_assert(status == PJ_SUCCESS); 1668 1669 status = pjmedia_conf_get_port_info(pjsua_var.mconf, 0, &port0_info); 1670 pj_assert(status == PJ_SUCCESS); 1671 1672 /* Check if sound device is instantiated. */ 1673 need_reopen = (pjsua_var.snd_port==NULL && pjsua_var.null_snd==NULL && 1674 !pjsua_var.no_snd); 1675 1676 /* Check if sound device need to reopen because it needs to modify 1677 * settings to match its peer. Sound device must be idle in this case 1678 * though. 1679 */ 1680 if (!need_reopen && 1681 port0_info.listener_cnt==0 && port0_info.transmitter_cnt==0) 1682 { 1683 need_reopen = (peer_info.format.id != port0_info.format.id || 1684 peer_info.format.bitrate != port0_info.format.bitrate || 1685 peer_info.clock_rate != port0_info.clock_rate || 1686 peer_info.channel_count != port0_info.channel_count); 1687 } 1688 1689 if (need_reopen) { 1690 pjmedia_aud_param param; 1691 1692 /* Create parameter based on peer info */ 1693 status = create_aud_param(¶m, pjsua_var.cap_dev, 1694 pjsua_var.play_dev, 1695 peer_info.clock_rate, 1696 peer_info.channel_count, 1697 peer_info.samples_per_frame, 1698 peer_info.bits_per_sample); 1699 1700 /* And peer format */ 1701 if (peer_info.format.id != PJMEDIA_FORMAT_PCM) { 1702 param.flags |= PJMEDIA_AUD_DEV_CAP_EXT_FORMAT; 1703 param.ext_fmt = peer_info.format; 1704 } 1705 1706 status = open_snd_dev(¶m); 1707 if (status != PJ_SUCCESS) { 1708 pjsua_perror(THIS_FILE, "Error opening sound device", status); 1709 return status; 1710 } 1711 } 1712 1713 } else { 1714 /* The bridge version */ 1715 1716 /* Create sound port if none is instantiated */ 1717 if (pjsua_var.snd_port==NULL && pjsua_var.null_snd==NULL && 1718 !pjsua_var.no_snd) 1719 { 1720 pj_status_t status; 1721 1722 status = pjsua_set_snd_dev(pjsua_var.cap_dev, pjsua_var.play_dev); 1723 if (status != PJ_SUCCESS) { 1724 pjsua_perror(THIS_FILE, "Error opening sound device", status); 1725 return status; 1726 } 1727 } 1728 1624 1729 } 1625 1730 … … 2098 2203 * Enum sound devices. 2099 2204 */ 2205 2206 PJ_DEF(pj_status_t) pjsua_enum_aud_devs( pjmedia_aud_dev_info info[], 2207 unsigned *count) 2208 { 2209 unsigned i, dev_count; 2210 2211 dev_count = pjmedia_aud_dev_count(); 2212 2213 if (dev_count > *count) dev_count = *count; 2214 2215 for (i=0; i<dev_count; ++i) { 2216 pj_status_t status; 2217 2218 status = pjmedia_aud_dev_get_info(i, &info[i]); 2219 if (status != PJ_SUCCESS) 2220 return status; 2221 } 2222 2223 *count = dev_count; 2224 2225 return PJ_SUCCESS; 2226 } 2227 2228 2100 2229 PJ_DEF(pj_status_t) pjsua_enum_snd_devs( pjmedia_snd_dev_info info[], 2101 2230 unsigned *count) … … 2103 2232 unsigned i, dev_count; 2104 2233 2105 dev_count = pjmedia_ snd_get_dev_count();2234 dev_count = pjmedia_aud_dev_count(); 2106 2235 2107 2236 if (dev_count > *count) dev_count = *count; 2237 pj_bzero(info, dev_count * sizeof(pjmedia_snd_dev_info)); 2108 2238 2109 2239 for (i=0; i<dev_count; ++i) { 2110 const pjmedia_snd_dev_info *ci; 2111 2112 ci = pjmedia_snd_get_dev_info(i); 2113 pj_memcpy(&info[i], ci, sizeof(*ci)); 2240 pjmedia_aud_dev_info ai; 2241 pj_status_t status; 2242 2243 status = pjmedia_aud_dev_get_info(i, &ai); 2244 if (status != PJ_SUCCESS) 2245 return status; 2246 2247 strncpy(info[i].name, ai.name, sizeof(info[i].name)); 2248 info[i].name[sizeof(info[i].name)-1] = '\0'; 2249 info[i].input_count = ai.input_count; 2250 info[i].output_count = ai.output_count; 2251 info[i].default_samples_per_sec = ai.default_samples_per_sec; 2114 2252 } 2115 2253 … … 2119 2257 } 2120 2258 2121 2122 /* Close existing sound device */ 2123 static void close_snd_dev(void) 2124 { 2125 /* Close sound device */ 2126 if (pjsua_var.snd_port) { 2127 const pjmedia_snd_dev_info *cap_info, *play_info; 2128 2129 cap_info = pjmedia_snd_get_dev_info(pjsua_var.cap_dev); 2130 play_info = pjmedia_snd_get_dev_info(pjsua_var.play_dev); 2131 2132 PJ_LOG(4,(THIS_FILE, "Closing %s sound playback device and " 2133 "%s sound capture device", 2134 play_info->name, cap_info->name)); 2135 2136 pjmedia_snd_port_disconnect(pjsua_var.snd_port); 2137 pjmedia_snd_port_destroy(pjsua_var.snd_port); 2138 pjsua_var.snd_port = NULL; 2139 } 2140 2141 /* Close null sound device */ 2142 if (pjsua_var.null_snd) { 2143 PJ_LOG(4,(THIS_FILE, "Closing null sound device..")); 2144 pjmedia_master_port_destroy(pjsua_var.null_snd, PJ_FALSE); 2145 pjsua_var.null_snd = NULL; 2146 } 2147 2148 if (pjsua_var.snd_pool) 2149 pj_pool_release(pjsua_var.snd_pool); 2150 pjsua_var.snd_pool = NULL; 2151 } 2152 2153 /* 2154 * Select or change sound device. Application may call this function at 2155 * any time to replace current sound device. 2156 */ 2157 PJ_DEF(pj_status_t) pjsua_set_snd_dev( int capture_dev, 2158 int playback_dev) 2259 /* Create audio device parameter to open the device */ 2260 static pj_status_t create_aud_param(pjmedia_aud_param *param, 2261 pjmedia_aud_dev_index capture_dev, 2262 pjmedia_aud_dev_index playback_dev, 2263 unsigned clock_rate, 2264 unsigned channel_count, 2265 unsigned samples_per_frame, 2266 unsigned bits_per_sample) 2267 { 2268 pj_status_t status; 2269 2270 /* Normalize device ID with new convention about default device ID */ 2271 if (playback_dev == PJMEDIA_AUD_DEFAULT_CAPTURE_DEV) 2272 playback_dev = PJMEDIA_AUD_DEFAULT_PLAYBACK_DEV; 2273 2274 /* Create default parameters for the device */ 2275 status = pjmedia_aud_dev_default_param(capture_dev, param); 2276 if (status != PJ_SUCCESS) { 2277 pjsua_perror(THIS_FILE, "Error retrieving default audio " 2278 "device parameters", status); 2279 return status; 2280 } 2281 param->dir = PJMEDIA_DIR_CAPTURE_PLAYBACK; 2282 param->rec_id = capture_dev; 2283 param->play_id = playback_dev; 2284 param->clock_rate = clock_rate; 2285 param->channel_count = channel_count; 2286 param->samples_per_frame = samples_per_frame; 2287 param->bits_per_sample = bits_per_sample; 2288 2289 /* Update the setting with user preference */ 2290 #define update_param(cap, field) \ 2291 if (pjsua_var.aud_param.flags & cap) { \ 2292 param->flags |= cap; \ 2293 param->field = pjsua_var.aud_param.field; \ 2294 } 2295 update_param( PJMEDIA_AUD_DEV_CAP_INPUT_VOLUME_SETTING, input_vol); 2296 update_param( PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING, output_vol); 2297 update_param( PJMEDIA_AUD_DEV_CAP_INPUT_ROUTE, input_route); 2298 update_param( PJMEDIA_AUD_DEV_CAP_OUTPUT_ROUTE, output_route); 2299 #undef update_param 2300 2301 /* Latency settings */ 2302 param->flags |= (PJMEDIA_AUD_DEV_CAP_INPUT_LATENCY | 2303 PJMEDIA_AUD_DEV_CAP_OUTPUT_LATENCY); 2304 param->input_latency_ms = pjsua_var.media_cfg.snd_rec_latency; 2305 param->output_latency_ms = pjsua_var.media_cfg.snd_play_latency; 2306 2307 /* EC settings */ 2308 if (pjsua_var.media_cfg.ec_tail_len) { 2309 param->flags |= (PJMEDIA_AUD_DEV_CAP_EC | PJMEDIA_AUD_DEV_CAP_EC_TAIL); 2310 param->ec_enabled = PJ_TRUE; 2311 param->ec_tail_ms = pjsua_var.media_cfg.ec_tail_len; 2312 } else { 2313 param->flags &= ~(PJMEDIA_AUD_DEV_CAP_EC|PJMEDIA_AUD_DEV_CAP_EC_TAIL); 2314 } 2315 2316 return PJ_SUCCESS; 2317 } 2318 2319 /* Internal: the first time the audio device is opened (during app 2320 * startup), retrieve the audio settings such as volume level 2321 * so that aud_get_settings() will work. 2322 */ 2323 static pj_status_t update_initial_aud_param() 2324 { 2325 pjmedia_aud_stream *strm; 2326 pjmedia_aud_param param; 2327 pj_status_t status; 2328 2329 PJ_ASSERT_RETURN(pjsua_var.snd_port != NULL, PJ_EBUG); 2330 2331 strm = pjmedia_snd_port_get_snd_stream(pjsua_var.snd_port); 2332 2333 status = pjmedia_aud_stream_get_param(strm, ¶m); 2334 if (status != PJ_SUCCESS) { 2335 pjsua_perror(THIS_FILE, "Error audio stream " 2336 "device parameters", status); 2337 return status; 2338 } 2339 2340 #define update_saved_param(cap, field) \ 2341 if (param.flags & cap) { \ 2342 pjsua_var.aud_param.flags |= cap; \ 2343 pjsua_var.aud_param.field = param.field; \ 2344 } 2345 2346 update_saved_param(PJMEDIA_AUD_DEV_CAP_INPUT_VOLUME_SETTING, input_vol); 2347 update_saved_param(PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING, output_vol); 2348 update_saved_param(PJMEDIA_AUD_DEV_CAP_INPUT_ROUTE, input_route); 2349 update_saved_param(PJMEDIA_AUD_DEV_CAP_OUTPUT_ROUTE, output_route); 2350 #undef update_saved_param 2351 2352 return PJ_SUCCESS; 2353 } 2354 2355 /* Get format name */ 2356 static const char *get_fmt_name(pj_uint32_t id) 2357 { 2358 static char name[8]; 2359 2360 if (id == PJMEDIA_FORMAT_L16) 2361 return "PCM"; 2362 pj_memcpy(name, &id, 4); 2363 name[4] = '\0'; 2364 return name; 2365 } 2366 2367 /* Open sound device with the setting. */ 2368 static pj_status_t open_snd_dev(pjmedia_aud_param *param) 2159 2369 { 2160 2370 pjmedia_port *conf_port; 2161 const pjmedia_snd_dev_info *play_info; 2162 unsigned clock_rates[] = {0, 44100, 48000, 32000, 16000, 8000}; 2163 unsigned selected_clock_rate = 0; 2164 unsigned i; 2165 pjmedia_snd_stream *strm; 2166 pjmedia_snd_stream_info si; 2167 pj_str_t tmp; 2168 pj_status_t status = -1; 2371 pj_status_t status; 2372 2373 PJ_ASSERT_RETURN(param, PJ_EINVAL); 2169 2374 2170 2375 /* Check if NULL sound device is used */ 2171 if (NULL_SND_DEV_ID == capture_dev || NULL_SND_DEV_ID == playback_dev) {2376 if (NULL_SND_DEV_ID==param->rec_id || NULL_SND_DEV_ID==param->play_id) { 2172 2377 return pjsua_set_null_snd_dev(); 2173 2378 } … … 2180 2385 PJ_ASSERT_RETURN(pjsua_var.snd_pool, PJ_ENOMEM); 2181 2386 2182 /* Set default clock rate */ 2183 clock_rates[0] = pjsua_var.media_cfg.snd_clock_rate; 2184 if (clock_rates[0] == 0) 2185 clock_rates[0] = pjsua_var.media_cfg.clock_rate; 2387 2388 PJ_LOG(4,(THIS_FILE, "Opening sound device %s@%d/%d/%dms", 2389 get_fmt_name(param->ext_fmt.id), 2390 param->clock_rate, param->channel_count, 2391 param->samples_per_frame / param->channel_count * 1000 / 2392 param->clock_rate)); 2393 2394 status = pjmedia_snd_port_create2( pjsua_var.snd_pool, 2395 param, &pjsua_var.snd_port); 2396 if (status != PJ_SUCCESS) 2397 return status; 2186 2398 2187 2399 /* Get the port0 of the conference bridge. */ … … 2189 2401 pj_assert(conf_port != NULL); 2190 2402 2191 /* Attempts to open the sound device with different clock rates */ 2192 for (i=0; i<PJ_ARRAY_SIZE(clock_rates); ++i) { 2193 char errmsg[PJ_ERR_MSG_SIZE]; 2194 unsigned samples_per_frame; 2195 2196 PJ_LOG(4,(THIS_FILE, 2197 "pjsua_set_snd_dev(): attempting to open devices " 2198 "@%d Hz", clock_rates[i])); 2199 2200 samples_per_frame = clock_rates[i] * 2201 pjsua_var.media_cfg.audio_frame_ptime * 2202 pjsua_var.media_cfg.channel_count / 1000; 2203 2204 /* Create the sound device. Sound port will start immediately. */ 2205 status = pjmedia_snd_port_create(pjsua_var.snd_pool, capture_dev, 2206 playback_dev, 2207 clock_rates[i], 2208 pjsua_var.media_cfg.channel_count, 2209 samples_per_frame, 2210 16, 0, &pjsua_var.snd_port); 2211 2212 if (status == PJ_SUCCESS) { 2213 selected_clock_rate = clock_rates[i]; 2214 2215 /* If there's mismatch between sound port and conference's port, 2216 * create a resample port to bridge them. 2217 */ 2218 if (selected_clock_rate != pjsua_var.media_cfg.clock_rate) { 2219 pjmedia_port *resample_port; 2220 unsigned resample_opt = 0; 2221 2222 if (pjsua_var.media_cfg.quality >= 3 && 2223 pjsua_var.media_cfg.quality <= 4) 2224 { 2225 resample_opt |= PJMEDIA_RESAMPLE_USE_SMALL_FILTER; 2226 } 2227 else if (pjsua_var.media_cfg.quality < 3) { 2228 resample_opt |= PJMEDIA_RESAMPLE_USE_LINEAR; 2229 } 2230 2231 status = pjmedia_resample_port_create(pjsua_var.snd_pool, 2232 conf_port, 2233 selected_clock_rate, 2234 resample_opt, 2235 &resample_port); 2236 if (status != PJ_SUCCESS) { 2237 pj_strerror(status, errmsg, sizeof(errmsg)); 2238 PJ_LOG(4, (THIS_FILE, 2239 "Error creating resample port, trying next " 2240 "clock rate", 2241 errmsg)); 2242 pjmedia_snd_port_destroy(pjsua_var.snd_port); 2243 pjsua_var.snd_port = NULL; 2244 continue; 2245 } else { 2246 conf_port = resample_port; 2247 break; 2248 } 2249 2250 } else { 2251 break; 2252 } 2253 } 2254 2255 pj_strerror(status, errmsg, sizeof(errmsg)); 2256 PJ_LOG(4, (THIS_FILE, "..failed: %s", errmsg)); 2257 } 2258 2259 if (status != PJ_SUCCESS) { 2260 pjsua_perror(THIS_FILE, "Unable to open sound device", status); 2261 return status; 2262 } 2263 2264 /* Set AEC */ 2265 pjmedia_snd_port_set_ec( pjsua_var.snd_port, pjsua_var.snd_pool, 2266 pjsua_var.media_cfg.ec_tail_len, 2267 pjsua_var.media_cfg.ec_options); 2268 2269 /* Connect sound port to the bridge */ 2403 /* For conference bridge, resample if necessary if the bridge's 2404 * clock rate is different than the sound device's clock rate. 2405 */ 2406 if (!pjsua_var.is_mswitch && 2407 param->ext_fmt.id == PJMEDIA_FORMAT_PCM && 2408 conf_port->info.clock_rate != param->clock_rate) 2409 { 2410 pjmedia_port *resample_port; 2411 unsigned resample_opt = 0; 2412 2413 if (pjsua_var.media_cfg.quality >= 3 && 2414 pjsua_var.media_cfg.quality <= 4) 2415 { 2416 resample_opt |= PJMEDIA_RESAMPLE_USE_SMALL_FILTER; 2417 } 2418 else if (pjsua_var.media_cfg.quality < 3) { 2419 resample_opt |= PJMEDIA_RESAMPLE_USE_LINEAR; 2420 } 2421 2422 status = pjmedia_resample_port_create(pjsua_var.snd_pool, 2423 conf_port, 2424 param->clock_rate, 2425 resample_opt, 2426 &resample_port); 2427 if (status != PJ_SUCCESS) { 2428 char errmsg[PJ_ERR_MSG_SIZE]; 2429 pj_strerror(status, errmsg, sizeof(errmsg)); 2430 PJ_LOG(4, (THIS_FILE, 2431 "Error creating resample port: %s", 2432 errmsg)); 2433 close_snd_dev(); 2434 return status; 2435 } 2436 2437 conf_port = resample_port; 2438 } 2439 2440 /* Otherwise for audio switchboard, the switch's port0 setting is 2441 * derived from the sound device setting, so update the setting. 2442 */ 2443 if (pjsua_var.is_mswitch) { 2444 pj_memcpy(&conf_port->info.format, ¶m->ext_fmt, 2445 sizeof(conf_port->info.format)); 2446 conf_port->info.clock_rate = param->clock_rate; 2447 conf_port->info.samples_per_frame = param->samples_per_frame; 2448 conf_port->info.channel_count = param->channel_count; 2449 conf_port->info.bits_per_sample = 16; 2450 } 2451 2452 /* Connect sound port to the bridge */ 2270 2453 status = pjmedia_snd_port_connect(pjsua_var.snd_port, 2271 2454 conf_port ); … … 2279 2462 2280 2463 /* Save the device IDs */ 2281 pjsua_var.cap_dev = capture_dev;2282 pjsua_var.play_dev = p layback_dev;2464 pjsua_var.cap_dev = param->rec_id; 2465 pjsua_var.play_dev = param->play_id; 2283 2466 2284 2467 /* Update sound device name. */ 2285 strm = pjmedia_snd_port_get_snd_stream(pjsua_var.snd_port); 2286 pjmedia_snd_stream_get_info(strm, &si); 2287 play_info = pjmedia_snd_get_dev_info(si.rec_id); 2288 2289 if (si.clock_rate != pjsua_var.media_cfg.clock_rate) { 2290 char tmp_buf[128]; 2291 int tmp_buf_len = sizeof(tmp_buf); 2292 2293 tmp_buf_len = pj_ansi_snprintf(tmp_buf, sizeof(tmp_buf)-1, "%s (%dKHz)", 2294 play_info->name, si.clock_rate/1000); 2295 pj_strset(&tmp, tmp_buf, tmp_buf_len); 2296 pjmedia_conf_set_port0_name(pjsua_var.mconf, &tmp); 2468 { 2469 pjmedia_aud_dev_info rec_info; 2470 pjmedia_aud_stream *strm; 2471 pjmedia_aud_param si; 2472 pj_str_t tmp; 2473 2474 strm = pjmedia_snd_port_get_snd_stream(pjsua_var.snd_port); 2475 status = pjmedia_aud_stream_get_param(strm, &si); 2476 if (status == PJ_SUCCESS) 2477 status = pjmedia_aud_dev_get_info(si.rec_id, &rec_info); 2478 2479 if (status==PJ_SUCCESS) { 2480 if (param->clock_rate != pjsua_var.media_cfg.clock_rate) { 2481 char tmp_buf[128]; 2482 int tmp_buf_len = sizeof(tmp_buf); 2483 2484 tmp_buf_len = pj_ansi_snprintf(tmp_buf, sizeof(tmp_buf)-1, 2485 "%s (%dKHz)", 2486 rec_info.name, 2487 param->clock_rate/1000); 2488 pj_strset(&tmp, tmp_buf, tmp_buf_len); 2489 pjmedia_conf_set_port0_name(pjsua_var.mconf, &tmp); 2490 } else { 2491 pjmedia_conf_set_port0_name(pjsua_var.mconf, 2492 pj_cstr(&tmp, rec_info.name)); 2493 } 2494 } 2495 2496 /* Any error is not major, let it through */ 2497 status = PJ_SUCCESS; 2498 }; 2499 2500 /* If this is the first time the audio device is open, retrieve some 2501 * settings from the device (such as volume settings) so that the 2502 * pjsua_snd_get_setting() work. 2503 */ 2504 if (pjsua_var.aud_open_cnt == 0) { 2505 update_initial_aud_param(); 2506 ++pjsua_var.aud_open_cnt; 2507 } 2508 2509 return PJ_SUCCESS; 2510 } 2511 2512 2513 /* Close existing sound device */ 2514 static void close_snd_dev(void) 2515 { 2516 /* Close sound device */ 2517 if (pjsua_var.snd_port) { 2518 pjmedia_aud_dev_info cap_info, play_info; 2519 pjmedia_aud_stream *strm; 2520 pjmedia_aud_param param; 2521 2522 strm = pjmedia_snd_port_get_snd_stream(pjsua_var.snd_port); 2523 pjmedia_aud_stream_get_param(strm, ¶m); 2524 2525 if (pjmedia_aud_dev_get_info(param.rec_id, &cap_info) != PJ_SUCCESS) 2526 cap_info.name[0] = '\0'; 2527 if (pjmedia_aud_dev_get_info(param.play_id, &play_info) != PJ_SUCCESS) 2528 play_info.name[0] = '\0'; 2529 2530 PJ_LOG(4,(THIS_FILE, "Closing %s sound playback device and " 2531 "%s sound capture device", 2532 play_info.name, cap_info.name)); 2533 2534 pjmedia_snd_port_disconnect(pjsua_var.snd_port); 2535 pjmedia_snd_port_destroy(pjsua_var.snd_port); 2536 pjsua_var.snd_port = NULL; 2537 } 2538 2539 /* Close null sound device */ 2540 if (pjsua_var.null_snd) { 2541 PJ_LOG(4,(THIS_FILE, "Closing null sound device..")); 2542 pjmedia_master_port_destroy(pjsua_var.null_snd, PJ_FALSE); 2543 pjsua_var.null_snd = NULL; 2544 } 2545 2546 if (pjsua_var.snd_pool) 2547 pj_pool_release(pjsua_var.snd_pool); 2548 pjsua_var.snd_pool = NULL; 2549 } 2550 2551 2552 /* 2553 * Select or change sound device. Application may call this function at 2554 * any time to replace current sound device. 2555 */ 2556 PJ_DEF(pj_status_t) pjsua_set_snd_dev( int capture_dev, 2557 int playback_dev) 2558 { 2559 unsigned alt_cr_cnt = 1; 2560 unsigned alt_cr[] = {0, 44100, 48000, 32000, 16000, 8000}; 2561 unsigned i; 2562 pj_status_t status = -1; 2563 2564 /* Set default clock rate */ 2565 alt_cr[0] = pjsua_var.media_cfg.snd_clock_rate; 2566 if (alt_cr[0] == 0) 2567 alt_cr[0] = pjsua_var.media_cfg.clock_rate; 2568 2569 /* Allow retrying of different clock rate if we're using conference 2570 * bridge (meaning audio format is always PCM), otherwise lock on 2571 * to one clock rate. 2572 */ 2573 if (pjsua_var.is_mswitch) { 2574 alt_cr_cnt = 1; 2297 2575 } else { 2298 pjmedia_conf_set_port0_name(pjsua_var.mconf, 2299 pj_cstr(&tmp, play_info->name)); 2576 alt_cr_cnt = PJ_ARRAY_SIZE(alt_cr); 2577 } 2578 2579 /* Attempts to open the sound device with different clock rates */ 2580 for (i=0; i<alt_cr_cnt; ++i) { 2581 pjmedia_aud_param param; 2582 unsigned samples_per_frame; 2583 2584 /* Create the default audio param */ 2585 samples_per_frame = alt_cr[i] * 2586 pjsua_var.media_cfg.audio_frame_ptime * 2587 pjsua_var.media_cfg.channel_count / 1000; 2588 status = create_aud_param(¶m, capture_dev, playback_dev, 2589 alt_cr[i], pjsua_var.media_cfg.channel_count, 2590 samples_per_frame, 16); 2591 if (status != PJ_SUCCESS) 2592 return status; 2593 2594 /* Open! */ 2595 status = open_snd_dev(¶m); 2596 if (status == PJ_SUCCESS) 2597 break; 2598 } 2599 2600 if (status != PJ_SUCCESS) { 2601 pjsua_perror(THIS_FILE, "Unable to open sound device", status); 2602 return status; 2300 2603 } 2301 2604 … … 2405 2708 2406 2709 2710 /* 2711 * Check whether the sound device is currently active. 2712 */ 2713 PJ_DEF(pj_bool_t) pjsua_snd_is_active(void) 2714 { 2715 return pjsua_var.snd_port != NULL; 2716 } 2717 2718 2719 /* 2720 * Configure sound device setting to the sound device being used. 2721 */ 2722 PJ_DEF(pj_status_t) pjsua_snd_set_setting( pjmedia_aud_dev_cap cap, 2723 const void *pval, 2724 pj_bool_t keep) 2725 { 2726 pj_status_t status; 2727 2728 /* Check if we are allowed to set the cap */ 2729 if ((cap & pjsua_var.aud_svmask) == 0) { 2730 return PJMEDIA_EAUD_INVCAP; 2731 } 2732 2733 /* If sound is active, set it immediately */ 2734 if (pjsua_snd_is_active()) { 2735 pjmedia_aud_stream *strm; 2736 2737 strm = pjmedia_snd_port_get_snd_stream(pjsua_var.snd_port); 2738 status = pjmedia_aud_stream_set_cap(strm, cap, pval); 2739 } else { 2740 status = PJ_SUCCESS; 2741 } 2742 2743 if (status != PJ_SUCCESS) 2744 return status; 2745 2746 /* Save in internal param for later device open */ 2747 if (keep) { 2748 status = pjmedia_aud_param_set_cap(&pjsua_var.aud_param, 2749 cap, pval); 2750 } 2751 2752 return status; 2753 } 2754 2755 /* 2756 * Retrieve a sound device setting. 2757 */ 2758 PJ_DEF(pj_status_t) pjsua_snd_get_setting( pjmedia_aud_dev_cap cap, 2759 void *pval) 2760 { 2761 /* If sound device has never been opened before, open it to 2762 * retrieve the initial setting from the device (e.g. audio 2763 * volume) 2764 */ 2765 if (pjsua_var.aud_open_cnt==0) { 2766 PJ_LOG(4,(THIS_FILE, "Opening sound device to get initial settings")); 2767 pjsua_set_snd_dev(pjsua_var.cap_dev, pjsua_var.play_dev); 2768 close_snd_dev(); 2769 } 2770 2771 if (pjsua_snd_is_active()) { 2772 /* Sound is active, retrieve from device directly */ 2773 pjmedia_aud_stream *strm; 2774 2775 strm = pjmedia_snd_port_get_snd_stream(pjsua_var.snd_port); 2776 return pjmedia_aud_stream_get_cap(strm, cap, pval); 2777 } else { 2778 /* Otherwise retrieve from internal param */ 2779 return pjmedia_aud_param_get_cap(&pjsua_var.aud_param, 2780 cap, pval); 2781 } 2782 } 2783 2784 2407 2785 /***************************************************************************** 2408 2786 * Codecs.
Note: See TracChangeset
for help on using the changeset viewer.