2009-05-22 4 views
36

Я пытаюсь устранить задержку запуска при воспроизведении аудиофайла (очень короткого - менее 2 секунд) через AVAudioPlayer на iPhone.Медленный запуск для AVAudioPlayer при первом воспроизведении звука

Во-первых, код:

NSString *audioFile = [NSString stringWithFormat:@"%@/%@.caf", [[NSBundle mainBundle] resourcePath], @"audiofile"]; 
NSData *audioData = [NSData dataWithContentsOfMappedFile:audioFile]; 

NSError *err; 
AVAudioPlayer *audioPlayer = [(AVAudioPlayer*)[AVAudioPlayer alloc] initWithData:audioData error:&err]; 

audioPlayer.delegate = self; 
[audioPlayer play]; 

Я также реализовать метод audioPlayerDidFinishPlaying, чтобы освободить AVAudioPlayer как только я сделал.

В первый раз, когда я воспроизвожу аудио, отставание ощутимо - не менее 2 секунд. Однако после этого звук воспроизводится немедленно. Я подозреваю, что виновником является то, что [NSData dataWithContentsOfMappedFile] долгое время читает со вспышки, но затем быстро переходит к более позднему чтению. Я не уверен, как это проверить.

Это тот случай? Если да, должен ли я просто предварительно кэшировать объекты NSData и быть агрессивным относительно их очистки в условиях низкой памяти?

+0

Благодарим за информацию. Вы должны ответить на вопрос и принять свой ответ. Инициализация AVAudioPlayer при запуске обеспечила воспроизведение звука без задержки в остальной части приложения. – brianegge

+1

@johnbiesnecker воспроизводит любой звук с томом 0, тогда все вызовы звукового воспроизведения должны быть внутри блока глобальной очереди async с приоритетом по умолчанию или с высоким приоритетом, звук не должен воспроизводиться в основной очереди. –

+1

В дополнение к тому, что сказал @JuanPabloBoero, я также играл громкость звука 0 при получении 'UIApplicationWillEnterForegroundNotification', иначе будет задержка после возобновления приложения с фона. – Pang

ответ

36

Задержка, похоже, связана с созданием AVAudioPlayer в первый раз. Если я загружаю любой звук, запустите [audioPlayer prepareToPlay], а затем немедленно отпустите его, время загрузки для всего моего другого звука очень близко к незаметному. Итак, теперь я делаю это в applicationDidFinishLaunching, и все остальное работает хорошо.

Я не могу найти что-либо об этом в документах, но, похоже, это так.

+1

Хмм, я не знаю об этом. prepareToPlay не полностью работает для меня.prepareToPlay вроде работает, но поскольку он, как представляется, загружает аудио асинхронно, невозможно точно узнать, когда звук действительно готов к воспроизведению. См. Мой недавний ответ на решение, которое я придумал. –

+0

Я получаю задержку с AVQueuePlayer, а также всякий раз, когда я сначала загружаю в нее актив. Игрок получает инициализацию только один раз. Похоже, общая проблема: http://stackoverflow.com/questions/11171374/how-to-reduce-ios-avplayer-start-delay – Oren

-1

Я точно не знаю, но я подозреваю, что объект NSData ленив и загружает содержимое файла по требованию. Вы можете попробовать «обмануть», позвонив [audioData getBytes:someBuffer length:1]; в какой-то ранний момент, чтобы загрузить его, прежде чем он понадобится.

-1

Ответ

AVAudioPlayer *audioplayer; 
[audioplayer prepareToPlay]; 
+2

Собственно, [audioplayer prepareToPlay] не является ответом ... задержка I говорил о том, что происходит при первом назначении и инициализации объекта AVAudioPlayer, прежде чем вы вызовете любой из его методов. Это происходит только в первый раз, когда вы загружаете один. prepareToPlay только предварительно загружает аудио, но не устраняет отставание, о котором я действительно спрашивал. Кстати, UIWebView демонстрирует то же поведение - если вы выделите и затем сразу же отпустите один, остальная загрузка будет очень быстрой. –

10

Вот что я сделал (в отдельном потоке):

[audioplayer start] 
[audioplayer stop] 
self.audioplayer = audioplayer 

[аудиоплеер prepareToPlay], как представляется, асинхронный метод, так что вы не можете убедитесь, что когда он вернется, если звук фактически готов к воспроизведению.

В моем случае я вызываю начало фактически начать играть - это кажется синхронным. Затем я немедленно прекращаю это. В симуляторе, в любом случае, я не слышу никакого звука из этой активности. Теперь, когда звук «действительно» готов к воспроизведению, я назначаю локальную переменную переменной-члену, чтобы код вне потока имел к ней доступ.

Я должен сказать, что я нахожу это несколько удивительно, что даже на 4 прошивке это занимает около 2 секунд, просто загрузить аудио файла, который находится всего в 4 секунды в длине ....

