IMedia作为强大的brew音频视频播放接口,其功能必然很完善。今天讲一下用IMedia 播放流声音,这个常用于用在网络音频在线播放等等。这次主要针对PCM和wav格式,这类是比较基础的流播放格式。个人理解流播放其实就是一个无头音乐的播放,网络传送来的buffer不会每次都带音频信息,所以我个人叫他“无头播放”。而一个音乐没有头信息怎么会被播放接口失败呢?识别了如何填充buffer持续播放?有几种填充方式呢?下面介绍第一种做法IFIFO实现:#include "AEEFIFO.h" #include "AEEIMedia.h"//首先定义两个结构体变量:AEEMediaDataEx MediaDataEx;//这个是用来填充IMedia 的结构体AEEMediaWaveSpec WaveSpec;//这个就是音频格式信息IFIFO *m_pFIFO;IMedia * pIMedia;ISource *m_pISource =NULL;ISHELL_CreateInstance(pMe->applet.m_pIShell, AEECLSID_FIFO, (void**)&m_pFIFO); ISHELL_CreateInstance(pMe->applet.m_pIShell,AEECLSID_MEDIAPCM,(void**)&pIMedia);IFIFO_OpenEx(GET_IFIFO(),"fifo://shared//test", AEEFIFO_MODE_RW);//fs:/shared/test这个目录IFIFO_QueryInterface(GET_IFIFO(), AEECLSID_SOURCE, (void**)&m_pISource);IFIFO_SetBufSize(GET_IFIFO(), 2048*4);//大小自己决定MEMSET(&WaveSpec, 0x00, sizeof(WaveSpec)); //初始化WaveSpec.wSize = sizeof(WaveSpec);//spec的sizeWaveSpec.clsMedia = AEECLSID_MEDIAPCM;//这里用PCM接口WaveSpec.wChannels = 1;//channel,Number of channels. One for mono, two for stereo. WaveSpec.dwSamplesPerSec = 8000;//Channel sample rate in samples per second(Hertz). 只能取值8000 16000 32000 这样的采样率WaveSpec.wBitsPerSample = 16;// Number of bits per sample 取值8 或者 16WaveSpec.bUnsigned = FALSE; //这个填写falseWaveSpec.dwExtra = 0;//填写0//上面这一堆复制其实就是说明这个音频的格式,比如采样率,channel等等MediaDataEx.clsData = MMD_ISOURCE; // pData is ISourceMediaDataEx.pData = (void *)m_pISource; // ISource objectMediaDataEx.dwSize = 0; MediaDataEx.dwStructSize = sizeof(MediaDataEx); // Size of AEEMediaDataEx structureMediaDataEx.dwCaps = 0; // What capabilities to enable. 0 means all. MediaDataEx.dwBufferSize = 0; // Internal buffer size. 0 means use default.MediaDataEx.bRaw = TRUE; // Is this Raw data? Set it to no (FALSE)MediaDataEx.pSpec = &WaveSpec; // Valid only for raw dataMediaDataEx.dwSpecSize = sizeof(WaveSpec); // Valid only for raw data //上面赋值是用来初始化IMedia接口数组,然后传给 IMediaIMEDIA_SetMediaDataEx(pIMedia,&MediaDataEx, 1);IMEDIA_RegisterNotify(pIMedia,(PFNMEDIANOTIFY)CB_Play,pISource);IMEDIA_Play(pIMedia);//开始播放,但这个时候其实是没声音的!接下来在获得到buffer后只要做一件事:IFIFO_Write(m_pFIFO,(char *)music_buf, music_buf_len);//这样就看到音频播放比较流畅了这是一种做法,另一种做法参考下面的源代码:
这个源码有些地方不是很适合,具体改动在这里:void SMISOURCE_UpdateWriteable(SMISource *pis)//更改 by狮子//里面的判断比较生硬,这样就动态多了{if ( pis->nWritePos < pis->nReadPos ){ if (( pis->nReadPos - pis->nWritePos ) < pis->nWriteSize ) { pis->bWriteable = FALSE; } else { pis->bWriteable = TRUE; }}else if ( pis->nWritePos > pis->nReadPos ){ if (( pis->nWritePos + pis->nWriteSize ) >= pis->nBufSize ) { if (( pis->nWritePos + pis->nWriteSize - pis->nBufSize ) < pis->nReadPos ) { pis->bWriteable = TRUE; } else { pis->bWriteable = FALSE; } } else { pis->bWriteable = TRUE; }}else//更改 by狮子//部分当指针相等时其实是可以写的{ pis->bWriteable = TRUE;}}int SMISOURCE_SourceFromMemory( int nBufLen, SMISource **ppis){SMISource *pis = NULL;int nRet = 0;//sf_dbgprintf("SMISOURCE|SMISOURCE_SourceFromMemory");if (/*( NULL == pBuf ) || */( nBufLen <= 0 )) return 1;pis = (SMISource*)MALLOC(sizeof(SMISource));if ( NULL == pis ){ //sf_dbgprintf("SMISOURCE|"); return ENOMEMORY;}pis->pVtbl = (ISourceVtbl*)MALLOC(sizeof(ISourceVtbl));if ( NULL == pis->pVtbl ){ //sf_dbgprintf("SMISOURCE|"); FREE(pis); return ENOMEMORY;}pis->pVtbl->AddRef = SMISOURCE_AddRef;pis->pVtbl->Release = SMISOURCE_Release;pis->pVtbl->QueryInterface = SMISOURCE_QueryInterface;pis->pVtbl->Read = SMISOURCE_Read;pis->pVtbl->Readable = SMISOURCE_Readable;pis->pDataBuf = MALLOC(nBufLen);//更改 by狮子//使用内部buffer,外部不再关心其存储方式pis->nBufSize = nBufLen;MEMSET(pis->pDataBuf,0x00,nBufLen);pis->nRefCnt = 1;pis->bWriteable = TRUE;pis->nDataSize = 0;pis->nReadPos = 0;pis->nWritePos = 0;pis->pReadableCB = NULL;*ppis = pis;return SUCCESS;}int SMISOURCE_SourceFree(SMISource *pis){//sf_dbgprintf("SMISOURCE|");if ( NULL != pis ){ FREEIF(pis->pVtbl); FREEIF(pis->pDataBuf); FREE(pis);}return 0;}具体的实现可以看源代码,不过源代码是用多线程的,其实每次buffer到了调用SMISource_Write 就OK了