diff options
-rw-r--r-- | src/cubeb_winmm.c | 45 |
1 files changed, 34 insertions, 11 deletions
diff --git a/src/cubeb_winmm.c b/src/cubeb_winmm.c index 44aec86..dc1db9c 100644 --- a/src/cubeb_winmm.c +++ b/src/cubeb_winmm.c @@ -109,6 +109,8 @@ struct cubeb_stream { HWAVEOUT waveout; CRITICAL_SECTION lock; uint64_t written; + /* number of frames written during preroll */ + uint64_t position_base; float soft_volume; /* For position wrap-around handling: */ size_t frame_size; @@ -150,6 +152,13 @@ winmm_get_next_buffer(cubeb_stream * stm) return hdr; } +static long +preroll_callback(cubeb_stream * stream, void * user, const void * inputbuffer, void * outputbuffer, long nframes) +{ + memset((uint8_t*)outputbuffer, 0, nframes * bytes_per_frame(stream->params)); + return nframes; +} + static void winmm_refill_stream(cubeb_stream * stm) { @@ -486,7 +495,11 @@ winmm_stream_init(cubeb * context, cubeb_stream ** stream, stm->params = *output_stream_params; - stm->data_callback = data_callback; + // Data callback is set to the user-provided data callback after + // the initialization and potential preroll callback calls are done, because + // cubeb users don't expect the data callback to be called during + // initialization. + stm->data_callback = preroll_callback; stm->state_callback = state_callback; stm->user_ptr = user_ptr; stm->written = 0; @@ -553,6 +566,13 @@ winmm_stream_init(cubeb * context, cubeb_stream ** stream, stm->frame_size = bytes_per_frame(stm->params); stm->prev_pos_lo_dword = 0; stm->pos_hi_dword = 0; + // Set the user data callback now that preroll has finished. + stm->data_callback = data_callback; + stm->position_base = 0; + + // Offset the position by the number of frames written during preroll. + stm->position_base = stm->written; + stm->written = 0; *stream = stm; @@ -774,7 +794,15 @@ winmm_stream_get_position(cubeb_stream * stm, uint64_t * position) return CUBEB_ERROR; } - *position = update_64bit_position(stm, time.u.cb) / stm->frame_size; + uint64_t position_not_adjusted = update_64bit_position(stm, time.u.cb) / stm->frame_size; + + // Subtract the number of frames that were written while prerolling, during initialization. + if (position_not_adjusted < stm->position_base) { + *position = 0; + } else { + *position = position_not_adjusted - stm->position_base; + } + LeaveCriticalSection(&stm->lock); return CUBEB_OK; @@ -787,17 +815,12 @@ winmm_stream_get_latency(cubeb_stream * stm, uint32_t * latency) MMTIME time; uint64_t written, position; - EnterCriticalSection(&stm->lock); - /* See the long comment above for why not just use TIME_SAMPLES here. */ - time.wType = TIME_BYTES; - r = waveOutGetPosition(stm->waveout, &time, sizeof(time)); - - if (r != MMSYSERR_NOERROR || time.wType != TIME_BYTES) { - LeaveCriticalSection(&stm->lock); - return CUBEB_ERROR; + int rv = winmm_stream_get_position(stm, &position); + if (rv != CUBEB_OK) { + return rv; } - position = update_64bit_position(stm, time.u.cb); + EnterCriticalSection(&stm->lock); written = stm->written; LeaveCriticalSection(&stm->lock); |