diff options
Diffstat (limited to 'audio/out')
-rw-r--r-- | audio/out/ao_alsa.c | 78 | ||||
-rw-r--r-- | audio/out/ao_coreaudio.c | 5 | ||||
-rw-r--r-- | audio/out/ao_coreaudio_utils.c | 27 | ||||
-rw-r--r-- | audio/out/ao_coreaudio_utils.h | 1 | ||||
-rw-r--r-- | audio/out/ao_lavc.c | 82 | ||||
-rw-r--r-- | audio/out/ao_opensles.c | 1 | ||||
-rw-r--r-- | audio/out/ao_oss.c | 2 | ||||
-rw-r--r-- | audio/out/ao_wasapi.c | 4 | ||||
-rw-r--r-- | audio/out/ao_wasapi_changenotify.c | 1 | ||||
-rw-r--r-- | audio/out/push.c | 27 |
10 files changed, 136 insertions, 92 deletions
diff --git a/audio/out/ao_alsa.c b/audio/out/ao_alsa.c index 9ffd4792ee..d09f5fc499 100644 --- a/audio/out/ao_alsa.c +++ b/audio/out/ao_alsa.c @@ -58,6 +58,8 @@ struct priv { snd_pcm_uframes_t buffersize; snd_pcm_uframes_t outburst; + snd_output_t *output; + char *cfg_device; char *cfg_mixer_device; char *cfg_mixer_name; @@ -477,6 +479,22 @@ static int set_chmap(struct ao *ao, struct mp_chmap *dev_chmap, int num_channels #endif /* else HAVE_CHMAP_API */ +static void dump_hw_params(struct ao *ao, int msglevel, const char *msg, + snd_pcm_hw_params_t *hw_params) +{ + struct priv *p = ao->priv; + int err; + + err = snd_pcm_hw_params_dump(hw_params, p->output); + CHECK_ALSA_WARN("Dump hwparams error"); + + char *tmp = NULL; + size_t tmp_s = snd_output_buffer_string(p->output, &tmp); + if (tmp) + mp_msg(ao->log, msglevel, "%s---\n%.*s---\n", msg, (int)tmp_s, tmp); + snd_output_flush(p->output); +} + static int map_iec958_srate(int srate) { switch (srate) { @@ -520,7 +538,7 @@ static char *append_params(void *ta_parent, const char *device, const char *p) abort(); } -static int try_open_device(struct ao *ao, const char *device) +static int try_open_device(struct ao *ao, const char *device, int mode) { struct priv *p = ao->priv; int err; @@ -534,7 +552,7 @@ static int try_open_device(struct ao *ao, const char *device) map_iec958_srate(ao->samplerate)); const char *ac3_device = append_params(tmp, device, params); MP_VERBOSE(ao, "opening device '%s' => '%s'\n", device, ac3_device); - err = snd_pcm_open(&p->alsa, ac3_device, SND_PCM_STREAM_PLAYBACK, 0); + err = snd_pcm_open(&p->alsa, ac3_device, SND_PCM_STREAM_PLAYBACK, mode); if (err < 0) { // Some spdif-capable devices do not accept the AES0 parameter, // and instead require the iec958 pseudo-device (they will play @@ -547,13 +565,13 @@ static int try_open_device(struct ao *ao, const char *device) MP_VERBOSE(ao, "got error %d; opening iec fallback device '%s'\n", err, ac3_device); err = snd_pcm_open - (&p->alsa, ac3_device, SND_PCM_STREAM_PLAYBACK, 0); + (&p->alsa, ac3_device, SND_PCM_STREAM_PLAYBACK, mode); } } talloc_free(tmp); } else { MP_VERBOSE(ao, "opening device '%s'\n", device); - err = snd_pcm_open(&p->alsa, device, SND_PCM_STREAM_PLAYBACK, 0); + err = snd_pcm_open(&p->alsa, device, SND_PCM_STREAM_PLAYBACK, mode); } return err; @@ -563,6 +581,10 @@ static void uninit(struct ao *ao) { struct priv *p = ao->priv; + if (p->output) + snd_output_close(p->output); + p->output = NULL; + if (p->alsa) { int err; @@ -574,20 +596,35 @@ static void uninit(struct ao *ao) alsa_error: ; } -static int init_device(struct ao *ao) +#define INIT_DEVICE_ERR_GENERIC -1 +#define INIT_DEVICE_ERR_HWPARAMS -2 +static int init_device(struct ao *ao, int mode) { struct priv *p = ao->priv; + int ret = INIT_DEVICE_ERR_GENERIC; + char *tmp; + size_t tmp_s; int err; + err = snd_output_buffer_open(&p->output); + CHECK_ALSA_ERROR("Unable to create output buffer"); + const char *device = "default"; if (ao->device) device = ao->device; if (p->cfg_device && p->cfg_device[0]) device = p->cfg_device; - err = try_open_device(ao, device); + err = try_open_device(ao, device, mode); CHECK_ALSA_ERROR("Playback open error"); + err = snd_pcm_dump(p->alsa, p->output); + CHECK_ALSA_WARN("Dump PCM error"); + tmp_s = snd_output_buffer_string(p->output, &tmp); + if (tmp) + MP_DBG(ao, "PCM setup:\n---\n%.*s---\n", (int)tmp_s, tmp); + snd_output_flush(p->output); + err = snd_pcm_nonblock(p->alsa, 0); CHECK_ALSA_WARN("Unable to set blocking mode"); @@ -597,12 +634,15 @@ static int init_device(struct ao *ao) err = snd_pcm_hw_params_any(p->alsa, alsa_hwparams); CHECK_ALSA_ERROR("Unable to get initial parameters"); + dump_hw_params(ao, MSGL_DEBUG, "Start HW params:\n", alsa_hwparams); + // Some ALSA drivers have broken delay reporting, so disable the ALSA // resampling plugin by default. if (!p->cfg_resample) { err = snd_pcm_hw_params_set_rate_resample(p->alsa, alsa_hwparams, 0); CHECK_ALSA_ERROR("Unable to disable resampling"); } + dump_hw_params(ao, MSGL_DEBUG, "HW params after rate:\n", alsa_hwparams); snd_pcm_access_t access = af_fmt_is_planar(ao->format) ? SND_PCM_ACCESS_RW_NONINTERLEAVED @@ -614,6 +654,7 @@ static int init_device(struct ao *ao) err = snd_pcm_hw_params_set_access(p->alsa, alsa_hwparams, access); } CHECK_ALSA_ERROR("Unable to set access type"); + dump_hw_params(ao, MSGL_DEBUG, "HW params after access:\n", alsa_hwparams); bool found_format = false; int try_formats[AF_FORMAT_COUNT]; @@ -637,6 +678,7 @@ static int init_device(struct ao *ao) err = snd_pcm_hw_params_set_format(p->alsa, alsa_hwparams, p->alsa_fmt); CHECK_ALSA_ERROR("Unable to set format"); + dump_hw_params(ao, MSGL_DEBUG, "HW params after format:\n", alsa_hwparams); struct mp_chmap dev_chmap = ao->channels; if (af_fmt_is_spdif(ao->format) || p->cfg_ignore_chmap) { @@ -656,6 +698,7 @@ static int init_device(struct ao *ao) err = snd_pcm_hw_params_set_channels_near (p->alsa, alsa_hwparams, &num_channels); CHECK_ALSA_ERROR("Unable to set channels"); + dump_hw_params(ao, MSGL_DEBUG, "HW params after channels:\n", alsa_hwparams); if (num_channels > MP_NUM_CHANNELS) { MP_FATAL(ao, "Too many audio channels (%d).\n", num_channels); @@ -665,6 +708,7 @@ static int init_device(struct ao *ao) err = snd_pcm_hw_params_set_rate_near (p->alsa, alsa_hwparams, &ao->samplerate, NULL); CHECK_ALSA_ERROR("Unable to set samplerate-2"); + dump_hw_params(ao, MSGL_DEBUG, "HW params after rate-2:\n", alsa_hwparams); snd_pcm_hw_params_t *hwparams_backup; snd_pcm_hw_params_alloca(&hwparams_backup); @@ -682,9 +726,14 @@ static int init_device(struct ao *ao) if (err < 0) snd_pcm_hw_params_copy(alsa_hwparams, hwparams_backup); + dump_hw_params(ao, MSGL_V, "Going to set final HW params:\n", alsa_hwparams); + /* finally install hardware parameters */ err = snd_pcm_hw_params(p->alsa, alsa_hwparams); + ret = INIT_DEVICE_ERR_HWPARAMS; CHECK_ALSA_ERROR("Unable to set hw-parameters"); + ret = INIT_DEVICE_ERR_GENERIC; + dump_hw_params(ao, MSGL_DEBUG, "Final HW params:\n", alsa_hwparams); if (set_chmap(ao, &dev_chmap, num_channels) < 0) goto alsa_error; @@ -740,7 +789,7 @@ static int init_device(struct ao *ao) alsa_error: uninit(ao); - return -1; + return ret; } static int init(struct ao *ao) @@ -751,7 +800,18 @@ static int init(struct ao *ao) MP_VERBOSE(ao, "using ALSA version: %s\n", snd_asoundlib_version()); - int r = init_device(ao); + int mode = 0; + int r = init_device(ao, mode); + if (r == INIT_DEVICE_ERR_HWPARAMS) { + // With some drivers, ALSA appears to be unable to set valid hwparams, + // but they work if at least SND_PCM_NO_AUTO_FORMAT is set. Also, it + // appears you can set this flag only on opening a device, thus there + // is the need to retry opening the device. + MP_WARN(ao, "Attempting to work around even more ALSA bugs...\n"); + mode |= SND_PCM_NO_AUTO_CHANNELS | SND_PCM_NO_AUTO_FORMAT | + SND_PCM_NO_AUTO_RESAMPLE; + r = init_device(ao, mode); + } // Sometimes, ALSA will advertise certain chmaps, but it's not possible to // set them. This can happen with dmix: as of alsa 1.0.29, dmix can do @@ -773,7 +833,7 @@ static int init(struct ao *ao) MP_VERBOSE(ao, "Working around braindead dmix multichannel behavior.\n"); uninit(ao); ao->channels = without_na; - r = init_device(ao); + r = init_device(ao, mode); } } diff --git a/audio/out/ao_coreaudio.c b/audio/out/ao_coreaudio.c index 471ab6d928..b0a5dc0da1 100644 --- a/audio/out/ao_coreaudio.c +++ b/audio/out/ao_coreaudio.c @@ -133,11 +133,6 @@ static bool reinit_device(struct ao *ao) { OSStatus err = ca_select_device(ao, ao->device, &p->device); CHECK_CA_ERROR("failed to select device"); - char *uid; - err = CA_GET_STR(p->device, kAudioDevicePropertyDeviceUID, &uid); - CHECK_CA_ERROR("failed to get device UID"); - ao->detected_device = talloc_steal(ao, uid); - return true; coreaudio_error: diff --git a/audio/out/ao_coreaudio_utils.c b/audio/out/ao_coreaudio_utils.c index 6b5d8a7195..8f9690fc22 100644 --- a/audio/out/ao_coreaudio_utils.c +++ b/audio/out/ao_coreaudio_utils.c @@ -323,6 +323,9 @@ bool ca_stream_supports_compressed(struct ao *ao, AudioStreamID stream) for (int i = 0; i < n_formats; i++) { AudioStreamBasicDescription asbd = formats[i].mFormat; + + ca_print_asbd(ao, "- ", &asbd); + if (ca_formatid_is_compressed(asbd.mFormatID)) { talloc_free(formats); return true; @@ -334,30 +337,6 @@ coreaudio_error: return false; } -bool ca_device_supports_compressed(struct ao *ao, AudioDeviceID device) -{ - AudioStreamID *streams = NULL; - size_t n_streams; - - /* Retrieve all the output streams. */ - OSStatus err = - CA_GET_ARY_O(device, kAudioDevicePropertyStreams, &streams, &n_streams); - - CHECK_CA_ERROR("could not get number of streams."); - - for (int i = 0; i < n_streams; i++) { - if (ca_stream_supports_compressed(ao, streams[i])) { - talloc_free(streams); - return true; - } - } - - talloc_free(streams); - -coreaudio_error: - return false; -} - OSStatus ca_lock_device(AudioDeviceID device, pid_t *pid) { *pid = getpid(); diff --git a/audio/out/ao_coreaudio_utils.h b/audio/out/ao_coreaudio_utils.h index 780c56864b..5cc7db53be 100644 --- a/audio/out/ao_coreaudio_utils.h +++ b/audio/out/ao_coreaudio_utils.h @@ -65,7 +65,6 @@ bool ca_asbd_is_better(AudioStreamBasicDescription *req, int64_t ca_frames_to_us(struct ao *ao, uint32_t frames); int64_t ca_get_latency(const AudioTimeStamp *ts); -bool ca_device_supports_compressed(struct ao *ao, AudioDeviceID device); 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_lavc.c b/audio/out/ao_lavc.c index bf1728682a..572874d27c 100644 --- a/audio/out/ao_lavc.c +++ b/audio/out/ao_lavc.c @@ -42,6 +42,7 @@ struct priv { uint8_t *buffer; size_t buffer_size; AVStream *stream; + AVCodecContext *codec; int pcmhack; int aframesize; int aframecount; @@ -98,15 +99,14 @@ static int init(struct ao *ao) pthread_mutex_lock(&ao->encode_lavc_ctx->lock); - ac->stream = encode_lavc_alloc_stream(ao->encode_lavc_ctx, - AVMEDIA_TYPE_AUDIO); - - if (!ac->stream) { - MP_ERR(ao, "could not get a new audio stream\n"); - goto fail; + if (encode_lavc_alloc_stream(ao->encode_lavc_ctx, + AVMEDIA_TYPE_AUDIO, + &ac->stream, &ac->codec) < 0) { + MP_ERR(ao, "could not get a new audio stream\n"); + goto fail; } - codec = encode_lavc_get_codec(ao->encode_lavc_ctx, ac->stream); + codec = ao->encode_lavc_ctx->ac; int samplerate = af_select_best_samplerate(ao->samplerate, codec->supported_samplerates); @@ -118,40 +118,40 @@ static int init(struct ao *ao) // Using codec->time_bvase is deprecated, but needed for older lavf. ac->stream->time_base.num = 1; ac->stream->time_base.den = ao->samplerate; - ac->stream->codec->time_base.num = 1; - ac->stream->codec->time_base.den = ao->samplerate; + ac->codec->time_base.num = 1; + ac->codec->time_base.den = ao->samplerate; - ac->stream->codec->sample_rate = ao->samplerate; + ac->codec->sample_rate = ao->samplerate; struct mp_chmap_sel sel = {0}; mp_chmap_sel_add_any(&sel); if (!ao_chmap_sel_adjust(ao, &sel, &ao->channels)) goto fail; mp_chmap_reorder_to_lavc(&ao->channels); - ac->stream->codec->channels = ao->channels.num; - ac->stream->codec->channel_layout = mp_chmap_to_lavc(&ao->channels); + ac->codec->channels = ao->channels.num; + ac->codec->channel_layout = mp_chmap_to_lavc(&ao->channels); - ac->stream->codec->sample_fmt = AV_SAMPLE_FMT_NONE; + ac->codec->sample_fmt = AV_SAMPLE_FMT_NONE; select_format(ao, codec); ac->sample_size = af_fmt_to_bytes(ao->format); - ac->stream->codec->sample_fmt = af_to_avformat(ao->format); - ac->stream->codec->bits_per_raw_sample = ac->sample_size * 8; + ac->codec->sample_fmt = af_to_avformat(ao->format); + ac->codec->bits_per_raw_sample = ac->sample_size * 8; - if (encode_lavc_open_codec(ao->encode_lavc_ctx, ac->stream) < 0) + if (encode_lavc_open_codec(ao->encode_lavc_ctx, ac->codec) < 0) goto fail; ac->pcmhack = 0; - if (ac->stream->codec->frame_size <= 1) - ac->pcmhack = av_get_bits_per_sample(ac->stream->codec->codec_id) / 8; + if (ac->codec->frame_size <= 1) + ac->pcmhack = av_get_bits_per_sample(ac->codec->codec_id) / 8; if (ac->pcmhack) { ac->aframesize = 16384; // "enough" ac->buffer_size = ac->aframesize * ac->pcmhack * ao->channels.num * 2 + 200; } else { - ac->aframesize = ac->stream->codec->frame_size; + ac->aframesize = ac->codec->frame_size; ac->buffer_size = ac->aframesize * ac->sample_size * ao->channels.num * 2 + 200; } @@ -203,7 +203,7 @@ static void uninit(struct ao *ao) double outpts = ac->expected_next_pts; if (!ectx->options->rawts && ectx->options->copyts) outpts += ectx->discontinuity_pts_offset; - outpts += encode_lavc_getoffset(ectx, ac->stream); + outpts += encode_lavc_getoffset(ectx, ac->codec); while (encode(ao, outpts, NULL) > 0) ; } @@ -252,25 +252,25 @@ static int encode(struct ao *ao, double apts, void **data) if (ectx->options->rawts || ectx->options->copyts) { // real audio pts - frame->pts = floor(apts * ac->stream->codec->time_base.den / ac->stream->codec->time_base.num + 0.5); + frame->pts = floor(apts * ac->codec->time_base.den / ac->codec->time_base.num + 0.5); } else { // audio playback time - frame->pts = floor(realapts * ac->stream->codec->time_base.den / ac->stream->codec->time_base.num + 0.5); + frame->pts = floor(realapts * ac->codec->time_base.den / ac->codec->time_base.num + 0.5); } - int64_t frame_pts = av_rescale_q(frame->pts, ac->stream->codec->time_base, ac->worst_time_base); + int64_t frame_pts = av_rescale_q(frame->pts, ac->codec->time_base, ac->worst_time_base); if (ac->lastpts != AV_NOPTS_VALUE && frame_pts <= ac->lastpts) { // this indicates broken video // (video pts failing to increase fast enough to match audio) MP_WARN(ao, "audio frame pts went backwards (%d <- %d), autofixed\n", (int)frame->pts, (int)ac->lastpts); frame_pts = ac->lastpts + 1; - frame->pts = av_rescale_q(frame_pts, ac->worst_time_base, ac->stream->codec->time_base); + frame->pts = av_rescale_q(frame_pts, ac->worst_time_base, ac->codec->time_base); } ac->lastpts = frame_pts; - frame->quality = ac->stream->codec->global_quality; - status = avcodec_encode_audio2(ac->stream->codec, &packet, frame, &gotpacket); + frame->quality = ac->codec->global_quality; + status = avcodec_encode_audio2(ac->codec, &packet, frame, &gotpacket); if (!status) { if (ac->savepts == AV_NOPTS_VALUE) @@ -281,7 +281,7 @@ static int encode(struct ao *ao, double apts, void **data) } else { - status = avcodec_encode_audio2(ac->stream->codec, &packet, NULL, &gotpacket); + status = avcodec_encode_audio2(ac->codec, &packet, NULL, &gotpacket); } if(status) { @@ -295,7 +295,7 @@ static int encode(struct ao *ao, double apts, void **data) MP_DBG(ao, "got pts %f (playback time: %f); out size: %d\n", apts, realapts, packet.size); - encode_lavc_write_stats(ao->encode_lavc_ctx, ac->stream); + encode_lavc_write_stats(ao->encode_lavc_ctx, ac->codec); packet.stream_index = ac->stream->index; @@ -307,20 +307,20 @@ static int encode(struct ao *ao, double apts, void **data) } if (packet.pts != AV_NOPTS_VALUE) - packet.pts = av_rescale_q(packet.pts, ac->stream->codec->time_base, + packet.pts = av_rescale_q(packet.pts, ac->codec->time_base, ac->stream->time_base); if (packet.dts != AV_NOPTS_VALUE) - packet.dts = av_rescale_q(packet.dts, ac->stream->codec->time_base, + packet.dts = av_rescale_q(packet.dts, ac->codec->time_base, ac->stream->time_base); if(packet.duration > 0) - packet.duration = av_rescale_q(packet.duration, ac->stream->codec->time_base, + packet.duration = av_rescale_q(packet.duration, ac->codec->time_base, ac->stream->time_base); ac->savepts = AV_NOPTS_VALUE; - if (encode_lavc_write_frame(ao->encode_lavc_ctx, &packet) < 0) { + if (encode_lavc_write_frame(ao->encode_lavc_ctx, ac->stream, &packet) < 0) { MP_ERR(ao, "error writing at %f %f/%f\n", realapts, (double) ac->stream->time_base.num, (double) ac->stream->time_base.den); @@ -377,22 +377,22 @@ static int play(struct ao *ao, void **data, int samples, int flags) } if (ac->worst_time_base.den == 0) { - //if (ac->stream->codec->time_base.num / ac->stream->codec->time_base.den >= ac->stream->time_base.num / ac->stream->time_base.den) - if (ac->stream->codec->time_base.num * (double) ac->stream->time_base.den >= - ac->stream->time_base.num * (double) ac->stream->codec->time_base.den) { + //if (ac->codec->time_base.num / ac->codec->time_base.den >= ac->stream->time_base.num / ac->stream->time_base.den) + if (ac->codec->time_base.num * (double) ac->stream->time_base.den >= + ac->stream->time_base.num * (double) ac->codec->time_base.den) { MP_VERBOSE(ao, "NOTE: using codec time base (%d/%d) for pts " "adjustment; the stream base (%d/%d) is not worse.\n", - (int)ac->stream->codec->time_base.num, - (int)ac->stream->codec->time_base.den, + (int)ac->codec->time_base.num, + (int)ac->codec->time_base.den, (int)ac->stream->time_base.num, (int)ac->stream->time_base.den); - ac->worst_time_base = ac->stream->codec->time_base; + ac->worst_time_base = ac->codec->time_base; ac->worst_time_base_is_stream = 0; } else { MP_WARN(ao, "NOTE: not using codec time base (%d/%d) for pts " "adjustment; the stream base (%d/%d) is worse.\n", - (int)ac->stream->codec->time_base.num, - (int)ac->stream->codec->time_base.den, + (int)ac->codec->time_base.num, + (int)ac->codec->time_base.den, (int)ac->stream->time_base.num, (int)ac->stream->time_base.den); ac->worst_time_base = ac->stream->time_base; @@ -437,7 +437,7 @@ static int play(struct ao *ao, void **data, int samples, int flags) } // Shift pts by the pts offset first. - outpts += encode_lavc_getoffset(ectx, ac->stream); + outpts += encode_lavc_getoffset(ectx, ac->codec); while (samples - bufpos >= ac->aframesize) { void *start[MP_NUM_CHANNELS] = {0}; diff --git a/audio/out/ao_opensles.c b/audio/out/ao_opensles.c index 0e80829557..2ce7b01552 100644 --- a/audio/out/ao_opensles.c +++ b/audio/out/ao_opensles.c @@ -46,7 +46,6 @@ struct priv { static const int fmtmap[][2] = { { AF_FORMAT_U8, SL_PCMSAMPLEFORMAT_FIXED_8 }, { AF_FORMAT_S16, SL_PCMSAMPLEFORMAT_FIXED_16 }, - { AF_FORMAT_S32, SL_PCMSAMPLEFORMAT_FIXED_32 }, { 0 } }; diff --git a/audio/out/ao_oss.c b/audio/out/ao_oss.c index 393c9db780..3216d673e1 100644 --- a/audio/out/ao_oss.c +++ b/audio/out/ao_oss.c @@ -462,7 +462,7 @@ static int init(struct ao *ao) p->buffersize = 0; memset(data, 0, p->outburst); while (p->buffersize < 0x40000 && device_writable(ao) > 0) { - write(p->audio_fd, data, p->outburst); + (void)write(p->audio_fd, data, p->outburst); p->buffersize += p->outburst; } free(data); diff --git a/audio/out/ao_wasapi.c b/audio/out/ao_wasapi.c index eecfded9e1..ae6bd3d9dc 100644 --- a/audio/out/ao_wasapi.c +++ b/audio/out/ao_wasapi.c @@ -270,7 +270,7 @@ static void uninit(struct ao *ao) static int init(struct ao *ao) { MP_DBG(ao, "Init wasapi\n"); - CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); + CoInitializeEx(NULL, COINIT_MULTITHREADED); struct wasapi_state *state = ao->priv; state->log = ao->log; @@ -469,7 +469,7 @@ static int hotplug_init(struct ao *ao) MP_DBG(ao, "Hotplug init\n"); struct wasapi_state *state = ao->priv; state->log = ao->log; - CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); + CoInitializeEx(NULL, COINIT_MULTITHREADED); HRESULT hr = wasapi_change_init(ao, true); EXIT_ON_ERROR(hr); diff --git a/audio/out/ao_wasapi_changenotify.c b/audio/out/ao_wasapi_changenotify.c index 661e957bcc..e3ca4e4936 100644 --- a/audio/out/ao_wasapi_changenotify.c +++ b/audio/out/ao_wasapi_changenotify.c @@ -17,6 +17,7 @@ * License along with mpv. If not, see <http://www.gnu.org/licenses/>. */ +#include <initguid.h> #include <wchar.h> #include "ao_wasapi.h" diff --git a/audio/out/push.c b/audio/out/push.c index 4fa2bc53d5..ac87c62a96 100644 --- a/audio/out/push.c +++ b/audio/out/push.c @@ -142,6 +142,7 @@ static void resume(struct ao *ao) static void drain(struct ao *ao) { struct ao_push_state *p = ao->api_priv; + double maxbuffer = ao->buffer / (double)ao->samplerate + 1; MP_VERBOSE(ao, "draining...\n"); @@ -151,14 +152,23 @@ static void drain(struct ao *ao) p->final_chunk = true; wakeup_playthread(ao); - while (p->still_playing && mp_audio_buffer_samples(p->buffer) > 0) - pthread_cond_wait(&p->wakeup, &p->lock); + + // Wait until everything is done. Since the audio API (especially ALSA) + // can't be trusted to do this right, and we're hard-blocking here, apply + // an upper bound timeout. + struct timespec until = mp_rel_time_to_timespec(maxbuffer); + while (p->still_playing && mp_audio_buffer_samples(p->buffer) > 0) { + if (pthread_cond_timedwait(&p->wakeup, &p->lock, &until)) { + MP_WARN(ao, "Draining is taking too long, aborting.\n"); + goto done; + } + } if (ao->driver->drain) { ao->driver->drain(ao); } else { double time = unlocked_get_delay(ao); - mp_sleep_us(MPMIN(time, ao->buffer / (double)ao->samplerate + 1) * 1e6); + mp_sleep_us(MPMIN(time, maxbuffer) * 1e6); } done: @@ -292,11 +302,12 @@ static void ao_play_data(struct ao *ao) // If we just filled the AO completely (r == space), don't refill for a // while. Prevents wakeup feedback with byte-granular AOs. int needed = unlocked_get_space(ao); - bool more = needed >= (r == space ? ao->device_buffer / 4 : 1) && !stuck; + bool more = needed >= (r == space ? ao->device_buffer / 4 : 1) && !stuck && + !(flags & AOPLAY_FINAL_CHUNK); if (more) mp_input_wakeup(ao->input_ctx); // request more data - MP_TRACE(ao, "in=%d flags=%d space=%d r=%d wa=%d needed=%d more=%d\n", - max, flags, space, r, p->wait_on_ao, needed, more); + MP_TRACE(ao, "in=%d flags=%d space=%d r=%d wa/pl=%d/%d needed=%d more=%d\n", + max, flags, space, r, p->wait_on_ao, p->still_playing, needed, more); } static void *playthread(void *arg) @@ -489,7 +500,7 @@ int ao_wait_poll(struct ao *ao, struct pollfd *fds, int num_fds, // flush the wakeup pipe contents - might "drown" some wakeups, but // that's ok for our use-case char buf[100]; - read(p->wakeup_pipe[0], buf, sizeof(buf)); + (void)read(p->wakeup_pipe[0], buf, sizeof(buf)); } return (r >= 0 || r == -EINTR) ? wakeup : -1; } @@ -499,7 +510,7 @@ void ao_wakeup_poll(struct ao *ao) assert(ao->api == &ao_api_push); struct ao_push_state *p = ao->api_priv; - write(p->wakeup_pipe[1], &(char){0}, 1); + (void)write(p->wakeup_pipe[1], &(char){0}, 1); } #endif |