Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

IOS system sounds with custom audio sessions

I have an iOS application that plays different audio effects and records audio at the same time. The purpose of the application is currently not important, but I'm having problems with stock iOS audio effects.

To play the effects, I use SimpleAudioEngine from CocosDenshion API (which uses AVAudioPlayer, as far as I can see). The effects are preloaded and they work fine (I actually play them on buttons, scrolling and similar). Effects are played with the following code:

In willFinishLaunchingWithOptions method:

[[SimpleAudioEngine sharedEngine] preloadEffect:@"sound.wav"];

In other methods when playing is required:

[[SimpleAudioEngine sharedEngine] playEffect:@"sound.wav"];

No wonders here, but at the same time, I am recording noise from the built-in microphone with AVCaptureSession API. The capture session code is from one of the examples found on the web.

AVCaptureDevice *audioDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeAudio];

captureSession = [[AVCaptureSession alloc] init];

NSError *error = nil;
captureAudioDeviceInput = [AVCaptureDeviceInput deviceInputWithDevice:audioDevice error:&error];

if ([captureSession canAddInput: captureAudioDeviceInput])
{
    [captureSession addInput:captureAudioDeviceInput];
}

captureAudioDataOutput = [AVCaptureAudioDataOutput new];

if ([captureSession canAddOutput:captureAudioDataOutput])
{
    [captureSession addOutput:captureAudioDataOutput];
}

// Create a serial dispatch queue and set it on the AVCaptureAudioDataOutput object
dispatch_queue_t audioDataOutputQueue = dispatch_queue_create("AudioDataOutputQueue", DISPATCH_QUEUE_SERIAL);

[captureAudioDataOutput setSampleBufferDelegate:self queue:audioDataOutputQueue];
dispatch_release(audioDataOutputQueue);

[captureSession startRunning];

Both parts of the code are working flawlessly one by one. But when they are both activated at the same time, one of them breaks the other. For example: the microphone is reading data without a problem, until one sound effect is played. I found a way around this, to activate mixWithOthers category, which is done with the following code:

[[AVAudioSession sharedInstance] setCategory: AVAudioSessionCategoryAmbient error: nil];
UInt32 doSetProperty = 1;
AudioSessionSetProperty (kAudioSessionProperty_OverrideCategoryMixWithOthers, sizeof(doSetProperty), &doSetProperty);
[[AVAudioSession sharedInstance] setActive: YES error: nil];

This is done before creating the AVCaptureDevice and AVCaptureSession. The application works like it should, sounds are played and microphone reads the data. Hardware buttons are also working on the CocosDenshion SimpleAudioEngine (mute and volume).

But apparently, the application has a bug.

When mute is disabled and application is playing sounds, the iOS keyboard clicking sounds on TextField are not played. I want the clicking sounds to play.

I have debugged the code a bit and apparently it has something to do with Audio session settings. If I set the category to AVAudioSessionCategorySoloAmbient, the clicking sounds are played, but at very low volume (the volume is maxed out and application sounds play out at max volume just nicely). And it gives another problem, SoloAmbient cancels my CaptureSession, which is understandable.

I am testing the application on iPhone 5, but the same thing happens on the simulator too.

So, what am I doing wrong with settings? How could I fix the settings so I keep all my audio sessions active and keep the iOS system sounds?

Thank you!

like image 582
Legoless Avatar asked Mar 21 '13 22:03

Legoless


1 Answers

Check out my question here: https://stackoverflow.com/questions/15680503/how-to-get-the-audio-level-of-the-microphone-without-disabling-system-sounds

There are no answers unfortunately. System sounds are disabled by default when recording is taking place. I expect this is to prevent them being recorded by mistake, which under most circumstances would be what you would want.

You could implement the UITextFieldDelegate protocol and play your own click every time textField:shouldChangeCharactersInRange:replacementString: is called, perhaps.

like image 187
Lewis Gordon Avatar answered Nov 08 '22 23:11

Lewis Gordon