+1

сделать это во время просмотра загрузки, это быстрый взлом, и он работает – yasirmturk

2

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

Короче говоря, предварите звуковую систему, загрузив и сыграв короткий, «пустой» звук, прежде чем делать что-либо еще. Код выглядит это на короткий mp3 файл я предварительно загрузить в viewDidLoad методе моего взгляда контроллера, что это из .1 секунд:

NSError* error = nil; 
    NSString* soundfilePath = [[NSBundle mainBundle] pathForResource:@"point1sec" ofType:@"mp3"]; 
    NSURL* soundfileURL = [NSURL fileURLWithPath:soundfilePath]; 
    AVAudioPlayer* player = [[[AVAudioPlayer alloc] initWithContentsOfURL:soundfileURL error:&error] autorelease]; 
    [player play]; 

Вы можете создать свой собственный пустой mp3, если вы хотите, или сделать поиск Google на " пустые mp3s ", чтобы найти и скачать один, уже построенный кем-то другим.

+0

, используя это с включенным NSZombies, и сообщение «impl» отправляется игроку после dealloc. я получил его, чтобы избежать этого, не автореализуя его, а вместо этого вручную отправив ему сообщение [player release] в файле audioPlayerDidFinishPlaying: успешно: событие (в обратном вызове ) – unsynchronized

+0

в дополнение к последнему комментарию, см. мой обновленный ответ на этот вопрос для решение для исходного кода: http://stackoverflow.com/a/7426406/830899 – unsynchronized

8

Если звук менее чем за 30 секунд долго в длину и в линейной PCM или IMA4 формате, и упаковывается как .caf, .wav или .aiff вы можете использовать системные звуки:

Импортируйте AudioToolbox Framework

в файле .h создать эту переменную:

SystemSoundID mySound; 

в файле .m реализовать в методе инициализации:

-(id)init{ 
if (self) { 
    //Get path of VICTORY.WAV <-- the sound file in your bundle 
    NSString* soundPath = [[NSBundle mainBundle] pathForResource:@"VICTORY" ofType:@"WAV"]; 
    //If the file is in the bundle 
    if (soundPath) { 
     //Create a file URL with this path 
     NSURL* soundURL = [NSURL fileURLWithPath:soundPath]; 

     //Register sound file located at that URL as a system sound 
     OSStatus err = AudioServicesCreateSystemSoundID((CFURLRef)soundURL, &mySound); 

      if (err != kAudioServicesNoError) { 
       NSLog(@"Could not load %@, error code: %ld", soundURL, err); 
      } 
     } 
    } 
return self; 
} 

В вашем методе IBAction вы называете звук с этим:

AudioServicesPlaySystemSound(mySound); 

Это работает для меня, воспроизводит звук довольно чертовски близко к тому, когда нажата кнопка. Надеюсь, это вам поможет.

+0

Это отличный ответ. Спасибо, что опубликовали это! –

3

Я написал простую оболочку для AVAudioPlayer, который обеспечивает метод prepareToPlay, который на самом деле работает:

https://github.com/nicklockwood/SoundManager

Это в основном просто сканирует ваше приложение для звуковых файлов, выбирает один и воспроизводит его при нулевом объеме. Это инициализирует звуковое оборудование и позволяет сразу воспроизводить следующий звук.

+0

Я просто попробовал, и это кажется действительно хорошим. Благодаря ;) – Beny

0

Другим способом является создание короткого & тикового звука и воспроизведение его при первом запуске игрока.

  1. Установите уровень микрофона на 0 в системных настройках.
  2. Открыть QuickTime.
  3. Создайте новую аудиозапись (Файл> Новая аудиозапись).
  4. Запись на 1 или 2 секунды.
  5. Сохраните/экспортируйте аудиофайл. (он будет иметь расширение .m4a и около 2 kb по размеру).
  6. Добавьте файл в свой проект и воспроизведите его.

Если вы не хотите, чтобы создать новый звук файл самостоятельно, вы можете скачать короткий & тихий звуковой файл здесь: https://www.dropbox.com/s/3u45x9v72ic70tk/silent.m4a?dl=0

0

Вот простой Swift расширение AVAudioPlayer, который использует в плей-и-стоп на 0 объемная идея представлена ​​в предыдущих ответах. PrepareToPlay(), к сожалению, по крайней мере, для меня не трюк.

extension AVAudioPlayer { 
    private func initDelaylessPlayback() { 
     volume = 0 
     play() 
     stop() 
     volume = 1 
    } 

    convenience init(contentsOfWithoutDelay : URL) throws { 
     try self.init(contentsOf: contentsOfWithoutDelay, fileTypeHint: nil) 
     initDelaylessPlayback() 
    } 
}