2011-08-06 3 views
3

J'ai créé une application simple qui émet une alarme lorsqu'un certain niveau de bruit est dépassé. Ainsi donc j'ai un AudioQueue qui enregistre le son et mètres le niveau du son enregistré (seulement les parties de code importantes ci-dessous):ios: Lecture du son en dehors du fil principal

#import "AudioRecorder.h" 

#include <AudioToolbox/AudioToolbox.h> 

#include <iostream> 

using namespace std; 

@implementation AudioRecorder 

@synthesize sp; //custom object SoundPlayer 
@synthesize bias; //a bias, if the soundlevel exeeds this bias something happens 

AudioRecorder* ar;  

//callback function to handle the audio data contained in the audio buffer. 
//In my case it is called every 0.5 seconds 
static void HandleInputBuffer (...) { 
    ... 
    char* levelMeterData = new char[size]; 
    AudioQueueGetProperty (inAQ, kAudioQueueProperty_CurrentLevelMeter, levelMeterData, &size); 
    AudioQueueLevelMeterState* meterState = reinterpret_cast<AudioQueueLevelMeterState*>(levelMeterData); 
    cout << "mAveragePower = " << meterState->mAveragePower << endl; 
    cout << "mPeakPower = " << meterState->mPeakPower << endl; 
    if(meterState->mPeakPower > ar.bias) 
     [ar playAlarmSound]; 

} 
... 
//The constructor of the AudioRecorder class 
-(id) init { 
    self = [super init]; 
    if(self) { 
     ar = self; 
     sp = [[SoundPlayer alloc] init]; 
    } 
    return self; 
} 

-(void)playAlarmSound { 
    [sp playSound]; 
} 

donc ce qui se passe essentiellement ici est la suivante:

je tape sur la écran de l'iPhone sur un bouton qui amène la chaîne audio à enregistrer le son du micro dans l'iphone. Lorsqu'une file d'attente est pleine, la fonction de rappel "HandleInputBuffer" est appelée pour gérer les données dans le tampon audio. Manipuler les données signifie dans mon cas particulier que je veux mesurer l'intensité sonore. Si l'intensité dépasse un biais, la méthode "playAlarmSound" est invoquée. Par conséquent, cette invocation se produit en dehors du thread principal, c'est-à-dire dans un thread supplémentaire.

L'objet « sp » (SoundPlayer) a la mise en œuvre suivante:

//callback function. Gets called when the sound has finished playing 
void soundDidFinishPlaying(SystemSoundID ssID, void *clientData) { 
    NSLog(@"Finished playing system sound"); 
    sp.soundIsPlaying = NO; 
} 

-(id)init { 
    self = [super init]; 
    if(self) { 
     self.soundIsPlaying = NO; 
     srand(time(NULL)); 
     soundFilenames = [[NSArray alloc] initWithObjects:@"Alarm Clock Bell.wav", @"Bark.wav", @"Cartoon Boing.wav", @"Chimpanzee Calls.wav", @"School Bell Ringing.wav", @"Sheep Bah.wav", @"Squeeze Toy.wav", @"Tape Rewinding.wav", nil]; 
     [self copySoundsIfNeeded]; 
     sp = self; 
     [self playSound]; //gets played without any problems 
    } 
    return self; 
} 

-(void)playSound { 
    if(!self.soundIsPlaying) { 
     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 
     int index = rand() % [soundFilenames count]; 
     NSString* filePath = [ [self getBasePath] stringByAppendingPathComponent: [soundFilenames objectAtIndex:index] ]; 

     NSFileManager *fileManager = [NSFileManager defaultManager]; 
     if([fileManager fileExistsAtPath:filePath]) 
      NSLog(@"File %@ exists", [soundFilenames objectAtIndex:index]); 
     else 
      NSLog(@"File %@ NOT exists", [soundFilenames objectAtIndex:index]); 

     CFURLRef url = CFURLCreateWithFileSystemPath (0, (CFStringRef) filePath, kCFURLPOSIXPathStyle, NO); 
     SystemSoundID outSystemSoundID; 
     AudioServicesCreateSystemSoundID(url, &outSystemSoundID); 
     AudioServicesAddSystemSoundCompletion (outSystemSoundID, 0, 0, soundDidFinishPlaying, 0); 
     self.soundIsPlaying = YES; 
     AudioServicesPlaySystemSound(outSystemSoundID); 
     [pool drain]; 
    } 
} 

En fait, le code fonctionne très bien, donc il ne devrait y avoir aucune erreur dans le code, également le format des fichiers wave est correcte. Et voici ce qui se passe:

  1. iPhone Simulator: Tout fonctionne très bien. Lorsque l'objet SoundPlayer est créé, l'appel de [self playSound] dans le constructeur fait que le simulateur joue un son aléatoire, ce qui prouve que la méthode est correctement implémentée. Ensuite, je commence à enregistrer le son et quand un certain niveau de son est dépassé, la méthode est invoquée depuis AudioRecorder (dans un thread séparé) et les sons sont également joués. Donc, c'est le comportement souhaité.

  2. Appareil iPhone actuel: Lorsque l'objet SoundPlayer est créé, un son aléatoire est émis, donc cela fonctionne correctement. MAIS quand je commence l'enregistrement audio et qu'un niveau de bruit est dépassé la méthode playSound dans Soundplayer est invoquée par AudioRecorder mais aucun son n'est joué. Je suppose que c'est parce que cela se passe dans un fil séparé. Mais je n'ai aucune idée de comment cela pourrait être réparé.

J'ai déjà essayé de le réparer en utilisant les notifications du centre de notifications par défaut, mais cela ne fonctionnait pas non plus. Comment puis-je gérer que le son est joué?

Répondre

3

une ou deux choses à considérer:

1) assurez-vous permettre de jouer & enregistrer:

UInt32 category = kAudioSessionCategory_PlayAndRecord; 
AudioSessionSetProperty(kAudioSessionProperty_AudioCategory, 
         sizeof(category), &category); 

2) vérifier les valeurs de retour des différents AudioServices* appels à -(void)playSound pour voir où il fait échoue.

3) faire en sorte que la propriété sp en classe AudioRecorder est initialisé correctement (à savoir que vous appelez la méthode d'initialisation correcte de AudioRecorder)

4) Il est possible que (certains) les appareils iOS ne prennent pas en charge différents échantillonnage taux pour l'enregistrement simultané & lecture. Si vos fichiers .wav ont un taux d'échantillonnage différent de celui de votre enregistrement AudioQueue, cela vaut la peine d'essayer d'en adapter un.

5) au lieu d'appeler [sp playSound] utiliser cette instruction pour l'appeler sur le thread principal:

[sp performSelectorOnMainThread:@selector(playSound) withObject:nil waitUntilDone:NO]; 

Notez également que très probablement, le son d'alarme sera entendu sur l'enregistrement (si l'iPhone 4 peut filtrer en dehors).

Questions connexes