summaryrefslogtreecommitdiffstats
path: root/audio
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2013-11-10 23:39:08 +0100
committerwm4 <wm4@nowhere>2013-11-12 23:30:25 +0100
commitdab6eaaa5e48d7a333564a29b0e04440d24a4ba5 (patch)
treef05d3833364a34dc10afd1f2f835c87843efba24 /audio
parentfedb9229d508df6ee1207f8fe264aa868068a03e (diff)
downloadmpv-dab6eaaa5e48d7a333564a29b0e04440d24a4ba5.tar.bz2
mpv-dab6eaaa5e48d7a333564a29b0e04440d24a4ba5.tar.xz
ao_alsa: support non-interleaved audio
ALSA supports non-interleaved audio natively using a separate API function for writing audio. (Though you have to tell it about this on initialization.) ALSA doesn't have separate sample formats for this, so just pretend to negotiate the interleaved format, and assume that all non-interleaved formats have an interleaved companion format.
Diffstat (limited to 'audio')
-rw-r--r--audio/out/ao_alsa.c48
1 files changed, 23 insertions, 25 deletions
diff --git a/audio/out/ao_alsa.c b/audio/out/ao_alsa.c
index 97c8b5acfd..2ef35db6cf 100644
--- a/audio/out/ao_alsa.c
+++ b/audio/out/ao_alsa.c
@@ -52,12 +52,11 @@
struct priv {
snd_pcm_t *alsa;
snd_pcm_format_t alsa_fmt;
- size_t bytes_per_sample;
int can_pause;
snd_pcm_sframes_t prepause_frames;
float delay_before_pause;
- int buffersize;
- int outburst;
+ int buffersize; // in frames
+ int outburst; // in frames
int cfg_block;
char *cfg_device;
@@ -251,6 +250,7 @@ static const int mp_to_alsa_format[][2] = {
static int find_alsa_format(int af_format)
{
+ af_format = af_fmt_from_planar(af_format);
for (int n = 0; mp_to_alsa_format[n][0] != AF_FORMAT_UNKNOWN; n++) {
if (mp_to_alsa_format[n][0] == af_format)
return mp_to_alsa_format[n][1];
@@ -432,12 +432,6 @@ static int init(struct ao *ao)
err = snd_pcm_hw_params_any(p->alsa, alsa_hwparams);
CHECK_ALSA_ERROR("Unable to get initial parameters");
- err = snd_pcm_hw_params_set_access
- (p->alsa, alsa_hwparams, SND_PCM_ACCESS_RW_INTERLEAVED);
- CHECK_ALSA_ERROR("Unable to set access type");
-
- ao->format = af_fmt_from_planar(ao->format);
-
p->alsa_fmt = find_alsa_format(ao->format);
if (p->alsa_fmt == SND_PCM_FORMAT_UNKNOWN) {
p->alsa_fmt = SND_PCM_FORMAT_S16;
@@ -460,6 +454,12 @@ static int init(struct ao *ao)
err = snd_pcm_hw_params_set_format(p->alsa, alsa_hwparams, p->alsa_fmt);
CHECK_ALSA_ERROR("Unable to set format");
+ snd_pcm_access_t access = af_fmt_is_planar(ao->format)
+ ? SND_PCM_ACCESS_RW_NONINTERLEAVED
+ : SND_PCM_ACCESS_RW_INTERLEAVED;
+ err = snd_pcm_hw_params_set_access(p->alsa, alsa_hwparams, access);
+ CHECK_ALSA_ERROR("Unable to set access type");
+
int num_channels = ao->channels.num;
err = snd_pcm_hw_params_set_channels_near
(p->alsa, alsa_hwparams, &num_channels);
@@ -480,9 +480,6 @@ static int init(struct ao *ao)
(p->alsa, alsa_hwparams, &ao->samplerate, NULL);
CHECK_ALSA_ERROR("Unable to set samplerate-2");
- p->bytes_per_sample = af_fmt2bits(ao->format) / 8;
- p->bytes_per_sample *= ao->channels.num;
-
err = snd_pcm_hw_params_set_buffer_time_near
(p->alsa, alsa_hwparams, &(unsigned int){BUFFER_TIME}, NULL);
CHECK_ALSA_ERROR("Unable to set buffer time near");
@@ -501,14 +498,14 @@ static int init(struct ao *ao)
err = snd_pcm_hw_params_get_buffer_size(alsa_hwparams, &bufsize);
CHECK_ALSA_ERROR("Unable to get buffersize");
- p->buffersize = bufsize * p->bytes_per_sample;
- MP_VERBOSE(ao, "got buffersize=%i\n", p->buffersize);
+ p->buffersize = bufsize;
+ MP_VERBOSE(ao, "got buffersize=%i samples\n", p->buffersize);
err = snd_pcm_hw_params_get_period_size(alsa_hwparams, &chunk_size, NULL);
CHECK_ALSA_ERROR("Unable to get period size");
MP_VERBOSE(ao, "got period size %li\n", chunk_size);
- p->outburst = chunk_size * p->bytes_per_sample;
+ p->outburst = chunk_size;
/* setting software parameters */
err = snd_pcm_sw_params_current(p->alsa, alsa_swparams);
@@ -539,8 +536,8 @@ static int init(struct ao *ao)
p->can_pause = snd_pcm_hw_params_can_pause(alsa_hwparams);
- MP_VERBOSE(ao, "opened: %d Hz/%d channels/%d bpf/%d bytes buffer/%s\n",
- ao->samplerate, ao->channels.num, (int)p->bytes_per_sample,
+ MP_VERBOSE(ao, "opened: %d Hz/%d channels/%d bps/%d samples buffer/%s\n",
+ ao->samplerate, ao->channels.num, af_fmt2bits(ao->format),
p->buffersize, snd_pcm_format_description(p->alsa_fmt));
return 0;
@@ -639,23 +636,24 @@ alsa_error: ;
static int play(struct ao *ao, void **data, int samples, int flags)
{
struct priv *p = ao->priv;
- int num_frames;
snd_pcm_sframes_t res = 0;
- int len = samples * p->bytes_per_sample;
if (!(flags & AOPLAY_FINAL_CHUNK))
- len = len / p->outburst * p->outburst;
- num_frames = len / p->bytes_per_sample;
+ samples = samples / p->outburst * p->outburst;
if (!p->alsa) {
MP_ERR(ao, "Device configuration error.");
return -1;
}
- if (num_frames == 0)
+ if (samples == 0)
return 0;
do {
- res = snd_pcm_writei(p->alsa, data[0], num_frames);
+ if (af_fmt_is_planar(ao->format)) {
+ res = snd_pcm_writen(p->alsa, data, samples);
+ } else {
+ res = snd_pcm_writei(p->alsa, data[0], samples);
+ }
if (res == -EINTR) {
/* nothing to do */
@@ -692,10 +690,10 @@ static int get_space(struct ao *ao)
err = snd_pcm_status(p->alsa, status);
CHECK_ALSA_ERROR("cannot get pcm status");
- unsigned space = snd_pcm_status_get_avail(status) * p->bytes_per_sample;
+ unsigned space = snd_pcm_status_get_avail(status);
if (space > p->buffersize) // Buffer underrun?
space = p->buffersize;
- return space / p->bytes_per_sample;
+ return space;
alsa_error:
return 0;