Pergunta

Eu estou tentando eliminar lag arranque quando se joga a. (Muito curto - menos de 2 segundos) arquivo de áudio via AVAudioPlayer no iPhone

Primeiro, o código:

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];

Eu também implementar o método audioPlayerDidFinishPlaying para liberar o AVAudioPlayer uma vez que eu sou feito.

A primeira vez que reproduzir o áudio do lag é palpável - pelo menos 2 segundos. No entanto, depois que o som é reproduzido imediatamente. Eu suspeito que o culpado, então, é o [NSData dataWithContentsOfMappedFile] levando muito tempo lendo do flash, inicialmente, mas, em seguida, ser rápido na tarde lê. Não tenho certeza como testar isso, entretanto.

É esse o caso? Se assim for, devo apenas pré-cache o NSData objetos e ser agressivo sobre limpá-los em condições de pouca memória?

Foi útil?

Solução

O atraso parece estar relacionado com instanciar AVAudioPlayer pela primeira vez. Se eu carregar qualquer áudio, execute [Audioplayer prepareToPlay] e logo em seguida liberá-lo, os tempos de carga para todos os meus outros tipos de áudio está muito perto imperceptível. Então agora eu estou fazendo isso em applicationDidFinishLaunching e tudo corre bem.

Eu não consigo encontrar nada sobre isso nos docs, mas certamente parece ser o caso.

Outras dicas

Aqui está o que eu fiz (em um segmento separado):

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

[audioplayer prepareToPlay] parece ser um método assíncrono, então você não pode ter certeza de quando ele retorna se o áudio é de fato pronto para jogar.

No meu caso eu chamo começar a realmente começar a jogar - este parece ser síncrono. Então eu parar com isso imediatamente. No simulador de qualquer maneira eu não ouvir qualquer som que sai desta actividade. Agora que o som é "realmente" pronto para jogar, eu atribuir a variável local para uma variável de membro para que o código fora do segmento tem acesso a ele.

Devo dizer que eu achar que é um pouco surpreendente que, mesmo no iOS 4 que leva cerca de 2 segundos apenas para carregar um arquivo de áudio que é de apenas 4 segundos de duração ....

Se o áudio é inferior a 30 segundos de duração de comprimento e está no formato PCM ou IMA4 linear, e é empacotado como um .caf, .wav ou .aiff você pode usar sons do sistema:

Import a AudioToolbox Framework

Em seu arquivo .h criar esta variável:

SystemSoundID mySound;

Em seu arquivo .m implementá-lo em seu método 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;
}

No seu método de IBAction você ligar o som com este:

AudioServicesPlaySystemSound(mySound);

Isso funciona para mim, reproduz o som muito muito perto de quando o botão é pressionado. Espero que isso ajude você.

Eu tomei uma abordagem alternativa que funciona para mim. Eu vi essa técnica mencionado em outros lugares (tho eu não me lembro no momento em que foi).

Em suma, pré-impressão de sistema de som por carga e jogando um curto, "em branco" som antes de fazer qualquer outra coisa. Os olhares código como este para um mp3 arquivo I pré-carga curta no meu método controller'sviewDidLoad vista que é de 0,1 segundo de duração:

   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];  

Você pode criar seu próprio branco mp3, se quiser, ou fazer uma pesquisa no Google sobre "mp3s em branco" para encontrar e baixar um já construídos por outra pessoa.

Eu escrevi um invólucro simples para AVAudioPlayer que fornece um método prepareToPlay que realmente funciona:

https://github.com/nicklockwood/SoundManager

É basicamente apenas verifica o aplicativo para arquivos de som, escolhe uma e joga-lo no volume zero. Que inicializa o hardware de áudio e permite que o próximo som para tocar instantaneamente.

Outra solução é criar um curto e áudio em silêncio e reproduzi-lo na primeira vez jogador é iniciado.

  1. Definir o nível do microfone para 0 em Preferências do Sistema.
  2. Open QuickTime.
  3. Criar uma nova gravação de áudio (File> Gravação New Audio).
  4. Record para 1 ou 2 segundo.
  5. Salvar / exportar o arquivo de áudio. (Ele terá .m4a extensão e cerca de 2 kb do tamanho).
  6. Adicione o arquivo ao seu projeto e reproduzi-lo.

Se você não quiser criar um novo arquivo de som, você pode fazer download de um arquivo de áudio curta e silenciosa aqui: https://www.dropbox.com/s/3u45x9v72ic70tk/silent.m4a?dl=0

Aqui está uma simples extensão Swift para AVAudioPlayer que usa o play-e-stop na ideia 0 de volume apresentado nas respostas anteriores. PrepareToPlay () infelizmente, pelo menos para mim não fazer o truque.

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

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

Eu não sei ao certo, mas eu suspeito que o objeto NSData está sendo preguiçoso e carregar o conteúdo do arquivo na demanda. Você pode tentar "enganar" chamando [audioData getBytes:someBuffer length:1]; em algum momento cedo para obtê-lo para carregar esse arquivo antes que seja necessário.

A resposta é

AVAudioPlayer *audioplayer;
[audioplayer prepareToPlay];
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top