Maarten Lankhorst wrote: [nice to hear from you] >> IMHO AudioClient_Stop must not map to >> snd_pcm_drop. It is more like snd_pcm_pause. Or perhaps simply lead >> ALSA into an underrun. >afaict pause, with reset mapped to drop, Indeed. But I believe I need a fallback because ALSA says that pause "works only on the hardware which supports" it.
>I can't remember why pause didn't work, but if it works go for it. I was solely thinking aloud that pause is TRT, not tried out yet. However, I received test results from a "Windows 7 Ultimate" machine. It exhibits a similar bug -- in exclusive mode only: render.c:948: Test failed: Position 18191 too far after 100ms Shared mode works as my tests expect it (<= 48000/10 frames). >> + snd_pcm_status_alloca(&status); >HeapAlloc(GetProcessHeap(), HEAP_ZERO_FLAG, snd_pcm_status_sizeof()) > or something like that if available please.. Really? I don't want to go through the overhead of memory allocation when all I need is a stupid small amount of stack allocated memory. >> + if(!This->initted){ >> + return AUDCLNT_E_NOT_INITIALIZED; >Unneeded part. Can't you obtain a handle to that COM object prior to calling Initialize which sets This->fmt? >Follow that flow.. I beg your pardon? >> + if(0){ >> + avail_frames = snd_pcm_status_get_avail(status); >> + delay_frames = snd_pcm_status_get_delay(status); >if 0 is bad... I tried out pcm_status because somebody in alsa-devel mentioned that it allows to grab avail + delay in one (sync'ed?). However, I found delay to be always 0 inside status!?! Also, I found out that I need to call avail_update and delay in a particular order, otherwise I get stale values from an old call prior to the last sleep... >> + if(avail_frames <= This->bufsize_alsa + MAX_LATE_SECONDS * >> This->fmt->nSamplesPerSec >> + && delay_frames > 0) >Isn't delay_frames < 0 the definition of underrun? Indeed. There are potentially N distinct underruns: - the front end -- what snd_pcm_avail_update knows about; - intermittent buffers (USB); - the speaker -- what snd_pcm_delay knows about. There could be a short front-end buffer underrun that goes unnoticed by the speaker if the TCP or USB in between buffers enough data *and* is able to speed up. >no point in adding MAX_LATE_SECONDS That is some form of guard against broken values. E.g. people reporting in alsa-devel that PA sometimes complains about avail ~ MAXINT and such weird values. >Getting an avail update again? Why? The theory is: position = written_frames(into ALSA) - delay and translates to: This->written_frames - This->held_frames - delay However sometimes I can't trust delay. I still need to figure out when. - IIRC after an underrun, snd_pcm_delay yields error X. - or was it before starting? - ... The upper bound on position is always: This->written_frames(ReleaseBuffer) - This->held_frames - ALSA_padding (what ALSA's front end has not yet processed, in absence of underrun). Perhaps that would be robust: 1. Compute upper bound 2. position = clamp(0, delay > 0 ? written-delay : written, upper_bound); 2b. except when not yet started ... 2c. except while stopped ... I was even considering: 3. if position < This->previous_position stick to previous... Yet perhaps it's better to allow intermittent garbage values than to stick to garbage! OTOH, the delay values I see in the logs are subject to such variation (with PA) that I'm considering going with a clock instead, or perhaps: - query delay once per tick (e.g. 10ms) => last_pos - when asked, compute position from last_pos + time since tick * rate The last_pos slot may be needed anyway once stopped in pause mode. Regards, Jörg Höhle