web-dev-qa-db-fra.com

Démarrage lent pour AVAudioPlayer lors de la première lecture d'un son

J'essaie d'éliminer le décalage au démarrage lorsque vous lisez un fichier audio (très court - moins de 2 secondes) via AVAudioPlayer sur l'iPhone.

Tout d'abord, le code:

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

J'implémente également la méthode audioPlayerDidFinishPlaying pour libérer AVAudioPlayer une fois que j'ai terminé.

La première fois que je joue le son, le décalage est palpable - au moins 2 secondes. Cependant, après cela, le son est joué immédiatement. Je soupçonne que le coupable, alors, est le [NSData dataWithContentsOfMappedFile] qui prend beaucoup de temps à lire à partir de la mémoire flash, puis à lire rapidement. Je ne sais pas comment tester cela, cependant.

Est-ce le cas? Si tel est le cas, devrais-je simplement mettre en cache les objets NSData et redoubler d'efforts pour les effacer dans des conditions de mémoire insuffisante?

36
John Biesnecker

Le délai semble être lié à l'instanciation de AVAudioPlayer pour la première fois. Si je charge un fichier audio, exécutez [audioPlayer prepareToPlay], puis relâchez-le immédiatement. Les temps de chargement de tous mes autres fichiers audio sont très proches de l’imperceptible. Alors maintenant, je le fais dans applicationDidFinishLaunching et tout le reste fonctionne bien.

Je ne trouve rien à ce sujet dans la documentation, mais cela semble certainement être le cas.

37
John Biesnecker

Voici ce que j'ai fait (dans un fil séparé):

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

[audioplayer prepareToPlay] semble être une méthode asynchrone, vous ne pouvez donc pas être sûr à son retour si le son est réellement prêt à être lu.

Dans mon cas, je commence à jouer pour commencer à jouer - cela semble être synchrone. Puis je l'arrête immédiatement. De toute façon, dans le simulateur, aucun son ne sort de cette activité. Maintenant que le son est "vraiment" prêt à être joué, j'attribue la variable locale à une variable membre afin que le code situé en dehors du thread y ait accès.

Je dois dire que je trouve quelque peu surprenant que, même sur iOS 4, il faut environ 2 secondes pour charger un fichier audio de seulement 4 secondes ....

11
Taylor Gautier

Si votre fichier audio dure moins de 30 secondes et qu'il est au format PCM linéaire ou IMA4 et qu'il est présenté au format .caf, .wav ou .aiff, vous pouvez utiliser les sons du système:

Importer le cadre AudioToolbox

Dans votre fichier .h, créez cette variable:

SystemSoundID mySound;

Dans votre fichier .m, implémentez-le dans votre méthode 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;
}

Dans votre méthode IBAction, vous appelez le son avec ceci:

AudioServicesPlaySystemSound(mySound);

Cela fonctionne pour moi, joue le son sacrément proche de lorsque le bouton est enfoncé. J'espère que cela vous aide.

8
M Jesse

J'ai écrit un wrapper simple pour AVAudioPlayer qui fournit une méthode prepareToPlay qui fonctionne réellement:

https://github.com/nicklockwood/SoundManager

Fondamentalement, il ne fait que scanner votre application à la recherche de fichiers son, en choisir un et la lire à volume zéro. Cela initialise le matériel audio et permet au son suivant de jouer instantanément.

3
Nick Lockwood

J'ai adopté une approche alternative qui fonctionne pour moi. J'ai vu cette technique mentionnée ailleurs (mais je ne me souviens pas pour le moment où c'était).

En bref, effectuez un contrôle en amont du système audio en chargeant et en lisant un son bref et «vierge» avant de faire autre chose. Le code ressemble à ceci pour un fichier mp3 court que je précharge dans la méthode viewDidLoad de mon contrôleur de vue d’une durée de 0,1 seconde:

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

Vous pouvez créer vos propres mp3 vierges si vous le souhaitez ou faire une recherche google sur les "mp3 vierges" pour trouver et télécharger ceux déjà construits par quelqu'un d'autre.

2
hkatz

Voici une simple extension Swift d’AVAudioPlayer qui utilise l’idée de jouer à l’arrêt à 0 volume présentée dans les réponses précédentes. PrepareToPlay () malheureusement au moins pour moi n'a pas fait le tour.

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
GOR

Une autre solution consiste à créer un son court et silencieux et à le lire lors du premier lancement du lecteur.

  1. Définissez le niveau du microphone sur 0 dans les Préférences Système.
  2. Ouvrez QuickTime.
  3. Créez un nouvel enregistrement audio (Fichier> Nouvel enregistrement audio).
  4. Enregistrez pendant 1 ou 2 secondes.
  5. Enregistrez/exportez le fichier audio. (il aura une extension .m4a et environ 2 Ko sur la taille).
  6. Ajoutez le fichier à votre projet et jouez-le.

Si vous ne voulez pas créer un nouveau fichier son vous-même, vous pouvez télécharger un fichier audio court & silencieux ici: https://www.dropbox.com/s/3u45x9v72ic70tk/silent.m4a?dl=0

0
Adi Nugroho