Получение аудиоустройства с 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 (хотя я предполагаю, что это вызовет обратную проблему).