我做了一个简单的应用程序,当超过特定的噪音水平时播放警报。所以,所以我有一个记录声音和仪表录制的声音水平(如下图所示唯一重要的部分代码)的AudioQueue:ios:在主线程外播放声音
#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];
}
那么基本上在这里发生如下:
我轻按iPhone屏幕上的一个按钮,导致音频从iPhone中的麦克风录制声音。当一个队列已满时,调用回调函数“HandleInputBuffer”来处理音频缓冲区中的数据。处理数据意味着我要测量声音强度。如果强度超过偏差,则会调用“playAlarmSound”方法。
所以这个调用发生在主线程之外,即在一个额外的线程中。
对象“SP”(声音播放)具有以下实现:
//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];
}
}
实际上,代码工作正常,所以应该在代码中没有错误,也波形文件的格式是正确的。这是什么情况:
iPhone模拟器: 一切工作正常。创建对象SoundPlayer时,在构造函数中调用[self playSound]会导致模拟器播放随机声音,以便证明该方法已正确实施。然后我开始声音记录,当超过某个声级时,方法从AudioRecorder(在一个单独的线程中)被调用,并且声音也被播放。所以这是所需的行为。
实际的iPhone设备: 当创建对象SoundPlayer时播放随机声音,所以这工作正常。但是当我开始录音并且超过噪音水平时,Soundplayer中的playSound方法被AudioRecorder调用,但没有播放声音。我怀疑这是因为这发生在一个单独的线程中。但我不知道如何修复。
我已经尝试通过使用默认通知中心的通知来修复它,但它也没有工作。我如何管理声音播放?