Получение аудиоустройства с OpenAL

Я пытаюсь использовать OpenAL для игры IOS, над которой я работаю, но у меня возникла проблема с открытием аудиоустройства. В частности, когда я вызываю функцию alcOpenDevice(NULL), я получаю 'NULL' взамен. Конечно, это вызывает проблемы, но я не могу сказать, что я делаю неправильно.

Я новичок в OpenAL, поэтому я посмотрел пару руководств здесь и здесь, чтобы увидеть, что мне нужно сделать. Если я скачаю их примеры проектов и протестирую их, они оба будут работать нормально. Если я скопирую их файлы в свой проект и проигнорирую созданные мной файлы, они все равно будут работать нормально. Я предполагаю, что что-то потеряно в переводе, когда я начал перестраивать код для использования в моем проекте. Однако поиск по сайту и поиск в Интернете не дали мне никаких поводов, поэтому я надеюсь, что кто-то здесь сможет поставить меня на правильный путь.

Вот фактический код установки, который я использую в моем 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]];
    }
}

Примечание: я использую IOS 7.1.1 на новом iPad Air и использую Xcode 5.1.1. Эта проблема была подтверждена на iPad, моем симуляторе и iPod touch.

3 ответа

Решение

Хорошо, так что я закончил тем, что начал заново в новом проекте с вставленной в копию версией AudioSamplePlayer из первого примера проекта, который я связал. -Это сработало.

Затем я отредактировал его шаг за шагом к формату, установленному в моем проекте. -Он все еще работает!

Я до сих пор не знаю, что я сделал неправильно в первый раз, и я не уверен, что это было даже в моем аудиоплеере, но он работает сейчас. Я виню гремлинов.

... возможно наблюдение за пришельцами.

Краткий ответ:

Реализация Apple alcOpenDevice() возвращает устройство только один раз. Каждый последующий вызов возвращает NULL. Эта функция может вызываться большим количеством аудиокода Apple, поэтому вынимайте КАЖДЫЙ ТРАССИРОВКУ аудиокода перед использованием OpenAL и ручным вызовом этой функции самостоятельно.

Длинный ответ:

Я потратил полдня на решение этой проблемы, используя ObjectAL, и в итоге сделал именно то, что сделал ты, переделав весь проект. Это работало до тех пор, пока из любопытства я не скопировал весь проект, затем снова возникла та же проблема, alcOpenDevice(NULL) вернулся NULL. Случайно наткнулся на ответ. Это был фрагмент кода в моей быстрой игровой сцене:

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

А потом я вспомнил, что раньше у меня была эта проблема без участия SKAction. Тогда оказалось, что я использовал ObjectAL двумя разными способами, я использовал OALSimpleAudio в одном месте и объекты OpenAL в другом, и он дважды инициализировал мой аудио сеанс.

Общая нить между этими двумя инцидентами alcOpenDevice() был вызван более одного раза в течение срока действия приложения. В первый раз ObjectAL вызвал его дважды из-за неправильного использования библиотеки. Второй SKAction.playSoundFileNamed() Должно быть, позвонил alcOpenDevice() до того, как мой объектный код сделал. После дальнейших исследований я нашел этот бит в спецификации OpenAL 1.1:


6.1.1. Подключение к устройству

Функция alcOpenDevice позволяет приложению (т.е. клиентской программе) подключаться к устройству (то есть к серверу). ALCdevice * alcOpenDevice (const ALCchar *deviceSpecifier); Если функция возвращает NULL, звуковой драйвер / устройство не найдено. Аргумент представляет собой строку с нулевым символом в конце, которая запрашивает определенное устройство или конфигурацию устройства. Если указано значение NULL, реализация будет предоставлять конкретную реализацию по умолчанию.


Я догадываюсь, что реализация Apple этой функции только возвращает правильное устройство ОДИН РАЗ в течение срока службы приложения. Каждый раз, когда alcOpenDevice вызывается после этого, он возвращает NULL. Итак, суть: удалите все следы аудиокода перед переключением на OpenAL. Даже код, который кажется безопасным, как SKAction.playSoundFileNamed() все еще может содержать призыв к alcOpenDevice() похоронен глубоко в своей реализации.

Для тех, кто использует ObjectAL, вот консольный вывод этой проблемы, чтобы помочь им найти свой путь здесь от Google, так как я не мог найти хороший ответ сам:

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

Этот SO ответ, кажется, подтверждает мой комментарий о AVAudioSession конфликтует с OpenAL. Попробуйте удалить AVAudioSessionили сначала инициализировать OpenAL (хотя я предполагаю, что это вызовет обратную проблему).

Другие вопросы по тегам