Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
V
vlc
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Redmine
Redmine
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Metrics
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
videolan
vlc
Commits
345a3e31
Commit
345a3e31
authored
Dec 09, 2012
by
Rémi Denis-Courmont
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
ALSA: use channels map functions (fixes #7796)
parent
9f9f7d54
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
162 additions
and
68 deletions
+162
-68
modules/audio_output/alsa.c
modules/audio_output/alsa.c
+162
-68
No files found.
modules/audio_output/alsa.c
View file @
345a3e31
...
...
@@ -43,8 +43,9 @@
struct
aout_sys_t
{
snd_pcm_t
*
pcm
;
void
(
*
reorder
)
(
void
*
,
size_t
,
unsigned
);
unsigned
rate
;
/**< Sample rate */
uint8_t
chans_table
[
AOUT_CHAN_MAX
];
/**< Channels order table */
uint8_t
chans_to_reorder
;
/**< Number of channels to reorder */
uint8_t
bits
;
/**< Bits per sample per channel */
bool
soft_mute
;
float
soft_gain
;
...
...
@@ -154,12 +155,157 @@ static int DeviceChanged (vlc_object_t *obj, const char *varname,
return
VLC_SUCCESS
;
}
static
unsigned
SetupChannelsUnknown
(
vlc_object_t
*
obj
,
uint16_t
*
restrict
mask
)
{
uint16_t
map
=
var_InheritInteger
(
obj
,
"alsa-audio-channels"
);
uint16_t
chans
=
*
mask
&
map
;
if
(
unlikely
(
chans
==
0
))
/* WTH? */
chans
=
AOUT_CHANS_STEREO
;
if
(
popcount
(
chans
)
<
popcount
(
*
mask
))
msg_Dbg
(
obj
,
"downmixing from %u to %u channels"
,
popcount
(
*
mask
),
popcount
(
chans
));
else
msg_Dbg
(
obj
,
"keeping %u channels"
,
popcount
(
chans
));
*
mask
=
chans
;
return
0
;
}
#if (SND_LIB_VERSION >= 0x01001B)
static
const
uint16_t
vlc_chans
[]
=
{
[
SND_CHMAP_MONO
]
=
AOUT_CHAN_CENTER
,
[
SND_CHMAP_FL
]
=
AOUT_CHAN_LEFT
,
[
SND_CHMAP_FR
]
=
AOUT_CHAN_RIGHT
,
[
SND_CHMAP_RL
]
=
AOUT_CHAN_REARLEFT
,
[
SND_CHMAP_RR
]
=
AOUT_CHAN_REARRIGHT
,
[
SND_CHMAP_FC
]
=
AOUT_CHAN_CENTER
,
[
SND_CHMAP_LFE
]
=
AOUT_CHAN_LFE
,
[
SND_CHMAP_SL
]
=
AOUT_CHAN_MIDDLELEFT
,
[
SND_CHMAP_SR
]
=
AOUT_CHAN_MIDDLERIGHT
,
[
SND_CHMAP_RC
]
=
AOUT_CHAN_REARCENTER
,
};
static
int
Map2Mask
(
vlc_object_t
*
obj
,
const
snd_pcm_chmap_t
*
restrict
map
)
{
uint16_t
mask
=
0
;
for
(
unsigned
i
=
0
;
i
<
map
->
channels
;
i
++
)
{
const
unsigned
pos
=
map
->
pos
[
i
];
uint_fast16_t
vlc_chan
=
0
;
if
(
pos
<
sizeof
(
vlc_chans
)
/
sizeof
(
vlc_chans
[
0
]))
vlc_chan
=
vlc_chans
[
pos
];
if
(
vlc_chan
==
0
)
{
msg_Dbg
(
obj
,
" %s channel %u position %u"
,
"unsupported"
,
i
,
pos
);
return
-
1
;
}
if
(
mask
&
vlc_chan
)
{
msg_Dbg
(
obj
,
" %s channel %u position %u"
,
"duplicate"
,
i
,
pos
);
return
-
1
;
}
mask
|=
vlc_chan
;
}
return
mask
;
}
/**
* Compares a fixed ALSA channels map with the VLC channels order.
*/
static
unsigned
SetupChannelsFixed
(
const
snd_pcm_chmap_t
*
restrict
map
,
uint16_t
*
restrict
mask
,
uint8_t
*
restrict
tab
)
{
uint32_t
chans_out
[
AOUT_CHAN_MAX
];
for
(
unsigned
i
=
0
;
i
<
map
->
channels
;
i
++
)
{
uint_fast16_t
vlc_chan
=
vlc_chans
[
map
->
pos
[
i
]];
chans_out
[
i
]
=
vlc_chan
;
*
mask
|=
vlc_chan
;
}
return
aout_CheckChannelReorder
(
NULL
,
chans_out
,
*
mask
,
tab
);
}
/**
* Negotiate channels mapping.
*/
static
unsigned
SetupChannels
(
vlc_object_t
*
obj
,
snd_pcm_t
*
pcm
,
uint16_t
*
restrict
mask
,
uint8_t
*
restrict
tab
)
{
snd_pcm_chmap_query_t
**
maps
=
snd_pcm_query_chmaps
(
pcm
);
if
(
tab
==
NULL
)
{
/* Fallback to manual configuration */
msg_Dbg
(
obj
,
"channels map not provided"
);
return
SetupChannelsUnknown
(
obj
,
mask
);
}
/* Find most appropriate available channels map */
unsigned
best_offset
;
unsigned
best_score
=
0
;
for
(
snd_pcm_chmap_query_t
*
const
*
p
=
maps
;
*
p
!=
NULL
;
p
++
)
{
snd_pcm_chmap_query_t
*
map
=
*
p
;
switch
(
map
->
type
)
{
case
SND_CHMAP_TYPE_FIXED
:
case
SND_CHMAP_TYPE_PAIRED
:
case
SND_CHMAP_TYPE_VAR
:
break
;
default:
msg_Err
(
obj
,
"unknown channels map type %u"
,
map
->
type
);
continue
;
}
int
chans
=
Map2Mask
(
obj
,
&
map
->
map
);
if
(
chans
==
-
1
)
continue
;
unsigned
score
=
popcount
(
chans
&
*
mask
);
if
(
score
>
best_score
)
{
best_offset
=
p
-
maps
;
best_score
=
score
;
}
}
if
(
best_score
==
0
)
{
msg_Err
(
obj
,
"cannot find supported channels map"
);
snd_pcm_free_chmaps
(
maps
);
return
SetupChannelsUnknown
(
obj
,
mask
);
}
const
snd_pcm_chmap_t
*
map
=
&
maps
[
best_offset
]
->
map
;
msg_Dbg
(
obj
,
"using channels map %u, type %u, %u channel(s)"
,
best_offset
,
maps
[
best_offset
]
->
type
,
best_score
);
/* Setup channels map */
unsigned
to_reorder
=
SetupChannelsFixed
(
map
,
mask
,
tab
);
/* TODO: avoid reordering for PAIRED and VAR types */
//snd_pcm_set_chmap (pcm, ...)
snd_pcm_free_chmaps
(
maps
);
return
to_reorder
;
}
#else
/* (SND_LIB_VERSION < 0x01001B) */
# define SetupChannels(obj, pcm, mask, tab) \
SetupChannelsUnknown(obj, mask)
#endif
static
int
TimeGet
(
audio_output_t
*
aout
,
mtime_t
*
);
static
void
Play
(
audio_output_t
*
,
block_t
*
);
static
void
Pause
(
audio_output_t
*
,
bool
,
mtime_t
);
static
void
PauseDummy
(
audio_output_t
*
,
bool
,
mtime_t
);
static
void
Flush
(
audio_output_t
*
,
bool
);
static
void
Reorder71
(
void
*
,
size_t
,
unsigned
);
/** Initializes an ALSA playback stream */
static
int
Start
(
audio_output_t
*
aout
,
audio_sample_format_t
*
restrict
fmt
)
...
...
@@ -246,20 +392,6 @@ static int Start (audio_output_t *aout, audio_sample_format_t *restrict fmt)
}
}
/* ALSA channels */
/* XXX: maybe this should be shared with other dumb outputs */
uint32_t
map
=
var_InheritInteger
(
aout
,
"alsa-audio-channels"
);
map
&=
fmt
->
i_physical_channels
;
if
(
unlikely
(
map
==
0
))
/* WTH? */
map
=
AOUT_CHANS_STEREO
;
unsigned
channels
=
popcount
(
map
);
if
(
channels
<
aout_FormatNbChannels
(
fmt
))
msg_Dbg
(
aout
,
"downmixing from %u to %u channels"
,
aout_FormatNbChannels
(
fmt
),
channels
);
else
msg_Dbg
(
aout
,
"keeping %u channels"
,
channels
);
/* Choose the IEC device for S/PDIF output:
if the device is overridden by the user then it will be the one.
Otherwise we compute the default device based on the output format. */
...
...
@@ -370,6 +502,17 @@ static int Start (audio_output_t *aout, audio_sample_format_t *restrict fmt)
}
/* Set channels count */
unsigned
channels
;
if
(
!
spdif
)
{
sys
->
chans_to_reorder
=
SetupChannels
(
VLC_OBJECT
(
aout
),
pcm
,
&
fmt
->
i_physical_channels
,
sys
->
chans_table
);
channels
=
popcount
(
fmt
->
i_physical_channels
);
}
else
channels
=
2
;
fmt
->
i_original_channels
=
fmt
->
i_physical_channels
;
/* By default, ALSA plug will pad missing channels with zeroes, which is
* usually fine. However, it will also discard extraneous channels, which
* is not acceptable. Thus the user must configure the physically
...
...
@@ -470,7 +613,6 @@ static int Start (audio_output_t *aout, audio_sample_format_t *restrict fmt)
fmt
->
i_format
=
fourcc
;
fmt
->
i_rate
=
rate
;
sys
->
rate
=
rate
;
sys
->
reorder
=
NULL
;
if
(
spdif
)
{
fmt
->
i_bytes_per_frame
=
AOUT_SPDIF_SIZE
;
...
...
@@ -478,14 +620,6 @@ static int Start (audio_output_t *aout, audio_sample_format_t *restrict fmt)
}
else
{
fmt
->
i_original_channels
=
fmt
->
i_physical_channels
=
map
;
switch
(
popcount
(
map
))
{
case
8
:
sys
->
reorder
=
Reorder71
;
break
;
}
aout_FormatPrepare
(
fmt
);
sys
->
bits
=
fmt
->
i_bitspersample
;
}
...
...
@@ -545,8 +679,9 @@ static void Play (audio_output_t *aout, block_t *block)
{
aout_sys_t
*
sys
=
aout
->
sys
;
if
(
sys
->
reorder
!=
NULL
)
sys
->
reorder
(
block
->
p_buffer
,
block
->
i_nb_samples
,
sys
->
bits
);
if
(
sys
->
chans_to_reorder
!=
0
)
aout_ChannelReorder
(
block
->
p_buffer
,
block
->
i_buffer
,
sys
->
chans_to_reorder
,
sys
->
chans_table
,
sys
->
bits
);
snd_pcm_t
*
pcm
=
sys
->
pcm
;
...
...
@@ -636,47 +771,6 @@ static void Stop (audio_output_t *aout)
snd_pcm_close
(
pcm
);
}
/**
* Converts from VLC to ALSA order for 7.1.
* VLC has middle channels in position 2 and 3, ALSA in position 6 and 7.
*/
static
void
Reorder71
(
void
*
p
,
size_t
n
,
unsigned
bits
)
{
switch
(
bits
)
{
case
32
:
for
(
uint64_t
*
ptr
=
p
;
n
>
0
;
ptr
+=
4
,
n
--
)
{
uint64_t
middle
=
ptr
[
1
],
c_lfe
=
ptr
[
2
],
rear
=
ptr
[
3
];
ptr
[
1
]
=
c_lfe
;
ptr
[
2
]
=
rear
;
ptr
[
3
]
=
middle
;
}
break
;
case
16
:
for
(
uint32_t
*
ptr
=
p
;
n
>
0
;
ptr
+=
4
,
n
--
)
{
uint32_t
middle
=
ptr
[
1
],
c_lfe
=
ptr
[
2
],
rear
=
ptr
[
3
];
ptr
[
1
]
=
c_lfe
;
ptr
[
2
]
=
rear
;
ptr
[
3
]
=
middle
;
}
break
;
default:
for
(
uint16_t
*
ptr
=
p
;
n
>
0
;
n
--
)
{
uint16_t
middle
[
bits
/
8
];
memcpy
(
middle
,
ptr
+
(
bits
/
8
),
bits
/
4
);
ptr
+=
bits
/
4
;
memcpy
(
ptr
,
ptr
+
(
bits
/
8
),
bits
/
4
);
ptr
+=
bits
/
4
;
memcpy
(
ptr
,
ptr
+
(
bits
/
8
),
bits
/
4
);
ptr
+=
bits
/
4
;
memcpy
(
ptr
,
middle
,
bits
/
4
);
ptr
+=
bits
/
4
;
}
break
;
}
}
/**
* Enumerates ALSA output devices.
*/
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment