diff options
Diffstat (limited to 'audio')
-rw-r--r-- | audio/filter/af_scaletempo2.c | 33 | ||||
-rw-r--r-- | audio/filter/af_scaletempo2_internals.c | 72 | ||||
-rw-r--r-- | audio/filter/af_scaletempo2_internals.h | 1 | ||||
-rw-r--r-- | audio/out/ao_coreaudio.c | 10 | ||||
-rw-r--r-- | audio/out/ao_coreaudio_chmap.c | 2 | ||||
-rw-r--r-- | audio/out/ao_coreaudio_chmap.h | 7 | ||||
-rw-r--r-- | audio/out/ao_coreaudio_properties.h | 5 | ||||
-rw-r--r-- | audio/out/ao_coreaudio_utils.c | 8 | ||||
-rw-r--r-- | audio/out/ao_coreaudio_utils.h | 9 | ||||
-rw-r--r-- | audio/out/ao_wasapi.c | 53 | ||||
-rw-r--r-- | audio/out/ao_wasapi.h | 2 |
11 files changed, 81 insertions, 121 deletions
diff --git a/audio/filter/af_scaletempo2.c b/audio/filter/af_scaletempo2.c index e43c29ac01..749e219454 100644 --- a/audio/filter/af_scaletempo2.c +++ b/audio/filter/af_scaletempo2.c @@ -8,7 +8,7 @@ #include "options/m_option.h" struct priv { - struct mp_scaletempo2 data; + struct mp_scaletempo2 *data; struct mp_pin *in_pin; struct mp_aframe *cur_format; struct mp_aframe_pool *out_pool; @@ -29,7 +29,7 @@ static void af_scaletempo2_process(struct mp_filter *f) return; while (!p->initialized || !p->pending || - !mp_scaletempo2_frames_available(&p->data, p->speed)) + !mp_scaletempo2_frames_available(p->data, p->speed)) { bool eof = false; if (!p->pending || !mp_aframe_get_size(p->pending)) { @@ -64,16 +64,16 @@ static void af_scaletempo2_process(struct mp_filter *f) if (p->pending && !format_change && !p->sent_final) { int frame_size = mp_aframe_get_size(p->pending); uint8_t **planes = mp_aframe_get_data_ro(p->pending); - int read = mp_scaletempo2_fill_input_buffer(&p->data, + int read = mp_scaletempo2_fill_input_buffer(p->data, planes, frame_size, p->speed); mp_aframe_skip_samples(p->pending, read); } if (final && p->pending && !p->sent_final) { - mp_scaletempo2_set_final(&p->data); + mp_scaletempo2_set_final(p->data); p->sent_final = true; } - if (mp_scaletempo2_frames_available(&p->data, p->speed)) { + if (mp_scaletempo2_frames_available(p->data, p->speed)) { if (eof) { mp_pin_out_repeat_eof(p->in_pin); // drain more next time } @@ -89,9 +89,9 @@ static void af_scaletempo2_process(struct mp_filter *f) } assert(p->pending); - if (mp_scaletempo2_frames_available(&p->data, p->speed)) { + if (mp_scaletempo2_frames_available(p->data, p->speed)) { struct mp_aframe *out = mp_aframe_new_ref(p->cur_format); - int out_samples = p->data.ola_hop_size; + int out_samples = p->data->ola_hop_size; if (mp_aframe_pool_allocate(p->out_pool, out, out_samples) < 0) { talloc_free(out); goto error; @@ -101,14 +101,14 @@ static void af_scaletempo2_process(struct mp_filter *f) uint8_t **planes = mp_aframe_get_data_rw(out); assert(planes); - assert(mp_aframe_get_planes(out) == p->data.channels); + assert(mp_aframe_get_planes(out) == p->data->channels); - out_samples = mp_scaletempo2_fill_buffer(&p->data, + out_samples = mp_scaletempo2_fill_buffer(p->data, (float**)planes, out_samples, p->speed); double pts = mp_aframe_get_pts(p->pending); if (pts != MP_NOPTS_VALUE) { - double frame_delay = mp_scaletempo2_get_latency(&p->data, p->speed) + double frame_delay = mp_scaletempo2_get_latency(p->data, p->speed) + out_samples * p->speed; mp_aframe_set_pts(out, pts - frame_delay / mp_aframe_get_effective_rate(out)); @@ -122,7 +122,7 @@ static void af_scaletempo2_process(struct mp_filter *f) // reset the filter to ensure it stops generating audio // and mp_scaletempo2_frames_available returns false - mp_scaletempo2_reset(&p->data); + mp_scaletempo2_reset(p->data); } } } @@ -150,7 +150,7 @@ static bool init_scaletempo2(struct mp_filter *f) p->sent_final = false; mp_aframe_config_copy(p->cur_format, p->pending); - mp_scaletempo2_init(&p->data, mp_aframe_get_channels(p->pending), + mp_scaletempo2_init(p->data, mp_aframe_get_channels(p->pending), mp_aframe_get_rate(p->pending)); return true; @@ -172,7 +172,7 @@ static bool af_scaletempo2_command(struct mp_filter *f, struct mp_filter_command static void af_scaletempo2_reset(struct mp_filter *f) { struct priv *p = f->priv; - mp_scaletempo2_reset(&p->data); + mp_scaletempo2_reset(p->data); p->initialized = false; TA_FREEP(&p->pending); } @@ -180,8 +180,8 @@ static void af_scaletempo2_reset(struct mp_filter *f) static void af_scaletempo2_destroy(struct mp_filter *f) { struct priv *p = f->priv; - mp_scaletempo2_destroy(&p->data); - talloc_free(p->pending); + TA_FREEP(&p->data); + TA_FREEP(&p->pending); } static const struct mp_filter_info af_scaletempo2_filter = { @@ -206,7 +206,8 @@ static struct mp_filter *af_scaletempo2_create( mp_filter_add_pin(f, MP_PIN_OUT, "out"); struct priv *p = f->priv; - p->data.opts = talloc_steal(p, options); + p->data = talloc_zero(p, struct mp_scaletempo2); + p->data->opts = talloc_steal(p, options); p->speed = 1.0; p->cur_format = talloc_steal(p, mp_aframe_create()); p->out_pool = mp_aframe_pool_create(p); diff --git a/audio/filter/af_scaletempo2_internals.c b/audio/filter/af_scaletempo2_internals.c index 924c0914b3..7f3a99638f 100644 --- a/audio/filter/af_scaletempo2_internals.c +++ b/audio/filter/af_scaletempo2_internals.c @@ -41,19 +41,15 @@ static bool in_interval(int n, struct interval q) return n >= q.lo && n <= q.hi; } -static float **realloc_2d(float **p, int x, int y) +static void alloc_sample_buffer(struct mp_scaletempo2 *p, float ***ptr, size_t size) { - float **array = realloc(p, sizeof(float*) * x + sizeof(float) * x * y); - float* data = (float*) (array + x); - for (int i = 0; i < x; ++i) { - array[i] = data + i * y; - } - return array; -} + talloc_free(*ptr); -static void zero_2d(float **a, int x, int y) -{ - memset(a + x, 0, sizeof(float) * x * y); + float **buff = talloc_array(p, float*, p->channels); + for (int i = 0; i < p->channels; ++i) { + buff[i] = talloc_array(buff, float, size); + } + *ptr = buff; } static void zero_2d_partial(float **a, int x, int y) @@ -480,12 +476,6 @@ static bool can_perform_wsola(struct mp_scaletempo2 *p, double playback_rate) return frames_needed(p, playback_rate) <= 0; } -static void resize_input_buffer(struct mp_scaletempo2 *p, int size) -{ - p->input_buffer_size = size; - p->input_buffer = realloc_2d(p->input_buffer, p->channels, size); -} - // pad end with silence until a wsola iteration can be performed static void add_input_buffer_final_silence(struct mp_scaletempo2 *p, double playback_rate) { @@ -493,11 +483,9 @@ static void add_input_buffer_final_silence(struct mp_scaletempo2 *p, double play if (needed <= 0) return; // no silence needed for iteration - int required_size = needed + p->input_buffer_frames; - if (required_size > p->input_buffer_size) - resize_input_buffer(p, required_size); - + int last_index = needed + p->input_buffer_frames - 1; for (int i = 0; i < p->channels; ++i) { + MP_TARRAY_GROW(p, p->input_buffer[i], last_index); float *ch_input = p->input_buffer[i]; for (int j = 0; j < needed; ++j) { ch_input[p->input_buffer_frames + j] = 0.0f; @@ -523,11 +511,9 @@ int mp_scaletempo2_fill_input_buffer(struct mp_scaletempo2 *p, if (read == 0) return 0; - int required_size = read + p->input_buffer_frames; - if (required_size > p->input_buffer_size) - resize_input_buffer(p, required_size); - + int last_index = read + p->input_buffer_frames - 1; for (int i = 0; i < p->channels; ++i) { + MP_TARRAY_GROW(p, p->input_buffer[i], last_index); memcpy(p->input_buffer[i] + p->input_buffer_frames, planes[i], read * sizeof(float)); } @@ -771,18 +757,6 @@ bool mp_scaletempo2_frames_available(struct mp_scaletempo2 *p, double playback_r || p->num_complete_frames > 0; } -void mp_scaletempo2_destroy(struct mp_scaletempo2 *p) -{ - free(p->ola_window); - free(p->transition_window); - free(p->wsola_output); - free(p->optimal_block); - free(p->search_block); - free(p->target_block); - free(p->input_buffer); - free(p->energy_candidate_blocks); -} - void mp_scaletempo2_reset(struct mp_scaletempo2 *p) { p->input_buffer_frames = 0; @@ -791,8 +765,6 @@ void mp_scaletempo2_reset(struct mp_scaletempo2 *p) p->output_time = 0.0; p->search_block_index = 0; p->target_block_index = 0; - // Clear the queue of decoded packets. - zero_2d(p->wsola_output, p->channels, p->wsola_output_size); p->num_complete_frames = 0; p->wsola_output_started = false; } @@ -847,28 +819,26 @@ void mp_scaletempo2_init(struct mp_scaletempo2 *p, int channels, int rate) // 1, ... |num_candidate_blocks| p->search_block_center_offset = p->num_candidate_blocks / 2 + (p->ola_window_size / 2 - 1); - p->ola_window = realloc(p->ola_window, sizeof(float) * p->ola_window_size); + MP_RESIZE_ARRAY(p, p->ola_window, p->ola_window_size); get_symmetric_hanning_window(p->ola_window_size, p->ola_window); - p->transition_window = realloc(p->transition_window, - sizeof(float) * p->ola_window_size * 2); + MP_RESIZE_ARRAY(p, p->transition_window, p->ola_window_size * 2); get_symmetric_hanning_window(2 * p->ola_window_size, p->transition_window); p->wsola_output_size = p->ola_window_size + p->ola_hop_size; - p->wsola_output = realloc_2d(p->wsola_output, p->channels, p->wsola_output_size); - // Initialize for overlap-and-add of the first block. - zero_2d(p->wsola_output, p->channels, p->wsola_output_size); + alloc_sample_buffer(p, &p->wsola_output, p->wsola_output_size); // Auxiliary containers. - p->optimal_block = realloc_2d(p->optimal_block, p->channels, p->ola_window_size); + alloc_sample_buffer(p, &p->optimal_block, p->ola_window_size); p->search_block_size = p->num_candidate_blocks + (p->ola_window_size - 1); - p->search_block = realloc_2d(p->search_block, p->channels, p->search_block_size); - p->target_block = realloc_2d(p->target_block, p->channels, p->ola_window_size); + alloc_sample_buffer(p, &p->search_block, p->search_block_size); + alloc_sample_buffer(p, &p->target_block, p->ola_window_size); - resize_input_buffer(p, 4 * MPMAX(p->ola_window_size, p->search_block_size)); p->input_buffer_frames = 0; p->input_buffer_final_frames = 0; p->input_buffer_added_silence = 0; + size_t initial_size = 4 * MPMAX(p->ola_window_size, p->search_block_size); + alloc_sample_buffer(p, &p->input_buffer, initial_size); - p->energy_candidate_blocks = realloc(p->energy_candidate_blocks, - sizeof(float) * p->channels * p->num_candidate_blocks); + MP_RESIZE_ARRAY(p, p->energy_candidate_blocks, + p->channels * p->num_candidate_blocks); } diff --git a/audio/filter/af_scaletempo2_internals.h b/audio/filter/af_scaletempo2_internals.h index 6c3c94c0a9..254d0a7704 100644 --- a/audio/filter/af_scaletempo2_internals.h +++ b/audio/filter/af_scaletempo2_internals.h @@ -110,7 +110,6 @@ struct mp_scaletempo2 { float **target_block; // Buffered audio data. float **input_buffer; - int input_buffer_size; int input_buffer_frames; // How many frames in |input_buffer| need to be flushed by padding with // silence to process the final packet. While this is nonzero, the filter diff --git a/audio/out/ao_coreaudio.c b/audio/out/ao_coreaudio.c index ae743c90b2..4abfac38ee 100644 --- a/audio/out/ao_coreaudio.c +++ b/audio/out/ao_coreaudio.c @@ -89,14 +89,8 @@ static OSStatus render_cb_lpcm(void *ctx, AudioUnitRenderActionFlags *aflags, int64_t end = mp_time_ns(); end += p->hw_latency_ns + ca_get_latency(ts) + ca_frames_to_ns(ao, frames); - int samples = ao_read_data(ao, planes, frames, end); - - if (samples == 0) - *aflags |= kAudioUnitRenderAction_OutputIsSilence; - - for (int n = 0; n < buffer_list->mNumberBuffers; n++) - buffer_list->mBuffers[n].mDataByteSize = samples * ao->sstride; - + // don't use the returned sample count since CoreAudio always expects full frames + ao_read_data(ao, planes, frames, end); return noErr; } diff --git a/audio/out/ao_coreaudio_chmap.c b/audio/out/ao_coreaudio_chmap.c index 5a129c4e67..b45cf7799c 100644 --- a/audio/out/ao_coreaudio_chmap.c +++ b/audio/out/ao_coreaudio_chmap.c @@ -195,7 +195,7 @@ AudioChannelLabel mp_speaker_id_to_ca_label(int speaker_id) return -1; // kAudioChannelLabel_Unknown } -#if HAVE_COREAUDIO +#if HAVE_COREAUDIO || HAVE_AVFOUNDATION void ca_log_layout(struct ao *ao, int l, AudioChannelLayout *layout) { if (!mp_msg_test(ao->log, l)) diff --git a/audio/out/ao_coreaudio_chmap.h b/audio/out/ao_coreaudio_chmap.h index 0b21e8330c..5286f98e63 100644 --- a/audio/out/ao_coreaudio_chmap.h +++ b/audio/out/ao_coreaudio_chmap.h @@ -21,17 +21,12 @@ #include "config.h" #include <AudioToolbox/AudioToolbox.h> -#if HAVE_AVFOUNDATION || HAVE_AUDIOUNIT -#undef HAVE_COREAUDIO -#define HAVE_COREAUDIO 1 -#endif - struct mp_chmap; int ca_label_to_mp_speaker_id(AudioChannelLabel label); AudioChannelLabel mp_speaker_id_to_ca_label(int speaker_id); -#if HAVE_COREAUDIO +#if HAVE_COREAUDIO || HAVE_AVFOUNDATION AudioChannelLayout *ca_find_standard_layout(void *talloc_ctx, AudioChannelLayout *l); void ca_log_layout(struct ao *ao, int l, AudioChannelLayout *layout); bool ca_init_chmap(struct ao *ao, AudioDeviceID device); diff --git a/audio/out/ao_coreaudio_properties.h b/audio/out/ao_coreaudio_properties.h index 2c9c5657bb..f29396883d 100644 --- a/audio/out/ao_coreaudio_properties.h +++ b/audio/out/ao_coreaudio_properties.h @@ -23,11 +23,6 @@ #include "internal.h" -#if HAVE_AVFOUNDATION || HAVE_AUDIOUNIT -#undef HAVE_COREAUDIO -#define HAVE_COREAUDIO 1 -#endif - // CoreAudio names are way too verbose #define ca_sel AudioObjectPropertySelector #define ca_scope AudioObjectPropertyScope diff --git a/audio/out/ao_coreaudio_utils.c b/audio/out/ao_coreaudio_utils.c index e74092a8d2..44604e6df2 100644 --- a/audio/out/ao_coreaudio_utils.c +++ b/audio/out/ao_coreaudio_utils.c @@ -28,14 +28,14 @@ #include "osdep/semaphore.h" #include "audio/format.h" -#if HAVE_COREAUDIO +#if HAVE_COREAUDIO || HAVE_AVFOUNDATION #include "audio/out/ao_coreaudio_properties.h" #include <CoreAudio/HostTime.h> #else #include <mach/mach_time.h> #endif -#if HAVE_COREAUDIO +#if HAVE_COREAUDIO || HAVE_AVFOUNDATION static bool ca_is_output_device(struct ao *ao, AudioDeviceID dev) { size_t n_buffers; @@ -300,7 +300,7 @@ int64_t ca_frames_to_ns(struct ao *ao, uint32_t frames) int64_t ca_get_latency(const AudioTimeStamp *ts) { -#if HAVE_COREAUDIO +#if HAVE_COREAUDIO || HAVE_AVFOUNDATION uint64_t out = AudioConvertHostTimeToNanos(ts->mHostTime); uint64_t now = AudioConvertHostTimeToNanos(AudioGetCurrentHostTime()); @@ -323,7 +323,7 @@ int64_t ca_get_latency(const AudioTimeStamp *ts) #endif } -#if HAVE_COREAUDIO +#if HAVE_COREAUDIO || HAVE_AVFOUNDATION bool ca_stream_supports_compressed(struct ao *ao, AudioStreamID stream) { AudioStreamRangedDescription *formats = NULL; diff --git a/audio/out/ao_coreaudio_utils.h b/audio/out/ao_coreaudio_utils.h index 699ffde9a7..d11506c059 100644 --- a/audio/out/ao_coreaudio_utils.h +++ b/audio/out/ao_coreaudio_utils.h @@ -29,11 +29,6 @@ #include "internal.h" #include "osdep/utils-mac.h" -#if HAVE_AVFOUNDATION || HAVE_AUDIOUNIT -#undef HAVE_COREAUDIO -#define HAVE_COREAUDIO 1 -#endif - bool check_ca_st(struct ao *ao, int level, OSStatus code, const char *message); #define CHECK_CA_ERROR_L(label, message) \ @@ -52,7 +47,7 @@ bool check_ca_st(struct ao *ao, int level, OSStatus code, const char *message); } while (0) void ca_get_device_list(struct ao *ao, struct ao_device_list *list); -#if HAVE_COREAUDIO +#if HAVE_COREAUDIO || HAVE_AVFOUNDATION OSStatus ca_select_device(struct ao *ao, char* name, AudioDeviceID *device); #endif @@ -70,7 +65,7 @@ bool ca_asbd_is_better(AudioStreamBasicDescription *req, int64_t ca_frames_to_ns(struct ao *ao, uint32_t frames); int64_t ca_get_latency(const AudioTimeStamp *ts); -#if HAVE_COREAUDIO +#if HAVE_COREAUDIO || HAVE_AVFOUNDATION bool ca_stream_supports_compressed(struct ao *ao, AudioStreamID stream); OSStatus ca_lock_device(AudioDeviceID device, pid_t *pid); OSStatus ca_unlock_device(AudioDeviceID device, pid_t *pid); diff --git a/audio/out/ao_wasapi.c b/audio/out/ao_wasapi.c index 58d2acd09a..34c3b6193f 100644 --- a/audio/out/ao_wasapi.c +++ b/audio/out/ao_wasapi.c @@ -193,17 +193,19 @@ static void thread_resume(struct ao *ao) thread_unpause(ao); } -static void set_state_and_wakeup_thread(struct ao *ao, - enum wasapi_thread_state thread_state) +static void thread_wakeup(void *ptr) { + struct ao *ao = ptr; struct wasapi_state *state = ao->priv; - atomic_store(&state->thread_state, thread_state); - SetEvent(state->hWake); + SetEvent(state->hUserWake); } -static void thread_process_dispatch(void *ptr) +static void set_thread_state(struct ao *ao, + enum wasapi_thread_state thread_state) { - set_state_and_wakeup_thread(ptr, WASAPI_THREAD_DISPATCH); + struct wasapi_state *state = ao->priv; + atomic_store(&state->thread_state, thread_state); + thread_wakeup(ao); } static DWORD __stdcall AudioThread(void *lpParameter) @@ -220,18 +222,25 @@ static DWORD __stdcall AudioThread(void *lpParameter) MP_DBG(ao, "Entering dispatch loop\n"); while (true) { - if (WaitForSingleObject(state->hWake, INFINITE) != WAIT_OBJECT_0) - MP_ERR(ao, "Unexpected return value from WaitForSingleObject\n"); - - int thread_state = atomic_load(&state->thread_state); - switch (thread_state) { - case WASAPI_THREAD_FEED: + HANDLE handles[] = {state->hWake, state->hUserWake}; + switch (WaitForMultipleObjects(MP_ARRAY_SIZE(handles), handles, FALSE, INFINITE)) { + case WAIT_OBJECT_0: // fill twice on under-full buffer (see comment in thread_feed) if (thread_feed(ao) && thread_feed(ao)) MP_ERR(ao, "Unable to fill buffer fast enough\n"); + continue; + case WAIT_OBJECT_0 + 1: break; - case WASAPI_THREAD_DISPATCH: - mp_dispatch_queue_process(state->dispatch, 0); + default: + MP_ERR(ao, "Unexpected return value from WaitForMultipleObjects\n"); + break; + } + + mp_dispatch_queue_process(state->dispatch, 0); + + int thread_state = atomic_load(&state->thread_state); + switch (thread_state) { + case WASAPI_THREAD_FEED: break; case WASAPI_THREAD_RESET: thread_reset(ao); @@ -267,8 +276,8 @@ static void uninit(struct ao *ao) { MP_DBG(ao, "Uninit wasapi\n"); struct wasapi_state *state = ao->priv; - if (state->hWake) - set_state_and_wakeup_thread(ao, WASAPI_THREAD_SHUTDOWN); + if (state->hWake && state->hUserWake) + set_thread_state(ao, WASAPI_THREAD_SHUTDOWN); if (state->hAudioThread && WaitForSingleObject(state->hAudioThread, INFINITE) != WAIT_OBJECT_0) @@ -279,6 +288,7 @@ static void uninit(struct ao *ao) SAFE_DESTROY(state->hInitDone, CloseHandle(state->hInitDone)); SAFE_DESTROY(state->hWake, CloseHandle(state->hWake)); + SAFE_DESTROY(state->hUserWake, CloseHandle(state->hUserWake)); SAFE_DESTROY(state->hAudioThread,CloseHandle(state->hAudioThread)); wasapi_change_uninit(ao); @@ -312,14 +322,15 @@ static int init(struct ao *ao) state->hInitDone = CreateEventW(NULL, FALSE, FALSE, NULL); state->hWake = CreateEventW(NULL, FALSE, FALSE, NULL); - if (!state->hInitDone || !state->hWake) { + state->hUserWake = CreateEventW(NULL, FALSE, FALSE, NULL); + if (!state->hInitDone || !state->hWake || !state->hUserWake) { MP_FATAL(ao, "Error creating events\n"); uninit(ao); return -1; } state->dispatch = mp_dispatch_create(state); - mp_dispatch_set_wakeup_fn(state->dispatch, thread_process_dispatch, ao); + mp_dispatch_set_wakeup_fn(state->dispatch, thread_wakeup, ao); state->init_ok = false; state->hAudioThread = CreateThread(NULL, 0, &AudioThread, ao, 0, NULL); @@ -474,17 +485,17 @@ static int control(struct ao *ao, enum aocontrol cmd, void *arg) static void audio_reset(struct ao *ao) { - set_state_and_wakeup_thread(ao, WASAPI_THREAD_RESET); + set_thread_state(ao, WASAPI_THREAD_RESET); } static void audio_resume(struct ao *ao) { - set_state_and_wakeup_thread(ao, WASAPI_THREAD_RESUME); + set_thread_state(ao, WASAPI_THREAD_RESUME); } static bool audio_set_pause(struct ao *ao, bool paused) { - set_state_and_wakeup_thread(ao, paused ? WASAPI_THREAD_PAUSE : WASAPI_THREAD_UNPAUSE); + set_thread_state(ao, paused ? WASAPI_THREAD_PAUSE : WASAPI_THREAD_UNPAUSE); return true; } diff --git a/audio/out/ao_wasapi.h b/audio/out/ao_wasapi.h index e294e317c3..cbd4a3f933 100644 --- a/audio/out/ao_wasapi.h +++ b/audio/out/ao_wasapi.h @@ -48,7 +48,6 @@ void wasapi_change_uninit(struct ao* ao); enum wasapi_thread_state { WASAPI_THREAD_FEED = 0, - WASAPI_THREAD_DISPATCH, WASAPI_THREAD_RESUME, WASAPI_THREAD_RESET, WASAPI_THREAD_SHUTDOWN, @@ -66,6 +65,7 @@ typedef struct wasapi_state { HANDLE hWake; // thread wakeup event atomic_int thread_state; // enum wasapi_thread_state (what to do on wakeup) struct mp_dispatch_queue *dispatch; // for volume/mute/session display + HANDLE hUserWake; // mpv-requested wakeup event // for setting the audio thread priority HANDLE hTask; |