0

I'm trying to use OpenAL for an IOS game I'm working on, but having an issue opening the audio device. Specifically, when I call the function alcOpenDevice(NULL), I get 'NULL' in return. This is causing issues, of course, but I can't tell what I'm doing wrong.

I'm new to OpenAL, so I've been looking at a couple guides here and here to see what I need to do. If I download their sample projects and test 'em, they both work fine. If I copy their files into my project, and ignore the files I made, they still work fine. I'm assuming something got lost in translation when I started rebuilding the code for use in my project. Asking around and searching online hasn't given me any leads though, so I'm hoping someone here could put me on the right track.

Here's the actual setup code I'm using in my AudioPlayer.m

- (void)setup {
    audioSampleBuffers = [NSMutableDictionary new];
    audioSampleSources = [NSMutableArray new];


    [self setupAudioSession];
    [self setupAudioDevice];
    [self setupNotifications];
}

- (BOOL)setupAudioSession {

//    // This has been depricated.
//
//    /* Setup the Audio Session and monitor interruptions */
//    AudioSessionInitialize(NULL, NULL, AudioInterruptionListenerCallback, NULL);
//
//    /* Set the category for the Audio Session */
//    UInt32 session_category = kAudioSessionCategory_MediaPlayback;
//    AudioSessionSetProperty(kAudioSessionProperty_AudioCategory, sizeof(session_category), &session_category);
//
//    /* Make the Audio Session active */
//    AudioSessionSetActive(true);

    BOOL success = NO;
    NSError *error = nil;

    AVAudioSession *session = [AVAudioSession sharedInstance];

    success = [session setCategory:AVAudioSessionCategoryPlayback error:&error];
    if (!success) {
        NSLog(@"%@ Error setting category: %@", NSStringFromSelector(_cmd), [error localizedDescription]);

        return success;
    }

    success = [session setActive:YES error:&error];
    if (!success) {
        NSLog(@"Error activating session: %@", [error localizedDescription]);
    }

    return success;
}

- (BOOL)setupAudioDevice {
    // 'NULL' uses the default device.
    openALDevice = alcOpenDevice(NULL); // Returns 'NULL'
    ALenum error = alGetError(); // Returns '0'
    NSLog(@"%i", error);

    if (!openALDevice) {
        NSLog(@"Something went wrong setting up the audio device.");
        return NO;
    }


    // Create a context to use with the device, and make it the current context.
    openALContext = alcCreateContext(openALDevice, NULL);
    alcMakeContextCurrent(openALContext);

    [self createAudioSources];

    // Setup was successful
    return YES;
}

- (void)createAudioSources {
    ALuint sourceID;
    for (int i = 0; i < kMaxConcurrentSources; i++) {
        // Create a single source.
        alGenSources(1, &sourceID);
        // Add it to the array.
        [audioSampleSources addObject:[NSNumber numberWithUnsignedInt:sourceID]];
    }
}

Note: I'm running IOS 7.1.1 on a new iPad air, and using Xcode 5.1.1. This issue has been confirmed on the iPad, my simulator, and an iPod touch.

user1118321
  • 25,567
  • 4
  • 55
  • 86
Talidos
  • 1
  • 1
  • 4
  • well, I am using `OpenAL` no problem on iOS 7 so I can only assume that the problem is trying to use both `OpenAL` and `AVAudioSession`. try commenting out `[self setupAudioSession];` – Brad Allred Jun 05 '14 at 19:21
  • Hi Brad. I commented out the setupAudioSession line, but got the same result from alcOpenDevice. For fun, I also switched the order so that setupAudioDevice happened before setupAudioSession. It's still the same though. Question: What are you using instead of AVAudioSession? The AudioSessionInitialize... stuff that's normally used got deprecated in IOS7, and I haven't been able to get it compile. – Talidos Jun 05 '14 at 20:22
  • I use `OpenAL` alone. what is the OpenAL error after caling `alcOpenDevice()`? – Brad Allred Jun 05 '14 at 20:53
  • The alGetError() immediately after returns a 0, so no error. – Talidos Jun 05 '14 at 21:32
  • can you print your available devices using `alcGetString(NULL, ALC_DEVICE_SPECIFIER);`? – Brad Allred Jun 05 '14 at 21:54
  • NSLog(@"%s", alcGetString(NULL, ALC_DEVICE_SPECIFIER)); => "Default Audio Device" – Talidos Jun 05 '14 at 22:01

