如何从第三发音乐播放器中HOOK音频数据然后跟自己麦采集数据做

首先看看基本知识:

Directsound中常用的几个对象

对象数量作用主要接口

设备对象每个应用程序只有一个设备对象用来管理设备,创建辅助缓冲区IDirectSound8

辅助缓冲区对象每一个声音对应一个辅助缓冲区,可以有多个辅助缓冲区用来管理一个静态的或者动态的声音流,然后在主缓冲区中混音IDirectSoundBuffer8,IDirectSound3DBuffer8,IDirectSoundNotify8

主缓冲区对象一个应用程序只有一个主缓冲区将辅助缓冲区的数据进行混音,并且控制3D参数.IDirectSoundBuffer, IDirectSound3DListener8

特技对象没有来辅助缓冲的声音数据进行处理8个特技接口IDirectSoundFXChorus8

首先,要创建一个设备对象,然后通过设备对象创建缓冲区对象。辅助缓冲区由应用程序创建和管理,DirectSound会自动地创建和管理主缓冲区,一般来说,应用程序即使没有获取这个主缓冲区对象的接口也可以播放音频数据,但是,如果应用程序要想得到IDirectSound3DListener8接口,就必须要自己创建一个主缓冲区。

使用静态的缓冲区  如果我们的wave文件不是很大,那么我们就可以使用静态的缓冲区了。包含全部音频数据的缓冲区我们称为静态的缓冲区,尽管,不同的声音可能会反复使用同一个内存buffer,但严格来说,静态缓冲区的数据只写入一次。静态缓冲区的创建和管理和流缓冲区很相似,唯一的区别就是它们使用的方式不一样,静态缓冲区只填充一次数据,然后就可以play,然而,流缓冲区是一边play,一边填充数据。给静态缓冲区加载数据分下面几个步骤1、调用IDirectSoundBuffer8::Lock函数来锁定所有的内存,你要指定你锁定内存中你开始写入数据的偏移位置,并且取回该偏移位置的地址。2、采用标准的数据copy方法,将音频数据复制到返回的地址。3、调用IDirectSoundBuffer8::Unlock.,解锁该地址。下面我给出使用static buffer 播放wav文件的完整代码,首先定义我们需要的一些对象:

LPDIRECTSOUNDBUFFER8 g_pDSBuffer8 = NULL; //bufferLPDIRECTSOUND8 g_pDsd = NULL; //dsoundCWaveFile *g_pWaveFile= NULL;//下面初始化DirectSound工作。HRESULT hr;if(FAILED(hr = DirectSoundCreate8(NULL,&g_pDsd,NULL)))return FALSE;//设置设备的协作度if(FAILED(hr = g_pDsd->SetCooperativeLevel(m_hWnd,DSSCL_PRIORITY)))return FALSE;g_pWaveFile = new CWaveFile;g_pWaveFile->Open(_T("d:\\test.wav"),NULL,WAVEFILE_READ);DSBUFFERDESC dsbd;ZeroMemory( &dsbd, sizeof(DSBUFFERDESC) );dsbd.dwSize = sizeof(DSBUFFERDESC);dsbd.dwFlags = DSBCAPS_GLOBALFOCUS | DSBCAPS_CTRLFX| DSBCAPS_CTRLPOSITIONNOTIFY |DSBCAPS_GETCURRENTPOSITION2;dsbd.dwBufferBytes = g_pWaveFile->GetSize();//MAX_AUDIO_BUF * BUFFERNOTIFYSIZE ;dsbd.lpwfxFormat = g_pWaveFile->m_pwfx;LPDIRECTSOUNDBUFFER lpbuffer;//创建辅助缓冲区对象if(FAILED(hr = g_pDsd->CreateSoundBuffer(&dsbd,&lpbuffer,NULL)))return ;if( FAILED( hr = lpbuffer->QueryInterface( IID_IDirectSoundBuffer8, (LPVOID*) &g_pDSBuffer8) ) )return ;lpbuffer->Release();//准备工作做完了,下面就开始播放了LPVOID lplockbuf;DWORD len;DWORD dwWrite;g_pDSBuffer8->Lock(0,0,&lplockbuf,&len,NULL,NULL,DSBLOCK_ENTIREBUFFER);g_pWaveFile->Read((BYTE*)lplockbuf,len,&dwWrite);g_pDSBuffer8->Unlock(lplockbuf,len,NULL,0);g_pDSBuffer8->SetCurrentPosition(0);g_pDSBuffer8->Play(0,0,DSBPLAY_LOOPING);

流缓冲区用来播放那些比较长的音频文件,因为数据比较长,没法一次填充到缓冲区中,一边播放,一边将新的数据填充到DirectSound的缓冲区中。可以通过IDirectSoundBuffer8::Play函授来播放缓冲区中的内容,注意在该函数的参数中一定要设置DSBPLAY_LOOPING标志。通过IDirectSoundBuffer8::Stop方法中断播放,该方法会立即停止缓冲区播放,因此你要确保所有的数据都被播放,你可以通过拖动播放位置或者设置通知位置来实现。将音频流倒入缓冲区需要下面三个步骤1、确保你的缓冲区已经做好接收新数据的准备。你可以拖放播放的光标位置或者等待通知2、调用IDirectSoundBuffer8::Lock.函数锁住缓冲区的位置,这个函数返回一个或者两个可以写入数据的地址3、使用标准的copy数据的方法将音频数据写入缓冲区中4、IDirectSoundBuffer8::Unlock.,解锁这里我要讲一下DirectSound的通知机制。因为Stream buffer 大小只够容纳一部分数据,因此,在播放完缓冲区中的数据后,DirectSound就会通知应用程序,将新的数据填充到DirectSound的缓冲区中。假如我们设置DirectSound的buffersize 为1920*4,如下图我们可以给DirectSound设置一个事件,并且设置buffer通知大小,如下:HANDLE g_event[MAX_AUDIO_BUF];for(int i =0; i< MAX_AUDIO_BUF;i++){g_aPosNotify[i].dwOffset = i* BUFFERNOTIFYSIZE ;g_aPosNotify[i].hEventNotify = g_event[i];}if(FAILED(hr = g_pDSBuffer8->QueryInterface(IID_IDirectSoundNotify,(LPVOID *) &g_pDSNotify )))return ;g_pDSNotify->SetNotificationPositions(MAX_AUDIO_BUF,g_aPosNotify);g_pDSNotify->Release();

