Медленный запуск AVAudioPlayer при первом воспроизведении звука - PullRequest
36 голосов
/ 23 мая 2009

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

Сначала код:

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 и быть агрессивным в отношении очистки их в условиях нехватки памяти?

Ответы [ 9 ]

37 голосов
/ 21 июня 2010

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

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

11 голосов
/ 15 марта 2011

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

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

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

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

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

8 голосов
/ 03 января 2012

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

Импорт платформы AudioToolbox

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

SystemSoundID mySound;

В вашем файле .m внедрите его в метод init:

-(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);

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

3 голосов
/ 02 мая 2012

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

https://github.com/nicklockwood/SoundManager

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

3 голосов
/ 06 октября 2011

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

Короче говоря, прежде чем делать что-либо еще, предварительно загрузите звуковую систему, загрузив и воспроизведя короткий, пустой звук. Код выглядит следующим образом для короткого mp3-файла, который я предварительно загружаю в методе viewDidLoad моего контроллера представления, с продолжительностью 0,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 по "пустым mp3", чтобы найти и скачать уже созданный кем-то другим.

0 голосов
/ 14 августа 2017

Вот простое расширение 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()
    }
}
0 голосов
/ 26 ноября 2016

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

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

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

0 голосов
/ 19 июля 2010

Ответ

AVAudioPlayer *audioplayer;
[audioplayer prepareToPlay];
0 голосов
/ 23 мая 2009

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

...