From ecc6e379b24dd5e37b864ae599a154880a2bd2d0 Mon Sep 17 00:00:00 2001 From: wm4 Date: Thu, 9 May 2013 18:06:26 +0200 Subject: audio/out: channel map selection Make all AOs use what has been introduced in the previous commit. Note that even AOs which can handle all possible layouts (like ao_null) use the new functions. This might be important if in the future ao_select_champ() possibly honors global user options about downmixing and so on. --- audio/chmap.h | 2 -- audio/out/ao_alsa.c | 53 +++++++++++++++++++++++++++--------------------- audio/out/ao_coreaudio.c | 11 +++++++--- audio/out/ao_dsound.c | 18 +++++++--------- audio/out/ao_jack.c | 16 ++++++++------- audio/out/ao_lavc.c | 4 ++++ audio/out/ao_null.c | 6 ++++++ audio/out/ao_openal.c | 10 ++++----- audio/out/ao_oss.c | 8 ++++++-- audio/out/ao_pcm.c | 5 ++++- audio/out/ao_portaudio.c | 6 +++++- audio/out/ao_pulse.c | 21 ++++++++++--------- audio/out/ao_rsound.c | 8 +++++++- audio/out/ao_sdl.c | 14 +++++++++++-- 14 files changed, 114 insertions(+), 68 deletions(-) diff --git a/audio/chmap.h b/audio/chmap.h index 929283dfd5..1848c86efd 100644 --- a/audio/chmap.h +++ b/audio/chmap.h @@ -129,6 +129,4 @@ void mp_chmap_print_help(int msgt, int msgl); #define mp_chmap_is_waveext mp_chmap_is_lavc #define mp_chmap_reorder_to_waveext mp_chmap_reorder_to_lavc -#define mp_chmap_reorder_to_alsa(x) mp_chmap_from_channels_alsa((x), (x)->num) - #endif diff --git a/audio/out/ao_alsa.c b/audio/out/ao_alsa.c index 477caa51de..bb7a5cbb15 100644 --- a/audio/out/ao_alsa.c +++ b/audio/out/ao_alsa.c @@ -330,22 +330,35 @@ static const char *device_channel_layouts[][2] = { {"surround41", "fl-fr-bl-br-lfe"}, {"surround51", "fl-fr-bl-br-fc-lfe"}, {"surround71", "fl-fr-bl-br-fc-lfe-sl-sr"}, - {0} }; -// Find a device that contains exactly all the requested speakers. -// Set *request to the required channel order. -static const char *find_device(struct mp_chmap *request) +#define ARRAY_LEN(x) (sizeof(x) / sizeof((x)[0])) + +#define NUM_ALSA_CHMAPS ARRAY_LEN(device_channel_layouts) + +static const char *select_chmap(struct ao *ao) { - for (int n = 0; device_channel_layouts[n][0]; n++) { - struct mp_chmap map = {0}; - mp_chmap_from_str(&map, bstr0(device_channel_layouts[n][1])); - if (mp_chmap_equals_reordered(&map, request)) { - *request = map; + struct mp_chmap_sel sel = {0}; + struct mp_chmap maps[NUM_ALSA_CHMAPS]; + for (int n = 0; n < NUM_ALSA_CHMAPS; n++) { + mp_chmap_from_str(&maps[n], bstr0(device_channel_layouts[n][1])); + mp_chmap_sel_add_map(&sel, &maps[n]); + }; + + if (!ao_chmap_sel_adjust(ao, &sel, &ao->channels)) + return NULL; + + for (int n = 0; n < NUM_ALSA_CHMAPS; n++) { + if (mp_chmap_equals(&ao->channels, &maps[n])) return device_channel_layouts[n][0]; - } } - return NULL; + + char *name = mp_chmap_to_str(&ao->channels); + mp_tmsg(MSGT_AO, MSGL_ERR, + "[AO_ALSA] channel layout %s (%d ch) not supported.\n", + name, ao->channels.num); + talloc_free(name); + return "default"; } static int try_open_device(struct ao *ao, const char *device, int open_mode, @@ -449,16 +462,7 @@ static int init(struct ao *ao, char *params) "alsa-spdif-init: playing AC3/iec61937/iec958, %i channels\n", ao->channels.num); } else { - device.str = find_device(&ao->channels); - if (!device.str) { - char *name = mp_chmap_to_str(&ao->channels); - device.str = "default"; - mp_chmap_from_channels(&ao->channels, ao->channels.num); - mp_tmsg(MSGT_AO, MSGL_ERR, - "[AO_ALSA] channel layout %s (%d ch) not supported.\n", - name, ao->channels.num); - talloc_free(name); - } + device.str = select_chmap(ao); if (strcmp(device.str, "default") != 0 && ao->format == AF_FORMAT_FLOAT_NE) { // hack - use the converter plugin (why the heck?) @@ -535,8 +539,11 @@ static int init(struct ao *ao, char *params) (p->alsa, alsa_hwparams, &num_channels); CHECK_ALSA_ERROR("Unable to set channels"); - if (num_channels != ao->channels.num) - mp_chmap_from_channels(&ao->channels, num_channels); + if (num_channels != ao->channels.num) { + mp_tmsg(MSGT_AO, MSGL_ERR, + "[AO_ALSA] Couldn't get requested number of channels.\n"); + mp_chmap_from_channels_alsa(&ao->channels, num_channels); + } /* workaround for buggy rate plugin (should be fixed in ALSA 1.0.11) prefer our own resampler, since that allows users to choose the resampler, diff --git a/audio/out/ao_coreaudio.c b/audio/out/ao_coreaudio.c index a3c6907ed4..6a15690074 100644 --- a/audio/out/ao_coreaudio.c +++ b/audio/out/ao_coreaudio.c @@ -499,6 +499,11 @@ int device_id, display_help = 0; // Save selected device id ao->i_selected_dev = devid_def; + struct mp_chmap_sel chmap_sel = {0}; + mp_chmap_sel_add_waveext(&chmap_sel); + if (!ao_chmap_sel_adjust(&ao_data, &ao_data.channels, &chmap_sel)) + goto err_out; + // Build Description for the input format inDesc.mSampleRate=rate; inDesc.mFormatID=ao->b_supports_digital ? kAudioFormat60958AC3 : kAudioFormatLinearPCM; @@ -605,8 +610,8 @@ int device_id, display_help = 0; ao->chunk_size = maxFrames;//*inDesc.mBytesPerFrame; ao_data.samplerate = inDesc.mSampleRate; - mp_chmap_from_channels(&ao_data.channels, inDesc.mChannelsPerFrame); - mp_chmap_reorder_to_waveext(&ao_data.channels); + if (!ao_chmap_sel_get_def(&ao_data, &chmap_sel, &ao_data.channels, inDesc.mChannelsPerFrame)) + goto err_out2; ao_data.bps = ao_data.samplerate * inDesc.mBytesPerFrame; ao_data.outburst = ao->chunk_size; ao_data.buffersize = ao_data.bps; @@ -838,7 +843,7 @@ static int OpenSPDIF(void) ao->chunk_size = ao->stream_format.mBytesPerPacket; ao_data.samplerate = ao->stream_format.mSampleRate; - // Applies default ordering; ok becazse AC3 data is always in mpv internal channel order + // Applies default ordering; ok because AC3 data is always in mpv internal channel order mp_chmap_from_channels(&ao_data.channels, ao->stream_format.mChannelsPerFrame); ao_data.bps = ao_data.samplerate * (ao->stream_format.mBytesPerPacket/ao->stream_format.mFramesPerPacket); ao_data.outburst = ao->chunk_size; diff --git a/audio/out/ao_dsound.c b/audio/out/ao_dsound.c index b096dd28db..967084d3ae 100644 --- a/audio/out/ao_dsound.c +++ b/audio/out/ao_dsound.c @@ -390,18 +390,14 @@ static int init(int rate, const struct mp_chmap *channels, int format, int flags DSBUFFERDESC dsbpridesc; DSBUFFERDESC dsbdesc; - //check if the channel count and format is supported in general - if (ao_data.channels.num > 8) { - // More than 8 channels might just work, but needs testing - UninitDirectSound(); - mp_msg(MSGT_AO, MSGL_ERR, "ao_dsound: > 8 channel audio not yet supported\n"); - return 0; - } - - if (AF_FORMAT_IS_AC3(format)) + if (AF_FORMAT_IS_AC3(format)) { format = AF_FORMAT_AC3_NE; - else - mp_chmap_reorder_to_waveext(&ao_data.channels); + } else { + struct mp_chmap_sel sel = {0}; + mp_chmap_sel_add_waveext(&sel); + if (!ao_chmap_sel_adjust(&ao_data, &sel, &ao_data.channels)) + return 0; + } switch(format){ case AF_FORMAT_AC3_NE: case AF_FORMAT_S24_LE: diff --git a/audio/out/ao_jack.c b/audio/out/ao_jack.c index aea64ee02c..0f8baeab86 100644 --- a/audio/out/ao_jack.c +++ b/audio/out/ao_jack.c @@ -50,7 +50,7 @@ static const ao_info_t info = LIBAO_EXTERN(jack) //! maximum number of channels supported, avoids lots of mallocs -#define MAX_CHANS 8 +#define MAX_CHANS MP_NUM_CHANNELS static jack_port_t *ports[MAX_CHANS]; static int num_ports; ///< Number of used ports == number of channels static jack_client_t *client; @@ -223,11 +223,12 @@ static int init(int rate, const struct mp_chmap *channels, int format, int flags print_help(); return 0; } - if (ao_data.channels.num > MAX_CHANS) { - mp_msg(MSGT_AO, MSGL_FATAL, "[JACK] Invalid number of channels: %i\n", - ao_data.channels.num); + + struct mp_chmap_sel sel = {0}; + mp_chmap_sel_add_waveext(&sel); + if (!ao_chmap_sel_adjust(&ao_data, &sel, &ao_data.channels)) goto err_out; - } + if (!client_name) { client_name = malloc(40); sprintf(client_name, "mpv [%d]", getpid()); @@ -283,8 +284,9 @@ static int init(int rate, const struct mp_chmap *channels, int format, int flags / (float)rate; callback_interval = 0; - mp_chmap_from_channels(&ao_data.channels, num_ports); - mp_chmap_reorder_to_alsa(&ao_data.channels); // what order does hack use? + if (!ao_chmap_sel_get_def(&ao_data, &sel, &ao_data.channels, num_ports)) + goto err_out; + ao_data.samplerate = rate; ao_data.format = AF_FORMAT_FLOAT_NE; ao_data.bps = ao_data.channels.num * rate * sizeof(float); diff --git a/audio/out/ao_lavc.c b/audio/out/ao_lavc.c index ffe7d25415..0fda9a2b3a 100644 --- a/audio/out/ao_lavc.c +++ b/audio/out/ao_lavc.c @@ -102,6 +102,10 @@ static int init(struct ao *ao, char *params) ac->stream->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)) + return -1; 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); diff --git a/audio/out/ao_null.c b/audio/out/ao_null.c index c4288cffda..53ec2a9a83 100644 --- a/audio/out/ao_null.c +++ b/audio/out/ao_null.c @@ -48,6 +48,12 @@ static int init(struct ao *ao, char *params) { struct priv *priv = talloc_zero(ao, struct priv); ao->priv = priv; + + struct mp_chmap_sel sel = {0}; + mp_chmap_sel_add_any(&sel); + if (!ao_chmap_sel_adjust(ao, &sel, &ao->channels)) + return -1; + int samplesize = af_fmt2bits(ao->format) / 8; ao->outburst = 256 * ao->channels.num * samplesize; // A "buffer" for about 0.2 seconds of audio diff --git a/audio/out/ao_openal.c b/audio/out/ao_openal.c index 4c906802e1..08f8bc1978 100644 --- a/audio/out/ao_openal.c +++ b/audio/out/ao_openal.c @@ -53,7 +53,7 @@ static const ao_info_t info = LIBAO_EXTERN(openal) -#define MAX_CHANS 8 +#define MAX_CHANS MP_NUM_CHANNELS #define NUM_BUF 128 #define CHUNK_SIZE 512 static ALuint buffers[MAX_CHANS][NUM_BUF]; @@ -151,11 +151,11 @@ static int init(int rate, const struct mp_chmap *channels, int format, list_devices(); goto err_out; } - if (ao_data.channels.num > MAX_CHANS) { - mp_msg(MSGT_AO, MSGL_FATAL, "[OpenAL] Invalid number of channels: %i\n", - ao_data.channels.num); + struct mp_chmap_sel sel = {0}; + for (i = 0; speaker_pos[i].id != -1; i++) + mp_chmap_sel_add_speaker(&sel, speaker_pos[i].id); + if (!ao_chmap_sel_adjust(&ao_data, &sel, &ao_data.channels)) goto err_out; - } struct speaker speakers[MAX_CHANS]; for (i = 0; i < ao_data.channels.num; i++) { speakers[i].id = -1; diff --git a/audio/out/ao_oss.c b/audio/out/ao_oss.c index 805a14cd8f..4ff97b30b6 100644 --- a/audio/out/ao_oss.c +++ b/audio/out/ao_oss.c @@ -340,7 +340,10 @@ ac3_retry: af_fmt2str_short(ao_data.format), af_fmt2str_short(format)); if(!AF_FORMAT_IS_AC3(format)) { - mp_chmap_reorder_to_alsa(&ao_data.channels); + struct mp_chmap_sel sel = {0}; + mp_chmap_sel_add_alsa_def(&sel); + if (!ao_chmap_sel_adjust(&ao_data, &sel, &ao_data.channels)) + return 0; int reqchannels = ao_data.channels.num; // We only use SNDCTL_DSP_CHANNELS for >2 channels, in case some drivers don't have it if (reqchannels > 2) { @@ -357,7 +360,8 @@ ac3_retry: mp_tmsg(MSGT_AO,MSGL_ERR,"[AO OSS] audio_setup: Failed to set audio device to %d channels.\n", reqchannels); return 0; } - mp_chmap_from_channels(&ao_data.channels, c + 1); + if (!ao_chmap_sel_get_def(&ao_data, &sel, &ao_data.channels, c + 1)) + return 0; } mp_msg(MSGT_AO,MSGL_V,"audio_setup: using %d channels (requested: %d)\n", ao_data.channels.num, reqchannels); // set rate diff --git a/audio/out/ao_pcm.c b/audio/out/ao_pcm.c index 1199ab5a90..903e89bc8b 100644 --- a/audio/out/ao_pcm.c +++ b/audio/out/ao_pcm.c @@ -146,7 +146,10 @@ static int init(struct ao *ao, char *params) } } - mp_chmap_reorder_to_waveext(&ao->channels); + struct mp_chmap_sel sel = {0}; + mp_chmap_sel_add_waveext(&sel); + if (!ao_chmap_sel_adjust(ao, &sel, &ao->channels)) + return -1; ao->outburst = 65536; ao->bps = ao->channels.num * ao->samplerate * (af_fmt2bits(ao->format) / 8); diff --git a/audio/out/ao_portaudio.c b/audio/out/ao_portaudio.c index 382523d08e..f84447bdb4 100644 --- a/audio/out/ao_portaudio.c +++ b/audio/out/ao_portaudio.c @@ -273,7 +273,11 @@ static int init(struct ao *ao, char *params) if (pa_device == paNoDevice) goto error_exit; - mp_chmap_reorder_to_alsa(&ao->channels); + // The actual channel order probably depends on the platform. + struct mp_chmap_sel sel = {0}; + mp_chmap_sel_add_waveext_def(&sel); + if (!ao_chmap_sel_adjust(ao, &sel, &ao->channels)) + goto error_exit; PaStreamParameters sp = { .device = pa_device, diff --git a/audio/out/ao_pulse.c b/audio/out/ao_pulse.c index 9422fa319d..15a2b8b0a1 100644 --- a/audio/out/ao_pulse.c +++ b/audio/out/ao_pulse.c @@ -187,6 +187,15 @@ static bool chmap_pa_from_mp(pa_channel_map *dst, struct mp_chmap *src) return true; } +static bool select_chmap(struct ao *ao, pa_channel_map *dst) +{ + struct mp_chmap_sel sel = {0}; + for (int n = 0; speaker_map[n][1] != -1; n++) + mp_chmap_sel_add_speaker(&sel, speaker_map[n][1]); + return ao_chmap_sel_adjust(ao, &sel, &ao->channels) && + chmap_pa_from_mp(dst, &ao->channels); +} + static void uninit(struct ao *ao, bool cut_audio) { struct priv *priv = ao->priv; @@ -301,16 +310,8 @@ static int init(struct ao *ao, char *params) goto fail; } - if (!chmap_pa_from_mp(&map, &ao->channels)) { - char *name = mp_chmap_to_str(&ao->channels); - mp_msg(MSGT_AO, MSGL_ERR, "AO: [pulse] Can't map %s channel layout\n", - name); - talloc_free(name); - // Not a really good fallback, since this doesn't trigger if the - // channel map is valid, but unsupported by the output device. - ao->channels = (struct mp_chmap) MP_CHMAP_INIT_STEREO; - pa_channel_map_init_stereo(&map); - } + if (!select_chmap(ao, &map)) + goto fail; ao->bps = pa_bytes_per_second(&ss); diff --git a/audio/out/ao_rsound.c b/audio/out/ao_rsound.c index 80dfa4dc2b..78ea2c63f5 100644 --- a/audio/out/ao_rsound.c +++ b/audio/out/ao_rsound.c @@ -121,7 +121,13 @@ static int init(struct ao *ao, char *params) free(port); } - mp_chmap_reorder_to_alsa(&ao->channels); + // Actual channel layout unknown. + struct mp_chmap_sel sel = {0}; + mp_chmap_sel_add_waveext_def(&sel); + if (!ao_chmap_sel_adjust(ao, &sel, &ao->channels)) { + rsd_free(priv->rd); + return -1; + } rsd_set_param(priv->rd, RSD_SAMPLERATE, &ao->samplerate); rsd_set_param(priv->rd, RSD_CHANNELS, &ao->channels.num); diff --git a/audio/out/ao_sdl.c b/audio/out/ao_sdl.c index 4235a7c26c..6678cd3bd3 100644 --- a/audio/out/ao_sdl.c +++ b/audio/out/ao_sdl.c @@ -160,6 +160,13 @@ static int init(struct ao *ao, char *params) return -1; } + struct mp_chmap_sel sel = {0}; + mp_chmap_sel_add_waveext_def(&sel); + if (!ao_chmap_sel_adjust(ao, &sel, &ao->channels)) { + uninit(ao, true); + return -1; + } + SDL_AudioSpec desired, obtained; int bytes = 0; @@ -236,9 +243,12 @@ static int init(struct ao *ao, char *params) return -1; } + if (!ao_chmap_sel_get_def(ao, &sel, &ao->channels, obtained.channels)) { + uninit(ao, true); + return -1; + } + ao->samplerate = obtained.freq; - mp_chmap_from_channels(&ao->channels, obtained.channels); - mp_chmap_reorder_to_alsa(&ao->channels); ao->bps = ao->channels.num * ao->samplerate * bytes; ao->buffersize = obtained.size * bufcnt; ao->outburst = obtained.size; -- cgit v1.2.3