-/*****************************************************************************
- * DirectSoundThread: this thread will capture play notification events.
- *****************************************************************************
- * We use this thread to emulate a callback mechanism. The thread probes for
- * event notification and fills up the DS secondary buffer when needed.
- *****************************************************************************/
-static void* DirectSoundThread( void *data )
-{
- audio_output_t *p_aout = (audio_output_t *)data;
- notification_thread_t *p_notif = &p_aout->sys->notif;
- mtime_t last_time;
-
- msg_Dbg( p_aout, "DirectSoundThread ready" );
-
- /* Wait here until Play() is called */
- WaitForSingleObject( p_notif->event, INFINITE );
-
- if( !vlc_atomic_get( &p_notif->abort) )
- {
- HRESULT dsresult;
- mwait( p_notif->start_date - AOUT_MAX_PTS_ADVANCE / 2 );
-
- /* start playing the buffer */
- dsresult = IDirectSoundBuffer_Play( p_aout->sys->p_dsbuffer,
- 0, /* Unused */
- 0, /* Unused */
- DSBPLAY_LOOPING ); /* Flags */
- if( dsresult == DSERR_BUFFERLOST )
- {
- IDirectSoundBuffer_Restore( p_aout->sys->p_dsbuffer );
- dsresult = IDirectSoundBuffer_Play(
- p_aout->sys->p_dsbuffer,
- 0, /* Unused */
- 0, /* Unused */
- DSBPLAY_LOOPING ); /* Flags */
- }
- if( dsresult != DS_OK )
- {
- msg_Err( p_aout, "cannot start playing buffer" );
- }
- }
- last_time = mdate();
-
- while( !vlc_atomic_get( &p_notif->abort ) )
- {
- DWORD l_read;
- int l_queued = 0, l_free_slots;
- unsigned i_frame_siz = p_aout->sys->packet.samples;
- mtime_t mtime = mdate();
- int i;
-
- /* Update volume if required */
- LONG volume = InterlockedExchange( &p_aout->sys->volume.volume, -1 );
- if( unlikely(volume != -1) )
- IDirectSoundBuffer_SetVolume( p_aout->sys->p_dsbuffer, volume );
-
- /*
- * Fill in as much audio data as we can in our circular buffer
- */
-
- /* Find out current play position */
- if FAILED( IDirectSoundBuffer_GetCurrentPosition(
- p_aout->sys->p_dsbuffer, &l_read, NULL ) )
- {
- msg_Err( p_aout, "GetCurrentPosition() failed!" );
- l_read = 0;
- }
-
- /* Detect underruns */
- if( l_queued && mtime - last_time >
- INT64_C(1000000) * l_queued / p_aout->sys->packet.format.i_rate )
- {
- msg_Dbg( p_aout, "detected underrun!" );
- }
- last_time = mtime;
-
- /* Try to fill in as many frame buffers as possible */
- l_read /= (p_aout->sys->packet.format.i_bytes_per_frame /
- p_aout->sys->packet.format.i_frame_length);
- l_queued = p_notif->i_write_slot * i_frame_siz - l_read;
- if( l_queued < 0 ) l_queued += (i_frame_siz * FRAMES_NUM);
- l_free_slots = (FRAMES_NUM * i_frame_siz - l_queued) / i_frame_siz;
-
- for( i = 0; i < l_free_slots; i++ )
- {
- block_t *p_buffer = aout_PacketNext( p_aout,
- mtime + INT64_C(1000000) * (i * i_frame_siz + l_queued) /
- p_aout->sys->packet.format.i_rate );
-
- /* If there is no audio data available and we have some buffered
- * already, then just wait for the next time */
- if( !p_buffer && (i || l_queued / i_frame_siz) ) break;
-
- if( FillBuffer( p_aout, p_notif->i_write_slot % FRAMES_NUM,
- p_buffer ) != VLC_SUCCESS ) break;
- }
-
- /* Sleep a reasonable amount of time */
- l_queued += (i * i_frame_siz);
- msleep( INT64_C(1000000) * l_queued / p_aout->sys->packet.format.i_rate / 2 );
- }
-
- /* make sure the buffer isn't playing */
- IDirectSoundBuffer_Stop( p_aout->sys->p_dsbuffer );
-
- msg_Dbg( p_aout, "DirectSoundThread exiting" );
- return NULL;