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);
}