Exemple de code de streaming audio
[La fonctionnalité associée à cette page, DirectShow, est une fonctionnalité héritée. Il a été remplacé par MediaPlayer, IMFMediaEngine et Audio/Video Capture in Media Foundation. Ces fonctionnalités ont été optimisées pour Windows 10 et Windows 11. Microsoft recommande vivement que le nouveau code utilise MediaPlayer, IMFMediaEngine et Audio/Video Capture dans Media Foundation au lieu de DirectShow, si possible. Microsoft suggère que le code existant qui utilise les API héritées soit réécrit pour utiliser les nouvelles API si possible.]
Notes
Ces API sont déconseillées. Les applications doivent utiliser le filtre Sample Grabber ou implémenter un filtre personnalisé pour obtenir des données à partir d’un graphique de filtre DirectShow.
L’exemple de code suivant montre comment diffuser en continu des données audio à l’aide des interfaces IAudioMediaStream, IAudioStreamSample, IMemoryData et IAudioData . Par souci de concision, cet exemple effectue une vérification minimale des erreurs.
#include <windows.h>
#include <stdio.h>
#include <mmsystem.h>
#include <amstream.h>
class CWaveBuffer {
public:
~CWaveBuffer();
BOOL Init(HWAVEOUT hWave, int Size);
BOOL Write(PBYTE pData, int nBytes, int& BytesWritten);
void Flush();
private:
WAVEHDR m_Hdr;
HWAVEOUT m_hWave;
int m_nBytes;
};
class CWaveOut {
public:
CWaveOut(LPCWAVEFORMATEX Format, int nBuffers, int BufferSize);
~CWaveOut();
void Write(PBYTE Data, int nBytes);
void Flush();
void Wait();
void Reset();
private:
const HANDLE m_hSem;
const int m_nBuffers;
int m_CurrentBuffer;
BOOL m_NoBuffer;
CWaveBuffer *m_Hdrs;
HWAVEOUT m_hWave;
};
BOOL CWaveBuffer::Init(HWAVEOUT hWave, int Size)
{
m_hWave = hWave;
m_nBytes = 0;
/* Allocate a buffer and initialize the header. */
m_Hdr.lpData = (LPSTR)LocalAlloc(LMEM_FIXED, Size);
if (m_Hdr.lpData == NULL)
{
return FALSE;
}
m_Hdr.dwBufferLength = Size;
m_Hdr.dwBytesRecorded = 0;
m_Hdr.dwUser = 0;
m_Hdr.dwFlags = 0;
m_Hdr.dwLoops = 0;
m_Hdr.lpNext = 0;
m_Hdr.reserved = 0;
/* Prepare it. */
waveOutPrepareHeader(hWave, &m_Hdr, sizeof(WAVEHDR));
return TRUE;
}
CWaveBuffer::~CWaveBuffer()
{
if (m_Hdr.lpData)
{
waveOutUnprepareHeader(m_hWave, &m_Hdr, sizeof(WAVEHDR));
LocalFree(m_Hdr.lpData);
}
}
void CWaveBuffer::Flush()
{
// ASSERT(m_nBytes != 0);
m_nBytes = 0;
waveOutWrite(m_hWave, &m_Hdr, sizeof(WAVEHDR));
}
BOOL CWaveBuffer::Write(PBYTE pData, int nBytes, int& BytesWritten)
{
// ASSERT((DWORD)m_nBytes != m_Hdr.dwBufferLength);
BytesWritten = min((int)m_Hdr.dwBufferLength - m_nBytes, nBytes);
CopyMemory((PVOID)(m_Hdr.lpData + m_nBytes), (PVOID)pData, BytesWritten);
m_nBytes += BytesWritten;
if (m_nBytes == (int)m_Hdr.dwBufferLength)
{
/* Write it! */
m_nBytes = 0;
waveOutWrite(m_hWave, &m_Hdr, sizeof(WAVEHDR));
return TRUE;
}
return FALSE;
}
void CALLBACK WaveCallback(HWAVEOUT hWave, UINT uMsg, DWORD dwUser,
DWORD dw1, DWORD dw2)
{
if (uMsg == WOM_DONE)
{
ReleaseSemaphore((HANDLE)dwUser, 1, NULL);
}
}
CWaveOut::CWaveOut(LPCWAVEFORMATEX Format, int nBuffers, int BufferSize) :
m_nBuffers(nBuffers),
m_CurrentBuffer(0),
m_NoBuffer(TRUE),
m_hSem(CreateSemaphore(NULL, nBuffers, nBuffers, NULL)),
m_Hdrs(new CWaveBuffer[nBuffers]),
m_hWave(NULL)
{
/* Create wave device. */
waveOutOpen(&m_hWave,
WAVE_MAPPER,
Format,
(DWORD)WaveCallback,
(DWORD)m_hSem,
CALLBACK_FUNCTION);
/* Initialize the wave buffers. */
for (int i = 0; i < nBuffers; i++)
{
m_Hdrs[i].Init(m_hWave, BufferSize);
}
}
CWaveOut::~CWaveOut()
{
/* First, get the buffers back. */
waveOutReset(m_hWave);
/* Free the buffers. */
delete [] m_Hdrs;
/* Close the wave device. */
waveOutClose(m_hWave);
/* Free the semaphore. */
CloseHandle(m_hSem);
}
void CWaveOut::Flush()
{
if (!m_NoBuffer)
{
m_Hdrs[m_CurrentBuffer].Flush();
m_NoBuffer = TRUE;
m_CurrentBuffer = (m_CurrentBuffer + 1) % m_nBuffers;
}
}
void CWaveOut::Reset()
{
waveOutReset(m_hWave);
}
void CWaveOut::Write(PBYTE pData, int nBytes)
{
while (nBytes != 0)
{
/* Get a buffer if necessary. */
if (m_NoBuffer)
{
WaitForSingleObject(m_hSem, INFINITE);
m_NoBuffer = FALSE;
}
/* Write into a buffer. */
int nWritten;
if (m_Hdrs[m_CurrentBuffer].Write(pData, nBytes, nWritten))
{
m_NoBuffer = TRUE;
m_CurrentBuffer = (m_CurrentBuffer + 1) % m_nBuffers;
nBytes -= nWritten;
pData += nWritten;
}
else
{
// ASSERT(nWritten == nBytes);
break;
}
}
}
void CWaveOut::Wait()
{
/* Send any remaining buffers. */
Flush();
/* Wait for the buffers back. */
for (int i = 0; i < m_nBuffers; i++)
{
WaitForSingleObject(m_hSem, INFINITE);
}
LONG lPrevCount;
ReleaseSemaphore(m_hSem, m_nBuffers, &lPrevCount);
}
HRESULT RenderStreamToDevice(IMultiMediaStream *pMMStream)
{
WAVEFORMATEX wfx;
#define DATA_SIZE 5000
IMediaStream *pStream = NULL;
IAudioStreamSample *pSample = NULL;
IAudioMediaStream *pAudioStream = NULL;
IAudioData *pAudioData = NULL;
HRESULT hr = pMMStream->GetMediaStream(MSPID_PrimaryAudio, &pStream);
if (FAILED(hr))
{
return hr;
}
pStream->QueryInterface(IID_IAudioMediaStream, (void **)&pAudioStream);
pStream->Release();
hr = CoCreateInstance(CLSID_AMAudioData, NULL,
CLSCTX_INPROC_SERVER, IID_IAudioData, (void **)&pAudioData);
if (FAILED(hr))
{
pAudioStream->Release();
return hr;
}
PBYTE pBuffer = (PBYTE)LocalAlloc(LMEM_FIXED, DATA_SIZE);
if (pBuffer == NULL)
{
pAudioStream->Release();
pAudioData->Release();
return E_OUTOFMEMORY;
}
pAudioStream->GetFormat(&wfx);
pAudioData->SetBuffer(DATA_SIZE, pBuffer, 0);
pAudioData->SetFormat(&wfx);
hr = pAudioStream->CreateSample(pAudioData, 0, &pSample);
pAudioStream->Release();
if (FAILED(hr))
{
LocalFree((HLOCAL)pBuffer);
pAudioData->Release();
pSample->Release();
return hr;
}
CWaveOut WaveOut(&wfx, 4, 2048);
HANDLE hEvent = CreateEvent(FALSE, NULL, NULL, FALSE);
if (hEvent != 0)
{
int iTimes;
for (iTimes = 0; iTimes < 3; iTimes++)
{
DWORD dwStart = timeGetTime();
for (; ; )
{
hr = pSample->Update(0, hEvent, NULL, 0);
if (FAILED(hr) || hr == MS_S_ENDOFSTREAM)
{
break;
}
WaitForSingleObject(hEvent, INFINITE);
DWORD dwTimeDiff = timeGetTime() - dwStart;
// Limit to 10 seconds
if (dwTimeDiff > 10000) {
break;
}
DWORD dwLength;
pAudioData->GetInfo(NULL, NULL, &dwLength);
WaveOut.Write(pBuffer, dwLength);
}
pMMStream->Seek(0);
}
}
pAudioData->Release();
pSample->Release();
LocalFree((HLOCAL)pBuffer);
return S_OK;
}
HRESULT RenderFileToMMStream(
const char * szFileName,
IMultiMediaStream **ppMMStream)
{
if (strlen(szFileName) > MAX_PATH)
{
return E_INVALIDARG;
}
IAMMultiMediaStream *pAMStream;
HRESULT hr = CoCreateInstance(CLSID_AMMultiMediaStream, NULL,
CLSCTX_INPROC_SERVER, IID_IAMMultiMediaStream,
(void **)&pAMStream);
if (FAILED(hr))
{
return hr;
}
WCHAR wszName[MAX_PATH + 1];
MultiByteToWideChar(CP_ACP, 0, szFileName, -1, wszName,
MAX_PATH + 1);
pAMStream->Initialize(STREAMTYPE_READ, AMMSF_NOGRAPHTHREAD, NULL);
pAMStream->AddMediaStream(NULL, &MSPID_PrimaryAudio, 0, NULL);
hr = pAMStream->OpenFile(wszName, AMMSF_RUN);
{
if (SUCCEEDED(hr))
{
hr = pAMStream->QueryInterface(IID_IMultiMediaStream,
(void**)ppMMStream);
}
}
pAMStream->Release();
return hr;
}
int __cdecl main(int argc, char *argv[])
{
if (argc < 2)
{
printf("Specify a file name.\n");
exit(0);
}
IMultiMediaStream *pMMStream;
CoInitialize(NULL);
HRESULT hr = RenderFileToMMStream(argv[1], &pMMStream);
if (SUCCEEDED(hr))
{
RenderStreamToDevice(pMMStream);
pMMStream->Release();
}
CoUninitialize();
return 0;
}
Rubriques connexes