summaryrefslogtreecommitdiff
path: root/pjmedia
diff options
context:
space:
mode:
authorLiong Sauw Ming <ming@teluu.com>2011-02-15 05:33:23 +0000
committerLiong Sauw Ming <ming@teluu.com>2011-02-15 05:33:23 +0000
commit931198a3148faa32bf0620eae5891cb1fbf51027 (patch)
treef6032bc2f09fc80a5dfb0b1c0551721cf90992cf /pjmedia
parent4477551db5dbf220762db3e1dc8afa2a4d75e46f (diff)
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. git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@3413 74dad513-b988-da41-8d7b-12977e46ad98
Diffstat (limited to 'pjmedia')
-rw-r--r--pjmedia/src/pjmedia-audiodev/coreaudio_dev.c137
1 files changed, 50 insertions, 87 deletions
diff --git a/pjmedia/src/pjmedia-audiodev/coreaudio_dev.c b/pjmedia/src/pjmedia-audiodev/coreaudio_dev.c
index ad9c554f..89ae70ce 100644
--- a/pjmedia/src/pjmedia-audiodev/coreaudio_dev.c
+++ b/pjmedia/src/pjmedia-audiodev/coreaudio_dev.c
@@ -125,6 +125,8 @@ struct coreaudio_stream
unsigned resample_buf_size;
};
+/* Static variable */
+static struct coreaudio_factory *cf_instance = NULL;
/* Prototypes */
static pj_status_t ca_factory_init(pjmedia_aud_dev_factory *f);
@@ -286,7 +288,7 @@ static pj_status_t ca_factory_init(pjmedia_aud_dev_factory *f)
}
/* Initialize the Audio Session */
- ostatus = AudioSessionInitialize(NULL, NULL, interruptionListener, cf);
+ ostatus = AudioSessionInitialize(NULL, NULL, interruptionListener, NULL);
if (ostatus != kAudioSessionNoError) {
PJ_LOG(4, (THIS_FILE,
"Error: cannot initialize audio session services (%i)",
@@ -313,6 +315,8 @@ static pj_status_t ca_factory_init(pjmedia_aud_dev_factory *f)
"Error: cannot listen for audio route change "
"notifications (%i)", ostatus));
}
+
+ cf_instance = cf;
#endif
PJ_LOG(4, (THIS_FILE, "core audio initialized"));
@@ -334,13 +338,16 @@ static pj_status_t ca_factory_destroy(pjmedia_aud_dev_factory *f)
AudioSessionRemovePropertyListenerWithUserData(
kAudioSessionProperty_AudioRouteChange, propListener, cf);
#endif
-
+
if (cf->pool) {
pj_pool_release(cf->pool);
cf->pool = NULL;
}
if (cf->mutex) {
+ pj_mutex_lock(cf->mutex);
+ cf_instance = NULL;
+ pj_mutex_unlock(cf->mutex);
pj_mutex_destroy(cf->mutex);
cf->mutex = NULL;
}
@@ -1052,8 +1059,6 @@ static void propListener(void *inClientData,
{
struct coreaudio_factory *cf = (struct coreaudio_factory*)inClientData;
struct stream_list *it, *itBegin;
- pj_status_t status;
- OSStatus ostatus;
CFDictionaryRef routeDictionary;
CFNumberRef reason;
SInt32 reasonVal;
@@ -1069,14 +1074,8 @@ static void propListener(void *inClientData,
CFSTR(kAudioSession_AudioRouteChangeKey_Reason));
CFNumberGetValue(reason, kCFNumberSInt32Type, &reasonVal);
- if (reasonVal == kAudioSessionRouteChangeReason_CategoryChange) {
- PJ_LOG(3, (THIS_FILE, "audio route changed due to category change, "
- "ignoring..."));
- return;
- }
- if (reasonVal == kAudioSessionRouteChangeReason_Override) {
- PJ_LOG(3, (THIS_FILE, "audio route changed due to user override, "
- "ignoring..."));
+ if (reasonVal != kAudioSessionRouteChangeReason_OldDeviceUnavailable) {
+ PJ_LOG(3, (THIS_FILE, "ignoring audio route change..."));
return;
}
@@ -1085,83 +1084,67 @@ static void propListener(void *inClientData,
pj_mutex_lock(cf->mutex);
itBegin = &cf->streams;
for (it = itBegin->next; it != itBegin; it = it->next) {
- pj_bool_t running = it->stream->running;
-
if (it->stream->interrupted)
continue;
+ /* This does not seem necessary anymore. Just make sure
+ * that your application can receive remote control
+ * events by adding the code:
+ * [[UIApplication sharedApplication]
+ * beginReceivingRemoteControlEvents];
+ * Otherwise audio route change (such as headset plug/unplug)
+ * will not be processed while your application is in the
+ * background mode.
+ */
+ /*
status = ca_stream_stop((pjmedia_aud_stream *)it->stream);
-
- ostatus = AudioUnitUninitialize(it->stream->io_units[0]);
- ostatus = AudioComponentInstanceDispose(it->stream->io_units[0]);
-
- status = create_audio_unit(it->stream->cf->io_comp, 0,
- it->stream->param.dir,
- it->stream, &it->stream->io_units[0]);
- if (status != PJ_SUCCESS) {
- PJ_LOG(3, (THIS_FILE,
- "Error: failed to create a replacement audio unit (%i)",
- status));
- continue;
- }
-
- if (running) {
- status = ca_stream_start((pjmedia_aud_stream *)it->stream);
- }
+ status = ca_stream_start((pjmedia_aud_stream *)it->stream);
if (status != PJ_SUCCESS) {
PJ_LOG(3, (THIS_FILE,
"Error: failed to restart the audio unit (%i)",
status));
continue;
}
- PJ_LOG(3, (THIS_FILE, "core audio unit successfully reinstantiated"));
+ PJ_LOG(3, (THIS_FILE, "core audio unit successfully restarted"));
+ */
}
pj_mutex_unlock(cf->mutex);
}
static void interruptionListener(void *inClientData, UInt32 inInterruption)
{
- struct coreaudio_factory *cf = (struct coreaudio_factory*)inClientData;
struct stream_list *it, *itBegin;
pj_status_t status;
- OSStatus ostatus;
- pj_assert(cf);
PJ_LOG(3, (THIS_FILE, "Session interrupted! --- %s ---",
inInterruption == kAudioSessionBeginInterruption ?
"Begin Interruption" : "End Interruption"));
- pj_mutex_lock(cf->mutex);
- itBegin = &cf->streams;
+ if (!cf_instance)
+ return;
+
+ pj_mutex_lock(cf_instance->mutex);
+ itBegin = &cf_instance->streams;
for (it = itBegin->next; it != itBegin; it = it->next) {
- if (!it->stream->running)
- continue;
-
if (inInterruption == kAudioSessionEndInterruption &&
it->stream->interrupted == PJ_TRUE)
{
- ostatus = AudioUnitUninitialize(it->stream->io_units[0]);
- ostatus = AudioComponentInstanceDispose(it->stream->io_units[0]);
-
- status = create_audio_unit(it->stream->cf->io_comp, 0,
- it->stream->param.dir,
- it->stream, &it->stream->io_units[0]);
- if (status != PJ_SUCCESS) {
- PJ_LOG(3, (THIS_FILE,
- "Error: failed to create a replacement "
- "audio unit (%i)", ostatus));
- continue;
- }
-
+ /* Make sure that your application can receive remote control
+ * events by adding the code:
+ * [[UIApplication sharedApplication]
+ * beginReceivingRemoteControlEvents];
+ * Otherwise audio unit will fail to restart while your
+ * application is in the background mode.
+ */
status = ca_stream_start((pjmedia_aud_stream*)it->stream);
if (status != PJ_SUCCESS) {
PJ_LOG(3, (THIS_FILE,
"Error: failed to restart the audio unit (%i)",
- ostatus));
- continue;
+ status));
+ continue;
}
- PJ_LOG(3, (THIS_FILE, "core audio unit successfully "
- "reinstantiated"));
+ PJ_LOG(3, (THIS_FILE, "core audio unit successfully resumed"
+ " after interruption"));
} else if (inInterruption == kAudioSessionBeginInterruption &&
it->stream->running == PJ_TRUE)
{
@@ -1169,7 +1152,7 @@ static void interruptionListener(void *inClientData, UInt32 inInterruption)
it->stream->interrupted = PJ_TRUE;
}
}
- pj_mutex_unlock(cf->mutex);
+ pj_mutex_unlock(cf_instance->mutex);
}
#endif
@@ -1524,6 +1507,10 @@ static pj_status_t ca_factory_create_stream(pjmedia_aud_dev_factory *f,
ca_stream_set_cap(&strm->base,
PJMEDIA_AUD_DEV_CAP_EC,
&param->ec_enabled);
+ } else {
+ pj_bool_t ec = PJ_FALSE;
+ ca_stream_set_cap(&strm->base,
+ PJMEDIA_AUD_DEV_CAP_EC, &ec);
}
strm->io_units[0] = strm->io_units[1] = NULL;
@@ -1956,8 +1943,6 @@ static pj_status_t ca_stream_start(pjmedia_aud_stream *strm)
struct coreaudio_stream *stream = (struct coreaudio_stream*)strm;
OSStatus ostatus;
UInt32 i;
- pj_bool_t should_activate;
- struct stream_list *it, *itBegin;
if (stream->running)
return PJ_SUCCESS;
@@ -1974,6 +1959,10 @@ static pj_status_t ca_stream_start(pjmedia_aud_stream *strm)
return PJMEDIA_AUDIODEV_ERRNO_FROM_COREAUDIO(ostatus);
}
+#if !COREAUDIO_MAC
+ AudioSessionSetActive(true);
+#endif
+
for (i = 0; i < 2; i++) {
if (stream->io_units[i] == NULL) break;
ostatus = AudioOutputUnitStart(stream->io_units[i]);
@@ -1984,29 +1973,7 @@ static pj_status_t ca_stream_start(pjmedia_aud_stream *strm)
}
}
- /*
- * Make sure this stream is not in the list of running streams.
- * If this is the 1st stream that is running we need to activate
- * the audio session.
- */
- pj_mutex_lock(stream->cf->mutex);
- pj_assert(!pj_list_empty(&stream->cf->streams));
- pj_assert(!pj_list_empty(&stream->list_entry));
- should_activate = PJ_TRUE;
- itBegin = &stream->cf->streams;
- for (it = itBegin->next; it != itBegin; it = it->next) {
- if (it->stream->running) {
- should_activate = PJ_FALSE;
- break;
- }
- }
stream->running = PJ_TRUE;
- pj_mutex_unlock(stream->cf->mutex);
-
-#if !COREAUDIO_MAC
- if (should_activate)
- AudioSessionSetActive(true);
-#endif
PJ_LOG(4, (THIS_FILE, "core audio stream started"));
@@ -2035,11 +2002,7 @@ static pj_status_t ca_stream_stop(pjmedia_aud_stream *strm)
}
}
- /*
- * Make sure this stream is not in the list of running streams.
- * If this is the 1st stream that is running we need to activate
- * the audio session.
- */
+ /* Check whether we need to deactivate the audio session. */
pj_mutex_lock(stream->cf->mutex);
pj_assert(!pj_list_empty(&stream->cf->streams));
pj_assert(!pj_list_empty(&stream->list_entry));