iOS: Handle audio interruptions (e.g. incomming GSM call)

This commit is contained in:
bossiel 2014-05-16 01:55:20 +00:00
parent e2a41923f8
commit 4bf453344e
5 changed files with 85 additions and 6 deletions

View File

@ -54,6 +54,7 @@ int tdav_audiounit_handle_start(tdav_audiounit_handle_t* self);
uint32_t tdav_audiounit_handle_get_frame_duration(tdav_audiounit_handle_t* self);
int tdav_audiounit_handle_configure(tdav_audiounit_handle_t* self, tsk_bool_t consumer, uint32_t ptime, AudioStreamBasicDescription* audioFormat);
int tdav_audiounit_handle_mute(tdav_audiounit_handle_t* self, tsk_bool_t mute);
int tdav_audiounit_handle_interrupt(tdav_audiounit_handle_t* self, tsk_bool_t interrupt);
int tdav_audiounit_handle_stop(tdav_audiounit_handle_t* self);
int tdav_audiounit_handle_destroy(tdav_audiounit_handle_t** self);

View File

@ -29,12 +29,36 @@
#include "tsk_debug.h"
#if TARGET_OS_IPHONE
// deprecated in iOS7+
static void _AudioSessionInterruptionListener(void * inClientData, UInt32 inInterruptionState)
{
switch(inInterruptionState) {
case kAudioSessionBeginInterruption:
{
TSK_DEBUG_INFO("_AudioSessionInterruptionListener:kAudioSessionBeginInterruption");
break;
}
case kAudioSessionEndInterruption:
{
TSK_DEBUG_INFO("_AudioSessionInterruptionListener:kAudioSessionEndInterruption");
break;
}
default:
{
TSK_DEBUG_INFO("_AudioSessionInterruptionListener:%u", (unsigned int)inInterruptionState);
break;
}
}
}
#endif
static int tdav_apple_init()
{
// initialize audio session
#if TARGET_OS_IPHONE
OSStatus status;
status = AudioSessionInitialize(NULL, NULL, NULL, NULL);
status = AudioSessionInitialize(NULL, NULL, _AudioSessionInterruptionListener, NULL);
if(status){
TSK_DEBUG_ERROR("AudioSessionInitialize() failed with status code=%d", (int32_t)status);
return -1;

View File

@ -61,6 +61,7 @@ typedef struct tdav_audiounit_instance_s
unsigned producer:1;
} prepared;
unsigned started:1;
unsigned interrupted:1;
TSK_DECLARE_SAFEOBJ;
@ -202,10 +203,11 @@ int tdav_audiounit_handle_start(tdav_audiounit_handle_t* self)
}
tsk_safeobj_lock(inst);
if(!inst->started && (status = AudioOutputUnitStart(inst->audioUnit))){
if((!inst->started || inst->interrupted) && (status = AudioOutputUnitStart(inst->audioUnit))){
TSK_DEBUG_ERROR("AudioOutputUnitStart failed with status=%ld", (signed long)status);
}
inst->started = (status == noErr) ? tsk_true : tsk_false;
if (inst->started) inst->interrupted = 0;
tsk_safeobj_unlock(inst);
return status ? -2 : 0;
}
@ -234,7 +236,7 @@ int tdav_audiounit_handle_configure(tdav_audiounit_handle_t* self, tsk_bool_t co
UInt32 size = sizeof(preferredBufferSize);
status = AudioSessionSetProperty(kAudioSessionProperty_PreferredHardwareIOBufferDuration, sizeof(preferredBufferSize), &preferredBufferSize);
if(status != noErr){
TSK_DEBUG_ERROR("AudioSessionSetProperty(kAudioSessionProperty_PreferredHardwareIOBufferDuration) failed with status=%ld", status);
TSK_DEBUG_ERROR("AudioSessionSetProperty(kAudioSessionProperty_PreferredHardwareIOBufferDuration) failed with status=%d", (int)status);
TSK_OBJECT_SAFE_FREE(inst);
goto done;
}
@ -251,7 +253,7 @@ int tdav_audiounit_handle_configure(tdav_audiounit_handle_t* self, tsk_bool_t co
UInt32 audioCategory = kAudioSessionCategory_PlayAndRecord;
status = AudioSessionSetProperty(kAudioSessionProperty_AudioCategory, sizeof(audioCategory), &audioCategory);
if(status != noErr){
TSK_DEBUG_ERROR("AudioSessionSetProperty(kAudioSessionProperty_AudioCategory) failed with status code=%ld", status);
TSK_DEBUG_ERROR("AudioSessionSetProperty(kAudioSessionProperty_AudioCategory) failed with status code=%d", (int)status);
goto done;
}
@ -298,6 +300,40 @@ int tdav_audiounit_handle_mute(tdav_audiounit_handle_t* self, tsk_bool_t mute)
#endif
}
int tdav_audiounit_handle_interrupt(tdav_audiounit_handle_t* self, tsk_bool_t interrupt)
{
tdav_audiounit_instance_t* inst = (tdav_audiounit_instance_t*)self;
if (!inst){
TSK_DEBUG_ERROR("Invalid parameter");
return -1;
}
OSStatus status = noErr;
if (inst->interrupted != interrupt && inst->started) {
if (interrupt) {
status = AudioOutputUnitStop(inst->audioUnit);
if (status != noErr) {
TSK_DEBUG_ERROR("AudioOutputUnitStop failed with status=%ld", (signed long)status);
goto bail;
}
}
else {
status = AudioSessionSetActive(true);
if (status != noErr) {
TSK_DEBUG_ERROR("AudioSessionSetActive failed with status=%ld", (signed long)status);
goto bail;
}
status = AudioOutputUnitStart(inst->audioUnit);
if (status != noErr) {
TSK_DEBUG_ERROR("AudioOutputUnitStart failed with status=%ld", (signed long)status);
goto bail;
}
}
}
inst->interrupted = interrupt ? 1: 0;
bail:
return (status != noErr) ? -2 : 0;
}
int tdav_audiounit_handle_stop(tdav_audiounit_handle_t* self)
{
tdav_audiounit_instance_t* inst = (tdav_audiounit_instance_t*)self;
@ -313,7 +349,7 @@ int tdav_audiounit_handle_stop(tdav_audiounit_handle_t* self)
}
inst->started = (status == noErr ? tsk_false : tsk_true);
tsk_safeobj_unlock(inst);
return status ? -2 : 0;
return (status != noErr) ? -2 : 0;
}
int tdav_audiounit_handle_destroy(tdav_audiounit_handle_t** self){
@ -357,6 +393,7 @@ static tsk_object_t* tdav_audiounit_instance_dtor(tsk_object_t * self)
tsk_safeobj_unlock(inst);
tsk_safeobj_deinit(inst);
TSK_DEBUG_INFO("*** AudioUnit Instance destroyed ***");
}
return self;
}

