我使用Apple音频队列服务指南创建了一个命令行类型应用程序来播放磁盘中的文件
#import <Foundation/Foundation.h>
#import <AudioToolbox/AudioToolbox.h>
#define kNumberBuffers 3 // the number of audio queue buffers to use
//An AudioStreamBasicDescription structure (from CoreAudioTypes.h) representing the audio data format of the file being played. This format gets used by the audio queue specified in the mQueue field.
typedef struct AQPlayerState{
AudioStreamBasicDescription mDataFormat;
AudioQueueRef mQueue; //The playback audio queue created by your application.
AudioQueueBufferRef mBuffers[kNumberBuffers]; //An array holding pointers to the audio queue buffers managed by the audio queue.
AudioFileID mAudioFile; //An audio file object that represents the audio file your program plays.
UInt32 bufferByteSize; //The size, in bytes, for each audio queue buffer.
SInt64 mCurrentPacket;//The packet index for the next packet to play from the audio file.
UInt32 mNumPacketsToRead; //The number of packets to read on each invocation of the audio queue’s playback callback
AudioStreamPacketDescription *mPacketDecs; //For VBR audio data, the array of packet descriptions for the file being played. For CBR data, the value is NULL.
BOOL isRunning;
}AQPlayerState;
static void HandleOutputBuffer(
void *AQData,
AudioQueueRef inAQ,
AudioQueueBufferRef inBuffer
){
OSStatus error;
AQPlayerState *pAQData=(AQPlayerState*)AQData;
if(!pAQData->isRunning)return;
UInt32 numBytesReadFromFile; // A variable to hold the number of bytes of audio data read from the file being played.
UInt32 numPackets=pAQData->mNumPacketsToRead; // Initializes the numPackets variable with the number of packets to read from the file being played.
error=AudioFileReadPacketData(pAQData->mAudioFile,
false,
&numBytesReadFromFile,
pAQData->mPacketDecs,
pAQData->mCurrentPacket,
&numPackets,
inBuffer->mAudioData
);
assert(error==noErr);
// Tests whether some audio data was retrieved from the file. If so, enqueues the newly-filled buffer. If not, stops the audio queue.
if(numPackets > 0){
inBuffer->mAudioDataByteSize=numBytesReadFromFile; //Tells the audio queue buffer structure the number of bytes of data that were read.
error=AudioQueueEnqueueBuffer(pAQData->mQueue,inBuffer,
(pAQData->mPacketDecs ? numPackets : 0),
pAQData->mPacketDecs);
pAQData->mCurrentPacket+=numPackets; //Increments the packet index according to the number of packets that were read.
}else{
AudioQueueStop(pAQData->mQueue,0);
pAQData->isRunning=0;
}
}
void DeriveBufferSize(
AudioStreamBasicDescription *ASBDesc,
UInt32 maxPacketSize,
Float64 seconds,
UInt32 *outBufSize,
UInt32 *outNumPacketsToRead
){
static const int maxBufSize=0x50000;
static const int minBufSize=0x4000;
if(ASBDesc->mFramesPerPacket!=0){
Float64 numPacketsForTime=
ASBDesc->mSampleRate/ASBDesc->mFramesPerPacket * seconds;
*outBufSize=numPacketsForTime *maxPacketSize;
}else{
*outBufSize=maxBufSize > maxPacketSize ? maxBufSize : maxPacketSize;
}
if ( // 10
*outBufSize > maxBufSize &&
*outBufSize > maxPacketSize
)
*outBufSize = maxBufSize;
else { // 11
if (*outBufSize < minBufSize)
*outBufSize = minBufSize;
}
*outNumPacketsToRead = *outBufSize / maxPacketSize; // 12
}
int main(int argc, const char * argv[]) {
AQPlayerState AQPlayer;
CFURLRef audioFileURL=CFURLCreateFromFileSystemRepresentation(NULL,
(const UInt8*)argv[1], strlen(argv[1]),0);
OSStatus result;
result=AudioFileOpenURL(audioFileURL,fsRdPerm, 0,&AQPlayer.mAudioFile);
UInt32 dataFormatSize=sizeof(AQPlayer.mDataFormat);
AudioFileGetProperty(AQPlayer.mAudioFile,kAudioFilePropertyDataFormat,&dataFormatSize,&AQPlayer.mDataFormat);
// Create playback queue
AudioQueueNewOutput(&AQPlayer.mDataFormat,
HandleOutputBuffer,
&AQPlayer,
CFRunLoopGetCurrent(),
kCFRunLoopCommonModes,
0,
&AQPlayer.mQueue);
// Setting Buffer Size and Number of Packets to Read
UInt32 maxPacketSize;
UInt32 propertySize=sizeof(maxPacketSize);
// Getting audio File maximum packet size
AudioFileGetProperty(AQPlayer.mAudioFile,kAudioFilePropertyPacketSizeUpperBound,&propertySize,&maxPacketSize);
DeriveBufferSize(&AQPlayer.mDataFormat,maxPacketSize,0.5,&AQPlayer.bufferByteSize,&AQPlayer.mNumPacketsToRead);
// Allocating memory for a packet descriptions array
bool isFormatVBR=(AQPlayer.mDataFormat.mBytesPerPacket == 0 ||
AQPlayer.mDataFormat.mFramesPerPacket == 0);
if(isFormatVBR){
AQPlayer.mPacketDecs=(AudioStreamPacketDescription*)malloc(AQPlayer.mNumPacketsToRead*sizeof(AudioStreamPacketDescription));
}
else{
AQPlayer.mPacketDecs=NULL;
}
// Setting a magic cookie for a playback audio queue
UInt32 cookieSize=sizeof(UInt32);
// Captures the result of the AudioFileGetPropertyInfo function. If successful, this function returns a value of NoErr, equivalent to Boolean false.
bool couldNotGetProperty=AudioFileGetProperty(AQPlayer.mAudioFile,kAudioFilePropertyMagicCookieData,&cookieSize,NULL);
if(!couldNotGetProperty && cookieSize){
char* magicCookie=malloc(cookieSize);
AudioFileGetProperty(AQPlayer.mAudioFile,kAudioFilePropertyMagicCookieData,&cookieSize,magicCookie);
AudioQueueSetProperty(AQPlayer.mQueue,kAudioQueueProperty_MagicCookie,magicCookie,cookieSize);
free(magicCookie);
}
AQPlayer.mCurrentPacket=0;
for(int i =0;i<kNumberBuffers;++i){
AudioQueueAllocateBuffer(AQPlayer.mQueue,AQPlayer.bufferByteSize,&AQPlayer.mBuffers[i]);
HandleOutputBuffer(&AQPlayer,AQPlayer.mQueue,AQPlayer.mBuffers[i]);
}
Float32 gain=1.0; // Set Full Volume for playback
AudioQueueSetParameter(AQPlayer.mQueue,kAudioQueueParam_Volume,gain);
// start and play
AQPlayer.isRunning=true;
AudioQueueStart(AQPlayer.mQueue,NULL);
do{
CFRunLoopRunInMode(kCFRunLoopDefaultMode,0.25,false);
}while(AQPlayer.isRunning);
CFRunLoopRunInMode(kCFRunLoopDefaultMode,1,false);
// Cleaning up after playing an audio file
AudioQueueDispose(AQPlayer.mQueue,true);
AudioFileClose(AQPlayer.mAudioFile);
free(AQPlayer.mPacketDecs);
return 0;
}
所有内容构建和编译都没有错误但是当应用程序运行时,即使我将kAudioQueueParam_Volume
设置为1.0
答案 0 :(得分:0)
这可能是由于在完全调用音频回调之前退出的命令行应用程序引起的,并且在文件的整个长度上调用了足够的时间。您需要一些代码(运行循环和/或NSTimer?)来防止您的应用退出。
答案 1 :(得分:0)
您的代码存在一些问题。但是,主要问题是音频队列没有处理用于读取文件数据的HandleOutputBuffer回调...因此您的代码只是在主线程的运行循环中运行而根本不处理任何音频数据。 / p>
看起来好像发生了以下错误:
ERROR: >aq> 327: AudioConverterNew from AudioQueueNew returned -50
io: 32767 ch, 0 Hz, Float32, non-inter
我建议硬编码音频文件路径,然后通过Xcode运行和调试代码;这样您就可以单步执行主例程并检查每个API结果是否有错误。