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.
This commit is contained in:
wm4 2013-05-09 18:06:26 +02:00
parent ab8f28a672
commit ecc6e379b2
14 changed files with 114 additions and 68 deletions

View File

@ -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

View File

@ -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,

View File

@ -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;

View File

@ -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:

View File

@ -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);

View File

@ -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);

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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);

View File

@ -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,

View File

@ -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);

View File

@ -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);

View File

@ -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;