Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
SUSE:SLE-12-SP1:GA
alsa-utils.948
0008-speaker-test-Fix-chmapped-channel-selectio...
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File 0008-speaker-test-Fix-chmapped-channel-selection-without-.patch of Package alsa-utils.948
From a1992044d5813371ce71f5252187942f943b198d Mon Sep 17 00:00:00 2001 From: Anssi Hannula <anssi.hannula@iki.fi> Date: Tue, 12 Nov 2013 00:04:02 +0200 Subject: [PATCH] speaker-test: Fix chmapped channel selection without specified chmap The channel selection currently does not work properly when there is a driver-provided non-ALSA-traditional channel map but no manual channel map was explicitely requested with "-m". For example, the CEA/HDMI 8ch map is FL,FR,RLC,RRC,FC,LFE,RL,RR. Note that it is otherwise the same as the traditional ALSA channel map, except that the traditional rear speakers are considered rear-center speakers and the traditional side speakers are considered rear speakers. Speaker-test tries to play back channels in this following order: 0, /* Front Left */ 4, /* Center */ 1, /* Front Right */ 7, /* Side Right */ 3, /* Rear Right */ 2, /* Rear Left */ 6, /* Side Left */ 5, /* LFE */ When it is the time to play back Side Left/Right, speaker-test tries to look for SL/SR in the chmap, but doesn't find it, so it just plays back channels 6/7 (which indeed are the side speakers, or RL/RR in this channel map - so the correct channels are selected). When it becomes the time to playback Rear Left/Right, speaker-test again tries to find RL/RR in the chmap, and this time it does find them in the chmap positions 6/7. So the channels 6/7 are tested twice and 2/3 are never tested. To fix this, define a generic playback order channel_order[] to be used when the channel map is present (but not user-defined) and generate a (speaker/playback number => channel number) mapping with the channels ordered in the following order: 1. regular channels found in channel_order[] in the defined order, 2. channels not found in channel_order[] ordered by channel number. 3. UNKNOWN channels ordered by channel number. 4. NA channels ordered by channel number. For channels outside the channel map just use their channel numbers (so they will be last after all of the above). For example, if the playback device has a fictional default channel map of FR,FL,UNKNOWN1,FOO,BAR,RR,RL,UNKNOWN2, the playback order will be FL,FR,RR,RL,FOO,BAR,UNKNOWN1,UNKNOWN2(,any_extra_channels). When the channel mapping is specified manually, the specified order is used for playback as before. Signed-off-by: Anssi Hannula <anssi.hannula@iki.fi> Signed-off-by: Takashi Iwai <tiwai@suse.de> --- speaker-test/speaker-test.c | 113 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 91 insertions(+), 22 deletions(-) diff --git a/speaker-test/speaker-test.c b/speaker-test/speaker-test.c index d35065f73a7a..25b08dcee70b 100644 --- a/speaker-test/speaker-test.c +++ b/speaker-test/speaker-test.c @@ -88,6 +88,8 @@ enum { #define BE_INT(v) (v) #endif +#define ARRAY_SIZE(x) (int)(sizeof(x)/sizeof(x[0])) + static char *device = "default"; /* playback device */ static snd_pcm_format_t format = SND_PCM_FORMAT_S16; /* sample format */ static unsigned int rate = 48000; /* stream rate */ @@ -110,6 +112,7 @@ static snd_pcm_t *pcm_handle = NULL; #ifdef CONFIG_SUPPORT_CHMAP static snd_pcm_chmap_t *channel_map; static int channel_map_set; +static unsigned int *ordered_channels; #endif static const char *const channel_name[MAX_CHANNELS] = { @@ -156,36 +159,94 @@ static const int channels8[] = { 5, /* LFE */ }; -static int get_mapped_channel(int chn) -{ #ifdef CONFIG_SUPPORT_CHMAP - static const int maps[MAX_CHANNELS] = { - SND_CHMAP_FL, - SND_CHMAP_FR, - SND_CHMAP_RL, - SND_CHMAP_RR, - SND_CHMAP_FC, - SND_CHMAP_LFE, - SND_CHMAP_SL, - SND_CHMAP_SR, - }; +/* circular clockwise and bottom-to-top order */ +static const int channel_order[] = { + [SND_CHMAP_FLW] = 10, + [SND_CHMAP_FL] = 20, + [SND_CHMAP_TFL] = 30, + [SND_CHMAP_FLC] = 40, + [SND_CHMAP_TFLC] = 50, + [SND_CHMAP_FC] = 60, + [SND_CHMAP_TFC] = 70, + [SND_CHMAP_FRC] = 80, + [SND_CHMAP_TFRC] = 90, + [SND_CHMAP_FR] = 100, + [SND_CHMAP_TFR] = 110, + [SND_CHMAP_FRW] = 120, + [SND_CHMAP_SR] = 130, + [SND_CHMAP_TSR] = 140, + [SND_CHMAP_RR] = 150, + [SND_CHMAP_TRR] = 160, + [SND_CHMAP_RRC] = 170, + [SND_CHMAP_RC] = 180, + [SND_CHMAP_TRC] = 190, + [SND_CHMAP_RLC] = 200, + [SND_CHMAP_RL] = 210, + [SND_CHMAP_TRL] = 220, + [SND_CHMAP_SL] = 230, + [SND_CHMAP_TSL] = 240, + [SND_CHMAP_BC] = 250, + [SND_CHMAP_TC] = 260, + [SND_CHMAP_LLFE] = 270, + [SND_CHMAP_LFE] = 280, + [SND_CHMAP_RLFE] = 290, + /* not in table = 10000 */ + [SND_CHMAP_UNKNOWN] = 20000, + [SND_CHMAP_NA] = 30000, +}; - if (channel_map && maps[chn]) { - int i; - for (i = 0; i < channel_map->channels; i++) { - if (channel_map->pos[i] == maps[chn]) - return i; - } +static int chpos_cmp(const void *chnum1p, const void *chnum2p) +{ + int chnum1 = *(int *)chnum1p; + int chnum2 = *(int *)chnum2p; + int chpos1 = channel_map->pos[chnum1]; + int chpos2 = channel_map->pos[chnum2]; + int weight1 = 10000; + int weight2 = 10000; + + if (chpos1 < ARRAY_SIZE(channel_order) && channel_order[chpos1]) + weight1 = channel_order[chpos1]; + if (chpos2 < ARRAY_SIZE(channel_order) && channel_order[chpos2]) + weight2 = channel_order[chpos2]; + + if (weight1 == weight2) { + /* order by channel number if both have the same position (e.g. UNKNOWN) + * or if neither is in channel_order[] */ + return chnum1 - chnum2; } -#endif - return chn; + + /* order according to channel_order[] */ + return weight1 - weight2; +} + +static int *order_channels(void) +{ + /* create a (playback order => channel number) table with channels ordered + * according to channel_order[] values */ + int i; + int *ordered_chs; + + ordered_chs = calloc(channel_map->channels, sizeof(*ordered_chs)); + if (!ordered_chs) + return NULL; + + for (i = 0; i < channel_map->channels; i++) + ordered_chs[i] = i; + + qsort(ordered_chs, channel_map->channels, sizeof(*ordered_chs), chpos_cmp); + + return ordered_chs; } +#endif static int get_speaker_channel(int chn) { #ifdef CONFIG_SUPPORT_CHMAP - if (channel_map_set) + if (channel_map_set || (ordered_channels && chn >= channel_map->channels)) return chn; + if (ordered_channels) + return ordered_channels[chn]; #endif switch (channels) { @@ -200,7 +261,7 @@ static int get_speaker_channel(int chn) break; } - return get_mapped_channel(chn); + return chn; } static const char *get_channel_name(int chn) @@ -611,6 +672,11 @@ static int config_chmap(snd_pcm_t *handle, const char *mapstr) } channel_map = snd_pcm_get_chmap(handle); + + /* create a channel order table for default layouts */ + if (channel_map) + ordered_channels = order_channels(); + return 0; } #endif @@ -1230,6 +1296,9 @@ int main(int argc, char *argv[]) { free(frames); +#ifdef CONFIG_SUPPORT_CHMAP + free(ordered_channels); +#endif return prg_exit(EXIT_SUCCESS); } -- 1.8.4.3
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor