static OSStatus render_cb_lpcm(void *ctx, AudioUnitRenderActionFlags *aflags, const AudioTimeStamp *ts, UInt32 bus, UInt32 frames, AudioBufferList *buffer_list) { struct ao *ao = ctx; struct priv *p = ao->priv; AudioBuffer buf = buffer_list->mBuffers[0]; int64_t end = mp_time_us(); end += p->hw_latency_us + ca_get_latency(ts) + ca_frames_to_us(ao, frames); ao_read_data(ao, &buf.mData, frames, end); return noErr; }
static void audio_callback(void *userdata, Uint8 *stream, int len) { struct ao *ao = userdata; void *data[1] = {stream}; if (len % ao->sstride) MP_ERR(ao, "SDL audio callback not sample aligned"); // Time this buffer will take, plus assume 1 period (1 callback invocation) // fixed latency. double delay = 2 * len / (double)ao->bps; ao_read_data(ao, data, len / ao->sstride, mp_time_us() + 1000000LL * delay); }
static void thread_feed(struct ao *ao) { struct wasapi_state *state = ao->priv; HRESULT hr; UINT32 frame_count = state->bufferFrameCount; if (state->share_mode == AUDCLNT_SHAREMODE_SHARED) { UINT32 padding = 0; hr = IAudioClient_GetCurrentPadding(state->pAudioClient, &padding); EXIT_ON_ERROR(hr); frame_count -= padding; MP_TRACE(ao, "Frame to fill: %"PRIu32". Padding: %"PRIu32"\n", frame_count, padding); } double delay_us; hr = get_device_delay(state, &delay_us); EXIT_ON_ERROR(hr); // add the buffer delay delay_us += frame_count * 1e6 / state->format.Format.nSamplesPerSec; BYTE *pData; hr = IAudioRenderClient_GetBuffer(state->pRenderClient, frame_count, &pData); EXIT_ON_ERROR(hr); BYTE *data[1] = {pData}; ao_read_data(ao, (void **)data, frame_count, mp_time_us() + (int64_t)llrint(delay_us)); // note, we can't use ao_read_data return value here since we already // commited to frame_count above in the GetBuffer call hr = IAudioRenderClient_ReleaseBuffer(state->pRenderClient, frame_count, 0); EXIT_ON_ERROR(hr); atomic_fetch_add(&state->sample_count, frame_count); return; exit_label: MP_ERR(state, "Error feeding audio: %s\n", mp_HRESULT_to_str(hr)); MP_VERBOSE(ao, "Requesting ao reload\n"); ao_request_reload(ao); return; }
static int process(jack_nframes_t nframes, void *arg) { struct ao *ao = arg; struct priv *p = ao->priv; void *buffers[MP_NUM_CHANNELS]; for (int i = 0; i < p->num_ports; i++) buffers[i] = jack_port_get_buffer(p->ports[i], nframes); int64_t end_time = mp_time_us(); end_time += (p->jack_latency + nframes / (double)ao->samplerate) * 1000000.0; ao_read_data(ao, buffers, nframes, end_time); return 0; }
static void thread_feed(struct ao *ao) { struct wasapi_state *state = (struct wasapi_state *)ao->priv; HRESULT hr; UINT32 frame_count = state->bufferFrameCount; if (state->share_mode == AUDCLNT_SHAREMODE_SHARED) { UINT32 padding = 0; hr = IAudioClient_GetCurrentPadding(state->pAudioClient, &padding); EXIT_ON_ERROR(hr); frame_count -= padding; } BYTE *pData; hr = IAudioRenderClient_GetBuffer(state->pRenderClient, frame_count, &pData); EXIT_ON_ERROR(hr); BYTE *data[1] = {pData}; ao_read_data(ao, (void**)data, frame_count, (int64_t) ( mp_time_us() + get_device_delay(state) * 1e6 + frame_count * 1e6 / state->format.Format.nSamplesPerSec)); hr = IAudioRenderClient_ReleaseBuffer(state->pRenderClient, frame_count, 0); EXIT_ON_ERROR(hr); atomic_fetch_add(&state->sample_count, frame_count); return; exit_label: MP_ERR(state, "thread_feed fails with %"PRIx32"!\n", (uint32_t)hr); return; }