#define QUEUE_BUFFER_SIZE 4 //隊列緩沖個數(shù)
#define EVERY_READ_LENGTH 1000 //每次從文件讀取的長度
#define MIN_SIZE_PER_FRAME 2000 //每偵最小數(shù)據(jù)長度
@interface OLMyTapesCell ()
{
AudioStreamBasicDescription audioDescription; //音頻參數(shù)
AudioQueueRef audioQueue; //音頻播放隊列
AudioQueueBufferRef audioQueueBuffers[QUEUE_BUFFER_SIZE]; //音頻緩存
NSLock *synlock ; //同步控制
Byte *pcmDataBuffer; //pcm的讀文件數(shù)據(jù)區(qū)
FILE *file; //pcm源文件
BOOL isStaring;
}
// 初始化播放器
- (void)player{
NSFileManager *fileManger = [NSFileManager defaultManager];
NSString *filePath = @“文件路徑”;
[[fileManger attributesOfItemAtPath:filePath error:nil] fileSize];
file = fopen([filePath UTF8String],"r");
if (file) {
fseek(file, 0, SEEK_SET);
pcmDataBuffer = malloc(EVERY_READ_LENGTH);
}else{
NSLog(@"!!!!!!!!!!!!!!!!");
}
synlock = [[NSLock alloc] init];
[self initAudio];
AudioQueueStart(audioQueue, NULL);
for(int i=0;i<QUEUE_BUFFER_SIZE;i++)
{
[self readPCMAndPlay:audioQueue buffer:audioQueueBuffers[i]];
}
/*
audioQueue使用的是驅(qū)動回調(diào)方式,即通過AudioQueueEnqueueBuffer(outQ, outQB, 0, NULL);傳入一個buff去播放,播放完buffer區(qū)后通過回調(diào)通知用戶,
用戶得到通知后再重新初始化buff去播放,周而復始,當然,可以使用多個buff提高效率(測試發(fā)現(xiàn)使用單個buff會小卡)
*/
}
// 開始
-(void)AudioQueueStart
{
AudioQueueStart(audioQueue, NULL);
NSLog(@"onbutton2clicked");
}
// 結(jié)束
-(void)AudioQueueStop{
AudioQueueStop(audioQueue, YES);
}
// 暫停
-(void)AudioQueuePause
{
AudioQueuePause(audioQueue);
NSLog(@"onbutton2clicked");
}
#pragma mark player call back
/*
試了下其實可以不用靜態(tài)函數(shù),但是c寫法的函數(shù)內(nèi)是無法調(diào)用[self ***]這種格式的寫法,所以還是用靜態(tài)函數(shù)通過void *input來獲取原類指針
這個回調(diào)存在的意義是為了重用緩沖buffer區(qū),當通過AudioQueueEnqueueBuffer(outQ, outQB, 0, NULL);函數(shù)放入queue里面的音頻文件播放完以后,通過這個函數(shù)通知
調(diào)用者,這樣可以重新再使用回調(diào)傳回的AudioQueueBufferRef
*/
static void AudioPlayerAQInputCallback(void *input, AudioQueueRef outQ, AudioQueueBufferRef outQB)
{
NSLog(@"AudioPlayerAQInputCallback");
OLMyTapesCell *mainviewcontroller = (__bridge OLMyTapesCell *)input;
[mainviewcontroller checkUsedQueueBuffer:outQB];
[mainviewcontroller readPCMAndPlay:outQ buffer:outQB];
}
#pragma mark - 錄音播放
-(void)initAudio
{
///設置音頻參數(shù)
audioDescription.mSampleRate = 16000;//采樣率(每秒鐘采集多少個信號樣本)
audioDescription.mFormatID = kAudioFormatLinearPCM;
audioDescription.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
audioDescription.mChannelsPerFrame = 1;///單聲道
audioDescription.mFramesPerPacket = 1;//每一個packet一偵數(shù)據(jù)
audioDescription.mBitsPerChannel = 16;//每個采樣點16bit量化
audioDescription.mBytesPerFrame = (audioDescription.mBitsPerChannel/8) * audioDescription.mChannelsPerFrame;
audioDescription.mBytesPerPacket = audioDescription.mBytesPerFrame ;
///創(chuàng)建一個新的從audioqueue到硬件層的通道
// AudioQueueNewOutput(&audioDescription, AudioPlayerAQInputCallback, self, CFRunLoopGetCurrent(), kCFRunLoopCommonModes, 0, &audioQueue);///使用當前線程播
AudioQueueNewOutput(&audioDescription, AudioPlayerAQInputCallback, (__bridge void * _Nullable)(self), nil, nil, 0, &audioQueue);//使用player的內(nèi)部線程播
////添加buffer區(qū)
for(int i=0;i<QUEUE_BUFFER_SIZE;i++)
{
int result = AudioQueueAllocateBuffer(audioQueue, MIN_SIZE_PER_FRAME, &audioQueueBuffers[i]);///創(chuàng)建buffer區(qū),MIN_SIZE_PER_FRAME為每一偵所需要的最小的大小,該大小應該比每次往buffer里寫的最大的一次還大
NSLog(@"AudioQueueAllocateBuffer i = %d,result = %d",i,result);
}
}
-(void)readPCMAndPlay:(AudioQueueRef)outQ buffer:(AudioQueueBufferRef)outQB
{
[synlock lock];
int readLength = fread(pcmDataBuffer, 1, EVERY_READ_LENGTH, file);//讀取文件
if (readLength == 0) {
dispatch_async(dispatch_get_main_queue(), ^{
// 這里可以進行一些UI控件的刷新操作
});
}
NSLog(@"read raw data size = %d",readLength);
outQB->mAudioDataByteSize = readLength;
Byte *audiodata = (Byte *)outQB->mAudioData;
for(int i=0;i<readLength;i++)
{
audiodata[i] = pcmDataBuffer[i];
}
/*
將創(chuàng)建的buffer區(qū)添加到audioqueue里播放
AudioQueueBufferRef用來緩存待播放的數(shù)據(jù)區(qū),AudioQueueBufferRef有兩個比較重要的參數(shù),AudioQueueBufferRef->mAudioDataByteSize用來指示數(shù)據(jù)區(qū)大小,AudioQueueBufferRef->mAudioData用來保存數(shù)據(jù)區(qū)
*/
AudioQueueEnqueueBuffer(outQ, outQB, 0, NULL);
[synlock unlock];
}
-(void)checkUsedQueueBuffer:(AudioQueueBufferRef) qbuf
{
if(qbuf == audioQueueBuffers[0])
{
NSLog(@"AudioPlayerAQInputCallback,bufferindex = 0");
}
if(qbuf == audioQueueBuffers[1])
{
NSLog(@"AudioPlayerAQInputCallback,bufferindex = 1");
}
if(qbuf == audioQueueBuffers[2])
{
NSLog(@"AudioPlayerAQInputCallback,bufferindex = 2");
}
if(qbuf == audioQueueBuffers[3])
{
NSLog(@"AudioPlayerAQInputCallback,bufferindex = 3");
}
}
播放本地pcm數(shù)據(jù)音頻
最后編輯于 :
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。
相關閱讀更多精彩內(nèi)容
- 上一期剛剛掀完桌子沒多久<a href="http://www.itdecent.cn/p/2448e2903b0...
- 現(xiàn)在直播越來越火,儼然已經(jīng)成為了下一個紅海。作為一個資深碼農(nóng)(我只喜歡這樣稱呼自己,不喜歡別人這樣稱呼我),我必須...
- AVPlayer屬于AVFoundation框架,不僅能夠播放音頻,還可以播放視頻,支持本地和網(wǎng)鏈,更加接近底層,...