ios: воспроизведение звука вне основного потока - PullRequest
3 голосов
/ 06 августа 2011

Я сделал простое приложение, которое воспроизводит сигнал тревоги при превышении определенного уровня шума. Поэтому у меня есть AudioQueue, который записывает звук и измеряет уровень записанного звука (только важные части кода показаны ниже):

#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 (SoundPlayer) имеет следующую реализацию:

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

На самом деле код работает нормально, поэтому в коде не должно быть ошибок, а также формат волновых файлов правильный. И вот что происходит:

  1. Симулятор iPhone: Все отлично работает Когда объект SoundPlayer создан, вызов [self playSound] в конструкторе заставляет симулятор воспроизводить случайный звук, что доказывает, что метод реализован правильно. Затем я начинаю запись звука, и когда превышается определенный уровень звука, метод вызывается из AudioRecorder (в отдельном потоке), и звуки также воспроизводятся. Так что это желаемое поведение.

  2. Фактическое устройство iPhone: Когда объект SoundPlayer создан, воспроизводится случайный звук, так что это работает нормально. НО, когда я начинаю запись звука и уровень шума превышен, метод PlaySound в Soundplayer вызывается AudioRecorder, но звук не воспроизводится. Я подозреваю, что это потому, что это происходит в отдельном потоке. Но я понятия не имею, как это можно починить.

Я уже пытался восстановить его с помощью уведомлений из центра уведомлений по умолчанию, но он тоже не работал. Как я могу управлять воспроизведением звука?

1 Ответ

3 голосов
/ 08 августа 2011

пара вещей, которые следует учитывать:

1) убедитесь, что вы включили воспроизведение и запись:

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

2) проверьте значения возврата различных вызовов AudioServices* в -(void)playSoundчтобы увидеть, где на самом деле происходит сбой.

3) убедитесь, что свойство sp в классе AudioRecorder правильно инициализировано (т.е. вы вызываете правильный метод init AudioRecorder)

4)Возможно, что (некоторые) устройства iOS не поддерживают разные частоты дискретизации для одновременной записи и воспроизведения.Если ваши файлы .wav имеют частоту дискретизации, отличную от частоты записи AudioQueue, стоит попробовать адаптировать любой из них.

5) вместо вызова [sp playSound] используйте этот оператор для вызова его в главном потоке:

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

Также обратите внимание, что, скорее всего, ваш звук будильника будет слышен при записи (хотя iPhone 4 может его отфильтровать).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...