当前位置: 动力学知识库 > 问答 > 编程问答 >

objective c - No Volume in Audio File playback

问题描述:

I made a command-line type app using the Apple Audio Queue Services guide to playback a file from a disk

#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;

}

Everything builds and compiles without errors but when the app is running I cant hear anything from the speakers nor the headphones even though I set up the kAudioQueueParam_Volume to 1.0

网友答案:

This can be caused by a command-line app exiting before the audio callback can be called at all, and called enough times for the full length of the file. You need some code (run loop and/or NSTimer?) to keep your app from exiting.

网友答案:

There are several problems with your code. However, the main issue is that the audio queue is not processing the HandleOutputBuffer callback which is intended to read the file data... so your code is simply running in your main thread's run loop and not actually processing any audio data at all.

It looks like the below error is occurring:

ERROR:    >aq> 327: AudioConverterNew from AudioQueueNew returned -50
io:    32767 ch,      0 Hz, Float32, non-inter

I would recommend to hardcode an audio file path, and then run and debug your code via Xcode; so that you can single step through your main routine and check each API result for errors.

分享给朋友:
您可能感兴趣的文章:
随机阅读: