Playing Sounds
Playing a sound consists of the following steps:
- Lock a portion of the secondary buffer using IDirectSoundBuffer::Lock. This method returns a pointer to the address where writing will begin, based on the offset from the beginning of the buffer that you pass in to the method.
- Write the audio data to the buffer.
- Unlock the buffer using IDirectSoundBuffer::Unlock.
- Send the sound to the primary buffer and from there to the output device using IDirectSoundBuffer::Play. If the buffer is a streaming buffer, it will continue playing in a loop as steps 1 to 3 are repeated.
Because streaming sound buffers usually play continually and are conceptually circular, DirectSound returns two write pointers when locking a sound buffer. For example, if you tried to lock 3,000 bytes beginning at the midpoint of a 4,000-byte buffer, the Lock method would return one pointer to the last 2,000 bytes of the buffer, and a second pointer to the first 1,000 bytes. The second pointer is NULL if the locked portion of the buffer does not wrap around.
Normally the buffer stops playing automatically when the end is reached. However, if the DSBPLAY_LOOPING flag was set in the dwFlags parameter to the Play method, the buffer plays repeatedly until the application calls the IDirectSoundBuffer::Stop method.
Note When using a waveout driver, DirectSound will use waveOutGetPosition that returns a 32-bit value. This value will wrap in just under 7 hours, making the DirectSound subsystem unstable. If your application requires prolonged continuous playback of audio with DirectSound, a DirectSound driver should be developed to avoid this problem.
For streaming sound buffers, your application is responsible for ensuring that each block of data is written to the buffer ahead of the current play position. (For more on the play position, see Current Play and Write Positions.) Applications should write at least 1 second ahead of the current play position to minimize the possibility of gaps in the audio output during playback.
The following C example writes data to a sound buffer, starting at the offset into the buffer passed in dwOffset.
BOOL AppWriteDataToBuffer(
LPDIRECTSOUNDBUFFER lpDsb, // the DirectSound buffer
DWORD dwOffset, // our own write cursor
LPBYTE lpbSoundData, // start of our data
DWORD dwSoundBytes) // size of block to copy
{
LPVOID lpvPtr1;
DWORD dwBytes1;
LPVOID lpvPtr2;
DWORD dwBytes2;
HRESULT hr;
// Obtain memory address of write block. This will be in two parts
// if the block wraps around.
hr = lpDsb->lpVtbl->Lock(lpDsb, dwOffset, dwSoundBytes, &lpvPtr1,
&dwBytes1, &lpvPtr2, &dwBytes2, 0);
// If DSERR_BUFFERLOST is returned, restore and retry lock.
if (DSERR_BUFFERLOST == hr)
{
hr = lpDsb->lpVtbl->Restore(lpDsb);
if (DS_OK != hr)
{
// Process the failed call to Restore.
}
hr = lpDsb->lpVtbl->Lock(lpDsb, dwOffset, dwSoundBytes,
&lpvPtr1, &dwAudio1, &lpvPtr2, &dwAudio2, 0);
}
if SUCCEEDED(hr)
{
// Write to pointers.
CopyMemory(lpvPtr1, lpbSoundData, dwBytes1);
if (NULL != lpvPtr2)
{
CopyMemory(lpvPtr2, lpbSoundData+dwBytes1, dwBytes2);
}
// Release the data back to DirectSound.
hr = lpDsb->lpVtbl->Unlock(lpDsb, lpvPtr1, dwBytes1, lpvPtr2,
dwBytes2);
if SUCCEEDED(hr)
{
// Success.
return TRUE;
}
}
// Lock, Unlock, or Restore failed.
return FALSE;
}
Last updated on Thursday, April 08, 2004
© 1992-2003 Microsoft Corporation. All rights reserved.