View File

@ -31,6 +31,7 @@
#include "tsk_debug.h"
#include "tsk_memory.h"
#include "tsk_string.h"
#define kNoDataError -1
#define kRingPacketCount +10
@ -100,6 +101,15 @@ static tsk_size_t tdav_consumer_audiounit_get(tdav_consumer_audiounit_t* self, v
/* ============ Media Consumer Interface ================= */
int tdav_consumer_audiounit_set(tmedia_consumer_t* self, const tmedia_param_t* param)
{
tdav_consumer_audiounit_t* consumer = (tdav_consumer_audiounit_t*)self;
if (param->plugin_type == tmedia_ppt_consumer) {
if (param->value_type == tmedia_pvt_int32) {
if (tsk_striequals(param->key, "interrupt")) {
int32_t interrupt = *((uint8_t*)param->value) ? 1 : 0;
return tdav_audiounit_handle_interrupt(consumer->audioUnitHandle, interrupt);
}
}
}
return tdav_consumer_audio_set(TDAV_CONSUMER_AUDIO(self), param);
}
@ -401,6 +411,7 @@ static tsk_object_t* tdav_consumer_audiounit_dtor(tsk_object_t * self)
/* deinit base */
tdav_consumer_audio_deinit(TDAV_CONSUMER_AUDIO(consumer));
TSK_DEBUG_INFO("*** AudioUnit Consumer destroyed ***");
}
return self;

View File

@ -82,10 +82,14 @@ int tdav_producer_audiounit_set(tmedia_producer_t* self, const tmedia_param_t* p
tdav_producer_audiounit_t* producer = (tdav_producer_audiounit_t*)self;
if(param->plugin_type == tmedia_ppt_producer){
if(param->value_type == tmedia_pvt_int32){
if(tsk_striequals(param->key, "mute")){
if (tsk_striequals(param->key, "mute")) {
producer->muted = TSK_TO_INT32((uint8_t*)param->value);
return tdav_audiounit_handle_mute(((tdav_producer_audiounit_t*)self)->audioUnitHandle, producer->muted);
}
else if (tsk_striequals(param->key, "interrupt")) {
int32_t interrupt = *((uint8_t*)param->value) ? 1 : 0;
return tdav_audiounit_handle_interrupt(producer->audioUnitHandle, interrupt);
}
}
}
return tdav_producer_audio_set(TDAV_PRODUCER_AUDIO(self), param);
@ -384,6 +388,8 @@ static tsk_object_t* tdav_producer_audiounit_dtor(tsk_object_t * self)
}
/* deinit base */
tdav_producer_audio_deinit(TDAV_PRODUCER_AUDIO(producer));
TSK_DEBUG_INFO("*** AudioUnit Producer destroyed ***");
}
return self;