From f54909d4df1e1f00481e3ca4aae02f9bf7b78668 Mon Sep 17 00:00:00 2001 From: wm4 Date: Sat, 23 Mar 2013 17:23:33 +0100 Subject: ao_alsa: reorder channels from internal to alsa order Currently, internal and alsa order are exactly the same, so this will do absolutely nothing. --- audio/out/ao_alsa.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'audio/out') diff --git a/audio/out/ao_alsa.c b/audio/out/ao_alsa.c index 366b912b76..3682e76aa3 100644 --- a/audio/out/ao_alsa.c +++ b/audio/out/ao_alsa.c @@ -48,6 +48,7 @@ #include "ao.h" #include "audio_out_internal.h" #include "audio/format.h" +#include "audio/reorder_ch.h" static const ao_info_t info = { @@ -790,6 +791,11 @@ static int play(void* data, int len, int flags) len = len / ao_data.outburst * ao_data.outburst; num_frames = len / bytes_per_sample; + int bps = af_fmt2bits(ao_data.format) / 8; + reorder_channel_nch(data, AF_CHANNEL_LAYOUT_MPLAYER_DEFAULT, + AF_CHANNEL_LAYOUT_ALSA_DEFAULT, + ao_data.channels, len / bps, bps); + //mp_msg(MSGT_AO,MSGL_ERR,"alsa-play: frames=%i, len=%i\n",num_frames,len); if (!alsa_handler) { -- cgit v1.2.3 From 41aefce730efd7da6068b7f61697c65759cd3f84 Mon Sep 17 00:00:00 2001 From: wm4 Date: Sat, 23 Mar 2013 17:49:52 +0100 Subject: audio: switch to libavcodec channel order, use libavresample for mixing Switch the internal channel order to libavcodec's. If the channel number mismatches at some point, use libavresample for up- or downmixing. Remove the old af_pan automatic downmixing. The libavcodec channel order should be equivalent to WAVEFORMATEX order, at least nowadays. reorder_ch.h assumes that WAVEFORMATEX and libavcodec might be different, but all defined channels have the same mappings. Remove the downmixing with af_pan as well as the channel conversion with af_channels from af.c, and prefer af_lavrresample for this. The automatic downmixing behavior should be the same as before (if the --channels option is set to 2, which is the default, the audio output is forced to 2 channels, and libavresample does all downmixing). Note that mpv still can't do channel layouts. It will pick the default channel layout according to the channel count. This will be fixed later by passing down the channel layout as well. af_hrtf depends on the order of the input channels, so reorder to ALSA (for which this code was written). This is better than changing the filter code, which is more risky. ao_pulse can accept waveext order directly, so set that as channel mapping. --- audio/out/ao_pulse.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'audio/out') diff --git a/audio/out/ao_pulse.c b/audio/out/ao_pulse.c index 314ef778bd..bb5af6f851 100644 --- a/audio/out/ao_pulse.c +++ b/audio/out/ao_pulse.c @@ -230,7 +230,7 @@ static int init(struct ao *ao, char *params) goto fail; } - pa_channel_map_init_auto(&map, ss.channels, PA_CHANNEL_MAP_ALSA); + pa_channel_map_init_auto(&map, ss.channels, PA_CHANNEL_MAP_WAVEEX); ao->bps = pa_bytes_per_second(&ss); if (!(priv->mainloop = pa_threaded_mainloop_new())) { -- cgit v1.2.3 From f7a427676c0fe3c12509e3d9a243301f93626b0a Mon Sep 17 00:00:00 2001 From: wm4 Date: Fri, 5 Apr 2013 19:47:51 +0200 Subject: audio: add some setters for mp_audio, and require filters to use them mp_audio has some redundant fields. Setters like mp_audio_set_format() initialize these properly. Also move the mp_audio struct to a the file audio.c. We can remove a mysterious line of code from af.c: in.format |= af_bits2fmt(in.bps * 8); I'm not sure if this was ever actually needed, or if it was some kind of "make it work" quick-fix that works against the way things were supposed to work. All filters etc. now set the format correctly, so if there ever was a need for this code, it's definitely gone. --- audio/out/ao.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'audio/out') diff --git a/audio/out/ao.h b/audio/out/ao.h index 4a7c928824..e57fff7a95 100644 --- a/audio/out/ao.h +++ b/audio/out/ao.h @@ -88,7 +88,7 @@ struct ao { int samplerate; int channels; int format; - int bps; + int bps; // bytes per second int outburst; int buffersize; double pts; -- cgit v1.2.3 From aea2328906fc754c0d0cdea57c60d71522ae99a5 Mon Sep 17 00:00:00 2001 From: wm4 Date: Fri, 5 Apr 2013 23:06:22 +0200 Subject: audio/out: switch to channel map This actually breaks audio for 5/6/8 channels. There's no reordering done yet. The actual reordering will be done inside of af_lavrresample and has to be made part of the format negotiation. --- audio/out/ao.c | 2 +- audio/out/ao.h | 5 ++- audio/out/ao_alsa.c | 31 +++++++-------- audio/out/ao_coreaudio.c | 15 +++++--- audio/out/ao_dsound.c | 83 ++++++++-------------------------------- audio/out/ao_jack.c | 17 +++++---- audio/out/ao_lavc.c | 86 +++++++++++++++--------------------------- audio/out/ao_null.c | 4 +- audio/out/ao_openal.c | 43 +++++++++++---------- audio/out/ao_oss.c | 32 ++++++++-------- audio/out/ao_pcm.c | 34 ++++------------- audio/out/ao_portaudio.c | 6 ++- audio/out/ao_pulse.c | 6 ++- audio/out/ao_rsound.c | 6 ++- audio/out/ao_sdl.c | 7 ++-- audio/out/audio_out_internal.h | 3 +- 16 files changed, 150 insertions(+), 230 deletions(-) (limited to 'audio/out') diff --git a/audio/out/ao.c b/audio/out/ao.c index 9fb201a333..bf9b47a14e 100644 --- a/audio/out/ao.c +++ b/audio/out/ao.c @@ -257,7 +257,7 @@ int old_ao_init(struct ao *ao, char *params) assert(!global_ao); global_ao = ao; ao_subdevice = params ? talloc_strdup(ao, params) : NULL; - if (ao->driver->old_functions->init(ao->samplerate, ao->channels, + if (ao->driver->old_functions->init(ao->samplerate, &ao->channels, ao->format, 0) == 0) { global_ao = NULL; return -1; diff --git a/audio/out/ao.h b/audio/out/ao.h index e57fff7a95..465bcf6197 100644 --- a/audio/out/ao.h +++ b/audio/out/ao.h @@ -23,6 +23,7 @@ #include "core/bstr.h" #include "core/mp_common.h" +#include "audio/chmap.h" enum aocontrol { // _VOLUME commands take struct ao_control_vol pointer for input/output. @@ -55,7 +56,7 @@ typedef struct ao_info { /* interface towards mplayer and */ typedef struct ao_old_functions { int (*control)(int cmd, void *arg); - int (*init)(int rate, int channels, int format, int flags); + int (*init)(int rate, const struct mp_chmap *channels, int format, int flags); void (*uninit)(int immed); void (*reset)(void); int (*get_space)(void); @@ -86,7 +87,7 @@ struct ao_driver { /* global data used by mplayer and plugins */ struct ao { int samplerate; - int channels; + struct mp_chmap channels; int format; int bps; // bytes per second int outburst; diff --git a/audio/out/ao_alsa.c b/audio/out/ao_alsa.c index 3682e76aa3..a194ce0478 100644 --- a/audio/out/ao_alsa.c +++ b/audio/out/ao_alsa.c @@ -332,7 +332,8 @@ static int try_open_device(const char *device, int open_mode, int try_ac3) open & setup audio device return: 1=success 0=fail */ -static int init(int rate_hz, int channels, int format, int flags) +static int init(int rate_hz, const struct mp_chmap *channels, int format, + int flags) { int err; int block; @@ -351,7 +352,7 @@ static int init(int rate_hz, int channels, int format, int flags) memset(alsa_device, 0, ALSA_DEVICE_SIZE + 1); mp_msg(MSGT_AO,MSGL_V,"alsa-init: requested format: %d Hz, %d channels, %x\n", rate_hz, - channels, format); + ao_data.channels.num, format); alsa_handler = NULL; mp_msg(MSGT_AO,MSGL_V,"alsa-init: using ALSA %s\n", snd_asoundlib_version()); @@ -360,10 +361,6 @@ static int init(int rate_hz, int channels, int format, int flags) snd_lib_error_set_handler(alsa_error_handler); - ao_data.samplerate = rate_hz; - ao_data.format = format; - ao_data.channels = channels; - switch (format) { case AF_FORMAT_S8: @@ -435,13 +432,13 @@ static int init(int rate_hz, int channels, int format, int flags) */ if (AF_FORMAT_IS_IEC61937(format)) { device.str = "iec958"; - mp_msg(MSGT_AO,MSGL_V,"alsa-spdif-init: playing AC3/iec61937/iec958, %i channels\n", channels); + mp_msg(MSGT_AO,MSGL_V,"alsa-spdif-init: playing AC3/iec61937/iec958, %i channels\n", ao_data.channels.num); } else /* in any case for multichannel playback we should select * appropriate device */ - switch (channels) { + switch (ao_data.channels.num) { case 1: case 2: device.str = "default"; @@ -471,7 +468,8 @@ static int init(int rate_hz, int channels, int format, int flags) break; default: device.str = "default"; - mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] %d channels are not supported.\n",channels); + mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] %d channels are not supported.\n", + ao_data.channels.num); } device.len = strlen(device.str); if (subopt_parse(ao_subdevice, subopts) != 0) { @@ -554,13 +552,17 @@ static int init(int rate_hz, int channels, int format, int flags) return 0; } + int num_channels = ao_data.channels.num; if ((err = snd_pcm_hw_params_set_channels_near(alsa_handler, alsa_hwparams, - &ao_data.channels)) < 0) + &num_channels)) < 0) { mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] Unable to set channels: %s\n", snd_strerror(err)); return 0; } + mp_chmap_from_channels(&ao_data.channels, num_channels); + if (!AF_FORMAT_IS_IEC61937(format)) + mp_chmap_reorder_to_alsa(&ao_data.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, @@ -582,7 +584,7 @@ static int init(int rate_hz, int channels, int format, int flags) } bytes_per_sample = af_fmt2bits(ao_data.format) / 8; - bytes_per_sample *= ao_data.channels; + bytes_per_sample *= ao_data.channels.num; ao_data.bps = ao_data.samplerate * bytes_per_sample; if ((err = snd_pcm_hw_params_set_buffer_time_near(alsa_handler, alsa_hwparams, @@ -668,7 +670,7 @@ static int init(int rate_hz, int channels, int format, int flags) alsa_can_pause = snd_pcm_hw_params_can_pause(alsa_hwparams); mp_msg(MSGT_AO,MSGL_V,"alsa: %d Hz/%d channels/%d bpf/%d bytes buffer/%s\n", - ao_data.samplerate, ao_data.channels, (int)bytes_per_sample, ao_data.buffersize, + ao_data.samplerate, ao_data.channels.num, (int)bytes_per_sample, ao_data.buffersize, snd_pcm_format_description(alsa_format)); } // end switch alsa_handler (spdif) @@ -791,11 +793,6 @@ static int play(void* data, int len, int flags) len = len / ao_data.outburst * ao_data.outburst; num_frames = len / bytes_per_sample; - int bps = af_fmt2bits(ao_data.format) / 8; - reorder_channel_nch(data, AF_CHANNEL_LAYOUT_MPLAYER_DEFAULT, - AF_CHANNEL_LAYOUT_ALSA_DEFAULT, - ao_data.channels, len / bps, bps); - //mp_msg(MSGT_AO,MSGL_ERR,"alsa-play: frames=%i, len=%i\n",num_frames,len); if (!alsa_handler) { diff --git a/audio/out/ao_coreaudio.c b/audio/out/ao_coreaudio.c index 7993eac910..98b9f9adeb 100644 --- a/audio/out/ao_coreaudio.c +++ b/audio/out/ao_coreaudio.c @@ -412,7 +412,7 @@ static void print_help(void) free(devids); } -static int init(int rate,int channels,int format,int flags) +static int init(int rate,const struct mp_chmap *channels,int format,int flags) { AudioStreamBasicDescription inDesc; AudioComponentDescription desc; @@ -439,7 +439,7 @@ int device_id, display_help = 0; return 0; } - ao_msg(MSGT_AO,MSGL_V, "init([%dHz][%dch][%s][%d])\n", rate, channels, af_fmt2str_short(format), flags); + ao_msg(MSGT_AO,MSGL_V, "init([%dHz][%dch][%s][%d])\n", rate, ao_data.channels.num, af_fmt2str_short(format), flags); ao = calloc(1, sizeof(ao_coreaudio_t)); @@ -502,7 +502,7 @@ int device_id, display_help = 0; // Build Description for the input format inDesc.mSampleRate=rate; inDesc.mFormatID=ao->b_supports_digital ? kAudioFormat60958AC3 : kAudioFormatLinearPCM; - inDesc.mChannelsPerFrame=channels; + inDesc.mChannelsPerFrame=ao_data.channels.num; inDesc.mBitsPerChannel=af_fmt2bits(format); if((format&AF_FORMAT_POINT_MASK)==AF_FORMAT_F) { @@ -521,7 +521,7 @@ int device_id, display_help = 0; inDesc.mFormatFlags |= kAudioFormatFlagIsBigEndian; inDesc.mFramesPerPacket = 1; - ao->packetSize = inDesc.mBytesPerPacket = inDesc.mBytesPerFrame = inDesc.mFramesPerPacket*channels*(inDesc.mBitsPerChannel/8); + ao->packetSize = inDesc.mBytesPerPacket = inDesc.mBytesPerFrame = inDesc.mFramesPerPacket*ao_data.channels.num*(inDesc.mBitsPerChannel/8); print_format(MSGL_V, "source:",&inDesc); if (ao->b_supports_digital) @@ -605,7 +605,9 @@ int device_id, display_help = 0; ao->chunk_size = maxFrames;//*inDesc.mBytesPerFrame; ao_data.samplerate = inDesc.mSampleRate; - ao_data.channels = inDesc.mChannelsPerFrame; + mp_chmap_from_channels(&ao_data.channels, inDesc.mChannelsPerFrame); + // Most likely wrong, but that's what it has been set to. + mp_chmap_reorder_to_alsa(&ao_data.channels); ao_data.bps = ao_data.samplerate * inDesc.mBytesPerFrame; ao_data.outburst = ao->chunk_size; ao_data.buffersize = ao_data.bps; @@ -837,7 +839,8 @@ static int OpenSPDIF(void) ao->chunk_size = ao->stream_format.mBytesPerPacket; ao_data.samplerate = ao->stream_format.mSampleRate; - ao_data.channels = ao->stream_format.mChannelsPerFrame; + // Applies default ordering; ok becazse 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; ao_data.buffersize = ao_data.bps; diff --git a/audio/out/ao_dsound.c b/audio/out/ao_dsound.c index 9ad27306bd..b096dd28db 100644 --- a/audio/out/ao_dsound.c +++ b/audio/out/ao_dsound.c @@ -64,26 +64,6 @@ LIBAO_EXTERN(dsound) static const GUID KSDATAFORMAT_SUBTYPE_PCM = {0x1,0x0000,0x0010, {0x80,0x00,0x00,0xaa,0x00,0x38,0x9b,0x71}}; -#define SPEAKER_FRONT_LEFT 0x1 -#define SPEAKER_FRONT_RIGHT 0x2 -#define SPEAKER_FRONT_CENTER 0x4 -#define SPEAKER_LOW_FREQUENCY 0x8 -#define SPEAKER_BACK_LEFT 0x10 -#define SPEAKER_BACK_RIGHT 0x20 -#define SPEAKER_FRONT_LEFT_OF_CENTER 0x40 -#define SPEAKER_FRONT_RIGHT_OF_CENTER 0x80 -#define SPEAKER_BACK_CENTER 0x100 -#define SPEAKER_SIDE_LEFT 0x200 -#define SPEAKER_SIDE_RIGHT 0x400 -#define SPEAKER_TOP_CENTER 0x800 -#define SPEAKER_TOP_FRONT_LEFT 0x1000 -#define SPEAKER_TOP_FRONT_CENTER 0x2000 -#define SPEAKER_TOP_FRONT_RIGHT 0x4000 -#define SPEAKER_TOP_BACK_LEFT 0x8000 -#define SPEAKER_TOP_BACK_CENTER 0x10000 -#define SPEAKER_TOP_BACK_RIGHT 0x20000 -#define SPEAKER_RESERVED 0x80000000 - #if 0 #define DSSPEAKER_HEADPHONE 0x00000001 #define DSSPEAKER_MONO 0x00000002 @@ -107,28 +87,6 @@ typedef struct { } WAVEFORMATEXTENSIBLE, *PWAVEFORMATEXTENSIBLE; #endif -static const int channel_mask[] = { - /* 1 */ SPEAKER_FRONT_CENTER, - /* 2 */ SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT, - /* 3 */ SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT - | SPEAKER_LOW_FREQUENCY, - /* 4 */ SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT - | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT, - /* 5 */ SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT - | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT - | SPEAKER_LOW_FREQUENCY, - /* 6 */ SPEAKER_FRONT_LEFT | SPEAKER_FRONT_CENTER | SPEAKER_FRONT_RIGHT - | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT - | SPEAKER_LOW_FREQUENCY, - /* 7 */ SPEAKER_FRONT_LEFT | SPEAKER_FRONT_CENTER | SPEAKER_FRONT_RIGHT - | SPEAKER_BACK_LEFT | SPEAKER_BACK_CENTER | SPEAKER_BACK_RIGHT - | SPEAKER_LOW_FREQUENCY, - /* 8 */ SPEAKER_FRONT_LEFT | SPEAKER_FRONT_CENTER | SPEAKER_FRONT_RIGHT - | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT - | SPEAKER_SIDE_LEFT | SPEAKER_SIDE_RIGHT - | SPEAKER_LOW_FREQUENCY, -}; - static HINSTANCE hdsound_dll = NULL; ///handle to the dll static LPDIRECTSOUND hds = NULL; ///direct sound object static LPDIRECTSOUNDBUFFER hdspribuf = NULL; ///primary direct sound buffer @@ -349,22 +307,9 @@ static int write_buffer(unsigned char *data, int len) if (SUCCEEDED(res)) { if (!AF_FORMAT_IS_AC3(ao_data.format)) { - int sampsize = af_fmt2bits(ao_data.format) / 8; - reorder_channel_copy_nch(data, - AF_CHANNEL_LAYOUT_MPLAYER_DEFAULT, - lpvPtr1, - AF_CHANNEL_LAYOUT_WAVEEX_DEFAULT, - ao_data.channels, - dwBytes1 / sampsize, - sampsize); + memcpy(lpvPtr1, data, dwBytes1); if (lpvPtr2 != NULL) - reorder_channel_copy_nch(data + dwBytes1, - AF_CHANNEL_LAYOUT_MPLAYER_DEFAULT, - lpvPtr2, - AF_CHANNEL_LAYOUT_WAVEEX_DEFAULT, - ao_data.channels, - dwBytes2 / sampsize, - sampsize); + memcpy(lpvPtr2, (char *)data + dwBytes1, dwBytes2); write_offset+=dwBytes1+dwBytes2; if(write_offset>=buffer_size) @@ -432,7 +377,7 @@ static int control(int cmd, void *arg) \param flags unused \return 1=success 0=fail */ -static int init(int rate, int channels, int format, int flags) +static int init(int rate, const struct mp_chmap *channels, int format, int flags) { int res; if (!InitDirectSound()) return 0; @@ -446,14 +391,17 @@ static int init(int rate, int channels, int format, int flags) DSBUFFERDESC dsbdesc; //check if the channel count and format is supported in general - if (channels > FF_ARRAY_ELEMS(channel_mask)) { + 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"); + mp_msg(MSGT_AO, MSGL_ERR, "ao_dsound: > 8 channel audio not yet supported\n"); return 0; } if (AF_FORMAT_IS_AC3(format)) format = AF_FORMAT_AC3_NE; + else + mp_chmap_reorder_to_waveext(&ao_data.channels); switch(format){ case AF_FORMAT_AC3_NE: case AF_FORMAT_S24_LE: @@ -465,25 +413,24 @@ static int init(int rate, int channels, int format, int flags) format=AF_FORMAT_S16_LE; } //fill global ao_data - ao_data.channels = channels; ao_data.samplerate = rate; ao_data.format = format; - ao_data.bps = channels * rate * (af_fmt2bits(format)>>3); + ao_data.bps = ao_data.channels.num * rate * (af_fmt2bits(format)>>3); if(ao_data.buffersize==-1) ao_data.buffersize = ao_data.bps; // space for 1 sec - mp_msg(MSGT_AO, MSGL_V,"ao_dsound: Samplerate:%iHz Channels:%i Format:%s\n", rate, channels, af_fmt2str_short(format)); + mp_msg(MSGT_AO, MSGL_V,"ao_dsound: Samplerate:%iHz Channels:%i Format:%s\n", rate, ao_data.channels.num, af_fmt2str_short(format)); mp_msg(MSGT_AO, MSGL_V,"ao_dsound: Buffersize:%d bytes (%d msec)\n", ao_data.buffersize, ao_data.buffersize / ao_data.bps * 1000); //fill waveformatex ZeroMemory(&wformat, sizeof(WAVEFORMATEXTENSIBLE)); - wformat.Format.cbSize = (channels > 2) ? sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX) : 0; - wformat.Format.nChannels = channels; + wformat.Format.cbSize = (ao_data.channels.num > 2) ? sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX) : 0; + wformat.Format.nChannels = ao_data.channels.num; wformat.Format.nSamplesPerSec = rate; if (AF_FORMAT_IS_AC3(format)) { wformat.Format.wFormatTag = WAVE_FORMAT_DOLBY_AC3_SPDIF; wformat.Format.wBitsPerSample = 16; wformat.Format.nBlockAlign = 4; } else { - wformat.Format.wFormatTag = (channels > 2) ? WAVE_FORMAT_EXTENSIBLE : WAVE_FORMAT_PCM; + wformat.Format.wFormatTag = (ao_data.channels.num > 2) ? WAVE_FORMAT_EXTENSIBLE : WAVE_FORMAT_PCM; wformat.Format.wBitsPerSample = af_fmt2bits(format); wformat.Format.nBlockAlign = wformat.Format.nChannels * (wformat.Format.wBitsPerSample >> 3); } @@ -503,8 +450,8 @@ static int init(int rate, int channels, int format, int flags) | DSBCAPS_GLOBALFOCUS /** Allows background playing */ | DSBCAPS_CTRLVOLUME; /** volume control enabled */ - if (channels > 2) { - wformat.dwChannelMask = channel_mask[channels - 1]; + if (ao_data.channels.num > 2) { + wformat.dwChannelMask = mp_chmap_to_waveext(&ao_data.channels); wformat.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; wformat.Samples.wValidBitsPerSample = wformat.Format.wBitsPerSample; // Needed for 5.1 on emu101k - shit soundblaster diff --git a/audio/out/ao_jack.c b/audio/out/ao_jack.c index b75122dc17..aea64ee02c 100644 --- a/audio/out/ao_jack.c +++ b/audio/out/ao_jack.c @@ -202,7 +202,8 @@ static void print_help (void) ); } -static int init(int rate, int channels, int format, int flags) { +static int init(int rate, const struct mp_chmap *channels, int format, int flags) +{ const char **matching_ports = NULL; char *port_name = NULL; char *client_name = NULL; @@ -222,8 +223,9 @@ static int init(int rate, int channels, int format, int flags) { print_help(); return 0; } - if (channels > MAX_CHANS) { - mp_msg(MSGT_AO, MSGL_FATAL, "[JACK] Invalid number of channels: %i\n", channels); + if (ao_data.channels.num > MAX_CHANS) { + mp_msg(MSGT_AO, MSGL_FATAL, "[JACK] Invalid number of channels: %i\n", + ao_data.channels.num); goto err_out; } if (!client_name) { @@ -249,9 +251,9 @@ static int init(int rate, int channels, int format, int flags) { goto err_out; } i = 1; + num_ports = ao_data.channels.num; while (matching_ports[i]) i++; - if (channels > i) channels = i; - num_ports = channels; + if (num_ports > i) num_ports = i; // create out output ports for (i = 0; i < num_ports; i++) { @@ -281,10 +283,11 @@ static int init(int rate, int channels, int format, int flags) { / (float)rate; callback_interval = 0; - ao_data.channels = channels; + mp_chmap_from_channels(&ao_data.channels, num_ports); + mp_chmap_reorder_to_alsa(&ao_data.channels); // what order does hack use? ao_data.samplerate = rate; ao_data.format = AF_FORMAT_FLOAT_NE; - ao_data.bps = channels * rate * sizeof(float); + ao_data.bps = ao_data.channels.num * rate * sizeof(float); ao_data.buffersize = CHUNK_SIZE * NUM_CHUNKS; ao_data.outburst = CHUNK_SIZE; free(matching_ports); diff --git a/audio/out/ao_lavc.c b/audio/out/ao_lavc.c index 062d1b928b..0b989224c4 100644 --- a/audio/out/ao_lavc.c +++ b/audio/out/ao_lavc.c @@ -101,7 +101,10 @@ static int init(struct ao *ao, char *params) ac->stream->codec->time_base.den = ao->samplerate; ac->stream->codec->sample_rate = ao->samplerate; - ac->stream->codec->channels = ao->channels; + + 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->stream->codec->sample_fmt = AV_SAMPLE_FMT_NONE; @@ -243,36 +246,6 @@ out_takefirst: ac->stream->codec->bits_per_raw_sample = ac->sample_size * 8; - switch (ao->channels) { - case 1: - ac->stream->codec->channel_layout = AV_CH_LAYOUT_MONO; - break; - case 2: - ac->stream->codec->channel_layout = AV_CH_LAYOUT_STEREO; - break; - /* someone please check if these are what mplayer normally assumes - case 3: - ac->stream->codec->channel_layout = AV_CH_LAYOUT_SURROUND; - break; - case 4: - ac->stream->codec->channel_layout = AV_CH_LAYOUT_2_2; - break; - */ - case 5: - ac->stream->codec->channel_layout = AV_CH_LAYOUT_5POINT0; - break; - case 6: - ac->stream->codec->channel_layout = AV_CH_LAYOUT_5POINT1; - break; - case 8: - ac->stream->codec->channel_layout = AV_CH_LAYOUT_7POINT1; - break; - default: - mp_msg(MSGT_ENCODE, MSGL_ERR, - "ao-lavc: unknown channel layout; hoping for the best\n"); - break; - } - if (encode_lavc_open_codec(ao->encode_lavc_ctx, ac->stream) < 0) return -1; @@ -282,11 +255,12 @@ out_takefirst: if (ac->pcmhack) { ac->aframesize = 16384; // "enough" - ac->buffer_size = ac->aframesize * ac->pcmhack * ao->channels * 2 + 200; + ac->buffer_size = + ac->aframesize * ac->pcmhack * ao->channels.num * 2 + 200; } else { ac->aframesize = ac->stream->codec->frame_size; - ac->buffer_size = ac->aframesize * ac->sample_size * ao->channels * 2 + - 200; + 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; @@ -304,10 +278,10 @@ out_takefirst: ac->offset_left = ac->offset; //fill_ao_data: - ao->outburst = ac->aframesize * ac->sample_size * ao->channels * - ac->framecount; + ao->outburst = + ac->aframesize * ac->sample_size * ao->channels.num * ac->framecount; ao->buffersize = ao->outburst * 2; - ao->bps = ao->channels * ao->samplerate * ac->sample_size; + ao->bps = ao->channels.num * ao->samplerate * ac->sample_size; ao->untimed = true; ao->priv = ac; @@ -346,12 +320,12 @@ static void uninit(struct ao *ao, bool cut_audio) double pts = ao->pts + ac->offset / (double) ao->samplerate; if (ao->buffer.len > 0) { void *paddingbuf = talloc_size(ao, - ac->aframesize * ao->channels * ac->sample_size); + ac->aframesize * ao->channels.num * ac->sample_size); memcpy(paddingbuf, ao->buffer.start, ao->buffer.len); fill_with_padding((char *) paddingbuf + ao->buffer.len, - (ac->aframesize * ao->channels * ac->sample_size - - ao->buffer.len) / ac->sample_size, - ac->sample_size, ac->sample_padding); + (ac->aframesize * ao->channels.num * ac->sample_size - + ao->buffer.len) / ac->sample_size, + ac->sample_size, ac->sample_padding); encode(ao, pts, paddingbuf); pts += ac->aframesize / (double) ao->samplerate; talloc_free(paddingbuf); @@ -381,12 +355,6 @@ static int encode(struct ao *ao, double apts, void *data) int status, gotpacket; ac->aframecount++; - if (data && (ao->channels == 5 || ao->channels == 6 || ao->channels == 8)) { - reorder_channel_nch(data, AF_CHANNEL_LAYOUT_MPLAYER_DEFAULT, - AF_CHANNEL_LAYOUT_LAVC_DEFAULT, - ao->channels, - ac->aframesize * ao->channels, ac->sample_size); - } if (data) ectx->audio_pts_offset = realapts - apts; @@ -400,12 +368,18 @@ static int encode(struct ao *ao, double apts, void *data) frame->nb_samples = ac->aframesize; if (ac->planarize) { - void *data2 = talloc_size(ao, ac->aframesize * ao->channels * ac->sample_size); - reorder_to_planar(data2, data, ac->sample_size, ao->channels, ac->aframesize); + void *data2 = talloc_size(ao, ac->aframesize * ao->channels.num * + ac->sample_size); + reorder_to_planar(data2, data, ac->sample_size, ao->channels.num, + ac->aframesize); data = data2; } - if (avcodec_fill_audio_frame(frame, ao->channels, ac->stream->codec->sample_fmt, data, ac->aframesize * ao->channels * ac->sample_size, 1)) { + size_t audiolen = ac->aframesize * ao->channels.num * ac->sample_size; + if (avcodec_fill_audio_frame(frame, ao->channels.num, + ac->stream->codec->sample_fmt, data, + audiolen, 1)) + { mp_msg(MSGT_ENCODE, MSGL_ERR, "ao-lavc: error filling\n"); return -1; } @@ -512,7 +486,7 @@ static int play(struct ao *ao, void *data, int len, int flags) double pts = ao->pts; double outpts; - len /= ac->sample_size * ao->channels; + len /= ac->sample_size * ao->channels.num; if (!encode_lavc_start(ectx)) { mp_msg(MSGT_ENCODE, MSGL_WARN, @@ -581,7 +555,7 @@ static int play(struct ao *ao, void *data, int len, int flags) if (ac->offset_left <= -len) { // skip whole frame ac->offset_left += len; - return len * ac->sample_size * ao->channels; + return len * ac->sample_size * ao->channels.num; } else { // skip part of this frame, buffer/encode the rest bufpos -= ac->offset_left; @@ -592,11 +566,11 @@ static int play(struct ao *ao, void *data, int len, int flags) // make a temporary buffer, filled with zeroes at the start // (don't worry, only happens once) - paddingbuf = talloc_size(ac, ac->sample_size * ao->channels * + paddingbuf = talloc_size(ac, ac->sample_size * ao->channels.num * (ac->offset_left + len)); fill_with_padding(paddingbuf, ac->offset_left, ac->sample_size, ac->sample_padding); - data = (char *) paddingbuf + ac->sample_size * ao->channels * + data = (char *) paddingbuf + ac->sample_size * ao->channels.num * ac->offset_left; bufpos -= ac->offset_left; // yes, negative! ptsoffset += ac->offset_left; @@ -639,7 +613,7 @@ static int play(struct ao *ao, void *data, int len, int flags) while (len - bufpos >= ac->aframesize) { encode(ao, outpts + (bufpos + ptsoffset) / (double) ao->samplerate + encode_lavc_getoffset(ectx, ac->stream), - (char *) data + ac->sample_size * bufpos * ao->channels); + (char *) data + ac->sample_size * bufpos * ao->channels.num); bufpos += ac->aframesize; } @@ -655,7 +629,7 @@ static int play(struct ao *ao, void *data, int len, int flags) ectx->next_in_pts = nextpts; } - return bufpos * ac->sample_size * ao->channels; + return bufpos * ac->sample_size * ao->channels.num; } const struct ao_driver audio_out_lavc = { diff --git a/audio/out/ao_null.c b/audio/out/ao_null.c index 102f0a7013..f6d7bb0c5f 100644 --- a/audio/out/ao_null.c +++ b/audio/out/ao_null.c @@ -49,10 +49,10 @@ static int init(struct ao *ao, char *params) struct priv *priv = talloc_zero(ao, struct priv); ao->priv = priv; int samplesize = af_fmt2bits(ao->format) / 8; - ao->outburst = 256 * ao->channels * samplesize; + ao->outburst = 256 * ao->channels.num * samplesize; // A "buffer" for about 0.2 seconds of audio ao->buffersize = (int)(ao->samplerate * 0.2 / 256 + 1) * ao->outburst; - ao->bps = ao->channels * ao->samplerate * samplesize; + ao->bps = ao->channels.num * ao->samplerate * samplesize; priv->last_time = GetTimer(); return 0; diff --git a/audio/out/ao_openal.c b/audio/out/ao_openal.c index 157cf93ac4..e6e1369a2f 100644 --- a/audio/out/ao_openal.c +++ b/audio/out/ao_openal.c @@ -109,7 +109,9 @@ static void list_devices(void) { } } -static int init(int rate, int channels, int format, int flags) { +static int init(int rate, const struct mp_chmap *channels, int format, + int flags) +{ float position[3] = {0, 0, 0}; float direction[6] = {0, 0, 1, 0, -1, 0}; float sppos[MAX_CHANS][3] = { @@ -137,8 +139,9 @@ static int init(int rate, int channels, int format, int flags) { list_devices(); goto err_out; } - if (channels > MAX_CHANS) { - mp_msg(MSGT_AO, MSGL_FATAL, "[OpenAL] Invalid number of channels: %i\n", channels); + if (ao_data.channels.num > MAX_CHANS) { + mp_msg(MSGT_AO, MSGL_FATAL, "[OpenAL] Invalid number of channels: %i\n", + ao_data.channels.num); goto err_out; } dev = alcOpenDevice(device); @@ -150,25 +153,25 @@ static int init(int rate, int channels, int format, int flags) { alcMakeContextCurrent(ctx); alListenerfv(AL_POSITION, position); alListenerfv(AL_ORIENTATION, direction); - alGenSources(channels, sources); - for (i = 0; i < channels; i++) { + alGenSources(ao_data.channels.num, sources); + for (i = 0; i < ao_data.channels.num; i++) { cur_buf[i] = 0; unqueue_buf[i] = 0; alGenBuffers(NUM_BUF, buffers[i]); alSourcefv(sources[i], AL_POSITION, sppos[i]); alSource3f(sources[i], AL_VELOCITY, 0, 0, 0); } - if (channels == 1) + if (ao_data.channels.num == 1) alSource3f(sources[0], AL_POSITION, 0, 0, 1); - ao_data.channels = channels; alcGetIntegerv(dev, ALC_FREQUENCY, 1, &freq); if (alcGetError(dev) == ALC_NO_ERROR && freq) rate = freq; ao_data.samplerate = rate; ao_data.format = AF_FORMAT_S16_NE; - ao_data.bps = channels * rate * 2; + ao_data.bps = ao_data.channels.num * rate * 2; ao_data.buffersize = CHUNK_SIZE * NUM_BUF; - ao_data.outburst = channels * CHUNK_SIZE; + ao_data.outburst = ao_data.channels.num * CHUNK_SIZE; + mp_chmap_reorder_to_alsa(&ao_data.channels); // sppos[][] matrix is for ALSA tmpbuf = malloc(CHUNK_SIZE); free(device); return 1; @@ -200,7 +203,7 @@ static void uninit(int immed) { static void unqueue_buffers(void) { ALint p; int s; - for (s = 0; s < ao_data.channels; s++) { + for (s = 0; s < ao_data.channels.num; s++) { int till_wrap = NUM_BUF - unqueue_buf[s]; alGetSourcei(sources[s], AL_BUFFERS_PROCESSED, &p); if (p >= till_wrap) { @@ -219,7 +222,7 @@ static void unqueue_buffers(void) { * \brief stop playing and empty buffers (for seeking/pause) */ static void reset(void) { - alSourceStopv(ao_data.channels, sources); + alSourceStopv(ao_data.channels.num, sources); unqueue_buffers(); } @@ -227,14 +230,14 @@ static void reset(void) { * \brief stop playing, keep buffers (for pause) */ static void audio_pause(void) { - alSourcePausev(ao_data.channels, sources); + alSourcePausev(ao_data.channels.num, sources); } /** * \brief resume playing, after audio_pause() */ static void audio_resume(void) { - alSourcePlayv(ao_data.channels, sources); + alSourcePlayv(ao_data.channels.num, sources); } static int get_space(void) { @@ -243,7 +246,7 @@ static int get_space(void) { alGetSourcei(sources[0], AL_BUFFERS_QUEUED, &queued); queued = NUM_BUF - queued - 3; if (queued < 0) return 0; - return queued * CHUNK_SIZE * ao_data.channels; + return queued * CHUNK_SIZE * ao_data.channels.num; } /** @@ -254,22 +257,22 @@ static int play(void *data, int len, int flags) { int i, j, k; int ch; int16_t *d = data; - len /= ao_data.channels * CHUNK_SIZE; + len /= ao_data.channels.num * CHUNK_SIZE; for (i = 0; i < len; i++) { - for (ch = 0; ch < ao_data.channels; ch++) { - for (j = 0, k = ch; j < CHUNK_SIZE / 2; j++, k += ao_data.channels) + for (ch = 0; ch < ao_data.channels.num; ch++) { + for (j = 0, k = ch; j < CHUNK_SIZE / 2; j++, k += ao_data.channels.num) tmpbuf[j] = d[k]; alBufferData(buffers[ch][cur_buf[ch]], AL_FORMAT_MONO16, tmpbuf, CHUNK_SIZE, ao_data.samplerate); alSourceQueueBuffers(sources[ch], 1, &buffers[ch][cur_buf[ch]]); cur_buf[ch] = (cur_buf[ch] + 1) % NUM_BUF; } - d += ao_data.channels * CHUNK_SIZE / 2; + d += ao_data.channels.num * CHUNK_SIZE / 2; } alGetSourcei(sources[0], AL_SOURCE_STATE, &state); if (state != AL_PLAYING) // checked here in case of an underrun - alSourcePlayv(ao_data.channels, sources); - return len * ao_data.channels * CHUNK_SIZE; + alSourcePlayv(ao_data.channels.num, sources); + return len * ao_data.channels.num * CHUNK_SIZE; } static float get_delay(void) { diff --git a/audio/out/ao_oss.c b/audio/out/ao_oss.c index fa8eccdeea..805a14cd8f 100644 --- a/audio/out/ao_oss.c +++ b/audio/out/ao_oss.c @@ -221,12 +221,12 @@ static int control(int cmd,void *arg){ // open & setup audio device // return: 1=success 0=fail -static int init(int rate,int channels,int format,int flags){ +static int init(int rate,const struct mp_chmap *channels,int format,int flags){ char *mixer_channels [SOUND_MIXER_NRDEVICES] = SOUND_DEVICE_NAMES; int oss_format; char *mdev = mixer_device, *mchan = mixer_channel; - mp_msg(MSGT_AO,MSGL_V,"ao2: %d Hz %d chans %s\n",rate,channels, + mp_msg(MSGT_AO,MSGL_V,"ao2: %d Hz %d chans %s\n",rate,ao_data.channels.num, af_fmt2str_short(format)); if (ao_subdevice) { @@ -339,25 +339,27 @@ ac3_retry: mp_msg(MSGT_AO,MSGL_V,"audio_setup: sample format: %s (requested: %s)\n", af_fmt2str_short(ao_data.format), af_fmt2str_short(format)); - ao_data.channels = channels; if(!AF_FORMAT_IS_AC3(format)) { + mp_chmap_reorder_to_alsa(&ao_data.channels); + int reqchannels = ao_data.channels.num; // We only use SNDCTL_DSP_CHANNELS for >2 channels, in case some drivers don't have it - if (ao_data.channels > 2) { - if ( ioctl(audio_fd, SNDCTL_DSP_CHANNELS, &ao_data.channels) == -1 || - ao_data.channels != channels ) { - mp_tmsg(MSGT_AO,MSGL_ERR,"[AO OSS] audio_setup: Failed to set audio device to %d channels.\n", channels); + if (reqchannels > 2) { + int nchannels = reqchannels; + if ( ioctl(audio_fd, SNDCTL_DSP_CHANNELS, &nchannels) == -1 || + nchannels != reqchannels ) { + mp_tmsg(MSGT_AO,MSGL_ERR,"[AO OSS] audio_setup: Failed to set audio device to %d channels.\n", reqchannels); return 0; } } else { - int c = ao_data.channels-1; + int c = reqchannels-1; if (ioctl (audio_fd, SNDCTL_DSP_STEREO, &c) == -1) { - mp_tmsg(MSGT_AO,MSGL_ERR,"[AO OSS] audio_setup: Failed to set audio device to %d channels.\n", ao_data.channels); + mp_tmsg(MSGT_AO,MSGL_ERR,"[AO OSS] audio_setup: Failed to set audio device to %d channels.\n", reqchannels); return 0; } - ao_data.channels=c+1; + mp_chmap_from_channels(&ao_data.channels, c + 1); } - mp_msg(MSGT_AO,MSGL_V,"audio_setup: using %d channels (requested: %d)\n", ao_data.channels, channels); + mp_msg(MSGT_AO,MSGL_V,"audio_setup: using %d channels (requested: %d)\n", ao_data.channels.num, reqchannels); // set rate ao_data.samplerate=rate; ioctl (audio_fd, SNDCTL_DSP_SPEED, &ao_data.samplerate); @@ -403,7 +405,7 @@ ac3_retry: #endif } - ao_data.bps=ao_data.channels; + ao_data.bps=ao_data.channels.num; switch (ao_data.format & AF_FORMAT_BITS_MASK) { case AF_FORMAT_8BIT: break; @@ -459,10 +461,10 @@ static void reset(void){ ioctl (audio_fd, SNDCTL_DSP_SPEED, &ao_data.samplerate); ioctl (audio_fd, SNDCTL_DSP_SETFMT, &oss_format); if(!AF_FORMAT_IS_AC3(ao_data.format)) { - if (ao_data.channels > 2) - ioctl (audio_fd, SNDCTL_DSP_CHANNELS, &ao_data.channels); + if (ao_data.channels.num > 2) + ioctl (audio_fd, SNDCTL_DSP_CHANNELS, &ao_data.channels.num); else { - int c = ao_data.channels-1; + int c = ao_data.channels.num-1; ioctl (audio_fd, SNDCTL_DSP_STEREO, &c); } ioctl (audio_fd, SNDCTL_DSP_SPEED, &ao_data.samplerate); diff --git a/audio/out/ao_pcm.c b/audio/out/ao_pcm.c index 5b3cc94395..22d40671cb 100644 --- a/audio/out/ao_pcm.c +++ b/audio/out/ao_pcm.c @@ -69,7 +69,7 @@ static void fput32le(uint32_t val, FILE *fp) static void write_wave_header(struct ao *ao, FILE *fp, uint64_t data_length) { - bool use_waveex = ao->channels >= 5 && ao->channels <= 8; + bool use_waveex = true; uint16_t fmt = ao->format == AF_FORMAT_FLOAT_LE ? WAV_ID_FLOAT_PCM : WAV_ID_PCM; uint32_t fmt_chunk_size = use_waveex ? 40 : 16; @@ -86,30 +86,17 @@ static void write_wave_header(struct ao *ao, FILE *fp, uint64_t data_length) fput32le(WAV_ID_FMT, fp); fput32le(fmt_chunk_size, fp); fput16le(use_waveex ? WAV_ID_FORMAT_EXTENSIBLE : fmt, fp); - fput16le(ao->channels, fp); + fput16le(ao->channels.num, fp); fput32le(ao->samplerate, fp); fput32le(ao->bps, fp); - fput16le(ao->channels * (bits / 8), fp); + fput16le(ao->channels.num * (bits / 8), fp); fput16le(bits, fp); if (use_waveex) { // Extension chunk fput16le(22, fp); fput16le(bits, fp); - switch (ao->channels) { - case 5: - fput32le(0x0607, fp); // L R C Lb Rb - break; - case 6: - fput32le(0x060f, fp); // L R C Lb Rb LFE - break; - case 7: - fput32le(0x0727, fp); // L R C Cb Ls Rs LFE - break; - case 8: - fput32le(0x063f, fp); // L R C Lb Rb Ls Rs LFE - break; - } + fput32le(mp_chmap_to_waveext(&ao->channels), fp); // 2 bytes format + 14 bytes guid fput32le(fmt, fp); fput32le(0x00100000, fp); @@ -159,14 +146,16 @@ static int init(struct ao *ao, char *params) } } + mp_chmap_reorder_to_waveext(&ao->channels); + ao->outburst = 65536; - ao->bps = ao->channels * ao->samplerate * (af_fmt2bits(ao->format) / 8); + ao->bps = ao->channels.num * ao->samplerate * (af_fmt2bits(ao->format) / 8); mp_tmsg(MSGT_AO, MSGL_INFO, "[AO PCM] File: %s (%s)\n" "PCM: Samplerate: %d Hz Channels: %d Format: %s\n", priv->outputfilename, priv->waveheader ? "WAVE" : "RAW PCM", ao->samplerate, - ao->channels, af_fmt2str_short(ao->format)); + ao->channels.num, af_fmt2str_short(ao->format)); mp_tmsg(MSGT_AO, MSGL_INFO, "[AO PCM] Info: Faster dumping is achieved with -no-video\n" "[AO PCM] Info: To write WAVE files use -ao pcm:waveheader (default).\n"); @@ -222,13 +211,6 @@ static int play(struct ao *ao, void *data, int len, int flags) { struct priv *priv = ao->priv; - if (ao->channels == 5 || ao->channels == 6 || ao->channels == 8) { - int frame_size = af_fmt2bits(ao->format) / 8; - len -= len % (frame_size * ao->channels); - reorder_channel_nch(data, AF_CHANNEL_LAYOUT_MPLAYER_DEFAULT, - AF_CHANNEL_LAYOUT_WAVEEX_DEFAULT, - ao->channels, len / frame_size, frame_size); - } fwrite(data, len, 1, priv->fp); priv->data_length += len; return len; diff --git a/audio/out/ao_portaudio.c b/audio/out/ao_portaudio.c index b0744e8f8a..0141e4796d 100644 --- a/audio/out/ao_portaudio.c +++ b/audio/out/ao_portaudio.c @@ -273,9 +273,11 @@ static int init(struct ao *ao, char *params) if (pa_device == paNoDevice) goto error_exit; + mp_chmap_reorder_to_alsa(&ao->channels); + PaStreamParameters sp = { .device = pa_device, - .channelCount = ao->channels, + .channelCount = ao->channels.num, .suggestedLatency = Pa_GetDeviceInfo(pa_device)->defaultHighOutputLatency, }; @@ -298,7 +300,7 @@ static int init(struct ao *ao, char *params) ao->format = fmt->mp_format; sp.sampleFormat = fmt->pa_format; - priv->framelen = ao->channels * (af_fmt2bits(ao->format) / 8); + priv->framelen = ao->channels.num * (af_fmt2bits(ao->format) / 8); ao->bps = ao->samplerate * priv->framelen; if (!check_pa_ret(Pa_IsFormatSupported(NULL, &sp, ao->samplerate))) diff --git a/audio/out/ao_pulse.c b/audio/out/ao_pulse.c index bb5af6f851..7f3619386e 100644 --- a/audio/out/ao_pulse.c +++ b/audio/out/ao_pulse.c @@ -209,7 +209,7 @@ static int init(struct ao *ao, char *params) priv->broken_pause = true; } - ss.channels = ao->channels; + ss.channels = ao->channels.num; ss.rate = ao->samplerate; const struct format_map *fmt_map = format_maps; @@ -230,7 +230,9 @@ static int init(struct ao *ao, char *params) goto fail; } + mp_chmap_reorder_to_waveext(&ao->channels); pa_channel_map_init_auto(&map, ss.channels, PA_CHANNEL_MAP_WAVEEX); + ao->bps = pa_bytes_per_second(&ss); if (!(priv->mainloop = pa_threaded_mainloop_new())) { @@ -495,7 +497,7 @@ static int control(struct ao *ao, enum aocontrol cmd, void *arg) const ao_control_vol_t *vol = arg; struct pa_cvolume volume; - pa_cvolume_reset(&volume, ao->channels); + pa_cvolume_reset(&volume, ao->channels.num); if (volume.channels != 2) pa_cvolume_set(&volume, volume.channels, VOL_MP2PA(vol->left)); else { diff --git a/audio/out/ao_rsound.c b/audio/out/ao_rsound.c index 7722bf19d2..004beb0867 100644 --- a/audio/out/ao_rsound.c +++ b/audio/out/ao_rsound.c @@ -121,8 +121,10 @@ static int init(struct ao *ao, char *params) free(port); } + mp_chmap_reorder_to_alsa(&ao->channels); + rsd_set_param(priv->rd, RSD_SAMPLERATE, &ao->samplerate); - rsd_set_param(priv->rd, RSD_CHANNELS, &ao->channels); + rsd_set_param(priv->rd, RSD_CHANNELS, &ao->channels.num); int rsd_format = set_format(ao); rsd_set_param(priv->rd, RSD_FORMAT, &rsd_format); @@ -132,7 +134,7 @@ static int init(struct ao *ao, char *params) return -1; } - ao->bps = ao->channels * ao->samplerate * af_fmt2bits(ao->format) / 8; + ao->bps = ao->channels.num * ao->samplerate * af_fmt2bits(ao->format) / 8; return 0; } diff --git a/audio/out/ao_sdl.c b/audio/out/ao_sdl.c index 7cfb1ae1e2..c91b16e4bc 100644 --- a/audio/out/ao_sdl.c +++ b/audio/out/ao_sdl.c @@ -185,7 +185,7 @@ static int init(struct ao *ao, char *params) #endif } desired.freq = ao->samplerate; - desired.channels = ao->channels; + desired.channels = ao->channels.num; desired.samples = FFMIN(32768, ceil_power_of_two(ao->samplerate * buflen)); desired.callback = audio_callback; desired.userdata = ao; @@ -237,8 +237,9 @@ static int init(struct ao *ao, char *params) } ao->samplerate = obtained.freq; - ao->channels = obtained.channels; - ao->bps = ao->channels * ao->samplerate * bytes; + 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; priv->buffer = av_fifo_alloc(ao->buffersize); diff --git a/audio/out/audio_out_internal.h b/audio/out/audio_out_internal.h index f3e92dff66..7b863cfd21 100644 --- a/audio/out/audio_out_internal.h +++ b/audio/out/audio_out_internal.h @@ -20,11 +20,12 @@ #define MPLAYER_AUDIO_OUT_INTERNAL_H #include "core/options.h" +#include "ao.h" // prototypes: //static ao_info_t info; static int control(int cmd, void *arg); -static int init(int rate,int channels,int format,int flags); +static int init(int rate,const struct mp_chmap *channels,int format,int flags); static void uninit(int immed); static void reset(void); static int get_space(void); -- cgit v1.2.3 From bf014677cecbc5ff425f0ad9f23e41c19be4ad3d Mon Sep 17 00:00:00 2001 From: wm4 Date: Sat, 6 Apr 2013 23:36:00 +0200 Subject: ao_pulse: try to set correct channel layout Like most other AOs, ao_pulse set the channel count only, always using a default layout. Try to set the exact layout. For this, we need a big lookup table to map waveex/lavc/mpv speaker position to PulseAudio's, since PA_CHANNEL_POSITION_ is apparently not compatible to waveext, and I haven't seen any API functions that would help mapping them. Completely untested. (Let's leave that to someone else...) --- audio/out/ao_pulse.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 54 insertions(+), 2 deletions(-) (limited to 'audio/out') diff --git a/audio/out/ao_pulse.c b/audio/out/ao_pulse.c index 7f3619386e..dedb067357 100644 --- a/audio/out/ao_pulse.c +++ b/audio/out/ao_pulse.c @@ -143,6 +143,50 @@ static const struct format_map { {AF_FORMAT_UNKNOWN, 0} }; +static const int speaker_map[][2] = { + {PA_CHANNEL_POSITION_MONO, MP_SPEAKER_ID_FC}, + {PA_CHANNEL_POSITION_FRONT_LEFT, MP_SPEAKER_ID_FL}, + {PA_CHANNEL_POSITION_FRONT_RIGHT, MP_SPEAKER_ID_FR}, + {PA_CHANNEL_POSITION_FRONT_CENTER, MP_SPEAKER_ID_FC}, + {PA_CHANNEL_POSITION_REAR_CENTER, MP_SPEAKER_ID_BC}, + {PA_CHANNEL_POSITION_REAR_LEFT, MP_SPEAKER_ID_BL}, + {PA_CHANNEL_POSITION_REAR_RIGHT, MP_SPEAKER_ID_BR}, + {PA_CHANNEL_POSITION_LFE, MP_SPEAKER_ID_LFE}, + {PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER, MP_SPEAKER_ID_FLC}, + {PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER, MP_SPEAKER_ID_FRC}, + {PA_CHANNEL_POSITION_SIDE_LEFT, MP_SPEAKER_ID_SL}, + {PA_CHANNEL_POSITION_SIDE_RIGHT, MP_SPEAKER_ID_SR}, + {PA_CHANNEL_POSITION_TOP_CENTER, MP_SPEAKER_ID_TC}, + {PA_CHANNEL_POSITION_TOP_FRONT_LEFT, MP_SPEAKER_ID_TFL}, + {PA_CHANNEL_POSITION_TOP_FRONT_RIGHT, MP_SPEAKER_ID_TFR}, + {PA_CHANNEL_POSITION_TOP_FRONT_CENTER, MP_SPEAKER_ID_TFC}, + {PA_CHANNEL_POSITION_TOP_REAR_LEFT, MP_SPEAKER_ID_TBL}, + {PA_CHANNEL_POSITION_TOP_REAR_RIGHT, MP_SPEAKER_ID_TBR}, + {PA_CHANNEL_POSITION_TOP_REAR_CENTER, MP_SPEAKER_ID_TBC}, + {PA_CHANNEL_POSITION_INVALID, -1} +}; + +static bool chmap_pa_from_mp(pa_channel_map *dst, struct mp_chmap *src) +{ + if (src->num > PA_CHANNELS_MAX) + return false; + dst->channels = src->num; + for (int n = 0; n < src->num; n++) { + int mp_speaker = src->speaker[n]; + int pa_speaker = PA_CHANNEL_POSITION_INVALID; + for (int i = 0; speaker_map[i][1] != -1; i++) { + if (speaker_map[i][1] == mp_speaker) { + pa_speaker = speaker_map[i][0]; + break; + } + } + if (pa_speaker == PA_CHANNEL_POSITION_INVALID) + return false; + dst->map[n] = pa_speaker; + } + return true; +} + static void uninit(struct ao *ao, bool cut_audio) { struct priv *priv = ao->priv; @@ -230,8 +274,16 @@ static int init(struct ao *ao, char *params) goto fail; } - mp_chmap_reorder_to_waveext(&ao->channels); - pa_channel_map_init_auto(&map, ss.channels, PA_CHANNEL_MAP_WAVEEX); + 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); + } ao->bps = pa_bytes_per_second(&ss); -- cgit v1.2.3 From ade08d676f11d183d1d0b1709be97acefd330cb6 Mon Sep 17 00:00:00 2001 From: wm4 Date: Sun, 7 Apr 2013 00:51:13 +0200 Subject: ao_coreaudio: switch to WAVEEXT channel order This used ALSA order, which was not correct. Most likely this has been wrong since forever. --- audio/out/ao_coreaudio.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'audio/out') diff --git a/audio/out/ao_coreaudio.c b/audio/out/ao_coreaudio.c index 98b9f9adeb..a3c6907ed4 100644 --- a/audio/out/ao_coreaudio.c +++ b/audio/out/ao_coreaudio.c @@ -606,8 +606,7 @@ int device_id, display_help = 0; ao_data.samplerate = inDesc.mSampleRate; mp_chmap_from_channels(&ao_data.channels, inDesc.mChannelsPerFrame); - // Most likely wrong, but that's what it has been set to. - mp_chmap_reorder_to_alsa(&ao_data.channels); + mp_chmap_reorder_to_waveext(&ao_data.channels); ao_data.bps = ao_data.samplerate * inDesc.mBytesPerFrame; ao_data.outburst = ao->chunk_size; ao_data.buffersize = ao_data.bps; -- cgit v1.2.3 From 7f0f33fc8f105144eaac9653564e91599692e1e7 Mon Sep 17 00:00:00 2001 From: wm4 Date: Sun, 7 Apr 2013 21:34:09 +0200 Subject: ao_alsa: uncrustify --- audio/out/ao_alsa.c | 1340 +++++++++++++++++++++++++++------------------------ 1 file changed, 717 insertions(+), 623 deletions(-) (limited to 'audio/out') diff --git a/audio/out/ao_alsa.c b/audio/out/ao_alsa.c index a194ce0478..7c925687c9 100644 --- a/audio/out/ao_alsa.c +++ b/audio/out/ao_alsa.c @@ -60,7 +60,7 @@ static const ao_info_t info = LIBAO_EXTERN(alsa) -static snd_pcm_t *alsa_handler; +static snd_pcm_t * alsa_handler; static snd_pcm_format_t alsa_format; #define BUFFER_TIME 500000 // 0.5 s @@ -75,263 +75,289 @@ static float delay_before_pause; #define ALSA_DEVICE_SIZE 256 static void alsa_error_handler(const char *file, int line, const char *function, - int err, const char *format, ...) + int err, const char *format, ...) { - char tmp[0xc00]; - va_list va; - - va_start(va, format); - vsnprintf(tmp, sizeof tmp, format, va); - va_end(va); - - if (err) - mp_msg(MSGT_AO, MSGL_ERR, "[AO_ALSA] alsa-lib: %s:%i:(%s) %s: %s\n", - file, line, function, tmp, snd_strerror(err)); - else - mp_msg(MSGT_AO, MSGL_ERR, "[AO_ALSA] alsa-lib: %s:%i:(%s) %s\n", - file, line, function, tmp); + char tmp[0xc00]; + va_list va; + + va_start(va, format); + vsnprintf(tmp, sizeof tmp, format, va); + va_end(va); + + if (err) + mp_msg(MSGT_AO, MSGL_ERR, "[AO_ALSA] alsa-lib: %s:%i:(%s) %s: %s\n", + file, line, function, tmp, snd_strerror(err)); + else + mp_msg(MSGT_AO, MSGL_ERR, "[AO_ALSA] alsa-lib: %s:%i:(%s) %s\n", + file, line, function, tmp); } /* to set/get/query special features/parameters */ static int control(int cmd, void *arg) { - switch(cmd) { - case AOCONTROL_GET_MUTE: - case AOCONTROL_SET_MUTE: - case AOCONTROL_GET_VOLUME: - case AOCONTROL_SET_VOLUME: + switch (cmd) { + case AOCONTROL_GET_MUTE: + case AOCONTROL_SET_MUTE: + case AOCONTROL_GET_VOLUME: + case AOCONTROL_SET_VOLUME: { - int err; - snd_mixer_t *handle; - snd_mixer_elem_t *elem; - snd_mixer_selem_id_t *sid; - - char *mix_name = "Master"; - char *card = "default"; - int mix_index = 0; - - long pmin, pmax; - long get_vol, set_vol; - float f_multi; - - if(AF_FORMAT_IS_IEC61937(ao_data.format)) - return CONTROL_TRUE; - - if(mixer_channel) { - char *test_mix_index; - - mix_name = strdup(mixer_channel); - if ((test_mix_index = strchr(mix_name, ','))){ - *test_mix_index = 0; - test_mix_index++; - mix_index = strtol(test_mix_index, &test_mix_index, 0); - - if (*test_mix_index){ - mp_tmsg(MSGT_AO,MSGL_ERR, - "[AO_ALSA] Invalid mixer index. Defaulting to 0.\n"); - mix_index = 0 ; - } - } - } - if(mixer_device) card = mixer_device; - - //allocate simple id - snd_mixer_selem_id_alloca(&sid); - - //sets simple-mixer index and name - snd_mixer_selem_id_set_index(sid, mix_index); - snd_mixer_selem_id_set_name(sid, mix_name); - - if (mixer_channel) { - free(mix_name); - mix_name = NULL; - } - - if ((err = snd_mixer_open(&handle, 0)) < 0) { - mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] Mixer open error: %s\n", snd_strerror(err)); - return CONTROL_ERROR; - } - - if ((err = snd_mixer_attach(handle, card)) < 0) { - mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] Mixer attach %s error: %s\n", - card, snd_strerror(err)); - snd_mixer_close(handle); - return CONTROL_ERROR; - } - - if ((err = snd_mixer_selem_register(handle, NULL, NULL)) < 0) { - mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] Mixer register error: %s\n", snd_strerror(err)); - snd_mixer_close(handle); - return CONTROL_ERROR; - } - err = snd_mixer_load(handle); - if (err < 0) { - mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] Mixer load error: %s\n", snd_strerror(err)); - snd_mixer_close(handle); - return CONTROL_ERROR; - } - - elem = snd_mixer_find_selem(handle, sid); - if (!elem) { - mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] Unable to find simple control '%s',%i.\n", - snd_mixer_selem_id_get_name(sid), snd_mixer_selem_id_get_index(sid)); - snd_mixer_close(handle); - return CONTROL_ERROR; - } - - snd_mixer_selem_get_playback_volume_range(elem,&pmin,&pmax); - f_multi = (100 / (float)(pmax - pmin)); - - switch (cmd) { - case AOCONTROL_SET_VOLUME: { - ao_control_vol_t *vol = arg; - set_vol = vol->left / f_multi + pmin + 0.5; - - //setting channels - if ((err = snd_mixer_selem_set_playback_volume(elem, SND_MIXER_SCHN_FRONT_LEFT, set_vol)) < 0) { - mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] Error setting left channel, %s\n", - snd_strerror(err)); - goto mixer_error; - } - mp_msg(MSGT_AO,MSGL_DBG2,"left=%li, ", set_vol); - - set_vol = vol->right / f_multi + pmin + 0.5; - - if ((err = snd_mixer_selem_set_playback_volume(elem, SND_MIXER_SCHN_FRONT_RIGHT, set_vol)) < 0) { - mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] Error setting right channel, %s\n", - snd_strerror(err)); - goto mixer_error; - } - mp_msg(MSGT_AO,MSGL_DBG2,"right=%li, pmin=%li, pmax=%li, mult=%f\n", - set_vol, pmin, pmax, f_multi); - break; - } - case AOCONTROL_GET_VOLUME: { - ao_control_vol_t *vol = arg; - snd_mixer_selem_get_playback_volume(elem, SND_MIXER_SCHN_FRONT_LEFT, &get_vol); - vol->left = (get_vol - pmin) * f_multi; - snd_mixer_selem_get_playback_volume(elem, SND_MIXER_SCHN_FRONT_RIGHT, &get_vol); - vol->right = (get_vol - pmin) * f_multi; - mp_msg(MSGT_AO,MSGL_DBG2,"left=%f, right=%f\n",vol->left,vol->right); - break; - } - case AOCONTROL_SET_MUTE: { - bool *mute = arg; - if (!snd_mixer_selem_has_playback_switch(elem)) - goto mixer_error; - if (!snd_mixer_selem_has_playback_switch_joined(elem)) { - snd_mixer_selem_set_playback_switch( - elem, SND_MIXER_SCHN_FRONT_RIGHT, !*mute); - } - snd_mixer_selem_set_playback_switch(elem, SND_MIXER_SCHN_FRONT_LEFT, - !*mute); - break; - } - case AOCONTROL_GET_MUTE: { - bool *mute = arg; - if (!snd_mixer_selem_has_playback_switch(elem)) - goto mixer_error; - int tmp = 1; - snd_mixer_selem_get_playback_switch(elem, SND_MIXER_SCHN_FRONT_LEFT, - &tmp); - *mute = !tmp; - if (!snd_mixer_selem_has_playback_switch_joined(elem)) { - snd_mixer_selem_get_playback_switch( - elem, SND_MIXER_SCHN_FRONT_RIGHT, &tmp); - *mute &= !tmp; + int err; + snd_mixer_t *handle; + snd_mixer_elem_t *elem; + snd_mixer_selem_id_t *sid; + + char *mix_name = "Master"; + char *card = "default"; + int mix_index = 0; + + long pmin, pmax; + long get_vol, set_vol; + float f_multi; + + if (AF_FORMAT_IS_IEC61937(ao_data.format)) + return CONTROL_TRUE; + + if (mixer_channel) { + char *test_mix_index; + + mix_name = strdup(mixer_channel); + if ((test_mix_index = strchr(mix_name, ','))) { + *test_mix_index = 0; + test_mix_index++; + mix_index = strtol(test_mix_index, &test_mix_index, 0); + + if (*test_mix_index) { + mp_tmsg(MSGT_AO, MSGL_ERR, + "[AO_ALSA] Invalid mixer index. Defaulting to 0.\n"); + mix_index = 0; + } + } } - break; - } - } - snd_mixer_close(handle); - return CONTROL_OK; - mixer_error: - snd_mixer_close(handle); - return CONTROL_ERROR; + if (mixer_device) + card = mixer_device; + + //allocate simple id + snd_mixer_selem_id_alloca(&sid); + + //sets simple-mixer index and name + snd_mixer_selem_id_set_index(sid, mix_index); + snd_mixer_selem_id_set_name(sid, mix_name); + + if (mixer_channel) { + free(mix_name); + mix_name = NULL; + } + + if ((err = snd_mixer_open(&handle, 0)) < 0) { + mp_tmsg(MSGT_AO, MSGL_ERR, "[AO_ALSA] Mixer open error: %s\n", + snd_strerror( + err)); + return CONTROL_ERROR; + } + + if ((err = snd_mixer_attach(handle, card)) < 0) { + mp_tmsg(MSGT_AO, MSGL_ERR, "[AO_ALSA] Mixer attach %s error: %s\n", + card, snd_strerror(err)); + snd_mixer_close(handle); + return CONTROL_ERROR; + } + + if ((err = snd_mixer_selem_register(handle, NULL, NULL)) < 0) { + mp_tmsg(MSGT_AO, MSGL_ERR, "[AO_ALSA] Mixer register error: %s\n", + snd_strerror( + err)); + snd_mixer_close(handle); + return CONTROL_ERROR; + } + err = snd_mixer_load(handle); + if (err < 0) { + mp_tmsg(MSGT_AO, MSGL_ERR, "[AO_ALSA] Mixer load error: %s\n", + snd_strerror( + err)); + snd_mixer_close(handle); + return CONTROL_ERROR; + } + + elem = snd_mixer_find_selem(handle, sid); + if (!elem) { + mp_tmsg(MSGT_AO, MSGL_ERR, + "[AO_ALSA] Unable to find simple control '%s',%i.\n", + snd_mixer_selem_id_get_name( + sid), snd_mixer_selem_id_get_index(sid)); + snd_mixer_close(handle); + return CONTROL_ERROR; + } + + snd_mixer_selem_get_playback_volume_range(elem, &pmin, &pmax); + f_multi = (100 / (float)(pmax - pmin)); + + switch (cmd) { + case AOCONTROL_SET_VOLUME: { + ao_control_vol_t *vol = arg; + set_vol = vol->left / f_multi + pmin + 0.5; + + //setting channels + if ((err = + snd_mixer_selem_set_playback_volume(elem, + SND_MIXER_SCHN_FRONT_LEFT, + set_vol)) < 0) { + mp_tmsg(MSGT_AO, MSGL_ERR, + "[AO_ALSA] Error setting left channel, %s\n", + snd_strerror( + err)); + goto mixer_error; + } + mp_msg(MSGT_AO, MSGL_DBG2, "left=%li, ", set_vol); + + set_vol = vol->right / f_multi + pmin + 0.5; + + if ((err = + snd_mixer_selem_set_playback_volume(elem, + SND_MIXER_SCHN_FRONT_RIGHT, + set_vol)) < 0) { + mp_tmsg(MSGT_AO, MSGL_ERR, + "[AO_ALSA] Error setting right channel, %s\n", + snd_strerror( + err)); + goto mixer_error; + } + mp_msg(MSGT_AO, MSGL_DBG2, + "right=%li, pmin=%li, pmax=%li, mult=%f\n", + set_vol, pmin, pmax, + f_multi); + break; + } + case AOCONTROL_GET_VOLUME: { + ao_control_vol_t *vol = arg; + snd_mixer_selem_get_playback_volume(elem, SND_MIXER_SCHN_FRONT_LEFT, + &get_vol); + vol->left = (get_vol - pm