音频文件播放没有音量

Posted

技术标签:

【中文标题】音频文件播放没有音量【英文标题】:No Volume in Audio File playback 【发布时间】:2016-03-11 21:10:43 【问题描述】:

我使用 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,我也听不到扬声器或耳机发出的任何声音

【问题讨论】:

【参考方案1】:

这可能是由于命令行应用程序在完全可以调用音频回调之前退出,并且调用了足够多的时间以达到文件的完整长度。您需要一些代码(运行循环和/或 NSTimer?)来防止您的应用退出。

【讨论】:

【参考方案2】:

您的代码存在几个问题。但是,主要问题是音频队列没有处理旨在读取文件数据的 HandleOutputBuffer 回调......所以您的代码只是在主线程的运行循环中运行,实际上根本没有处理任何音频数据。

似乎发生了以下错误:

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

我建议对音频文件路径进行硬编码,然后通过 Xcode 运行和调试您的代码;这样您就可以单步执行您的主程序并检查每个 API 结果是否有错误。

【讨论】:

以上是关于音频文件播放没有音量的主要内容,如果未能解决你的问题,请参考以下文章

播放音频文件和调整系统音量

HTML5 和 JavaScript 中每个音频播放器的音量滑块

iOS:静音右声道音量

播放结束后将音量控制返回给 iOS 设备铃声

有没有一款播放器可以同时播放两个音频,并且可以单独控制音量?

AVAudioPlayer 不播放音频文件 - swift