Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
V
vlc-1.1
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-1.1
Commits
d24f1af6
Commit
d24f1af6
authored
Aug 14, 2002
by
Arnaud de Bossoreille de Ribou
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
ALSA audio output v3.01 is out !
parent
ad830330
Changes
1
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
247 additions
and
204 deletions
+247
-204
modules/audio_output/alsa.c
modules/audio_output/alsa.c
+247
-204
No files found.
modules/audio_output/alsa.c
View file @
d24f1af6
...
@@ -2,11 +2,12 @@
...
@@ -2,11 +2,12 @@
* alsa.c : alsa plugin for vlc
* alsa.c : alsa plugin for vlc
*****************************************************************************
*****************************************************************************
* Copyright (C) 2000-2001 VideoLAN
* Copyright (C) 2000-2001 VideoLAN
* $Id: alsa.c,v 1.
1 2002/08/07 21:36:55 massiot
Exp $
* $Id: alsa.c,v 1.
2 2002/08/14 10:50:12 bozo
Exp $
*
*
* Authors: Henri Fallon <henri@videolan.org> - Original Author
* Authors: Henri Fallon <henri@videolan.org> - Original Author
* Jeffrey Baker <jwbaker@acm.org> - Port to ALSA 1.0 API
* Jeffrey Baker <jwbaker@acm.org> - Port to ALSA 1.0 API
* John Paul Lorenti <jpl31@columbia.edu> - Device selection
* John Paul Lorenti <jpl31@columbia.edu> - Device selection
* Arnaud de Bossoreille de Ribou <bozo@via.ecp.fr> - S/PDIF and aout3
*
*
* This program is free software; you can redistribute it and/or modify
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* it under the terms of the GNU General Public License as published by
...
@@ -31,61 +32,66 @@
...
@@ -31,61 +32,66 @@
#include <stdlib.h>
/* calloc(), malloc(), free() */
#include <stdlib.h>
/* calloc(), malloc(), free() */
#include <vlc/vlc.h>
#include <vlc/vlc.h>
#include <vlc/aout.h>
#include <vlc/aout.h>
#include "aout_internal.h"
/* ALSA part */
#include <alsa/asoundlib.h>
#include <alsa/asoundlib.h>
/*****************************************************************************
* aout_sys_t: ALSA audio output method descriptor
*****************************************************************************
* This structure is part of the audio output thread descriptor.
* It describes the ALSA specific properties of an audio device.
*****************************************************************************/
struct
aout_sys_t
{
snd_pcm_t
*
p_snd_pcm
;
snd_pcm_sframes_t
i_buffer_size
;
int
i_period_time
;
volatile
vlc_bool_t
b_initialized
;
#ifdef DEBUG
snd_output_t
*
p_snd_stderr
;
#endif
};
/* These values are in frames.
* To convert them to a numer of bytes you have to multiply them by the
* number of channel(s) (eg. 2 for stereo) and the size of a sample (eg.
* 2 for s16). */
#define ALSA_DEFAULT_PERIOD_SIZE 2048
#define ALSA_DEFAULT_BUFFER_SIZE ( ALSA_DEFAULT_PERIOD_SIZE << 4 )
#define ALSA_SPDIF_PERIOD_SIZE 1536
#define ALSA_SPDIF_BUFFER_SIZE ( ALSA_SPDIF_PERIOD_SIZE << 4 )
/*****************************************************************************
/*****************************************************************************
* Local prototypes
* Local prototypes
*****************************************************************************/
*****************************************************************************/
static
int
Open
(
vlc_object_t
*
);
static
int
Open
(
vlc_object_t
*
);
static
void
Close
(
vlc_object_t
*
);
static
void
Close
(
vlc_object_t
*
);
static
int
SetFormat
(
aout_
thread
_t
*
);
static
int
SetFormat
(
aout_
instance
_t
*
);
static
int
GetBufInfo
(
aout_thread_t
*
,
int
);
static
void
Play
(
aout_instance_t
*
,
static
void
Play
(
aout_thread_t
*
,
byte_t
*
,
int
);
aout_buffer_t
*
);
static
void
HandleXrun
(
aout_thread_t
*
);
static
int
ALSAThread
(
aout_instance_t
*
);
static
void
ALSAFill
(
aout_instance_t
*
);
/*****************************************************************************
/*****************************************************************************
* Module descriptor
* Module descriptor
*****************************************************************************/
*****************************************************************************/
vlc_module_begin
();
vlc_module_begin
();
add_category_hint
(
N_
(
"
Device
"
),
NULL
);
add_category_hint
(
N_
(
"
Audio
"
),
NULL
);
add_string
(
"alsa-device"
,
NULL
,
NULL
,
N_
(
"Name"
),
NULL
);
add_string
(
"alsa-device"
,
NULL
,
NULL
,
N_
(
"Name"
),
NULL
);
set_description
(
_
(
"ALSA audio module"
)
);
set_description
(
_
(
"ALSA audio module"
)
);
set_capability
(
"audio output"
,
50
);
set_capability
(
"audio output"
,
50
);
set_callbacks
(
Open
,
Close
);
set_callbacks
(
Open
,
Close
);
vlc_module_end
();
vlc_module_end
();
/*****************************************************************************
* Preamble
*****************************************************************************/
typedef
struct
alsa_device_t
{
int
i_num
;
}
alsa_device_t
;
typedef
struct
alsa_card_t
{
int
i_num
;
}
alsa_card_t
;
/* here we store plugin dependant informations */
struct
aout_sys_t
{
snd_pcm_t
*
p_alsa_handle
;
unsigned
long
buffer_time
;
unsigned
long
period_time
;
unsigned
long
chunk_size
;
unsigned
long
buffer_size
;
unsigned
long
rate
;
unsigned
int
bytes_per_sample
;
unsigned
int
samples_per_frame
;
unsigned
int
bytes_per_frame
;
};
/*****************************************************************************
/*****************************************************************************
* Open: create a handle and open an alsa device
* Open: create a handle and open an alsa device
*****************************************************************************
*****************************************************************************
...
@@ -93,24 +99,26 @@ struct aout_sys_t
...
@@ -93,24 +99,26 @@ struct aout_sys_t
*****************************************************************************/
*****************************************************************************/
static
int
Open
(
vlc_object_t
*
p_this
)
static
int
Open
(
vlc_object_t
*
p_this
)
{
{
aout_thread_t
*
p_aout
=
(
aout_thread_t
*
)
p_this
;
aout_instance_t
*
p_aout
=
(
aout_instance_t
*
)
p_this
;
struct
aout_sys_t
*
p_sys
;
char
*
psz_device
;
/* Allows user to choose which ALSA device to use */
/* Allows user to choose which ALSA device to use */
char
psz_alsadev
[
128
];
char
psz_alsadev
[
128
];
char
*
psz_device
,
*
psz_userdev
;
char
*
psz_userdev
;
int
i_
ret
;
int
i_
snd_rc
;
/* Allocate structures */
/* Allocate structures */
p_aout
->
p_sys
=
malloc
(
sizeof
(
aout_sys_t
)
);
p_aout
->
output
.
p_sys
=
p_sys
=
malloc
(
sizeof
(
aout_sys_t
)
);
if
(
p_
aout
->
p_
sys
==
NULL
)
if
(
p_sys
==
NULL
)
{
{
msg_Err
(
p_aout
,
"out of memory"
);
msg_Err
(
p_aout
,
"out of memory"
);
return
-
1
;
return
-
1
;
}
}
p_aout
->
pf_setformat
=
SetFormat
;
#ifdef DEBUG
p_aout
->
pf_getbufinfo
=
GetBufInfo
;
snd_output_stdio_attach
(
&
p_sys
->
p_snd_stderr
,
stderr
,
0
)
;
p_aout
->
pf_play
=
Play
;
#endif
/* Read in ALSA device preferences from configuration */
/* Read in ALSA device preferences from configuration */
psz_userdev
=
config_GetPsz
(
p_aout
,
"alsa-device"
);
psz_userdev
=
config_GetPsz
(
p_aout
,
"alsa-device"
);
...
@@ -122,11 +130,7 @@ static int Open( vlc_object_t *p_this )
...
@@ -122,11 +130,7 @@ static int Open( vlc_object_t *p_this )
else
else
{
{
/* Use the internal logic to decide on the device name */
/* Use the internal logic to decide on the device name */
if
(
p_aout
->
i_format
!=
AOUT_FMT_A52
)
if
(
p_aout
->
output
.
output
.
i_format
==
AOUT_FMT_SPDIF
)
{
psz_device
=
"default"
;
}
else
{
{
unsigned
char
s
[
4
];
unsigned
char
s
[
4
];
s
[
0
]
=
IEC958_AES0_CON_EMPHASIS_NONE
|
IEC958_AES0_NONAUDIO
;
s
[
0
]
=
IEC958_AES0_CON_EMPHASIS_NONE
|
IEC958_AES0_NONAUDIO
;
...
@@ -137,21 +141,28 @@ static int Open( vlc_object_t *p_this )
...
@@ -137,21 +141,28 @@ static int Open( vlc_object_t *p_this )
"iec958:AES0=0x%x,AES1=0x%x,AES2=0x%x,AES3=0x%x"
,
"iec958:AES0=0x%x,AES1=0x%x,AES2=0x%x,AES3=0x%x"
,
s
[
0
],
s
[
1
],
s
[
2
],
s
[
3
]
);
s
[
0
],
s
[
1
],
s
[
2
],
s
[
3
]
);
psz_device
=
psz_alsadev
;
psz_device
=
psz_alsadev
;
p_sys
->
i_buffer_size
=
ALSA_SPDIF_BUFFER_SIZE
;
p_aout
->
output
.
i_nb_samples
=
ALSA_SPDIF_PERIOD_SIZE
;
}
else
{
psz_device
=
"default"
;
p_sys
->
i_buffer_size
=
ALSA_DEFAULT_BUFFER_SIZE
;
p_aout
->
output
.
i_nb_samples
=
ALSA_DEFAULT_PERIOD_SIZE
;
}
}
}
}
/* Open device */
/* Open device */
i_
ret
=
snd_pcm_open
(
&
(
p_aout
->
p_sys
->
p_alsa_handle
)
,
i_
snd_rc
=
snd_pcm_open
(
&
p_sys
->
p_snd_pcm
,
psz_device
,
psz_device
,
SND_PCM_STREAM_PLAYBACK
,
0
);
SND_PCM_STREAM_PLAYBACK
,
SND_PCM_NONBLOCK
);
if
(
i_
ret
!=
0
)
if
(
i_
snd_rc
<
0
)
{
{
msg_Err
(
p_aout
,
"cannot open ALSA device `%s' (%s)"
,
msg_Err
(
p_aout
,
"cannot open ALSA device `%s' (%s)"
,
psz_device
,
snd_strerror
(
i_
ret
)
);
psz_device
,
snd_strerror
(
i_
snd_rc
)
);
if
(
psz_userdev
)
if
(
psz_userdev
)
{
free
(
psz_userdev
);
free
(
psz_userdev
);
}
free
(
p_sys
);
p_sys
->
p_snd_pcm
=
NULL
;
return
-
1
;
return
-
1
;
}
}
...
@@ -160,6 +171,20 @@ static int Open( vlc_object_t *p_this )
...
@@ -160,6 +171,20 @@ static int Open( vlc_object_t *p_this )
free
(
psz_userdev
);
free
(
psz_userdev
);
}
}
/* Create ALSA thread and wait for its readiness. */
p_sys
->
b_initialized
=
VLC_FALSE
;
if
(
vlc_thread_create
(
p_aout
,
"aout"
,
ALSAThread
,
VLC_FALSE
)
)
{
msg_Err
(
p_aout
,
"cannot create ALSA thread (%s)"
,
strerror
(
errno
)
);
if
(
psz_userdev
)
free
(
psz_userdev
);
free
(
p_sys
);
return
-
1
;
}
p_aout
->
output
.
pf_setformat
=
SetFormat
;
p_aout
->
output
.
pf_play
=
Play
;
return
0
;
return
0
;
}
}
...
@@ -169,9 +194,11 @@ static int Open( vlc_object_t *p_this )
...
@@ -169,9 +194,11 @@ static int Open( vlc_object_t *p_this )
* This function prepares the device, sets the rate, format, the mode
* This function prepares the device, sets the rate, format, the mode
* ( "play as soon as you have data" ), and buffer information.
* ( "play as soon as you have data" ), and buffer information.
*****************************************************************************/
*****************************************************************************/
static
int
SetFormat
(
aout_
thread_t
*
p_aout
)
static
int
SetFormat
(
aout_
instance_t
*
p_aout
)
{
{
int
i_rv
;
struct
aout_sys_t
*
p_sys
=
p_aout
->
output
.
p_sys
;
int
i_snd_rc
;
int
i_format
;
int
i_format
;
snd_pcm_hw_params_t
*
p_hw
;
snd_pcm_hw_params_t
*
p_hw
;
...
@@ -180,241 +207,257 @@ static int SetFormat( aout_thread_t *p_aout )
...
@@ -180,241 +207,257 @@ static int SetFormat( aout_thread_t *p_aout )
snd_pcm_hw_params_alloca
(
&
p_hw
);
snd_pcm_hw_params_alloca
(
&
p_hw
);
snd_pcm_sw_params_alloca
(
&
p_sw
);
snd_pcm_sw_params_alloca
(
&
p_sw
);
/* default value for snd_pcm_hw_params_set_buffer_time_near() */
switch
(
p_aout
->
output
.
output
.
i_format
)
p_aout
->
p_sys
->
buffer_time
=
AOUT_BUFFER_DURATION
;
switch
(
p_aout
->
i_format
)
{
{
case
AOUT_FMT_S16_LE
:
case
AOUT_FMT_MU_LAW
:
i_format
=
SND_PCM_FORMAT_MU_LAW
;
break
;
i_format
=
SND_PCM_FORMAT_S16_LE
;
case
AOUT_FMT_A_LAW
:
i_format
=
SND_PCM_FORMAT_A_LAW
;
break
;
p_aout
->
p_sys
->
bytes_per_sample
=
2
;
case
AOUT_FMT_IMA_ADPCM
:
i_format
=
SND_PCM_FORMAT_IMA_ADPCM
;
break
;
break
;
case
AOUT_FMT_U8
:
i_format
=
SND_PCM_FORMAT_U8
;
break
;
case
AOUT_FMT_S16_LE
:
i_format
=
SND_PCM_FORMAT_S16_LE
;
break
;
case
AOUT_FMT_A52
:
case
AOUT_FMT_S16_BE
:
i_format
=
SND_PCM_FORMAT_S16_BE
;
break
;
i_format
=
SND_PCM_FORMAT_S16_LE
;
case
AOUT_FMT_S8
:
i_format
=
SND_PCM_FORMAT_S8
;
break
;
p_aout
->
p_sys
->
bytes_per_sample
=
2
;
case
AOUT_FMT_U16_LE
:
i_format
=
SND_PCM_FORMAT_U16_LE
;
break
;
/* buffer_time must be 500000 to avoid a system crash */
case
AOUT_FMT_U16_BE
:
i_format
=
SND_PCM_FORMAT_U16_BE
;
break
;
p_aout
->
p_sys
->
buffer_time
=
500000
;
case
AOUT_FMT_FLOAT32
:
i_format
=
SND_PCM_FORMAT_FLOAT
;
break
;
break
;
case
AOUT_FMT_FIXED32
:
default:
default:
i_format
=
SND_PCM_FORMAT_S16_BE
;
msg_Err
(
p_aout
,
"audio output format 0x%x not supported"
,
p_aout
->
p_sys
->
bytes_per_sample
=
2
;
p_aout
->
output
.
output
.
i_format
);
return
-
1
;
break
;
break
;
}
}
p_aout
->
p_sys
->
samples_per_frame
=
p_aout
->
i_channels
;
i_snd_rc
=
snd_pcm_hw_params_any
(
p_sys
->
p_snd_pcm
,
p_hw
);
p_aout
->
p_sys
->
bytes_per_frame
=
p_aout
->
p_sys
->
samples_per_frame
*
if
(
i_snd_rc
<
0
)
p_aout
->
p_sys
->
bytes_per_sample
;
i_rv
=
snd_pcm_hw_params_any
(
p_aout
->
p_sys
->
p_alsa_handle
,
p_hw
);
if
(
i_rv
<
0
)
{
{
msg_Err
(
p_aout
,
"unable to retrieve initial parameters"
);
msg_Err
(
p_aout
,
"unable to retrieve initial
hardware
parameters"
);
return
-
1
;
return
-
1
;
}
}
i_
rv
=
snd_pcm_hw_params_set_access
(
p_aout
->
p_sys
->
p_alsa_handle
,
p_hw
,
i_
snd_rc
=
snd_pcm_hw_params_set_access
(
p_sys
->
p_snd_pcm
,
p_hw
,
SND_PCM_ACCESS_RW_INTERLEAVED
);
SND_PCM_ACCESS_RW_INTERLEAVED
);
if
(
i_
rv
<
0
)
if
(
i_
snd_rc
<
0
)
{
{
msg_Err
(
p_aout
,
"unable to set interleaved stream format"
);
msg_Err
(
p_aout
,
"unable to set interleaved stream format"
);
return
-
1
;
return
-
1
;
}
}
i_rv
=
snd_pcm_hw_params_set_format
(
p_aout
->
p_sys
->
p_alsa_handle
,
i_snd_rc
=
snd_pcm_hw_params_set_format
(
p_sys
->
p_snd_pcm
,
p_hw
,
i_format
);
p_hw
,
i_format
);
if
(
i_snd_rc
<
0
)
if
(
i_rv
<
0
)
{
{
msg_Err
(
p_aout
,
"unable to set stream sample size and word order"
);
msg_Err
(
p_aout
,
"unable to set stream sample size and word order"
);
return
-
1
;
return
-
1
;
}
}
i_
rv
=
snd_pcm_hw_params_set_channels
(
p_aout
->
p_sys
->
p_alsa_handle
,
p_hw
,
i_
snd_rc
=
snd_pcm_hw_params_set_channels
(
p_sys
->
p_snd_pcm
,
p_hw
,
p_aout
->
i_channels
);
p_aout
->
output
.
output
.
i_channels
);
if
(
i_
rv
<
0
)
if
(
i_
snd_rc
<
0
)
{
{
msg_Err
(
p_aout
,
"unable to set number of output channels"
);
msg_Err
(
p_aout
,
"unable to set number of output channels"
);
return
-
1
;
return
-
1
;
}
}
i_
rv
=
snd_pcm_hw_params_set_rate_near
(
p_aout
->
p_sys
->
p_alsa_handle
,
p_hw
,
i_
snd_rc
=
snd_pcm_hw_params_set_rate
(
p_sys
->
p_snd_pcm
,
p_hw
,
p_aout
->
i_rate
,
0
);
p_aout
->
output
.
output
.
i_rate
,
0
);
if
(
i_
rv
<
0
)
if
(
i_
snd_rc
<
0
)
{
{
msg_Err
(
p_aout
,
"unable to set sample rate"
);
msg_Err
(
p_aout
,
"unable to set sample rate"
);
return
-
1
;
return
-
1
;
}
}
p_aout
->
p_sys
->
rate
=
i_rv
;
i_rv
=
snd_pcm_hw_params_set_buffer_time_near
(
p_aout
->
p_sys
->
p_alsa_handle
,
i_snd_rc
=
snd_pcm_hw_params_set_buffer_size_near
(
p_sys
->
p_snd_pcm
,
p_hw
,
p_hw
,
p_sys
->
i_buffer_size
);
p_aout
->
p_sys
->
buffer_time
,
if
(
i_snd_rc
<
0
)
0
);
if
(
i_rv
<
0
)
{
{
msg_Err
(
p_aout
,
"unable to set buffer time"
);
msg_Err
(
p_aout
,
"unable to set buffer time"
);
return
-
1
;
return
-
1
;
}
}
p_
aout
->
p_sys
->
buffer_time
=
i_rv
;
p_
sys
->
i_buffer_size
=
i_snd_rc
;
i_
rv
=
snd_pcm_hw_params_set_period_time_near
(
p_aout
->
p_sys
->
p_alsa_handle
,
i_
snd_rc
=
snd_pcm_hw_params_set_period_size_near
(
p_hw
,
p_aout
->
p_sys
->
buffer_time
/
p_aout
->
p_sys
->
bytes_per_frame
,
0
);
p_sys
->
p_snd_pcm
,
p_hw
,
p_aout
->
output
.
i_nb_samples
,
0
);
if
(
i_
rv
<
0
)
if
(
i_
snd_rc
<
0
)
{
{
msg_Err
(
p_aout
,
"unable to set period
tim
e"
);
msg_Err
(
p_aout
,
"unable to set period
siz
e"
);
return
-
1
;
return
-
1
;
}
}
p_aout
->
p_sys
->
period_time
=
i_rv
;
p_aout
->
output
.
i_nb_samples
=
i_snd_rc
;
p_sys
->
i_period_time
=
snd_pcm_hw_params_get_period_time
(
p_hw
,
0
);
i_
rv
=
snd_pcm_hw_params
(
p_aout
->
p_sys
->
p_alsa_handle
,
p_hw
);
i_
snd_rc
=
snd_pcm_hw_params
(
p_sys
->
p_snd_pcm
,
p_hw
);
if
(
i_
rv
<
0
)
if
(
i_
snd_rc
<
0
)
{
{
msg_Err
(
p_aout
,
"unable to set hardware configuration"
);
msg_Err
(
p_aout
,
"unable to set hardware configuration"
);
return
-
1
;
return
-
1
;
}
}
p_aout
->
p_sys
->
chunk_size
=
snd_pcm_hw_params_get_period_size
(
p_hw
,
0
);
snd_pcm_sw_params_current
(
p_sys
->
p_snd_pcm
,
p_sw
);
p_aout
->
p_sys
->
buffer_size
=
snd_pcm_hw_params_get_buffer_size
(
p_hw
);
i_snd_rc
=
snd_pcm_sw_params_set_sleep_min
(
p_sys
->
p_snd_pcm
,
p_sw
,
0
);
snd_pcm_sw_params_current
(
p_aout
->
p_sys
->
p_alsa_handle
,
p_sw
);
i_snd_rc
=
snd_pcm_sw_params_set_avail_min
(
p_sys
->
p_snd_pcm
,
p_sw
,
i_rv
=
snd_pcm_sw_params_set_sleep_min
(
p_aout
->
p_sys
->
p_alsa_handle
,
p_sw
,
p_aout
->
output
.
i_nb_samples
);
0
);
i_rv
=
snd_pcm_sw_params_set_avail_min
(
p_aout
->
p_sys
->
p_alsa_handle
,
p_sw
,
i_snd_rc
=
snd_pcm_sw_params
(
p_sys
->
p_snd_pcm
,
p_sw
);
p_aout
->
p_sys
->
chunk_size
);
if
(
i_snd_rc
<
0
)
/* Worked with the CVS version but not with 0.9beta3
i_rv = snd_pcm_sw_params_set_start_threshold( p_aout->p_sys->p_alsa_handle,
p_sw, p_aout->p_sys->buffer_size );
i_rv = snd_pcm_sw_params_set_stop_threshold( p_aout->p_sys->p_alsa_handle,
p_sw, p_aout->p_sys->buffer_size);
*/
i_rv
=
snd_pcm_sw_params
(
p_aout
->
p_sys
->
p_alsa_handle
,
p_sw
);
if
(
i_rv
<
0
)
{
{
msg_Err
(
p_aout
,
"unable to set software configuration"
);
msg_Err
(
p_aout
,
"unable to set software configuration"
);
return
-
1
;
return
-
1
;
}
}
#ifdef DEBUG
snd_output_printf
(
p_sys
->
p_snd_stderr
,
"
\n
ALSA hardware setup:
\n\n
"
);
snd_pcm_dump_hw_setup
(
p_sys
->
p_snd_pcm
,
p_sys
->
p_snd_stderr
);
snd_output_printf
(
p_sys
->
p_snd_stderr
,
"
\n
ALSA software setup:
\n\n
"
);
snd_pcm_dump_sw_setup
(
p_sys
->
p_snd_pcm
,
p_sys
->
p_snd_stderr
);
snd_output_printf
(
p_sys
->
p_snd_stderr
,
"
\n
"
);
#endif
p_sys
->
b_initialized
=
VLC_TRUE
;
return
0
;
return
0
;
}
}
/*****************************************************************************
/*****************************************************************************
* HandleXrun : reprepare the output
* Play: queue a buffer for playing by ALSAThread
*****************************************************************************
* When buffer gets empty, the driver goes in "Xrun" state, where it needs
* to be reprepared before playing again
*****************************************************************************/
*****************************************************************************/
static
void
HandleXrun
(
aout_thread_t
*
p_aout
)
static
void
Play
(
aout_instance_t
*
p_aout
,
aout_buffer_t
*
p_buffer
)
{
{
int
i_rv
;
aout_FifoPush
(
p_aout
,
&
p_aout
->
output
.
fifo
,
p_buffer
);
msg_Err
(
p_aout
,
"resetting output after buffer underrun"
);
// i_rv = snd_pcm_reset( p_aout->p_sys->p_alsa_handle );
i_rv
=
snd_pcm_prepare
(
p_aout
->
p_sys
->
p_alsa_handle
);
if
(
i_rv
<
0
)
{
msg_Err
(
p_aout
,
"unable to recover from buffer underrun (%s)"
,
snd_strerror
(
i_rv
)
);
}
}
}
/*****************************************************************************
/*****************************************************************************
* BufInfo: buffer status query
* Close: close the Alsa device
*****************************************************************************
* This function returns the number of used byte in the queue.
* It also deals with errors : indeed if the device comes to run out
* of data to play, it switches to the "underrun" status. It has to
* be flushed and re-prepared
*****************************************************************************/
*****************************************************************************/
static
int
GetBufInfo
(
aout_thread_t
*
p_aout
,
int
i_buffer_limit
)
static
void
Close
(
vlc_object_t
*
p_this
)
{
{
snd_pcm_status_t
*
p_status
;
aout_instance_t
*
p_aout
=
(
aout_instance_t
*
)
p_this
;
int
i_alsa_get_status_returns
;
struct
aout_sys_t
*
p_sys
=
p_aout
->
output
.
p_sys
;
int
i_snd_rc
;
snd_pcm_status_alloca
(
&
p_status
);
p_aout
->
b_die
=
1
;
vlc_thread_join
(
p_aout
);
i_alsa_get_status_returns
=
snd_pcm_status
(
p_aout
->
p_sys
->
p_alsa_handle
,
if
(
p_sys
->
p_snd_pcm
)
p_status
);
{
i_snd_rc
=
snd_pcm_close
(
p_sys
->
p_snd_pcm
);
if
(
i_alsa_get_status_returns
)
if
(
i_snd_rc
>
0
)
{
{
msg_Err
(
p_aout
,
"failed getting alsa buffer info
(%s)"
,
msg_Err
(
p_aout
,
"failed closing ALSA device
(%s)"
,
snd_strerror
(
i_alsa_get_status_returns
)
);
snd_strerror
(
i_snd_rc
)
);
return
(
-
1
);
}
}
}
switch
(
snd_pcm_status_get_state
(
p_status
)
)
free
(
p_sys
);
}
/*****************************************************************************
* ALSAThread: asynchronous thread used to DMA the data to the device
*****************************************************************************/
static
int
ALSAThread
(
aout_instance_t
*
p_aout
)
{
struct
aout_sys_t
*
p_sys
=
p_aout
->
output
.
p_sys
;
while
(
!
p_aout
->
b_die
)
{
{
case
SND_PCM_STATE_XRUN
:
if
(
!
p_sys
->
b_initialized
)
HandleXrun
(
p_aout
);
{
break
;
msleep
(
THREAD_SLEEP
);
continue
;
}
case
SND_PCM_STATE_OPEN
:
ALSAFill
(
p_aout
);
case
SND_PCM_STATE_PREPARED
:
case
SND_PCM_STATE_RUNNING
:
break
;
default:
msleep
(
p_sys
->
i_period_time
);
msg_Err
(
p_aout
,
"unhandled condition %i"
,
snd_pcm_status_get_state
(
p_status
)
);
break
;
}
}
return
snd_pcm_status_get_avail
(
p_status
)
*
p_aout
->
p_sys
->
bytes_per_frame
;
return
0
;
}
}
/*****************************************************************************
/*****************************************************************************
* Play : plays a sample
* ALSAFill: function used to fill the ALSA buffer as much as possible
*****************************************************************************
* Plays a sample using the snd_pcm_writei function from the alsa API
*****************************************************************************/
*****************************************************************************/
static
void
Play
(
aout_thread_t
*
p_aout
,
byte_t
*
buffer
,
int
i_size
)
static
void
ALSAFill
(
aout_instance_t
*
p_aout
)
{
{
snd_pcm_uframes_t
tot_frames
;
struct
aout_sys_t
*
p_sys
=
p_aout
->
output
.
p_sys
;
snd_pcm_uframes_t
frames_left
;
snd_pcm_uframes_t
rv
;
tot_frames
=
i_size
/
p_aout
->
p_sys
->
bytes_per_frame
;
aout_buffer_t
*
p_buffer
;
frames_left
=
tot_frames
;
mtime_t
next_date
=
0
;
snd_pcm_status_t
*
p_status
;
snd_timestamp_t
ts_next
;
int
i_snd_rc
,
i_size
;
byte_t
*
p_bytes
;
snd_pcm_uframes_t
i_avail
;
snd_pcm_status_alloca
(
&
p_status
);
while
(
frames_left
>
0
)
i_snd_rc
=
snd_pcm_wait
(
p_sys
->
p_snd_pcm
,
THREAD_SLEEP
);
if
(
i_snd_rc
<
0
)
{
{
rv
=
snd_pcm_writei
(
p_aout
->
p_sys
->
p_alsa_handle
,
buffer
+
msg_Err
(
p_aout
,
"alsa device not ready !!! (%s)"
,
(
tot_frames
-
frames_left
)
*
snd_strerror
(
i_snd_rc
)
);
p_aout
->
p_sys
->
bytes_per_frame
,
frames_left
);
return
;
}
if
(
(
signed
int
)
rv
<
0
)
while
(
VLC_TRUE
)
{
i_snd_rc
=
snd_pcm_status
(
p_sys
->
p_snd_pcm
,
p_status
);
if
(
i_snd_rc
<
0
)
{
{
msg_Err
(
p_aout
,
"
failed writing to output
(%s)"
,
msg_Err
(
p_aout
,
"
unable to get the device's status
(%s)"
,
snd_strerror
(
rv
)
);
snd_strerror
(
i_snd_rc
)
);
return
;
return
;
}
}
frames_left
-=
rv
;
if
(
snd_pcm_status_get_state
(
p_status
)
==
SND_PCM_STATE_XRUN
)
{
i_snd_rc
=
snd_pcm_prepare
(
p_sys
->
p_snd_pcm
);
if
(
i_snd_rc
==
0
)
{
msg_Err
(
p_aout
,
"recovered from buffer underrun"
);
next_date
=
mdate
();
i_snd_rc
=
snd_pcm_status
(
p_sys
->
p_snd_pcm
,
p_status
);
if
(
i_snd_rc
<
0
)
{
msg_Err
(
p_aout
,
"unable to get the device's status after recovery (%s)"
,
snd_strerror
(
i_snd_rc
)
);
return
;
}
}
else
{
msg_Err
(
p_aout
,
"unable to recover from buffer underrun"
);
return
;
}
}
}
}
/*****************************************************************************
i_avail
=
snd_pcm_status_get_avail
(
p_status
);
* Close: close the Alsa device
if
(
i_avail
>=
p_aout
->
output
.
i_nb_samples
)
*****************************************************************************/
{
static
void
Close
(
vlc_object_t
*
p_this
)
snd_pcm_status_get_tstamp
(
p_status
,
&
ts_next
);
{
next_date
=
(
mtime_t
)
ts_next
.
tv_sec
*
1000000
+
ts_next
.
tv_usec
;
aout_thread_t
*
p_aout
=
(
aout_thread_t
*
)
p_this
;
int
i_close_returns
;
p_buffer
=
aout_OutputNextBuffer
(
p_aout
,
next_date
,
0
);
if
(
p_buffer
==
NULL
)
return
;
p_bytes
=
p_buffer
->
p_buffer
;
i_close_returns
=
snd_pcm_close
(
p_aout
->
p_sys
->
p_alsa_handle
);
i_snd_rc
=
snd_pcm_writei
(
p_sys
->
p_snd_pcm
,
p_bytes
,
p_buffer
->
i_nb_samples
);
if
(
i_close_returns
)
if
(
i_snd_rc
<
0
)
{
{
msg_Err
(
p_aout
,
"failed closing ALSA device (%s)"
,
msg_Err
(
p_aout
,
"write failed (%s)"
,
snd_strerror
(
i_close_returns
)
);
snd_strerror
(
i_snd_rc
)
);
}
else
{
aout_BufferFree
(
p_buffer
);
}
}
}
}
free
(
p_aout
->
p_sys
);
}
}
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