2

I continuously send data to IAudioClient (GetBufferSize / GetCurrentPadding / GetBuffer / ReleaseBuffer), but I want to know when the audio device finishes playing the last data I sent. I do not want to assume the player stopped just because I sent the last chunk of data to the device: it might still be playing the buffered data.

I tried using IAudioClock / IAudioClock2 to check the hardware buffer position, but it stays the same from the moment I send the last chunk.

I also don't see anything relevant in the IMMNotificationClient and IAudioSessionNotification interfaces...

What am I missing?

Thanks!

Dmitry Streblechenko
  • 62,942
  • 4
  • 53
  • 78

1 Answers1

1

IMMNotificationClient and IAudioSessionNotification are not gonna help you, these are for detecting new devices / new application sessions respectively. As far as i know there's nothing in WASAPI that explicitly sends out an event when the last sample is consumed by the device (exclusive mode) or audio engine (shared mode). A trick I used in the past (albeit with DirectSound, but should work equally well with WASAPI) is to continuously check the available space in the audio buffer (for WASAPI, using GetCurrentPadding). After you send the last sample, immediately record the current padding, let's say it is N frames. Then keep writing zeroes to the AudioClient untill N frames have been processed (as reported by IAudioClock(2), or just guestimate using a timer), then stop the stream. Whether this works on an exclusive event-driven mode stream is a driver quality issue; the driver may choose to report the "real" playback position or just process it in chunks of full buffer size.

Sjoerd van Kreel
  • 1,000
  • 6
  • 19
  • IAudioClock::GetPosition / etc. always returns the same value no matter whether the audio is playing or not. I can use IAudioMeterInformation.GetPeakValue and check if the returned value == 0. That seems to work in my case (the audio is a microphone recording with at least some ambient noise), but I do not really like it as a generic solution - one can certainly have periods on silence in the audio stream. – Dmitry Streblechenko Aug 12 '16 at 15:21
  • AudioClock should return continuously increasing positions as long as you don't stop the stream. Got any sample code that reproduces the problem? – Sjoerd van Kreel Aug 12 '16 at 18:21
  • Nothing I can post - I have a Delphi app that streams the data (works fine), and while streaming, I have a timer fire every 50ms (just a test) and call AudioClock::GetPosition. Both returned values are logged. They stay the same at all times and only differ when I reinitialize the device. – Dmitry Streblechenko Aug 12 '16 at 22:35
  • 1
    Turns out you can do this using GetCurrentPadding only. As soon as you send the last data packet, record the padding (= valid audio in the buffer), then immediately fill the rest of the buffer with zeros. After that, if P frames of valid audio were in the buffer, just keep writing zeroes untill you pushed at least P frames of silence. This way you can be sure the audio engine took P frames of valid audio data (and possibly some additional silence). See http://pastebin.com/Gqj8G3z2 – Sjoerd van Kreel Aug 15 '16 at 18:22