summaryrefslogtreecommitdiffstats
path: root/audio/out
diff options
context:
space:
mode:
Diffstat (limited to 'audio/out')
-rw-r--r--audio/out/ao.c5
-rw-r--r--audio/out/ao_coreaudio_utils.c7
-rw-r--r--audio/out/ao_lavc.c197
-rw-r--r--audio/out/ao_oss.c7
-rw-r--r--audio/out/ao_wasapi.c2
-rw-r--r--audio/out/ao_wasapi_changenotify.c2
6 files changed, 139 insertions, 81 deletions
diff --git a/audio/out/ao.c b/audio/out/ao.c
index 9c0f644c75..c9d8f42b4a 100644
--- a/audio/out/ao.c
+++ b/audio/out/ao.c
@@ -490,10 +490,9 @@ struct ao_hotplug *ao_hotplug_create(struct mpv_global *global,
static void get_devices(struct ao *ao, struct ao_device_list *list)
{
int num = list->num_devices;
- if (ao->driver->list_devs)
+ if (ao->driver->list_devs) {
ao->driver->list_devs(ao, list);
- // Add at least a default entry
- if (list->num_devices == num) {
+ } else {
char name[80] = "Default";
if (num > 1)
mp_snprintf_cat(name, sizeof(name), " (%s)", ao->driver->name);
diff --git a/audio/out/ao_coreaudio_utils.c b/audio/out/ao_coreaudio_utils.c
index 8f9690fc22..0bcc0d62a1 100644
--- a/audio/out/ao_coreaudio_utils.c
+++ b/audio/out/ao_coreaudio_utils.c
@@ -114,6 +114,13 @@ OSStatus ca_select_device(struct ao *ao, char* name, AudioDeviceID *device)
kAudioObjectSystemObject, &p_addr, 0, 0, &size, &v);
CFRelease(uid);
CHECK_CA_ERROR("unable to query for device UID");
+
+ uint32_t is_alive = 1;
+ err = CA_GET(*device, kAudioDevicePropertyDeviceIsAlive, &is_alive);
+ CHECK_CA_ERROR("could not check whether device is alive (invalid device?)");
+
+ if (!is_alive)
+ MP_WARN(ao, "device is not alive!\n");
} else {
// device not set by user, get the default one
err = CA_GET(kAudioObjectSystemObject,
diff --git a/audio/out/ao_lavc.c b/audio/out/ao_lavc.c
index 572874d27c..6b4279ca87 100644
--- a/audio/out/ao_lavc.c
+++ b/audio/out/ao_lavc.c
@@ -39,8 +39,6 @@
#include "common/encode_lavc.h"
struct priv {
- uint8_t *buffer;
- size_t buffer_size;
AVStream *stream;
AVCodecContext *codec;
int pcmhack;
@@ -146,18 +144,10 @@ static int init(struct ao *ao)
if (ac->codec->frame_size <= 1)
ac->pcmhack = av_get_bits_per_sample(ac->codec->codec_id) / 8;
- if (ac->pcmhack) {
+ if (ac->pcmhack)
ac->aframesize = 16384; // "enough"
- ac->buffer_size =
- ac->aframesize * ac->pcmhack * ao->channels.num * 2 + 200;
- } else {
+ else
ac->aframesize = ac->codec->frame_size;
- ac->buffer_size =
- ac->aframesize * ac->sample_size * ao->channels.num * 2 + 200;
- }
- if (ac->buffer_size < FF_MIN_BUFFER_SIZE)
- ac->buffer_size = FF_MIN_BUFFER_SIZE;
- ac->buffer = talloc_size(ac, ac->buffer_size);
// enough frames for at least 0.25 seconds
ac->framecount = ceil(ao->samplerate * 0.25 / ac->aframesize);
@@ -182,7 +172,7 @@ fail:
}
// close audio device
-static int encode(struct ao *ao, double apts, void **data);
+static void encode(struct ao *ao, double apts, void **data);
static void uninit(struct ao *ao)
{
struct priv *ac = ao->priv;
@@ -199,12 +189,12 @@ static void uninit(struct ao *ao)
return;
}
- if (ac->buffer) {
+ if (ac->stream) {
double outpts = ac->expected_next_pts;
if (!ectx->options->rawts && ectx->options->copyts)
outpts += ectx->discontinuity_pts_offset;
outpts += encode_lavc_getoffset(ectx, ac->codec);
- while (encode(ao, outpts, NULL) > 0) ;
+ encode(ao, outpts, NULL);
}
pthread_mutex_unlock(&ectx->lock);
@@ -220,24 +210,130 @@ static int get_space(struct ao *ao)
return ac->aframesize * ac->framecount;
}
+static void write_packet(struct ao *ao, AVPacket *packet)
+{
+ // TODO: Can we unify this with the equivalent video code path?
+ struct priv *ac = ao->priv;
+
+ packet->stream_index = ac->stream->index;
+ if (packet->pts != AV_NOPTS_VALUE) {
+ packet->pts = av_rescale_q(packet->pts,
+ ac->codec->time_base,
+ ac->stream->time_base);
+ } else {
+ // Do we need this at all? Better be safe than sorry...
+ MP_WARN(ao, "encoder lost pts, why?\n");
+ if (ac->savepts != MP_NOPTS_VALUE) {
+ packet->pts = av_rescale_q(ac->savepts,
+ ac->codec->time_base,
+ ac->stream->time_base);
+ }
+ }
+ if (packet->dts != AV_NOPTS_VALUE) {
+ 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->codec->time_base,
+ ac->stream->time_base);
+ }
+
+ ac->savepts = AV_NOPTS_VALUE;
+
+ if (encode_lavc_write_frame(ao->encode_lavc_ctx,
+ ac->stream, packet) < 0) {
+ MP_ERR(ao, "error writing at %d %d/%d\n",
+ (int) packet->pts,
+ ac->stream->time_base.num,
+ ac->stream->time_base.den);
+ return;
+ }
+}
+
+static void encode_audio_and_write(struct ao *ao, AVFrame *frame)
+{
+ // TODO: Can we unify this with the equivalent video code path?
+ struct priv *ac = ao->priv;
+ AVPacket packet = {0};
+
+#if HAVE_AVCODEC_NEW_CODEC_API
+ int status = avcodec_send_frame(ac->codec, frame);
+ if (status < 0) {
+ MP_ERR(ao, "error encoding at %d %d/%d\n",
+ frame ? (int) frame->pts : -1,
+ ac->codec->time_base.num,
+ ac->codec->time_base.den);
+ return;
+ }
+ for (;;) {
+ av_init_packet(&packet);
+ status = avcodec_receive_packet(ac->codec, &packet);
+ if (status == AVERROR(EAGAIN)) { // No more packets for now.
+ if (frame == NULL) {
+ MP_ERR(ao, "sent flush frame, got EAGAIN");
+ }
+ break;
+ }
+ if (status == AVERROR_EOF) { // No more packets, ever.
+ if (frame != NULL) {
+ MP_ERR(ao, "sent audio frame, got EOF");
+ }
+ break;
+ }
+ if (status < 0) {
+ MP_ERR(ao, "error encoding at %d %d/%d\n",
+ frame ? (int) frame->pts : -1,
+ ac->codec->time_base.num,
+ ac->codec->time_base.den);
+ break;
+ }
+ if (frame) {
+ if (ac->savepts == AV_NOPTS_VALUE)
+ ac->savepts = frame->pts;
+ }
+ encode_lavc_write_stats(ao->encode_lavc_ctx, ac->codec);
+ write_packet(ao, &packet);
+ av_packet_unref(&packet);
+ }
+#else
+ av_init_packet(&packet);
+ int got_packet = 0;
+ int status = avcodec_encode_audio2(ac->codec, &packet, frame, &got_packet);
+ if (status < 0) {
+ MP_ERR(ao, "error encoding at %d %d/%d\n",
+ frame ? (int) frame->pts : -1,
+ ac->codec->time_base.num,
+ ac->codec->time_base.den);
+ return;
+ }
+ if (!got_packet) {
+ return;
+ }
+ if (frame) {
+ if (ac->savepts == AV_NOPTS_VALUE)
+ ac->savepts = frame->pts;
+ }
+ encode_lavc_write_stats(ao->encode_lavc_ctx, ac->codec);
+ write_packet(ao, &packet);
+ av_packet_unref(&packet);
+#endif
+}
+
// must get exactly ac->aframesize amount of data
-static int encode(struct ao *ao, double apts, void **data)
+static void encode(struct ao *ao, double apts, void **data)
{
- AVPacket packet;
struct priv *ac = ao->priv;
struct encode_lavc_context *ectx = ao->encode_lavc_ctx;
double realapts = ac->aframecount * (double) ac->aframesize /
ao->samplerate;
- int status, gotpacket;
ac->aframecount++;
if (data)
ectx->audio_pts_offset = realapts - apts;
- av_init_packet(&packet);
- packet.data = ac->buffer;
- packet.size = ac->buffer_size;
if(data) {
AVFrame *frame = av_frame_alloc();
frame->format = af_to_avformat(ao->format);
@@ -270,64 +366,11 @@ static int encode(struct ao *ao, double apts, void **data)
ac->lastpts = frame_pts;
frame->quality = ac->codec->global_quality;
- status = avcodec_encode_audio2(ac->codec, &packet, frame, &gotpacket);
-
- if (!status) {
- if (ac->savepts == AV_NOPTS_VALUE)
- ac->savepts = frame->pts;
- }
-
+ encode_audio_and_write(ao, frame);
av_frame_free(&frame);
}
else
- {
- status = avcodec_encode_audio2(ac->codec, &packet, NULL, &gotpacket);
- }
-
- if(status) {
- MP_ERR(ao, "error encoding\n");
- return -1;
- }
-
- if(!gotpacket)
- return 0;
-
- 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->codec);
-
- packet.stream_index = ac->stream->index;
-
- // Do we need this at all? Better be safe than sorry...
- if (packet.pts == AV_NOPTS_VALUE) {
- MP_WARN(ao, "encoder lost pts, why?\n");
- if (ac->savepts != MP_NOPTS_VALUE)
- packet.pts = ac->savepts;
- }
-
- if (packet.pts != AV_NOPTS_VALUE)
- 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->codec->time_base,
- ac->stream->time_base);
-
- if(packet.duration > 0)
- 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, 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);
- return -1;
- }
-
- return packet.size;
+ encode_audio_and_write(ao, NULL);
}
// this should round samples down to frame sizes
@@ -492,3 +535,5 @@ const struct ao_driver audio_out_lavc = {
.play = play,
.drain = drain,
};
+
+// vim: sw=4 ts=4 et tw=80
diff --git a/audio/out/ao_oss.c b/audio/out/ao_oss.c
index 3216d673e1..90d3b3e5c5 100644
--- a/audio/out/ao_oss.c
+++ b/audio/out/ao_oss.c
@@ -612,6 +612,12 @@ static int audio_wait(struct ao *ao, pthread_mutex_t *lock)
return r;
}
+static void list_devs(struct ao *ao, struct ao_device_list *list)
+{
+ if (stat(PATH_DEV_DSP, &(struct stat){0}) == 0)
+ ao_device_list_add(list, ao, &(struct ao_device_desc){"", "Default"});
+}
+
#define OPT_BASE_STRUCT struct priv
const struct ao_driver audio_out_oss = {
@@ -629,6 +635,7 @@ const struct ao_driver audio_out_oss = {
.drain = drain,
.wait = audio_wait,
.wakeup = ao_wakeup_poll,
+ .list_devs = list_devs,
.priv_size = sizeof(struct priv),
.priv_defaults = &(const struct priv) {
.audio_fd = -1,
diff --git a/audio/out/ao_wasapi.c b/audio/out/ao_wasapi.c
index ae6bd3d9dc..325a7cf72b 100644
--- a/audio/out/ao_wasapi.c
+++ b/audio/out/ao_wasapi.c
@@ -132,7 +132,7 @@ static bool thread_feed(struct ao *ao)
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
+ // committed to frame_count above in the GetBuffer call
hr = IAudioRenderClient_ReleaseBuffer(state->pRenderClient,
frame_count, 0);
EXIT_ON_ERROR(hr);
diff --git a/audio/out/ao_wasapi_changenotify.c b/audio/out/ao_wasapi_changenotify.c
index e3ca4e4936..46843ec5e3 100644
--- a/audio/out/ao_wasapi_changenotify.c
+++ b/audio/out/ao_wasapi_changenotify.c
@@ -95,7 +95,7 @@ static HRESULT STDMETHODCALLTYPE sIMMNotificationClient_OnDeviceAdded(
return S_OK;
}
-// maybe MPV can go over to the prefered device once it is plugged in?
+// maybe MPV can go over to the preferred device once it is plugged in?
static HRESULT STDMETHODCALLTYPE sIMMNotificationClient_OnDeviceRemoved(
IMMNotificationClient *This,
LPCWSTR pwstrDeviceId)