私の最初の答えは十分ではなかったので、私は2チャンネルの16ビットウェーブファイルを再生する最小限の例をコンパイルしました。
あなたのコードとの主な違いは、再生開始イベントと停止イベントをリッスンするプロパティリスナーを作成したことです。
あなたのコードについては、一見すると正当だと思われます。しかし、私が指摘する2つの事柄: 1. TOO SMALLバッファサイズでバッファを割り当てているようです。私は、バッファが小さすぎるとAudioQueuesが再生されないことに気付きました。あなたの問題に合っているようです。 2.返されたプロパティを確認しましたか?戻る私のコード例に
:
すべては、ハード、それは正確に良いコーディング習慣ではありませんので、コード化されたが、それはあなたがそれを行うことができます方法を示しています。
AudioStreamTest.h
#import <Foundation/Foundation.h>
#import <AudioToolbox/AudioToolbox.h>
uint32_t bufferSizeInSamples;
AudioFileID file;
UInt32 currentPacket;
AudioQueueRef audioQueue;
AudioQueueBufferRef buffer[3];
AudioStreamBasicDescription audioStreamBasicDescription;
@interface AudioStreamTest : NSObject
- (void)start;
- (void)stop;
@end
AudioStreamTest。m
#import "AudioStreamTest.h"
@implementation AudioStreamTest
- (id)init
{
self = [super init];
if (self) {
bufferSizeInSamples = 441;
file = NULL;
currentPacket = 0;
audioStreamBasicDescription.mBitsPerChannel = 16;
audioStreamBasicDescription.mBytesPerFrame = 4;
audioStreamBasicDescription.mBytesPerPacket = 4;
audioStreamBasicDescription.mChannelsPerFrame = 2;
audioStreamBasicDescription.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
audioStreamBasicDescription.mFormatID = kAudioFormatLinearPCM;
audioStreamBasicDescription.mFramesPerPacket = 1;
audioStreamBasicDescription.mReserved = 0;
audioStreamBasicDescription.mSampleRate = 44100;
}
return self;
}
- (void)start {
AudioQueueNewOutput(&audioStreamBasicDescription, AudioEngineOutputBufferCallback, (__bridge void *)(self), NULL, NULL, 0, &audioQueue);
AudioQueueAddPropertyListener(audioQueue, kAudioQueueProperty_IsRunning, AudioEnginePropertyListenerProc, NULL);
AudioQueueStart(audioQueue, NULL);
}
- (void)stop {
AudioQueueStop(audioQueue, YES);
AudioQueueRemovePropertyListener(audioQueue, kAudioQueueProperty_IsRunning, AudioEnginePropertyListenerProc, NULL);
}
void AudioEngineOutputBufferCallback(void *inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer) {
if (file == NULL) return;
UInt32 bytesRead = bufferSizeInSamples * 4;
UInt32 packetsRead = bufferSizeInSamples;
AudioFileReadPacketData(file, false, &bytesRead, NULL, currentPacket, &packetsRead, inBuffer->mAudioData);
inBuffer->mAudioDataByteSize = bytesRead;
currentPacket += packetsRead;
if (bytesRead == 0) {
AudioQueueStop(inAQ, false);
}
else {
AudioQueueEnqueueBuffer(inAQ, inBuffer, 0, NULL);
}
}
void AudioEnginePropertyListenerProc (void *inUserData, AudioQueueRef inAQ, AudioQueuePropertyID inID) {
//We are only interested in the property kAudioQueueProperty_IsRunning
if (inID != kAudioQueueProperty_IsRunning) return;
//Get the status of the property
UInt32 isRunning = false;
UInt32 size = sizeof(isRunning);
AudioQueueGetProperty(inAQ, kAudioQueueProperty_IsRunning, &isRunning, &size);
if (isRunning) {
currentPacket = 0;
NSString *fileName = @"/Users/roy/Documents/XCodeProjectsData/FUZZ/03.wav";
NSURL *fileURL = [[NSURL alloc] initFileURLWithPath: fileName];
AudioFileOpenURL((__bridge CFURLRef) fileURL, kAudioFileReadPermission, 0, &file);
for (int i = 0; i < 3; i++){
AudioQueueAllocateBuffer(audioQueue, bufferSizeInSamples * 4, &buffer[i]);
UInt32 bytesRead = bufferSizeInSamples * 4;
UInt32 packetsRead = bufferSizeInSamples;
AudioFileReadPacketData(file, false, &bytesRead, NULL, currentPacket, &packetsRead, buffer[i]->mAudioData);
buffer[i]->mAudioDataByteSize = bytesRead;
currentPacket += packetsRead;
AudioQueueEnqueueBuffer(audioQueue, buffer[i], 0, NULL);
}
}
else {
if (file != NULL) {
AudioFileClose(file);
file = NULL;
for (int i = 0; i < 3; i++) {
AudioQueueFreeBuffer(audioQueue, buffer[i]);
buffer[i] = NULL;
}
}
}
}
-(void)dealloc {
[super dealloc];
AudioQueueDispose(audioQueue, true);
audioQueue = NULL;
}
@end
最後に、AudioQueuesの堅牢性をテストするために行ったいくつかの研究を取り上げたいと思います。
小さすぎるAudioQueueバッファを作成すると、まったく再生されません。それは私が少し遊んで、それがなぜ遊んでいないのか見てみました。
私は150サンプルしか保持できないバッファサイズを試しても、全く音が出ません。
175サンプルを保存できるバッファサイズを試してみると、曲全体が再生されますが、歪みが大きくなります。 175は、4ms未満の音声に相当する。
AudioQueueは、バッファを提供し続ける限り、新しいバッファを要求し続けます。これは、実際にあなたのバッファを再生しているかどうかに関係なくAudioQueueに関係します。
サイズ0のバッファを指定すると、バッファが失われ、そのキューのエンキュー要求に対してエラーkAudioQueueErr_BufferEmptyが返されます。 AudioQueueがそのバッファをもう一度埋めるように頼むことはありません。あなたが投稿した最後のキューでこれが発生した場合、AudioQueueはこれ以上バッファをいっぱいにするように要求しなくなります。その場合、そのセッションのオーディオはもう聞こえません。
AudioQueuesがバッファサイズの小さいものを再生しない理由を確認するために、サウンドがない場合でもコールバックが全く呼び出されているかどうかをテストしました。答えは、AudioQueuesが再生され、データを必要とする限り、バッファが常に呼び出されることです。
したがって、バッファをキューに入れ続けると、バッファは失われません。それは起こりません。エラーがなければ、もちろんです。
なぜサウンドが再生されないのですか?
「AudioQueueEnqueueBuffer()」がエラーを返したかどうかをテストしました。それはしませんでした。私の遊びのルーチンの中にも他のエラーはありません。ファイルからの読み込みから返されたデータも良好です。
すべて正常です、バッファは良好です、データは再エンキューされていますが、音はありません。
私の最後のテストは、私が何かを聞くことができるまで、ゆっくりバッファサイズを増やすことでした。私はついに、かすかで散発的な歪みを聞いた。
は、それからそれは...私に来た
問題は、システムがあなたがオーディオをエンキューするので、もし時間と同期して流れを維持しようとするものであるようだ、とあなたがしたかったオーディオのための時間演奏が終わったら、バッファのその部分をスキップします。バッファーのサイズが小さくなり過ぎると、オーディオシステムが再び同期するまで、より多くのデータがドロップまたはスキップされます。バッファサイズが小さすぎる場合は決してありません。 (連続再生をサポートできるほどのバッファサイズを選択した場合は歪みとして聞こえます)
これは、オーディオキューが機能する唯一の方法ですが、それは良い方法ですあなたが私のような無知で本当にどのように動作するかを「発見」するときの実現。
なぜ動作しないのかわかりません。しかし、なぜAudioUnitを使用しないのですか? –
@AliaksandrAndrashuk AudioUnitsはエフェクトだけでなく、ファイルからのストリーミングにそれらを使用することは合理的ですか? – Radiodef
はい。 AUFilePlayer - > RemoteIO(AUGraph)を設定して、ファイルを再生することができます。 –