音频文件播放中无音量

时间:2016-03-11 21:10:44

标签: objective-c xcode audio operating-system core-audio

我使用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

,我也无法听到扬声器和耳机的任何声音

2 个答案:

答案 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结果是否有错误。