当DirectSound播放到buffer的1920,3840,5760,7680等位置时,Directsound就会通知应用程序,将g_ event,设置为通知态,应用程序就可以通过WaitForMultipleObjects 函数等待DirectSound的通知,将数据填充到DirectSoun的辅助缓冲区。下面我给出Stream buffer 播放wave文件的代码。#define MAX_AUDIO_BUF 4#define BUFFERNOTIFYSIZE 1920LPDIRECTSOUNDBUFFER8 g_pDSBuffer8 = NULL; //bufferLPDIRECTSOUND8 g_pDsd = NULL; //dsoundCWaveFile *g_pWaveFile= NULL;BOOL g_bPlaying = FALSE; //是否正在播放LPDIRECTSOUNDNOTIFY8 g_pDSNotify = NULL;DSBPOSITIONNOTIFY g_aPosNotify[MAX_AUDIO_BUF];//设置通知标志的数组HANDLE g_event[MAX_AUDIO_BUF];DWORD g_dwNextWriteOffset = 0;//初始化DirectSoundHRESULT hr;if(FAILED(hr = DirectSoundCreate8(NULL,&g_pDsd,NULL)))return FALSE;if(FAILED(hr = g_pDsd->SetCooperativeLevel(m_hWnd,DSSCL_PRIORITY)))return FALSE;g_pWaveFile = new CWaveFile;g_pWaveFile->Open(_T("d:\\test.wav"),NULL,WAVEFILE_READ);DSBUFFERDESC dsbd;ZeroMemory( &dsbd, sizeof(DSBUFFERDESC) );dsbd.dwSize = sizeof(DSBUFFERDESC);dsbd.dwFlags = DSBCAPS_GLOBALFOCUS | DSBCAPS_CTRLPOSITIONNOTIFY |DSBCAPS_GETCURRENTPOSITION2;dsbd.dwBufferBytes = MAX_AUDIO_BUF * BUFFERNOTIFYSIZE ;dsbd.lpwfxFormat = g_pWaveFile->m_pwfx;LPDIRECTSOUNDBUFFER lpbuffer;//创建DirectSound辅助缓冲区if(FAILED(hr = g_pDsd->CreateSoundBuffer(&dsbd,&lpbuffer,NULL)))return FALSE;if( FAILED( hr = lpbuffer->QueryInterface( IID_IDirectSoundBuffer8, (LPVOID*) &g_pDSBuffer8) ) )return FALSE;lpbuffer->Release();//设置DirectSound通知 机制for(int i =0; i< MAX_AUDIO_BUF;i++){g_aPosNotify[i].dwOffset = i* BUFFERNOTIFYSIZE ;g_aPosNotify[i].hEventNotify = g_event[i];}if(FAILED(hr=g_pDSBuffer8->QueryInterface(IID_IDirectSoundNotify,(LPVOID*) g_pDSNotify )))return ;g_pDSNotify->SetNotificationPositions(MAX_AUDIO_BUF,g_aPosNotify);g_pDSNotify->Release();ok,在下面的play函数中,,我们就要单独启动一个线程,来播放了void OnBnClickedButtonPlay(){g_bPlaying =TRUE;g_pWaveFile->ResetFile();CreateThread(0,0,PlayThread,this,NULL,NULL);}//停止播放音频void CDsoundEffectDemoDlg::OnBnClickedButtonStop(){// TODO: 在此添加控件通知处理程序代码g_bPlaying =FALSE;Sleep(500);g_pDSBuffer8->Stop();}下面我们看看我们的播放线程,在线程里,我们首先将音频数据填充到DirectSound的辅助缓冲区中,然后调用DirectSound buffer 的play方法,开始播放,然后就在WaitForMultipleObjects 等待DirectSound的通知吧,然后读取wave文件将数据填充到DirectSound的空buffer中。DWORD WINAPI PlayThread(LPVOID lpParame){DWORD res;LPVOID lplockbuf;DWORD len;DWORD dwWrite;g_pDSBuffer8->Lock(0,0,&lplockbuf,&len,NULL,NULL,DSBLOCK_ENTIREBUFFER);g_pWaveFile->Read((BYTE*)lplockbuf,len,&dwWrite);g_pDSBuffer8->Unlock(lplockbuf,len,NULL,0);g_pDSBuffer8->SetCurrentPosition(0);g_pDSBuffer8->Play(0,0,DSBPLAY_LOOPING);g_dwNextWriteOffset = 0;while(g_bPlaying){res = WaitForMultipleObjects (MAX_AUDIO_BUF, g_event, FALSE, INFINITE);if(res > WAIT_OBJECT_0)ProcessBuffer();}return 0;}

人要有梦想,有了梦想才会努力奋斗,

如何从第三发音乐播放器中HOOK音频数据然后跟自己麦采集数据做

相关文章:

你感兴趣的文章:

标签云: