通过DirectSound实时播放PCM+混音
2016-09-22 11:01
267 查看
#include "StdAfx.h" #include "AudioPlayer.h" #define AUDIO_SECOND_COUNT 1 //10秒缓冲区 CAudioPlayer::CAudioPlayer(void) { for (int i = 0; i < AUDIO_MIX_COUNT; ++i) { m_pDS[i] = NULL; m_pDsb[i] = NULL; m_pDsb8[i] = NULL; m_dwCurPos[i] = 0; m_bStop[i] = TRUE; } } CAudioPlayer::~CAudioPlayer(void) { Uninit(); } BOOL CAudioPlayer::PlayerInit(DWORD dwChannel, DWORD dwSamplesPerSec, DWORD dwBitsPerSample,HWND wnd, int deviceindex) { /*缓存数据块格式*/ m_wfe.wFormatTag = WAVE_FORMAT_PCM; m_wfe.nChannels = dwChannel; m_wfe.nSamplesPerSec = dwSamplesPerSec; m_wfe.wBitsPerSample = dwBitsPerSample; m_wfe.nBlockAlign = (dwBitsPerSample/8)*dwChannel; m_wfe.nAvgBytesPerSec = dwSamplesPerSec*(dwBitsPerSample/8)*dwChannel; m_wfe.cbSize = 0; /*第一个参数代表应用程序的主窗口,而第二个参数则设定使用资源的优*/ // // Create Sound Buffer // DSBUFFERDESC dsbd; memset(&dsbd, 0, sizeof(DSBUFFERDESC)); dsbd.dwSize = sizeof(DSBUFFERDESC); //dsbd.dwBufferBytes = AUDIO_PLAYBUF_LEN; //40960 dsbd.dwBufferBytes = m_wfe.nBlockAlign*m_wfe.nAvgBytesPerSec; dsbd.lpwfxFormat = (LPWAVEFORMATEX) (&m_wfe); //其中GLOBALFOCUS标志位保证当程序窗口不在前面时仍能够播放 /*Pan(左右正道的差值)*/ // DSBCAPS_CTRL3D //缓冲区具有的3D音效控制能力,不能与DSBCAPS_CTRLPAN一起使用 // DSBCAPS_CTRLFREQUENCY //可设置采样频率 // DSBCAPS_CTRLFX //缓冲区支持特效处理,但缓冲区必须够大,可容纳更多的数据 // DSBCAPS_CTRLPAN //缓冲区可以控制声道 // DSBCAPS_CTRLPOSITIONNOTIFY //缓冲区具有播放位置通知能力 // DSBCAPS_CTRLVOLUME //缓冲区可设置音量大小 // DSBCAPS_GLOBALFOCUS //缓冲是一个全局声音资源,当前程序切换到其他程序依然可以继续播放. // DSBCAPS_LOCDEFER //缓冲区可绑定硬件内存或者软件内存来播放声音 // DSBCAPS_LOCHARDWARE //缓冲区必须使用硬件的混声器,如果不支持硬件内存或者混声器,都会导致创建缓冲区失败. // DSBCAPS_LOCSOFTWARE //缓冲区使用软件内存或者使用软件混音 // DSBCAPS_MUTE3DATMAXDISTANCE //超过声音可听的最大距离,将停止播放声音 // DSBCAPS_PRIMARYBUFFER //说明缓冲区的为主缓冲区(如果没说明,则用作次缓冲区) // DSBCAPS_STATIC //自动使用硬件内存做缓冲区 // DSBCAPS_STICKYFOCUS //当程序切换到其他不使用DIRECTSOUND 的程序时,缓冲区继续播放声音,但无法如常进行其他处理 //dsbd.dwFlags = DSBCAPS_CTRLPAN | DSBCAPS_CTRLVOLUME | DSBCAPS_STATIC | DSBCAPS_GLOBALFOCUS | DSBCAPS_GETCURRENTPOSITION2; dsbd.dwFlags = DSBCAPS_LOCSOFTWARE | DSBCAPS_GLOBALFOCUS | DSBCAPS_CTRLPAN | DSBCAPS_CTRLVOLUME; /*在设置协调层级时,标志位必须设定为DSSCL_PRIORITY. 次缓冲区则存储播放声音的文件。在加载声音文件后, 只要调用Play()方法,声音就会自动的送入主缓冲区中并进行播放*/ HRESULT result = 0; AdoAudioDevices adoad; int ncount = adoad.getDevCount(AdoAudioDevices::audio_render); for (int i = 0; i < AUDIO_MIX_COUNT; ++i) { result = DirectSoundCreate(&adoad.sysAudioDevIndex2DevGuid(deviceindex,AdoAudioDevices::audio_render), &m_pDS[i], NULL); if(result != DS_OK) { return FALSE; } result = m_pDS[i]->SetCooperativeLevel(wnd, DSSCL_PRIORITY); if(result != DS_OK) { return FALSE; } /*建立次缓冲区*/ /*每一个声音对应一个辅助缓冲区,可以有多个辅助缓冲区*/ if( FAILED(m_pDS[i]->CreateSoundBuffer(&dsbd,&m_pDsb[i],NULL))){ return FALSE; } } return TRUE; } BOOL CAudioPlayer::Start(int nCase) { /* 播放声音要通过以下步骤: 1、锁定辅助缓冲的一部分以获得你所需要的那部分缓冲的基址。 2、向缓冲写数据。 3、解锁。 4、使用IDirectSoundBuffer::Play方法来播放声音。 如果是使用的流缓冲,还需要反复的执行1-3步骤。*/ LPDIRECTSOUNDBUFFER pDsb; if ( ( nCase>=0 ) && ( nCaseGetStatus(&dwStatus)) { return FALSE; } if((dwStatus & DSBSTATUS_PLAYING) != DSBSTATUS_PLAYING) { /**/ pDsb->SetCurrentPosition(0); hr = pDsb->Play(0, 0,0);//DSBPLAY_LOOPING); //hr = pDsb->Play(0, 0, 0); if (DS_OK != hr) { m_bStop[nCase] = TRUE; return FALSE; } m_bStop[nCase] = FALSE; } return TRUE; } BOOL CAudioPlayer::Pause(int nCase) { LPDIRECTSOUNDBUFFER pDsb; if (m_bStop[nCase]) { return FALSE; } if ( ( nCase>=0 ) && ( nCaseStop(); if (rs != DS_OK) { Sleep(1); pDsb->Stop(); } FillBlankToBuf(0, nCase); m_bStop[nCase] = TRUE; return TRUE; } BOOL CAudioPlayer::Stop(int nCase) { if (m_bStop[nCase]) { return FALSE; } LPDIRECTSOUNDBUFFER pDsb; if( (nCase>=0) && (nCaseGetStatus(&dwStatus)) { return FALSE; } if ((dwStatus & DSBSTATUS_PLAYING) == DSBSTATUS_PLAYING) { MMRESULT rs; rs = pDsb->Stop(); if(rs != DS_OK) { Sleep(1); pDsb->Stop(); } FillBlankToBuf(0, nCase); m_bStop[nCase] = TRUE; } return TRUE; } BOOL CAudioPlayer::Uninit(void) { for( int i = 0 ; i < AUDIO_MIX_COUNT ; i++ ) { Stop(i); } return TRUE; } void CAudioPlayer::SetVolume(long nNewValue) { nNewValue *= -1; if ( nNewValue < DSBVOLUME_MIN ) { nNewValue = DSBVOLUME_MIN ; } if ( nNewValue > DSBVOLUME_MAX ) { nNewValue = DSBVOLUME_MAX ; } for ( int i = 0; i < AUDIO_MIX_COUNT; i++ ) { m_pDsb[i]->SetVolume(nNewValue); } } long CAudioPlayer::GetVolume(void) { long vol; m_pDsb[0]->GetVolume(&vol); return vol; } BOOL CAudioPlayer::FillBlankToBuf(ULONG pos , int nCase) // nCase 0基 { DWORD len = m_wfe.nAvgBytesPerSec; LPVOID lpvPtr1; DWORD dwBytes1; LPVOID lpvPtr2; DWORD dwBytes2; HRESULT hr; LPDIRECTSOUNDBUFFER pDsb; if( (nCase>=0) && (nCaseLock(pos, len, &lpvPtr1, &dwBytes1, &lpvPtr2, &dwBytes2, 0); if (DSERR_BUFFERLOST == hr) { pDsb->Restore(); hr = pDsb->Lock(pos, len, &lpvPtr1, &dwBytes1, &lpvPtr2, &dwBytes2, 0); } if (DS_OK == hr) { ZeroMemory(lpvPtr1, dwBytes1); if (NULL != lpvPtr2) { ZeroMemory(lpvPtr2, dwBytes2); } hr=pDsb->Unlock(lpvPtr1, dwBytes1, lpvPtr2, dwBytes2); return TRUE; } pDsb->SetCurrentPosition(0); return TRUE; } BOOL CAudioPlayer::FillBuffer(unsigned char *pdata, DWORD len, int nCase) // nCase 0基 { LPVOID lpvPtr1; DWORD dwBytes1; LPVOID lpvPtr2; DWORD dwBytes2; HRESULT hr; /* 首先要建立一个代表声卡的DirectSound对象*/ LPDIRECTSOUNDBUFFER pDsb; DWORD curpos; if( ( nCase >= 0 ) && ( nCase < AUDIO_MIX_COUNT ) ) { pDsb = m_pDsb[nCase]; curpos = m_dwCurPos[nCase]; } else { return FALSE; } // *********** ptr modify *********** DWORD wp1 , wp2 ; pDsb->GetCurrentPosition(&wp1, &wp2); //TRACE("[%d]",curpos); //DWORD dwCount = 0; // *********** end ptr modify ******* pDsb->SetCurrentPosition(0); hr = pDsb->Lock(wp2, len, &lpvPtr1, &dwBytes1,&lpvPtr2, &dwBytes2, DSBLOCK_FROMWRITECURSOR ); if (DSERR_BUFFERLOST == hr) { pDsb->Restore(); hr = pDsb->Lock(wp2, len, &lpvPtr1, &dwBytes1,&lpvPtr2, &dwBytes2, DSBLOCK_FROMWRITECURSOR ); } if (DS_OK == hr) { CopyMemory(lpvPtr1, pdata, len); if (NULL != lpvPtr2) { CopyMemory(lpvPtr2, pdata, len); } hr = pDsb->Unlock(lpvPtr1, dwBytes1,lpvPtr2, dwBytes2); if (hr != DS_OK) { return FALSE; } return TRUE; } pDsb->Restore(); pDsb->SetCurrentPosition(0); return FALSE; }
相关文章推荐
- 利用Directsound编程实现实时混音
- 利用Directsound编程实现实时混音
- DirectSound播放PCM(可播放实时采集的音频数据)
- android 通过数组,流播放声音的方法,音频实时传输
- android 通过数组,流播放声音的方法,音频实时传输(转)
- DirectSound播放PCM(可播放实时采集的音频数据)
- 利用Directsound编程实现实时混音
- 利用Directsound编程实现实时混音
- 运用Directsound编制程序完成实时混音
- 利用Directsound编程实现实时混音
- DirectSound编程实现实时混音
- android通过数组,流播放声音的方法,音频实时传输(安卓软件开发)
- android 通过数组,流播放声音的方法,音频实时传输
- 利用Directsound编程实现实时混音
- android通过数组,流播放声音的方法,音频实时传输
- 利用Directsound编程实现实时混音
- 微信小程序获取音频时长与实时获取播放进度问题
- 通过ViewFlipper和GestureDetector.OnGestureListener实现自动播放和手势滑屏事件
- 最简单的视音频播放示例6:OpenGL播放YUV420P(通过Texture,使用Shader)
- 通过nagios实现MD5实时监控iptables状态 推荐