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
08569199
Commit
08569199
authored
Jul 22, 2012
by
Rémi Denis-Courmont
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
OSS: rewrite and update to OSSv4
parent
9b1e5cc8
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
267 additions
and
557 deletions
+267
-557
modules/audio_output/oss.c
modules/audio_output/oss.c
+267
-557
No files found.
modules/audio_output/oss.c
View file @
08569199
/*****************************************************************************
* oss.c
: OSS /dev/dsp module for vlc
* oss.c
: Open Sound System audio output plugin for VLC
*****************************************************************************
* Copyright (C) 2000-2002 the VideoLAN team
*
$Id$
*
Copyright (C) 2007-2012 Rémi Denis-Courmont
*
* Authors: Michel Kaempf <maxx@via.ecp.fr>
* Sam Hocevar <sam@zoy.org>
...
...
@@ -23,651 +23,361 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
/*****************************************************************************
* Preamble
*****************************************************************************/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <fcntl.h>
/* open(), O_WRONLY */
#include <sys/ioctl.h>
/* ioctl() */
#include <unistd.h>
/* write(), close() */
#include <stdlib.h>
#include <math.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#ifdef HAVE_SOUNDCARD_H
# include <soundcard.h>
#else
# include <sys/soundcard.h>
#endif
#include <vlc_common.h>
#include <vlc_plugin.h>
#include <vlc_fs.h>
#include <vlc_cpu.h>
#include <vlc_aout.h>
/* SNDCTL_DSP_RESET, SNDCTL_DSP_SETFMT, SNDCTL_DSP_STEREO, SNDCTL_DSP_SPEED,
* SNDCTL_DSP_GETOSPACE */
#ifdef HAVE_SOUNDCARD_H
# include <soundcard.h>
#elif defined( HAVE_SYS_SOUNDCARD_H )
# include <sys/soundcard.h>
#endif
/* Patches for ignorant OSS versions */
#ifndef AFMT_AC3
# define AFMT_AC3 0x00000400
/* Dolby Digital AC3 */
#endif
#define A52_FRAME_NB 1536
#ifndef AFMT_S16_NE
# ifdef WORDS_BIGENDIAN
# define AFMT_S16_NE AFMT_S16_BE
# else
# define AFMT_S16_NE AFMT_S16_LE
# endif
#endif
/*****************************************************************************
* aout_sys_t: OSS audio output method descriptor
*****************************************************************************
* This structure is part of the audio output thread descriptor.
* It describes the DSP specific properties of an audio device.
*****************************************************************************/
struct
aout_sys_t
{
aout_packet_t
packet
;
int
i_fd
;
int
i_fragstotal
;
mtime_t
max_buffer_duration
;
vlc_thread_t
thread
;
float
soft_gain
;
bool
soft_mute
;
int
fd
;
uint8_t
level
;
bool
mute
;
};
/* This must be a power of 2. */
#define FRAME_SIZE 1024
#define FRAME_COUNT 32
/*****************************************************************************
* Local prototypes
*****************************************************************************/
static
int
Open
(
vlc_object_t
*
);
static
void
Close
(
vlc_object_t
*
);
static
void
*
OSSThread
(
void
*
);
static
mtime_t
BufferDuration
(
audio_output_t
*
p_aout
);
static
int
Open
(
vlc_object_t
*
);
static
void
Close
(
vlc_object_t
*
);
#include "volume.h"
#define AUDIO_DEV_TEXT N_("Audio output device")
#define AUDIO_DEV_LONGTEXT N_("OSS device node path.")
/*****************************************************************************
* Module descriptor
*****************************************************************************/
vlc_module_begin
()
set_shortname
(
"OSS"
)
set_description
(
N_
(
"Open Sound System"
)
)
set_description
(
N_
(
"Open Sound System audio output"
))
set_category
(
CAT_AUDIO
)
set_subcategory
(
SUBCAT_AUDIO_AOUT
)
add_loadfile
(
"oss-audio-device"
,
"/dev/dsp"
,
N_
(
"OSS DSP device"
),
NULL
,
false
)
add_sw_gain
()
add_string
(
"oss-audio-device"
,
""
,
AUDIO_DEV_TEXT
,
AUDIO_DEV_LONGTEXT
,
false
)
set_capability
(
"audio output"
,
100
)
add_shortcut
(
"oss"
)
set_callbacks
(
Open
,
Close
)
vlc_module_end
()
/*****************************************************************************
* Probe: probe the audio device for available formats and channels
*****************************************************************************/
static
void
Probe
(
audio_output_t
*
p_aout
)
{
struct
aout_sys_t
*
p_sys
=
p_aout
->
sys
;
vlc_value_t
val
,
text
;
int
i_format
,
i_nb_channels
;
var_Create
(
p_aout
,
"audio-device"
,
VLC_VAR_INTEGER
|
VLC_VAR_HASCHOICE
);
text
.
psz_string
=
_
(
"Audio Device"
);
var_Change
(
p_aout
,
"audio-device"
,
VLC_VAR_SETTEXT
,
&
text
,
NULL
);
static
void
Play
(
audio_output_t
*
,
block_t
*
);
static
void
Pause
(
audio_output_t
*
,
bool
,
mtime_t
);
static
void
Flush
(
audio_output_t
*
,
bool
);
static
int
VolumeSync
(
audio_output_t
*
);
static
int
VolumeSet
(
audio_output_t
*
,
float
);
static
int
MuteSet
(
audio_output_t
*
,
bool
);
/* Test for multi-channel. */
#ifdef SNDCTL_DSP_GETCHANNELMASK
if
(
aout_FormatNbChannels
(
&
p_aout
->
format
)
>
2
)
static
int
Open
(
vlc_object_t
*
obj
)
{
audio_output_t
*
aout
=
(
audio_output_t
*
)
obj
;
/* Open the device */
const
char
*
device
;
char
*
devicebuf
=
var_InheritString
(
aout
,
"oss-audio-device"
);
device
=
devicebuf
;
if
(
device
==
NULL
)
device
=
getenv
(
"OSS_AUDIODEV"
);
if
(
device
==
NULL
)
device
=
"/dev/dsp"
;
msg_Dbg
(
aout
,
"using OSS device: %s"
,
device
);
int
fd
=
vlc_open
(
device
,
O_WRONLY
);
free
(
devicebuf
);
if
(
fd
==
-
1
)
{
/* Check that the device supports this. */
msg_Err
(
aout
,
"cannot open OSS device: %m"
);
return
VLC_EGENERIC
;
}
int
i_chanmask
;
aout_sys_t
*
sys
=
malloc
(
sizeof
(
*
sys
));
if
(
unlikely
(
sys
==
NULL
))
goto
error
;
aout
->
sys
=
sys
;
sys
->
fd
=
fd
;
/* Reset all. */
i_format
=
AFMT_S16_NE
;
if
(
ioctl
(
p_sys
->
i_fd
,
SNDCTL_DSP_RESET
,
NULL
)
<
0
||
ioctl
(
p_sys
->
i_fd
,
SNDCTL_DSP_SETFMT
,
&
i_format
)
<
0
)
{
msg_Err
(
p_aout
,
"cannot reset OSS audio device"
);
var_Destroy
(
p_aout
,
"audio-device"
);
return
;
}
/* Select audio format */
int
format
;
vlc_fourcc_t
fourcc
=
aout
->
format
.
i_format
;
bool
spdif
=
false
;
if
(
ioctl
(
p_sys
->
i_fd
,
SNDCTL_DSP_GETCHANNELMASK
,
&
i_chanmask
)
==
0
)
{
if
(
!
(
i_chanmask
&
DSP_BIND_FRONT
)
)
{
msg_Err
(
p_aout
,
"no front channels! (%x)"
,
i_chanmask
);
return
;
}
switch
(
fourcc
)
{
case
VLC_CODEC_F64B
:
case
VLC_CODEC_F64L
:
case
VLC_CODEC_F32B
:
case
VLC_CODEC_F32L
:
format
=
AFMT_FLOAT
;
break
;
case
VLC_CODEC_S32B
:
format
=
AFMT_S32_BE
;
break
;
case
VLC_CODEC_S32L
:
format
=
AFMT_S32_LE
;
break
;
case
VLC_CODEC_S16B
:
format
=
AFMT_S16_BE
;
break
;
case
VLC_CODEC_S16L
:
format
=
AFMT_S16_LE
;
break
;
case
VLC_CODEC_S8
:
case
VLC_CODEC_U8
:
format
=
AFMT_U8
;
break
;
default:
if
(
AOUT_FMT_SPDIF
(
&
aout
->
format
))
spdif
=
var_InheritBool
(
aout
,
"spdif"
);
if
(
spdif
)
format
=
AFMT_AC3
;
else
if
(
HAVE_FPU
)
format
=
AFMT_FLOAT
;
else
format
=
AFMT_S16_NE
;
}
if
(
(
i_chanmask
&
(
DSP_BIND_SURR
|
DSP_BIND_CENTER_LFE
))
&&
(
p_aout
->
format
.
i_physical_channels
==
(
AOUT_CHAN_LEFT
|
AOUT_CHAN_RIGHT
|
AOUT_CHAN_CENTER
|
AOUT_CHAN_REARLEFT
|
AOUT_CHAN_REARRIGHT
|
AOUT_CHAN_LFE
))
)
{
val
.
i_int
=
AOUT_VAR_5_1
;
text
.
psz_string
=
(
char
*
)
"5.1"
;
var_Change
(
p_aout
,
"audio-device"
,
VLC_VAR_ADDCHOICE
,
&
val
,
&
text
);
}
if
(
ioctl
(
fd
,
SNDCTL_DSP_SETFMT
,
&
format
)
<
0
)
{
msg_Err
(
aout
,
"cannot set audio format 0x%X: %m"
,
format
);
goto
error
;
}
if
(
(
i_chanmask
&
DSP_BIND_SURR
)
&&
(
p_aout
->
format
.
i_physical_channels
&
(
AOUT_CHAN_LEFT
|
AOUT_CHAN_RIGHT
|
AOUT_CHAN_REARLEFT
|
AOUT_CHAN_REARRIGHT
))
)
switch
(
format
)
{
case
AFMT_S8
:
fourcc
=
VLC_CODEC_S8
;
break
;
case
AFMT_U8
:
fourcc
=
VLC_CODEC_U8
;
break
;
case
AFMT_S16_BE
:
fourcc
=
VLC_CODEC_S16B
;
break
;
case
AFMT_S16_LE
:
fourcc
=
VLC_CODEC_S16L
;
break
;
//case AFMT_S24_BE:
//case AFMT_S24_LE:
case
AFMT_S32_BE
:
fourcc
=
VLC_CODEC_S32B
;
break
;
case
AFMT_S32_LE
:
fourcc
=
VLC_CODEC_S32L
;
break
;
case
AFMT_FLOAT
:
fourcc
=
VLC_CODEC_FL32
;
break
;
case
AFMT_AC3
:
if
(
spdif
)
{
val
.
i_int
=
AOUT_VAR_2F2R
;
text
.
psz_string
=
_
(
"2 Front 2 Rear"
);
var_Change
(
p_aout
,
"audio-device"
,
VLC_VAR_ADDCHOICE
,
&
val
,
&
text
);
fourcc
=
VLC_CODEC_SPDIFL
;
break
;
}
}
default:
msg_Err
(
aout
,
"unsupported audio format 0x%X"
,
format
);
goto
error
;
}
#endif
/* Reset all. */
i_format
=
AFMT_S16_NE
;
if
(
ioctl
(
p_sys
->
i_fd
,
SNDCTL_DSP_RESET
,
NULL
)
<
0
||
ioctl
(
p_sys
->
i_fd
,
SNDCTL_DSP_SETFMT
,
&
i_format
)
<
0
)
/* Select channels count */
int
channels
=
spdif
?
2
:
aout_FormatNbChannels
(
&
aout
->
format
);
if
(
ioctl
(
fd
,
SNDCTL_DSP_CHANNELS
,
&
channels
)
<
0
)
{
msg_Err
(
p_aout
,
"cannot reset OSS audio device"
);
var_Destroy
(
p_aout
,
"audio-device"
);
return
;
msg_Err
(
aout
,
"cannot set %d channels: %m"
,
channels
);
goto
error
;
}
/* Test for stereo. */
i_nb_channels
=
2
;
if
(
ioctl
(
p_sys
->
i_fd
,
SNDCTL_DSP_CHANNELS
,
&
i_nb_channels
)
>=
0
&&
i_nb_channels
==
2
)
switch
(
channels
)
{
val
.
i_int
=
AOUT_VAR_STEREO
;
text
.
psz_string
=
_
(
"Stereo"
);
var_Change
(
p_aout
,
"audio-device"
,
VLC_VAR_ADDCHOICE
,
&
val
,
&
text
);
case
1
:
channels
=
AOUT_CHAN_CENTER
;
break
;
case
2
:
channels
=
AOUT_CHANS_STEREO
;
break
;
case
4
:
channels
=
AOUT_CHANS_4_0
;
break
;
case
6
:
channels
=
AOUT_CHANS_5_1
;
break
;
case
8
:
channels
=
AOUT_CHANS_7_1
;
break
;
default:
msg_Err
(
aout
,
"unsupported channels count %d"
,
channels
);
goto
error
;
}
/* Reset all. */
i_format
=
AFMT_S16_NE
;
if
(
ioctl
(
p_sys
->
i_fd
,
SNDCTL_DSP_RESET
,
NULL
)
<
0
||
ioctl
(
p_sys
->
i_fd
,
SNDCTL_DSP_SETFMT
,
&
i_format
)
<
0
)
/* Select sample rate */
int
rate
=
spdif
?
48000
:
aout
->
format
.
i_rate
;
if
(
ioctl
(
fd
,
SNDCTL_DSP_SPEED
,
&
rate
)
<
0
)
{
msg_Err
(
p_aout
,
"cannot reset OSS audio device"
);
var_Destroy
(
p_aout
,
"audio-device"
);
return
;
msg_Err
(
aout
,
"cannot set %d Hz sample rate: %m"
,
rate
);
goto
error
;
}
/* Test for mono. */
i_nb_channels
=
1
;
if
(
ioctl
(
p_sys
->
i_fd
,
SNDCTL_DSP_CHANNELS
,
&
i_nb_channels
)
>=
0
&&
i_nb_channels
==
1
)
{
val
.
i_int
=
AOUT_VAR_MONO
;
text
.
psz_string
=
_
(
"Mono"
);
var_Change
(
p_aout
,
"audio-device"
,
VLC_VAR_ADDCHOICE
,
&
val
,
&
text
);
if
(
p_aout
->
format
.
i_physical_channels
==
AOUT_CHAN_CENTER
)
{
var_Set
(
p_aout
,
"audio-device"
,
val
);
}
}
/* Setup audio_output_t */
aout
->
format
.
i_format
=
fourcc
;
aout
->
format
.
i_rate
=
rate
;
aout
->
pf_play
=
Play
;
aout
->
pf_pause
=
Pause
;
aout
->
pf_flush
=
Flush
;
aout
->
volume_set
=
NULL
;
aout
->
mute_set
=
NULL
;
if
(
ioctl
(
p_sys
->
i_fd
,
SNDCTL_DSP_RESET
,
NULL
)
<
0
)
if
(
spdif
)
{
msg_Err
(
p_aout
,
"cannot reset OSS audio device"
);
var_Destroy
(
p_aout
,
"audio-device"
);
return
;
aout
->
format
.
i_bytes_per_frame
=
AOUT_SPDIF_SIZE
;
aout
->
format
.
i_frame_length
=
A52_FRAME_NB
;
}
/* Test for spdif. */
if
(
AOUT_FMT_SPDIF
(
&
p_aout
->
format
)
)
else
{
i_format
=
AFMT_AC3
;
aout
->
format
.
i_original_channels
=
aout
->
format
.
i_physical_channels
=
channels
;
if
(
ioctl
(
p_sys
->
i_fd
,
SNDCTL_DSP_SETFMT
,
&
i_format
)
>=
0
&&
i_format
==
AFMT_AC3
)
{
val
.
i_int
=
AOUT_VAR_SPDIF
;
text
.
psz_string
=
_
(
"A/52 over S/PDIF"
);
var_Change
(
p_aout
,
"audio-device"
,
VLC_VAR_ADDCHOICE
,
&
val
,
&
text
);
if
(
var_InheritBool
(
p_aout
,
"spdif"
)
)
var_Set
(
p_aout
,
"audio-device"
,
val
);
}
else
if
(
var_InheritBool
(
p_aout
,
"spdif"
)
)
sys
->
level
=
100
;
sys
->
mute
=
false
;
if
(
VolumeSync
(
aout
)
==
0
)
{
msg_Warn
(
p_aout
,
"S/PDIF not supported by card"
);
aout
->
volume_set
=
VolumeSet
;
aout
->
mute_set
=
MuteSet
;
}
}
return
0
;
error:
close
(
fd
);
free
(
sys
);
return
VLC_EGENERIC
;
}
/*****************************************************************************
* Open: open the audio device (the digital sound processor)
*****************************************************************************
* This function opens the DSP as a usual non-blocking write-only file, and
* modifies the p_aout->p_sys->i_fd with the file's descriptor.
*****************************************************************************/
static
int
Open
(
vlc_object_t
*
p_this
)
/**
* Releases the audio output.
*/
static
void
Close
(
vlc_object_t
*
obj
)
{
audio_output_t
*
p_aout
=
(
audio_output_t
*
)
p_this
;
struct
aout_sys_t
*
p_sys
;
char
*
psz_device
;
vlc_value_t
val
;
/* Allocate structure */
p_aout
->
sys
=
p_sys
=
malloc
(
sizeof
(
aout_sys_t
)
);
if
(
p_sys
==
NULL
)
return
VLC_ENOMEM
;
/* Get device name */
if
(
(
psz_device
=
var_InheritString
(
p_aout
,
"oss-audio-device"
))
==
NULL
)
{
msg_Err
(
p_aout
,
"no audio device specified (maybe /dev/dsp?)"
);
free
(
p_sys
);
return
VLC_EGENERIC
;
}
/* Open the sound device in non-blocking mode, because ALSA's OSS
* emulation and some broken OSS drivers would make a blocking call
* wait forever until the device is available. Since this breaks the
* OSS spec, we immediately put it back to blocking mode if the
* operation was successful. */
p_sys
->
i_fd
=
vlc_open
(
psz_device
,
O_WRONLY
|
O_NDELAY
);
if
(
p_sys
->
i_fd
<
0
)
audio_output_t
*
aout
=
(
audio_output_t
*
)
obj
;
aout_sys_t
*
sys
=
aout
->
sys
;
int
fd
=
sys
->
fd
;
#if 0
/* FIXME: ugly hack so selected OSS device survives restart */
char *device = var_InheritString (obj, "audio-device");
if (device != NULL)
{
msg_Err
(
p_aout
,
"cannot open audio device (%s)"
,
psz_device
);
free
(
psz_device
);
free
(
p_sys
);
return
VLC_EGENERIC
;
if (!var_Type (obj, "oss-audio-device"))
var_Create (obj, "oss-audio-device", VLC_VAR_STRING
);
var_SetString (obj, "oss-audio-device", device
);
free (device)
;
}
/* if the opening was ok, put the device back in blocking mode */
fcntl
(
p_sys
->
i_fd
,
F_SETFL
,
fcntl
(
p_sys
->
i_fd
,
F_GETFL
)
&~
FNDELAY
);
free
(
psz_device
);
p_aout
->
pf_play
=
aout_PacketPlay
;
p_aout
->
pf_pause
=
aout_PacketPause
;
p_aout
->
pf_flush
=
aout_PacketFlush
;
var_DelCallback (obj, "audio-device", aout_ChannelsRestart, NULL);
var_Destroy (obj, "audio-device");
#endif
if
(
var_Type
(
p_aout
,
"audio-device"
)
==
0
)
Probe
(
p_aout
);
var_AddCallback
(
p_aout
,
"audio-device"
,
aout_ChannelsRestart
,
NULL
);
ioctl
(
fd
,
SNDCTL_DSP_HALT
,
NULL
);
close
(
fd
);
free
(
sys
);
}
if
(
var_Get
(
p_aout
,
"audio-device"
,
&
val
)
<
0
)
/* Probe() has failed. */
goto
error
;
/**
* Queues one audio buffer to the hardware.
*/
static
void
Play
(
audio_output_t
*
aout
,
block_t
*
block
)
{
aout_sys_t
*
sys
=
aout
->
sys
;
int
fd
=
sys
->
fd
;
if
(
val
.
i_int
==
AOUT_VAR_SPDIF
)
{
p_aout
->
format
.
i_format
=
VLC_CODEC_SPDIFL
;
}
else
if
(
val
.
i_int
==
AOUT_VAR_5_1
)
{
p_aout
->
format
.
i_format
=
VLC_CODEC_S16N
;
p_aout
->
format
.
i_physical_channels
=
AOUT_CHAN_LEFT
|
AOUT_CHAN_RIGHT
|
AOUT_CHAN_CENTER
|
AOUT_CHAN_REARLEFT
|
AOUT_CHAN_REARRIGHT
|
AOUT_CHAN_LFE
;
}
else
if
(
val
.
i_int
==
AOUT_VAR_2F2R
)
{
p_aout
->
format
.
i_format
=
VLC_CODEC_S16N
;
p_aout
->
format
.
i_physical_channels
=
AOUT_CHAN_LEFT
|
AOUT_CHAN_RIGHT
|
AOUT_CHAN_REARLEFT
|
AOUT_CHAN_REARRIGHT
;
}
else
if
(
val
.
i_int
==
AOUT_VAR_STEREO
)
{
p_aout
->
format
.
i_format
=
VLC_CODEC_S16N
;
p_aout
->
format
.
i_physical_channels
=
AOUT_CHAN_LEFT
|
AOUT_CHAN_RIGHT
;
}
else
if
(
val
.
i_int
==
AOUT_VAR_MONO
)
int
delay
;
if
(
ioctl
(
sys
->
fd
,
SNDCTL_DSP_GETODELAY
,
&
delay
)
>=
0
)
{
p_aout
->
format
.
i_format
=
VLC_CODEC_S16N
;
p_aout
->
format
.
i_physical_channels
=
AOUT_CHAN_CENTER
;
mtime_t
latency
=
(
delay
*
CLOCK_FREQ
*
aout
->
format
.
i_frame_length
)
/
(
aout
->
format
.
i_rate
*
aout
->
format
.
i_bytes_per_frame
);
/* TODO: insert zeroes when starting playback */
aout_TimeReport
(
aout
,
block
->
i_pts
-
latency
);
}
else
{
/* This should not happen ! */
msg_Err
(
p_aout
,
"internal: can't find audio-device (%"
PRId64
")"
,
val
.
i_int
);
goto
error
;
}
msg_Warn
(
aout
,
"cannot get delay: %m"
);
/* Reset the DSP device */
if
(
ioctl
(
p_sys
->
i_fd
,
SNDCTL_DSP_RESET
,
NULL
)
<
0
)
while
(
block
->
i_buffer
>
0
)
{
msg_Err
(
p_aout
,
"cannot reset OSS audio device"
);
goto
error
;
}
/* Set the output format */
if
(
AOUT_FMT_SPDIF
(
&
p_aout
->
format
)
)
{
int
i_format
=
AFMT_AC3
;
if
(
ioctl
(
p_sys
->
i_fd
,
SNDCTL_DSP_SETFMT
,
&
i_format
)
<
0
||
i_format
!=
AFMT_AC3
)
ssize_t
bytes
=
write
(
fd
,
block
->
p_buffer
,
block
->
i_buffer
);
if
(
bytes
>=
0
)
{
msg_Err
(
p_aout
,
"cannot reset OSS audio device"
)
;
goto
error
;
block
->
p_buffer
+=
bytes
;
block
->
i_buffer
-=
bytes
;
}
p_aout
->
format
.
i_format
=
VLC_CODEC_SPDIFL
;
p_aout
->
format
.
i_bytes_per_frame
=
AOUT_SPDIF_SIZE
;
p_aout
->
format
.
i_frame_length
=
A52_FRAME_NB
;
aout_PacketInit
(
p_aout
,
&
p_sys
->
packet
,
A52_FRAME_NB
);
p_aout
->
volume_set
=
NULL
;
p_aout
->
mute_set
=
NULL
;
}
else
{
unsigned
int
i_format
=
AFMT_S16_NE
;
unsigned
int
i_frame_size
,
i_fragments
;
unsigned
int
i_rate
;
unsigned
int
i_nb_channels
;
audio_buf_info
audio_buf
;
if
(
ioctl
(
p_sys
->
i_fd
,
SNDCTL_DSP_SETFMT
,
&
i_format
)
<
0
)
{
msg_Err
(
p_aout
,
"cannot set audio output format"
);
goto
error
;
}
switch
(
i_format
)
{
case
AFMT_U8
:
p_aout
->
format
.
i_format
=
VLC_CODEC_U8
;
break
;
case
AFMT_S8
:
p_aout
->
format
.
i_format
=
VLC_CODEC_S8
;
break
;
case
AFMT_U16_LE
:
p_aout
->
format
.
i_format
=
VLC_CODEC_U16L
;
break
;
case
AFMT_S16_LE
:
p_aout
->
format
.
i_format
=
VLC_CODEC_S16L
;
break
;
case
AFMT_U16_BE
:
p_aout
->
format
.
i_format
=
VLC_CODEC_U16B
;
break
;
case
AFMT_S16_BE
:
p_aout
->
format
.
i_format
=
VLC_CODEC_S16B
;
break
;
default:
msg_Err
(
p_aout
,
"OSS fell back to an unknown format (%d)"
,
i_format
);
goto
error
;
}
i_nb_channels
=
aout_FormatNbChannels
(
&
p_aout
->
format
);
/* Set the number of channels */
if
(
ioctl
(
p_sys
->
i_fd
,
SNDCTL_DSP_CHANNELS
,
&
i_nb_channels
)
<
0
||
i_nb_channels
!=
aout_FormatNbChannels
(
&
p_aout
->
format
)
)
{
msg_Err
(
p_aout
,
"cannot set number of audio channels (%s)"
,
aout_FormatPrintChannels
(
&
p_aout
->
format
)
);
goto
error
;
}
/* Set the output rate */
i_rate
=
p_aout
->
format
.
i_rate
;
if
(
ioctl
(
p_sys
->
i_fd
,
SNDCTL_DSP_SPEED
,
&
i_rate
)
<
0
)
{
msg_Err
(
p_aout
,
"cannot set audio output rate (%i)"
,
p_aout
->
format
.
i_rate
);
goto
error
;
}
if
(
i_rate
!=
p_aout
->
format
.
i_rate
)
{
p_aout
->
format
.
i_rate
=
i_rate
;
}
/* Set the fragment size */
aout_FormatPrepare
(
&
p_aout
->
format
);
/* i_fragment = xxxxyyyy where: xxxx is fragtotal
* 1 << yyyy is fragsize */
i_frame_size
=
((
uint64_t
)
p_aout
->
format
.
i_bytes_per_frame
*
p_aout
->
format
.
i_rate
*
65536
)
/
(
48000
*
2
*
2
)
/
FRAME_COUNT
;
i_fragments
=
4
;
while
(
i_fragments
<
12
&&
(
1U
<<
i_fragments
)
<
i_frame_size
)
{
++
i_fragments
;
}
i_fragments
|=
FRAME_COUNT
<<
16
;
if
(
ioctl
(
p_sys
->
i_fd
,
SNDCTL_DSP_SETFRAGMENT
,
&
i_fragments
)
<
0
)
{
msg_Warn
(
p_aout
,
"cannot set fragment size (%.8x)"
,
i_fragments
);
}
if
(
ioctl
(
p_sys
->
i_fd
,
SNDCTL_DSP_GETOSPACE
,
&
audio_buf
)
<
0
)
{
msg_Err
(
p_aout
,
"cannot get fragment size"
);
goto
error
;
}
/* Number of fragments actually allocated */
p_aout
->
sys
->
i_fragstotal
=
audio_buf
.
fragstotal
;
/* Maximum duration the soundcard's buffer can hold */
p_aout
->
sys
->
max_buffer_duration
=
(
mtime_t
)
audio_buf
.
fragstotal
*
audio_buf
.
fragsize
*
1000000
/
p_aout
->
format
.
i_bytes_per_frame
/
p_aout
->
format
.
i_rate
*
p_aout
->
format
.
i_frame_length
;
aout_PacketInit
(
p_aout
,
&
p_sys
->
packet
,
audio_buf
.
fragsize
/
p_aout
->
format
.
i_bytes_per_frame
);
aout_SoftVolumeInit
(
p_aout
);
}
/* Create OSS thread and wait for its readiness. */
if
(
vlc_clone
(
&
p_sys
->
thread
,
OSSThread
,
p_aout
,
VLC_THREAD_PRIORITY_OUTPUT
)
)
{
msg_Err
(
p_aout
,
"cannot create OSS thread (%m)"
);
aout_PacketDestroy
(
p_aout
);
goto
error
;
else
msg_Err
(
aout
,
"cannot write samples: %m"
);
}
block_Release
(
block
);
return
VLC_SUCCESS
;
error:
var_DelCallback
(
p_aout
,
"audio-device"
,
aout_ChannelsRestart
,
NULL
);
close
(
p_sys
->
i_fd
);
free
(
p_sys
);
return
VLC_EGENERIC
;
/* Dumb OSS cannot send any kind of events for this... */
VolumeSync
(
aout
);
}
/**
***************************************************************************
*
Close: close the DSP audio device
*
****************************************************************************
/
static
void
Close
(
vlc_object_t
*
p_this
)
/**
*
Pauses/resumes the audio playback.
*/
static
void
Pause
(
audio_output_t
*
aout
,
bool
pause
,
mtime_t
date
)
{
audio_output_t
*
p_aout
=
(
audio_output_t
*
)
p_this
;
struct
aout_sys_t
*
p_sys
=
p_aout
->
sys
;
vlc_cancel
(
p_sys
->
thread
);
vlc_join
(
p_sys
->
thread
,
NULL
);
p_aout
->
b_die
=
false
;
var_DelCallback
(
p_aout
,
"audio-device"
,
aout_ChannelsRestart
,
NULL
);
ioctl
(
p_sys
->
i_fd
,
SNDCTL_DSP_RESET
,
NULL
);
close
(
p_sys
->
i_fd
);
aout_sys_t
*
sys
=
aout
->
sys
;
int
fd
=
sys
->
fd
;
aout_PacketDestroy
(
p_aout
)
;
free
(
p_sys
);
(
void
)
date
;
ioctl
(
fd
,
pause
?
SNDCTL_DSP_SILENCE
:
SNDCTL_DSP_SKIP
,
NULL
);
}
/*****************************************************************************
* BufferDuration: buffer status query
*****************************************************************************
* This function returns the duration in microseconds of the current buffer.
*****************************************************************************/
static
mtime_t
BufferDuration
(
audio_output_t
*
p_aout
)
/**
* Flushes/drains the audio playback buffer.
*/
static
void
Flush
(
audio_output_t
*
aout
,
bool
wait
)
{
struct
aout_sys_t
*
p_sys
=
p_aout
->
sys
;
audio_buf_info
audio_buf
;
int
i_bytes
;
#ifdef SNDCTL_DSP_GETODELAY
if
(
ioctl
(
p_sys
->
i_fd
,
SNDCTL_DSP_GETODELAY
,
&
i_bytes
)
<
0
)
#endif
{
/* Fall back to GETOSPACE and approximate latency. */
/* Fill the audio_buf_info structure:
* - fragstotal: total number of fragments allocated
* - fragsize: size of a fragment in bytes
* - bytes: available space in bytes (includes partially used fragments)
* Note! 'bytes' could be more than fragments*fragsize */
ioctl
(
p_sys
->
i_fd
,
SNDCTL_DSP_GETOSPACE
,
&
audio_buf
);
/* calculate number of available fragments (not partially used ones) */
i_bytes
=
(
audio_buf
.
fragstotal
*
audio_buf
.
fragsize
)
-
audio_buf
.
bytes
;
}
aout_sys_t
*
sys
=
aout
->
sys
;
int
fd
=
sys
->
fd
;
/* Return the fragment duration */
return
(
mtime_t
)
i_bytes
*
1000000
/
p_aout
->
format
.
i_bytes_per_frame
/
p_aout
->
format
.
i_rate
*
p_aout
->
format
.
i_frame_length
;
if
(
wait
)
return
;
/* drain is implicit with OSS */
ioctl
(
fd
,
SNDCTL_DSP_HALT_OUTPUT
,
NULL
);
}
typedef
struct
static
int
VolumeSync
(
audio_output_t
*
aout
)
{
block_t
*
p_buffer
;
void
*
p_bytes
;
}
oss_thread_ctx_t
;
static
void
OSSThreadCleanup
(
void
*
data
)
{
oss_thread_ctx_t
*
p_ctx
=
data
;
if
(
p_ctx
->
p_buffer
)
block_Release
(
p_ctx
->
p_buffer
);
else
free
(
p_ctx
->
p_bytes
);
aout_sys_t
*
sys
=
aout
->
sys
;
int
fd
=
sys
->
fd
;
int
level
;
if
(
ioctl
(
fd
,
SNDCTL_DSP_GETPLAYVOL
,
&
level
)
<
0
)
return
-
1
;
sys
->
mute
=
!
level
;
if
(
level
)
/* try to keep last volume before mute */
sys
->
level
=
level
;
aout_MuteReport
(
aout
,
!
level
);
aout_VolumeReport
(
aout
,
(
float
)(
level
&
0xFF
)
/
100
.
f
);
return
0
;
}
/*****************************************************************************
* OSSThread: asynchronous thread used to DMA the data to the device
*****************************************************************************/
static
void
*
OSSThread
(
void
*
obj
)
static
int
VolumeSet
(
audio_output_t
*
aout
,
float
vol
)
{
audio_output_t
*
p_aout
=
(
audio_output_t
*
)
obj
;
struct
aout_sys_t
*
p_sys
=
p_aout
->
sys
;
mtime_t
next_date
=
0
;
aout_sys_t
*
sys
=
aout
->
sys
;
int
fd
=
sys
->
fd
;
for
(
;;
)
int
level
=
lroundf
(
vol
*
100
.
f
);
if
(
level
>
0xFF
)
level
=
0xFFFF
;
else
level
|=
level
<<
8
;
if
(
!
sys
->
mute
&&
ioctl
(
fd
,
SNDCTL_DSP_SETPLAYVOL
,
&
level
)
<
0
)
{
block_t
*
p_buffer
=
NULL
;
int
canc
=
vlc_savecancel
();
if
(
p_aout
->
format
.
i_format
!=
VLC_CODEC_SPDIFL
)
{
mtime_t
buffered
=
BufferDuration
(
p_aout
);
/* Next buffer will be played at mdate() + buffered */
p_buffer
=
aout_PacketNext
(
p_aout
,
mdate
()
+
buffered
);
if
(
p_buffer
==
NULL
&&
buffered
>
(
p_aout
->
sys
->
max_buffer_duration
/
p_aout
->
sys
->
i_fragstotal
)
)
{
vlc_restorecancel
(
canc
);
/* If we have at least a fragment full, then we can wait a
* little and retry to get a new audio buffer instead of
* playing a blank sample */
msleep
(
(
p_aout
->
sys
->
max_buffer_duration
/
p_aout
->
sys
->
i_fragstotal
/
2
)
);
continue
;
}
}
else
{
vlc_restorecancel
(
canc
);
/* emu10k1 driver does not report Buffer Duration correctly in
* passthrough mode so we have to cheat */
if
(
!
next_date
)
{
next_date
=
mdate
();
}
else
{
mtime_t
delay
=
next_date
-
mdate
();
if
(
delay
>
AOUT_MAX_PTS_ADVANCE
)
{
msleep
(
delay
/
2
);
}
}
for
(
;;
)
{
canc
=
vlc_savecancel
();
p_buffer
=
aout_PacketNext
(
p_aout
,
next_date
);
if
(
p_buffer
)
break
;
vlc_restorecancel
(
canc
);
msleep
(
VLC_HARD_MIN_SLEEP
);
next_date
=
mdate
();
}
}
uint8_t
*
p_bytes
;
int
i_size
;
if
(
p_buffer
!=
NULL
)
{
p_bytes
=
p_buffer
->
p_buffer
;
i_size
=
p_buffer
->
i_buffer
;
/* This is theoretical ... we'll see next iteration whether
* we're drifting */
next_date
+=
p_buffer
->
i_length
;
}
else
{
i_size
=
FRAME_SIZE
/
p_aout
->
format
.
i_frame_length
*
p_aout
->
format
.
i_bytes_per_frame
;
p_bytes
=
malloc
(
i_size
);
memset
(
p_bytes
,
0
,
i_size
);
next_date
=
0
;
}
oss_thread_ctx_t
ctx
=
{
.
p_buffer
=
p_buffer
,
.
p_bytes
=
p_bytes
,
};
msg_Err
(
aout
,
"cannot set volume: %m"
);
return
-
1
;
}
vlc_cleanup_push
(
OSSThreadCleanup
,
&
ctx
);
vlc_restorecancel
(
canc
);
sys
->
level
=
level
;
aout_VolumeReport
(
aout
,
(
float
)(
level
&
0xFF
)
/
100
.
f
);
return
0
;
}
int
i_tmp
=
write
(
p_sys
->
i_fd
,
p_bytes
,
i_size
);
static
int
MuteSet
(
audio_output_t
*
aout
,
bool
mute
)
{
aout_sys_t
*
sys
=
aout
->
sys
;
int
fd
=
sys
->
fd
;
if
(
i_tmp
<
0
)
{
msg_Err
(
p_aout
,
"write failed (%m)"
);
}
vlc_cleanup_run
()
;
int
level
=
mute
?
0
:
(
sys
->
level
|
(
sys
->
level
<<
8
));
if
(
ioctl
(
fd
,
SNDCTL_DSP_SETPLAYVOL
,
&
level
)
<
0
)
{
msg_Err
(
aout
,
"cannot mute: %m"
);
return
-
1
;
}
return
NULL
;
sys
->
mute
=
mute
;
aout_MuteReport
(
aout
,
mute
);
return
0
;
}
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