Ignore:
Timestamp:
Mar 12, 2009 6:11:37 PM (15 years ago)
Author:
bennylp
Message:

(Major) Task #737 and #738: integration of APS-Direct and Audiodev from aps-direct branch to trunk.

Location:
pjproject/trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • pjproject/trunk

  • pjproject/trunk/pjsip/src/pjsua-lib/pjsua_media.c

    r2425 r2506  
    3636static pj_uint16_t next_rtp_port; 
    3737 
     38/* Open sound dev */ 
     39static pj_status_t open_snd_dev(pjmedia_aud_param *param); 
    3840/* Close existing sound device */ 
    3941static void close_snd_dev(void); 
     42/* Create audio device param */ 
     43static 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); 
    4050 
    4151 
     
    6070    /* To suppress warning about unused var when all codecs are disabled */ 
    6171    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); 
    6282 
    6383    /* Copy configuration */ 
     
    172192 
    173193#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 */ 
    174204 
    175205#if PJMEDIA_HAS_L16_CODEC 
     
    226256        return status; 
    227257    } 
     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; 
    228262 
    229263    /* Create null port just in case user wants to use null sound. */ 
     
    574608            pjmedia_codec_ipp_deinit(); 
    575609#       endif   /* PJMEDIA_HAS_INTEL_IPP */ 
     610 
     611#       if PJMEDIA_HAS_PASSTHROUGH_CODECS 
     612            pjmedia_codec_passthrough_deinit(); 
     613#       endif /* PJMEDIA_HAS_PASSTHROUGH_CODECS */ 
    576614 
    577615#       if PJMEDIA_HAS_L16_CODEC 
     
    14961534} 
    14971535 
    1498  
    14991536/* 
    15001537 * Get maxinum number of conference ports. 
     
    16111648    } 
    16121649 
    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; 
    16171662        pj_status_t status; 
    16181663 
    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(&param, 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(&param); 
     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 
    16241729    } 
    16251730 
     
    20982203 * Enum sound devices. 
    20992204 */ 
     2205 
     2206PJ_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 
    21002229PJ_DEF(pj_status_t) pjsua_enum_snd_devs( pjmedia_snd_dev_info info[], 
    21012230                                         unsigned *count) 
     
    21032232    unsigned i, dev_count; 
    21042233 
    2105     dev_count = pjmedia_snd_get_dev_count(); 
     2234    dev_count = pjmedia_aud_dev_count(); 
    21062235     
    21072236    if (dev_count > *count) dev_count = *count; 
     2237    pj_bzero(info, dev_count * sizeof(pjmedia_snd_dev_info)); 
    21082238 
    21092239    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; 
    21142252    } 
    21152253 
     
    21192257} 
    21202258 
    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 */ 
     2260static 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 */ 
     2323static 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, &param); 
     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 */ 
     2356static 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. */ 
     2368static pj_status_t open_snd_dev(pjmedia_aud_param *param) 
    21592369{ 
    21602370    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); 
    21692374 
    21702375    /* 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) { 
    21722377        return pjsua_set_null_snd_dev(); 
    21732378    } 
     
    21802385    PJ_ASSERT_RETURN(pjsua_var.snd_pool, PJ_ENOMEM); 
    21812386 
    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; 
    21862398 
    21872399    /* Get the port0 of the conference bridge. */ 
     
    21892401    pj_assert(conf_port != NULL); 
    21902402 
    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, &param->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 */ 
    22702453    status = pjmedia_snd_port_connect(pjsua_var.snd_port,         
    22712454                                      conf_port );        
     
    22792462 
    22802463    /* Save the device IDs */ 
    2281     pjsua_var.cap_dev = capture_dev; 
    2282     pjsua_var.play_dev = playback_dev; 
     2464    pjsua_var.cap_dev = param->rec_id; 
     2465    pjsua_var.play_dev = param->play_id; 
    22832466 
    22842467    /* 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 */ 
     2514static 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, &param); 
     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 */ 
     2556PJ_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; 
    22972575    } 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(&param, 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(&param); 
     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; 
    23002603    } 
    23012604 
     
    24052708 
    24062709 
     2710/* 
     2711 * Check whether the sound device is currently active. 
     2712 */ 
     2713PJ_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 */ 
     2722PJ_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 */ 
     2758PJ_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 
    24072785/***************************************************************************** 
    24082786 * Codecs. 
Note: See TracChangeset for help on using the changeset viewer.