iPhone应用开发中关于PCM播放器源码学习是本文要介绍的内容,由于原始PCM文件不能容纳任何关于其自身频率或者帧大小之类的信息,本例将不得不对此自行设置。
我们会使用一种为经过压缩的PCM数据格式,具体参数喂16位、44KHz、单声道。这些信息通过程序顶部的三个预定义值指定:
- #define BYTES_PER_SAMPLE 2
16位等于两个字节
- #define SAMPLE_PATE 44100
每秒采样率44100次等于44KHz
- typedef unsigned short sampleFrame;
- 一个unsigned short 等于两个字节(每个采样)
- #include <stdio.h>
- #include <errno.h>
- #include <sys/stat.h>
- #include <AudioToolbox/AudioQueue.h>
- #define BYTES_PER_SAMPLE 2
- #define SAMPLE_PATE 44100
- typedef unsigned short sampleFrame;
- #define FRAME_COUNT 735
- #define AUDIO_BUFFERS 3
- typedef struct AQCallbackStruct{
- AudioQueueRef queue;//播放队列
- UInt32 FrameCount;
- AudioQueueBufferRef mBuffers[AUDIO_BUFFERS];
- AudioStreamBasicDescription mDataFormat;
- UInt32 sampleLen;
- UInt32 playPtr;
- sampleFrame *pcmBuffer;
- }AQCallbackStruct;
- void *loadpacm(const char *filename,unsigned long *len);
- int playbuffer(void *pcm,unsigned long len);
- void AQBufferCallback(void *in,AudioQueueRef inQ,AudioQueueBufferRef outQB);
- int main(int argc,char *argv[])
- {
- char *filename;
- unsigned long len;
- void *pcmBuffer;
- int ret;
- if (argc<2)
- {
- fprintf(stderr, "Syntax: %s [filename]\n", argv[0]);
- exit(EXIT_FAILURE);
- }
- filename = argv[1];
- pcmBuffer = loadpacm(filename, &len);
- if (!pcmBuffer)
- {
- fprintf(stderr, "%s: %s\n", filename, strerror(errno));
- exit(EXIT_FAILURE);
- }
- ret = playbuffer(pcmBuffer,len);
- free(pcmBuffer);
- return ret;
- }
- void *loadpcm(const char *filename,unsigned long *len)
- {
- FILE *file;
- struct stat s;
- void *pcm;
- if (stat(filename,&s)) {
- return NULL;
- *len = s.st_size;
- }
- pcm = (void *) malloc(s.st_size);
- if (!pcm) {
- return NULL;
- file = fopen(filename,"sb");
- }
- if(!file)
- {
- free(pcm);
- return NULL;
- }
- fread(pcm,s.st_size,1,file);
- fclose(file);
- return pcm;
- }
- int playbuffer(void *pcmBuffer,unsigned long len)
- {
- AQCallbackStruct agc;
- UInt32 err,bufferSize;
- int i;
- agc.mDataFormat.mSampleRate = SAMPLE_PATE;
- agc.mDataFormat.mFormatID = kAudioFormatLinearPCM;
- agc.mDataFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
- agc.mDataFormat.mBytesPerPacket = 4;
- agc.mDataFormat.mFramesPerPacket = 1;
- agc.mDataFormat.mBytesPerFrame = 4;
- agc.mDataFormat.mChannelsPerFrame = 2;
- agc.mDataFormat.mBitsPerChannel = 16;
- agc.FrameCount = FRAME_COUNT;
- agc.sampleLen = len/BYTES_PER_SAMPLE;
- agc.playPtr = 0;
- agc.pcmBuffer = pcmBuffer;
- err = AudioQueueNewOutput(&agc.mDataFormat,AQBufferCallback,&agc,NULL,
- kCFRunLoopCommonModes,0,&agc.queue);
- if(err) return err;
- agc.FrameCount = FRAME_COUNT;
- bufferSize = agc.FrameCount * agc.mDataFormat.mBytesPerFrame;
- for (i=0; i<AUDIO_BUFFERS; i++)
- {
- err = AudioQueueAllocateBuffer(agc.queue,bufferSize,&agc.mBuffers[i]);
- if(err) return err;
- AQBufferCallback(&agc,agc.queue,agc.mBuffers[i]);
- }
- err = AudioQueueStart(agc.queue,NULL);
- if(err) return err;
- while (agc.playPtr<agc.sampleLen)
- {
- select(NULL,NULL,NULL,NULL,1.0);
- }
- sleep(1);
- return 0;
- }
- void AQBufferCallback( void *in, AudioQueueRef inQ, AudioQueueBufferRef outQB)
- {
- AQCallbackStruct *agc;
- short *coreAudiobuffer;
- short sample;
- int i;
- agc=(AQCallbackStruct *) in;
- coreAudiobuffer =(short*) outQB->mAudioData;
- printf("Sync:%i / %i \n",agc->playPtr,agc->sampleLen);
- if (agc->FrameCount >0)
- {
- outQB->mAudioDataByteSize = 4*agc->FrameCount;
- for (i=0; i<agc->FrameCount*2; i++)
- {
- if(agc->playPtr > agc->sampleLen || agc->playPtr<0)
- {
- sample =0;
- }
- else
- {
- sample = (agc->pcmBuffer[agc->playPtr]);
- }
- coreAudiobuffer[i] = sample;
- coreAudiobuffer[i+1] = sample;
- agc->playPtr++;
- }
- AudioQueueEnqueueBuffer(inQ,outQB,0,NULL);
- }
}如果你无法找到一个原始的PCM元数据,你可以用.wav格式文件代替,制药以16位44KHz原始PCM编码的就行。
编译命令:
- $ gcc -o playpcm playpcm.c \
- -framework AudioToolbox -framework CoreAudio -framework CoreFoundation
小结:iPhone应用开发中关于PCM播放器源码学习的内容介绍完了,希望通过本文的学习能对你有所帮助!