Ignore:
Timestamp:
Feb 15, 2011 5:33:23 AM (14 years ago)
Author:
ming
Message:

Re #1174: fixed crash when pjsua is restarted, causing inClientData to be invalid since AudioSessionInitialize? can only be called once.
Re #1175: cleaning up interruption and audio route handling in coreaudio for iOS. In the case of interruption, there is no need to reinstantiate the audio unit (a simple restart will do), while for audio route change, nothing needs to be done.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • pjproject/trunk/pjmedia/src/pjmedia-audiodev/coreaudio_dev.c

    r3411 r3413  
    126126}; 
    127127 
     128/* Static variable */ 
     129static struct coreaudio_factory *cf_instance = NULL; 
    128130 
    129131/* Prototypes */ 
     
    287289 
    288290    /* Initialize the Audio Session */ 
    289     ostatus = AudioSessionInitialize(NULL, NULL, interruptionListener, cf); 
     291    ostatus = AudioSessionInitialize(NULL, NULL, interruptionListener, NULL); 
    290292    if (ostatus != kAudioSessionNoError) { 
    291293        PJ_LOG(4, (THIS_FILE, 
     
    314316                   "notifications (%i)", ostatus)); 
    315317    } 
     318     
     319    cf_instance = cf; 
    316320#endif 
    317321 
     
    335339        kAudioSessionProperty_AudioRouteChange, propListener, cf); 
    336340#endif 
    337  
     341     
    338342    if (cf->pool) { 
    339343        pj_pool_release(cf->pool); 
     
    342346 
    343347    if (cf->mutex) { 
     348        pj_mutex_lock(cf->mutex); 
     349        cf_instance = NULL; 
     350        pj_mutex_unlock(cf->mutex); 
    344351        pj_mutex_destroy(cf->mutex); 
    345352        cf->mutex = NULL; 
     
    10531060    struct coreaudio_factory *cf = (struct coreaudio_factory*)inClientData; 
    10541061    struct stream_list *it, *itBegin; 
    1055     pj_status_t status; 
    1056     OSStatus ostatus; 
    10571062    CFDictionaryRef routeDictionary; 
    10581063    CFNumberRef reason; 
     
    10701075    CFNumberGetValue(reason, kCFNumberSInt32Type, &reasonVal); 
    10711076 
    1072     if (reasonVal == kAudioSessionRouteChangeReason_CategoryChange) { 
    1073         PJ_LOG(3, (THIS_FILE, "audio route changed due to category change, " 
    1074                    "ignoring...")); 
    1075         return; 
    1076     } 
    1077     if (reasonVal == kAudioSessionRouteChangeReason_Override) { 
    1078         PJ_LOG(3, (THIS_FILE, "audio route changed due to user override, " 
    1079                    "ignoring...")); 
     1077    if (reasonVal != kAudioSessionRouteChangeReason_OldDeviceUnavailable) { 
     1078        PJ_LOG(3, (THIS_FILE, "ignoring audio route change...")); 
    10801079        return; 
    10811080    } 
     
    10861085    itBegin = &cf->streams; 
    10871086    for (it = itBegin->next; it != itBegin; it = it->next) { 
    1088         pj_bool_t running = it->stream->running; 
    1089  
    10901087        if (it->stream->interrupted) 
    10911088            continue; 
    10921089 
     1090        /* This does not seem necessary anymore. Just make sure  
     1091         * that your application can receive remote control 
     1092         * events by adding the code: 
     1093         *     [[UIApplication sharedApplication]  
     1094         *      beginReceivingRemoteControlEvents]; 
     1095         * Otherwise audio route change (such as headset plug/unplug) 
     1096         * will not be processed while your application is in the  
     1097         * background mode. 
     1098         */ 
     1099        /* 
    10931100        status = ca_stream_stop((pjmedia_aud_stream *)it->stream); 
    1094  
    1095         ostatus = AudioUnitUninitialize(it->stream->io_units[0]); 
    1096         ostatus = AudioComponentInstanceDispose(it->stream->io_units[0]); 
    1097  
    1098         status = create_audio_unit(it->stream->cf->io_comp, 0, 
    1099                                    it->stream->param.dir, 
    1100                                    it->stream, &it->stream->io_units[0]); 
    1101         if (status != PJ_SUCCESS) { 
    1102             PJ_LOG(3, (THIS_FILE, 
    1103                        "Error: failed to create a replacement audio unit (%i)", 
    1104                        status)); 
    1105             continue; 
    1106         } 
    1107  
    1108         if (running) { 
    1109             status = ca_stream_start((pjmedia_aud_stream *)it->stream); 
    1110         } 
     1101        status = ca_stream_start((pjmedia_aud_stream *)it->stream); 
    11111102        if (status != PJ_SUCCESS) { 
    11121103            PJ_LOG(3, (THIS_FILE, 
     
    11151106            continue; 
    11161107        } 
    1117         PJ_LOG(3, (THIS_FILE, "core audio unit successfully reinstantiated")); 
     1108        PJ_LOG(3, (THIS_FILE, "core audio unit successfully restarted")); 
     1109        */ 
    11181110    } 
    11191111    pj_mutex_unlock(cf->mutex); 
     
    11221114static void interruptionListener(void *inClientData, UInt32 inInterruption) 
    11231115{ 
    1124     struct coreaudio_factory *cf = (struct coreaudio_factory*)inClientData; 
    11251116    struct stream_list *it, *itBegin; 
    11261117    pj_status_t status; 
    1127     OSStatus ostatus; 
    1128     pj_assert(cf); 
    11291118 
    11301119    PJ_LOG(3, (THIS_FILE, "Session interrupted! --- %s ---", 
     
    11321121           "Begin Interruption" : "End Interruption")); 
    11331122 
    1134     pj_mutex_lock(cf->mutex); 
    1135     itBegin = &cf->streams; 
     1123    if (!cf_instance) 
     1124        return; 
     1125     
     1126    pj_mutex_lock(cf_instance->mutex); 
     1127    itBegin = &cf_instance->streams; 
    11361128    for (it = itBegin->next; it != itBegin; it = it->next) { 
    1137         if (!it->stream->running) 
    1138             continue; 
    1139  
    11401129        if (inInterruption == kAudioSessionEndInterruption && 
    11411130            it->stream->interrupted == PJ_TRUE) 
    11421131        { 
    1143             ostatus = AudioUnitUninitialize(it->stream->io_units[0]); 
    1144             ostatus = AudioComponentInstanceDispose(it->stream->io_units[0]); 
    1145  
    1146             status = create_audio_unit(it->stream->cf->io_comp, 0, 
    1147                                        it->stream->param.dir, 
    1148                                        it->stream, &it->stream->io_units[0]); 
    1149             if (status != PJ_SUCCESS) { 
    1150                 PJ_LOG(3, (THIS_FILE, 
    1151                            "Error: failed to create a replacement " 
    1152                            "audio unit (%i)", ostatus)); 
    1153                 continue; 
    1154             } 
    1155  
     1132            /* Make sure that your application can receive remote control 
     1133             * events by adding the code: 
     1134             *     [[UIApplication sharedApplication]  
     1135             *      beginReceivingRemoteControlEvents]; 
     1136             * Otherwise audio unit will fail to restart while your 
     1137             * application is in the background mode. 
     1138             */ 
    11561139            status = ca_stream_start((pjmedia_aud_stream*)it->stream); 
    11571140            if (status != PJ_SUCCESS) { 
    11581141                PJ_LOG(3, (THIS_FILE, 
    11591142                           "Error: failed to restart the audio unit (%i)", 
    1160                            ostatus)); 
    1161                        continue; 
     1143                           status)); 
     1144                continue; 
    11621145            } 
    1163             PJ_LOG(3, (THIS_FILE, "core audio unit successfully " 
    1164                        "reinstantiated")); 
     1146            PJ_LOG(3, (THIS_FILE, "core audio unit successfully resumed" 
     1147                       " after interruption")); 
    11651148        } else if (inInterruption == kAudioSessionBeginInterruption && 
    11661149                   it->stream->running == PJ_TRUE) 
     
    11701153        } 
    11711154    } 
    1172     pj_mutex_unlock(cf->mutex); 
     1155    pj_mutex_unlock(cf_instance->mutex); 
    11731156} 
    11741157 
     
    15251508                          PJMEDIA_AUD_DEV_CAP_EC, 
    15261509                          &param->ec_enabled); 
     1510    } else { 
     1511        pj_bool_t ec = PJ_FALSE; 
     1512        ca_stream_set_cap(&strm->base, 
     1513                          PJMEDIA_AUD_DEV_CAP_EC, &ec); 
    15271514    } 
    15281515 
     
    19571944    OSStatus ostatus; 
    19581945    UInt32 i; 
    1959     pj_bool_t should_activate; 
    1960     struct stream_list *it, *itBegin; 
    19611946 
    19621947    if (stream->running) 
     
    19751960    } 
    19761961 
     1962#if !COREAUDIO_MAC 
     1963    AudioSessionSetActive(true); 
     1964#endif 
     1965     
    19771966    for (i = 0; i < 2; i++) { 
    19781967        if (stream->io_units[i] == NULL) break; 
     
    19851974    } 
    19861975 
    1987     /* 
    1988      * Make sure this stream is not in the list of running streams. 
    1989      * If this is the 1st stream that is running we need to activate 
    1990      * the audio session. 
    1991      */ 
    1992     pj_mutex_lock(stream->cf->mutex); 
    1993     pj_assert(!pj_list_empty(&stream->cf->streams)); 
    1994     pj_assert(!pj_list_empty(&stream->list_entry)); 
    1995     should_activate = PJ_TRUE; 
    1996     itBegin = &stream->cf->streams; 
    1997     for (it = itBegin->next; it != itBegin; it = it->next) { 
    1998         if (it->stream->running) { 
    1999             should_activate = PJ_FALSE; 
    2000             break; 
    2001         } 
    2002     } 
    20031976    stream->running = PJ_TRUE; 
    2004     pj_mutex_unlock(stream->cf->mutex); 
    2005  
    2006 #if !COREAUDIO_MAC 
    2007     if (should_activate) 
    2008         AudioSessionSetActive(true); 
    2009 #endif 
    20101977 
    20111978    PJ_LOG(4, (THIS_FILE, "core audio stream started")); 
     
    20362003    } 
    20372004 
    2038     /* 
    2039      * Make sure this stream is not in the list of running streams. 
    2040      * If this is the 1st stream that is running we need to activate 
    2041      * the audio session. 
    2042      */ 
     2005    /* Check whether we need to deactivate the audio session. */ 
    20432006    pj_mutex_lock(stream->cf->mutex); 
    20442007    pj_assert(!pj_list_empty(&stream->cf->streams)); 
Note: See TracChangeset for help on using the changeset viewer.