3 Answers3

2

The Short Answer:

Apple's implementation of alcOpenDevice() only returns the device once. Every subsequent call returns NULL. This function can be called by a lot of Apple audio code, so take out EVERY TRACE of audio code before using OpenAL and manually calling that function yourself.

The Long Answer:

I spent half a day dealing with this problem while using ObjectAL, and ended up doing exactly what you did, re-making the entire project. It worked, until out of curiosity I copied the entire project over, then same problem again, alcOpenDevice(NULL) returned NULL. By chance I stumbled upon the answer. It was this bit of code in my swift game scene:

let jumpSound = SKAction.playSoundFileNamed("WhistleJump.mp3", waitForCompletion: false)

And then I remembered I had this problem before without SKAction involved. That time it turned out I was using ObjectAL in two different ways, I used OALSimpleAudio in one place, and OpenAL objects in another, and it was initializing my audio session twice.

The common thread between these two incidents is both times alcOpenDevice() was called more than once during the life of the application. The first time it was ObjectAL calling it twice due to my misuse of the library. The second SKAction.playSoundFileNamed() must have called alcOpenDevice() before my ObjectAL code did. Upon further research I found this bit in the OpenAL 1.1 Specification:


6.1.1. Connecting to a Device

The alcOpenDevice function allows the application (i.e. the client program) to connect to a device (i.e. the server). ALCdevice * alcOpenDevice (const ALCchar *deviceSpecifier); If the function returns NULL, then no sound driver/device has been found. The argument is a null terminated string that requests a certain device or device configuration. If NULL is specified, the implementation will provide an implementation specific default.


My hunch is that Apple's implementation of this function only returns the correct device ONCE for the life of the application. Every time alcOpenDevice is called after that, it returns NULL. So bottom line: Take out every trace of audio code before switching to OpenAL. Even code that seems safe, like SKAction.playSoundFileNamed() still might contain a call to alcOpenDevice() buried deep in its implementation.

For those using ObjectAL, here is the console output of this problem to help them find their way here from google, as I couldn't find a good answer myself:

OAL Error: +[ALWrapper openDevice:]: Could not open device (null)
OAL Error: -[ALDevice initWithDeviceSpecifier:]: <ALDevice: 0x17679b20>: Failed to create OpenAL device (null)
OAL Error: +[ALWrapper closeDevice:]: Invalid Enum (error code 0x0000a003)
OAL Warning: -[OALAudioSession onAudioError:]: Received audio error notification, but last reset was 0.012216 seconds ago. Doing nothing.
fatal error: unexpectedly found nil while unwrapping an Optional value
Community
  • 1
  • 1
mogelbuster
  • 1,066
  • 9
  • 19
  • A very good answer and it pointed me to my problem. I use Cocos2D 3.x, and the template code pre-initialises OAL for me. My own initialisation code was doing this a second time, causing the crash. ObjectAL needs to be a little more robust in this regard. – PKCLsoft Dec 14 '15 at 12:56
0

This SO answer seems to validate my comment about AVAudioSession conflicting with OpenAL. Try removing AVAudioSession, or initializing OpenAL first (tho I imagine this would cause the inverse problem).

Community
  • 1
  • 1
Brad Allred
  • 7,323
  • 1
  • 30
  • 49
  • Yeah, that's the one that gave me the idea to switch my setupAudioDevice and setupAudioSession methods. It didn't seem to have an effect though. The device still came back NULL. It's also worth noting that I've changed the session setup on the first sample project I linked (so it's the same as what I'm using) and it still runs fine. – Talidos Jun 05 '14 at 21:36
-2

Alright, so I ended up starting over in a fresh project with a copy-pasted version of AudioSamplePlayer from the first sample project I linked. -It worked.

I then edited it step by step back to the format I had set up in my project. -It still works!

I still don't know what I did wrong the first time, and I'm not sure it was even in my audio player anymore, but It's running now. I blame gremlins.

...maybe alien surveillance.

Talidos
  • 1
  • 1
  • 4