ios audioqueue 流播放接口
AudioMedia_ios.h
// // AudioMedia_ios.h // mmsplayer // // Created by Weiny on 12-4-4. // Copyright (c) 2012年 Weiny Zhou. All rights reserved. // #ifndef mmsplayer_AudioMedia_ios_h #define mmsplayer_AudioMedia_ios_h #include "wdef.h" typedef void* wAudio; #ifdef __cplusplus extern "C" { #endif wAudio audio_open(int sample,int nchannles,int bits,int nFrameSize);//初始化声音接口 int audio_play(wAudio audio);//播放 int audio_pause(wAudio audio); int audio_wirte(wAudio audio,unsigned char* pcm,size_t count,int64_t dts);//写入音频数据 int audio_stop(wAudio audio);//停止 int audio_close(wAudio audio);//关闭 #ifdef __cplusplus }; #endif #endif
AudioMedia_ios.c
// // AudioMedia_ios.cpp // mmsplayer // // Created by Weiny on 12-4-4. // Copyright (c) 2012年 Weiny Zhou. All rights reserved. // #include "AudioMedia_ios.h" #include <AudioToolbox/AudioQueue.h> #include "system/thread.h" #include "base/wlist.h" #include "system/lx_lock.h" #define AUDIO_LIST_COUNT 3 #define AUDIO_BUFFER_SECONDS 1 typedef struct WAudio_Ios { int playRequested; int framesize; Wlock mlock,mdecdonelock,mqueuelock; wlist_t mAudiolist;//声音队列 wlist_func mlistfunc; AudioQueueRef queue;//player list AudioQueueBufferRef mBuffers[AUDIO_LIST_COUNT]; AudioStreamBasicDescription mDataFormat; AudioQueueBufferRef emptyAudioBuffer;//空音频队列 }WAudio_Ios; typedef struct { void* data; size_t size; int64_t dst; }WAudio_item; void wAudio_CallBack(void * in,AudioQueueRef intq,AudioQueueBufferRef outQB); void wAudtio_fillAudioBuffer(WAudio_Ios* audio,AudioQueueBufferRef buffer); static inline void waudio_free_back(void* lpvoid,wlist_item_ptr data) { WAudio_item* item; INTOFUNC(); if(!data){PRINTF_ERROR_VALUE(ERROR_INITPARAM);goto error_lab;} item=(WAudio_item*)data; SAFE_FREE(item->data); SAFE_FREE(item); error_lab: EXITFUNC(); } wAudio audio_open(int sample,int nchannles,int bits,int nFrameSize) { WAudio_Ios* ptr=NULL; uint32_t err=0; int i=0; INTOFUNC(); ptr=WOS_MALLOC_(WAudio_Ios, 1); if(!ptr){ PRINTF_ERROR_VALUE(ERROR_NEWMEM); goto error_lab; } memset(ptr,0,sizeof(WAudio_Ios)); ptr->mDataFormat.mSampleRate=sample;//设置采样率 ptr->mDataFormat.mChannelsPerFrame=nchannles; ptr->mDataFormat.mBitsPerChannel=bits; ptr->mDataFormat.mFormatID=kAudioFormatLinearPCM;//设置数据格式 ptr->mDataFormat.mFormatFlags=kLinearPCMFormatFlagIsSignedInteger|kAudioFormatFlagIsPacked; ptr->mDataFormat.mFramesPerPacket=1; ptr->mDataFormat.mBytesPerFrame= ptr->mDataFormat.mBitsPerChannel/ ptr->mDataFormat.mChannelsPerFrame; ptr->mDataFormat.mBytesPerPacket= ptr->mDataFormat.mBytesPerFrame*ptr->mDataFormat. mFramesPerPacket; err=AudioQueueNewOutput(&ptr->mDataFormat,wAudio_CallBack, ptr, NULL, NULL/*kCFRunLoopCommonModes*/, 0 , &ptr->queue); if(err){ WERROR_A("init audio output error,sample=%d,channles=%d,bits=%d.\n",sample,nchannles,bits); goto error_lab; } for (i=0;i<AUDIO_LIST_COUNT;++i) { err=AudioQueueAllocateBufferWithPacketDescriptions(ptr->queue, bits*AUDIO_BUFFER_SECONDS/8, sample*AUDIO_BUFFER_SECONDS/nFrameSize+1,ptr->mBuffers+i); if(err){ WERROR_A("can't allocate audio queue buffer: %d",err); goto error_lab; } } ptr->mlock=lx_lock_init(); ptr->mdecdonelock=lx_lock_init(); ptr->mqueuelock=lx_lock_init(); ptr->mlistfunc=wlist_getfunc(); ptr->mAudiolist.free=waudio_free_back; ptr->framesize=nFrameSize; #if 1 err=AudioQueueStart(ptr->queue,NULL); if(err){ WERROR_A("Error: Audio queue failed to start: %d", err); goto error_lab; } ptr->playRequested=1; WDEBUG_OUT("Started Audio queue.",NULL); #endif #if 0 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); } #endif error_lab: if(err){ audio_close(ptr); SAFE_FREE(ptr); } EXITFUNC(); return (wAudio)ptr; } int audio_play(wAudio audio) { int nResult=0; WAudio_Ios* ptr=NULL; INTOFUNC(); if(!audio){ WERROR_A("input audio is null",NULL); nResult=ERROR_INITPARAM; goto error_lab; } ptr=(WAudio_Ios*)audio; if(ptr->playRequested==0||ptr->playRequested==2) {WERROR_A("state is %d",ptr->playRequested);goto error_lab;} ptr->playRequested=1; AudioQueueStart(ptr->queue,NULL); error_lab: EXITFUNC(); return nResult; } int audio_pause(wAudio audio) { int nResult=0; WAudio_Ios* ptr=NULL; INTOFUNC(); if(!audio){ WERROR_A("input audio is null",NULL); nResult=ERROR_INITPARAM; goto error_lab; } ptr=(WAudio_Ios*)audio; if(1!=ptr->playRequested) {WERROR_A("state is %d",ptr->playRequested);goto error_lab;} ptr->playRequested=2; AudioQueuePause(ptr->queue); error_lab: EXITFUNC(); return nResult; } int audio_wirte(wAudio audio,unsigned char* pcm,size_t count,int64_t dst) { int nResult=0; WAudio_Ios* ptr=NULL; WAudio_item* item=NULL; INTOFUNC(); if(!audio){ WERROR_A("input audio is null",NULL); nResult=ERROR_INITPARAM; goto error_lab; } ptr=(WAudio_Ios*)audio; item=WOS_MALLOC_(WAudio_item,1); if(!item){ nResult=ERROR_NEWMEM;PRINTF_ERROR_VALUE(nResult);goto error_lab; } item->data=pcm; item->size=count; item->dst=dst; lx_lock(ptr->mqueuelock); //先加入队列 ptr->mlistfunc.push_back(&ptr->mAudiolist,item); // if(ptr->emptyAudioBuffer) wAudtio_fillAudioBuffer(ptr,ptr->emptyAudioBuffer);//填充空buffer lx_unlock(ptr->mqueuelock); error_lab: EXITFUNC(); return nResult; } int audio_stop(wAudio audio) { int nResult=0; WAudio_Ios* ptr=NULL; INTOFUNC(); if(!audio){ WERROR_A("input audio is null",NULL); nResult=ERROR_INITPARAM; goto error_lab; } ptr=(WAudio_Ios*)audio; AudioQueueStop(ptr->queue,false); ptr->playRequested=0; error_lab: EXITFUNC(); return nResult; } int audio_close(wAudio audio) { int nResult=0; WAudio_Ios* ptr=NULL; INTOFUNC(); if(!audio){ WERROR_A("input audio is null.",NULL); nResult=ERROR_INITPARAM; goto error_lab; } ptr=(WAudio_Ios*)audio; ptr->mlistfunc.clear(&ptr->mAudiolist);//清空播放队列 lx_lock_free(ptr->mqueuelock); lx_lock_free(ptr->mdecdonelock); lx_lock_free(ptr->mlock); AudioQueueDispose(ptr->queue,false); SAFE_FREE(ptr); error_lab: EXITFUNC(); return nResult; } #if 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); } } #endif void wAudtio_fillAudioBuffer(WAudio_Ios* audio,AudioQueueBufferRef buffer) { AudioTimeStamp bufferStartTime; uint32_t err; INTOFUNC(); buffer->mAudioDataByteSize=0; buffer->mPacketDescriptionCount=0; if(audio->mAudiolist.size<=0){ WERROR_A("Warning: No audio packets in queue.",NULL); audio->emptyAudioBuffer=buffer; goto error_lab; } audio->emptyAudioBuffer=NULL; while(audio->mAudiolist.size&&buffer->mPacketDescriptionCount < buffer->mPacketDescriptionCapacity) { wlist_item* item=audio->mlistfunc.pop_front(&audio->mAudiolist); WAudio_item* data=(WAudio_item*)item->data; if(buffer->mAudioDataBytesCapacity - buffer->mAudioDataByteSize >=data->size) { if(buffer->mAudioDataBytesCapacity==0) { bufferStartTime.mSampleTime=data->dst*audio->framesize; bufferStartTime.mFlags=kAudioTimeStampSampleTimeValid; } memcpy((uint8_t *)buffer->mAudioData + buffer->mAudioDataByteSize, data->data, data->size); buffer->mPacketDescriptions[buffer->mPacketDescriptionCount].mStartOffset = buffer->mAudioDataByteSize; buffer->mPacketDescriptions[buffer->mPacketDescriptionCount].mDataByteSize = data->size; buffer->mPacketDescriptions[buffer->mPacketDescriptionCount].mVariableFramesInPacket = audio->framesize; buffer->mAudioDataByteSize += data->size; ++buffer->mPacketDescriptionCount; lx_lock(audio->mqueuelock); audio->mlistfunc.remove(&audio->mAudiolist,0); lx_unlock(audio->mqueuelock); } else break; } if(buffer->mPacketDescriptionCount>0) { if(err=AudioQueueEnqueueBufferWithParameters(audio->queue, buffer,0,NULL,0,0,0,NULL,&bufferStartTime,NULL)) WERROR_A("Error enqueuing audio buffer: %d", err); //decodelock lx_lock(audio->mdecdonelock); if(!audio->playRequested&&audio->mAudiolist.size==0){ if(err=AudioQueueStop(audio->queue,false)) WERROR_A("Error: Failed to stop audio queue: %d", err); else WERROR_A("Stopped audio queue",NULL); } lx_unlock(audio->mdecdonelock); //decodeunlock } error_lab: EXITFUNC(); } void wAudio_CallBack(void * in,AudioQueueRef intq,AudioQueueBufferRef buffer) { wAudtio_fillAudioBuffer((WAudio_Ios*)in,buffer); }