音频文件播放没有音量
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 中每个音频播放器的音量滑块