Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
V
vlc-2-2
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-2-2
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
Show 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 @@
...
@@ -43,8 +43,9 @@
struct
aout_sys_t
struct
aout_sys_t
{
{
snd_pcm_t
*
pcm
;
snd_pcm_t
*
pcm
;
void
(
*
reorder
)
(
void
*
,
size_t
,
unsigned
);
unsigned
rate
;
/**< Sample rate */
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 */
uint8_t
bits
;
/**< Bits per sample per channel */
bool
soft_mute
;
bool
soft_mute
;
float
soft_gain
;
float
soft_gain
;
...
@@ -154,12 +155,157 @@ static int DeviceChanged (vlc_object_t *obj, const char *varname,
...
@@ -154,12 +155,157 @@ static int DeviceChanged (vlc_object_t *obj, const char *varname,
return
VLC_SUCCESS
;
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
int
TimeGet
(
audio_output_t
*
aout
,
mtime_t
*
);
static
void
Play
(
audio_output_t
*
,
block_t
*
);
static
void
Play
(
audio_output_t
*
,
block_t
*
);
static
void
Pause
(
audio_output_t
*
,
bool
,
mtime_t
);
static
void
Pause
(
audio_output_t
*
,
bool
,
mtime_t
);
static
void
PauseDummy
(
audio_output_t
*
,
bool
,
mtime_t
);
static
void
PauseDummy
(
audio_output_t
*
,
bool
,
mtime_t
);
static
void
Flush
(
audio_output_t
*
,
bool
);
static
void
Flush
(
audio_output_t
*
,
bool
);
static
void
Reorder71
(
void
*
,
size_t
,
unsigned
);
/** Initializes an ALSA playback stream */
/** Initializes an ALSA playback stream */
static
int
Start
(
audio_output_t
*
aout
,
audio_sample_format_t
*
restrict
fmt
)
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)
...
@@ -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:
/* Choose the IEC device for S/PDIF output:
if the device is overridden by the user then it will be the one.
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. */
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)
...
@@ -370,6 +502,17 @@ static int Start (audio_output_t *aout, audio_sample_format_t *restrict fmt)
}
}
/* Set channels count */
/* 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
/* By default, ALSA plug will pad missing channels with zeroes, which is
* usually fine. However, it will also discard extraneous channels, which
* usually fine. However, it will also discard extraneous channels, which
* is not acceptable. Thus the user must configure the physically
* 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)
...
@@ -470,7 +613,6 @@ static int Start (audio_output_t *aout, audio_sample_format_t *restrict fmt)
fmt
->
i_format
=
fourcc
;
fmt
->
i_format
=
fourcc
;
fmt
->
i_rate
=
rate
;
fmt
->
i_rate
=
rate
;
sys
->
rate
=
rate
;
sys
->
rate
=
rate
;
sys
->
reorder
=
NULL
;
if
(
spdif
)
if
(
spdif
)
{
{
fmt
->
i_bytes_per_frame
=
AOUT_SPDIF_SIZE
;
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)
...
@@ -478,14 +620,6 @@ static int Start (audio_output_t *aout, audio_sample_format_t *restrict fmt)
}
}
else
else
{
{
fmt
->
i_original_channels
=
fmt
->
i_physical_channels
=
map
;
switch
(
popcount
(
map
))
{
case
8
:
sys
->
reorder
=
Reorder71
;
break
;
}
aout_FormatPrepare
(
fmt
);
aout_FormatPrepare
(
fmt
);
sys
->
bits
=
fmt
->
i_bitspersample
;
sys
->
bits
=
fmt
->
i_bitspersample
;
}
}
...
@@ -545,8 +679,9 @@ static void Play (audio_output_t *aout, block_t *block)
...
@@ -545,8 +679,9 @@ static void Play (audio_output_t *aout, block_t *block)
{
{
aout_sys_t
*
sys
=
aout
->
sys
;
aout_sys_t
*
sys
=
aout
->
sys
;
if
(
sys
->
reorder
!=
NULL
)
if
(
sys
->
chans_to_reorder
!=
0
)
sys
->
reorder
(
block
->
p_buffer
,
block
->
i_nb_samples
,
sys
->
bits
);
aout_ChannelReorder
(
block
->
p_buffer
,
block
->
i_buffer
,
sys
->
chans_to_reorder
,
sys
->
chans_table
,
sys
->
bits
);
snd_pcm_t
*
pcm
=
sys
->
pcm
;
snd_pcm_t
*
pcm
=
sys
->
pcm
;
...
@@ -636,47 +771,6 @@ static void Stop (audio_output_t *aout)
...
@@ -636,47 +771,6 @@ static void Stop (audio_output_t *aout)
snd_pcm_close
(
pcm
);
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.
* 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