1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
6 * Moonlight List (moonlight-list@lists.ximian.com)
8 * Copyright 2008 Novell, Inc. (http://www.novell.com)
10 * See the LICENSE file included with the distribution for details.
17 #include "audio-alsa.h"
22 typedef int (dyn_snd_pcm_open
) (snd_pcm_t
**pcm
, const char *name
, snd_pcm_stream_t stream
, int mode
);
23 typedef int (dyn_snd_pcm_close
) (snd_pcm_t
*pcm
);
24 typedef int (dyn_snd_pcm_get_params
) (snd_pcm_t
*pcm
, snd_pcm_uframes_t
*buffer_size
, snd_pcm_uframes_t
*period_size
);
25 typedef int (dyn_snd_pcm_poll_descriptors_count
) (snd_pcm_t
*pcm
);
26 typedef int (dyn_snd_pcm_poll_descriptors
) (snd_pcm_t
*pcm
, struct pollfd
*pfds
, unsigned int space
);
27 typedef int (dyn_snd_output_stdio_attach
) (snd_output_t
**outputp
, FILE *fp
, int _close
);
28 typedef int (dyn_snd_pcm_hw_params_malloc
) (snd_pcm_hw_params_t
**ptr
);
29 typedef int (dyn_snd_pcm_hw_params_any
) (snd_pcm_t
*pcm
, snd_pcm_hw_params_t
*params
);
30 typedef int (dyn_snd_pcm_hw_params_dump
) (snd_pcm_hw_params_t
*params
, snd_output_t
*out
);
31 typedef int (dyn_snd_pcm_hw_params_set_rate_resample
) (snd_pcm_t
*pcm
, snd_pcm_hw_params_t
*params
, unsigned int val
);
32 typedef int (dyn_snd_pcm_hw_params_test_access
) (snd_pcm_t
*pcm
, snd_pcm_hw_params_t
*params
, snd_pcm_access_t _access
);
33 typedef int (dyn_snd_pcm_hw_params_set_access
) (snd_pcm_t
*pcm
, snd_pcm_hw_params_t
*params
, snd_pcm_access_t _access
);
34 typedef int (dyn_snd_pcm_hw_params_set_format
) (snd_pcm_t
*pcm
, snd_pcm_hw_params_t
*params
, snd_pcm_format_t val
);
35 typedef int (dyn_snd_pcm_hw_params_set_channels
) (snd_pcm_t
*pcm
, snd_pcm_hw_params_t
*params
, unsigned int val
);
36 typedef int (dyn_snd_pcm_hw_params_set_rate_near
) (snd_pcm_t
*pcm
, snd_pcm_hw_params_t
*params
, unsigned int *val
, int *dir
);
37 typedef int (dyn_snd_pcm_hw_params_set_buffer_time_near
) (snd_pcm_t
*pcm
, snd_pcm_hw_params_t
*params
, unsigned int *val
, int *dir
);
38 typedef int (dyn_snd_pcm_hw_params
) (snd_pcm_t
*pcm
, snd_pcm_hw_params_t
*params
);
39 typedef int (dyn_snd_pcm_hw_params_can_pause
) (const snd_pcm_hw_params_t
*params
);
40 typedef void (dyn_snd_pcm_hw_params_free
) (snd_pcm_hw_params_t
*obj
);
41 typedef snd_pcm_state_t (dyn_snd_pcm_state
) (snd_pcm_t
*pcm
);
42 typedef const char * (dyn_snd_pcm_state_name
) (const snd_pcm_state_t state
);
43 typedef int (dyn_snd_pcm_drop
) (snd_pcm_t
*pcm
);
44 typedef snd_pcm_sframes_t (dyn_snd_pcm_writei
) (snd_pcm_t
*pcm
, const void *buffer
, snd_pcm_uframes_t size
);
45 typedef int (dyn_snd_pcm_mmap_begin
) (snd_pcm_t
*pcm
, const snd_pcm_channel_area_t
**areas
, snd_pcm_uframes_t
*offset
, snd_pcm_uframes_t
*frames
);
46 typedef snd_pcm_sframes_t (dyn_snd_pcm_mmap_commit
) (snd_pcm_t
*pcm
, snd_pcm_uframes_t offset
, snd_pcm_uframes_t frames
);
47 typedef int (dyn_snd_pcm_prepare
) (snd_pcm_t
*pcm
);
48 typedef int (dyn_snd_pcm_resume
) (snd_pcm_t
*pcm
);
49 typedef snd_pcm_sframes_t (dyn_snd_pcm_avail_update
) (snd_pcm_t
*pcm
);
50 typedef int (dyn_snd_pcm_start
) (snd_pcm_t
*pcm
);
51 typedef int (dyn_snd_pcm_delay
) (snd_pcm_t
*pcm
, snd_pcm_sframes_t
*delayp
);
52 typedef const char * (dyn_snd_strerror
) (int errnum
);
53 typedef const char * (dyn_snd_asoundlib_version
) (void);
55 dyn_snd_pcm_open
* d_snd_pcm_open
= NULL
;
56 dyn_snd_pcm_close
* d_snd_pcm_close
= NULL
;
57 dyn_snd_pcm_get_params
* d_snd_pcm_get_params
= NULL
;
58 dyn_snd_pcm_poll_descriptors_count
* d_snd_pcm_poll_descriptors_count
= NULL
;
59 dyn_snd_pcm_poll_descriptors
* d_snd_pcm_poll_descriptors
= NULL
;
60 dyn_snd_output_stdio_attach
* d_snd_output_stdio_attach
= NULL
;
61 dyn_snd_strerror
* d_snd_strerror
= NULL
;
62 dyn_snd_pcm_hw_params_malloc
* d_snd_pcm_hw_params_malloc
= NULL
;
63 dyn_snd_pcm_hw_params_any
* d_snd_pcm_hw_params_any
= NULL
;
64 dyn_snd_pcm_hw_params_dump
* d_snd_pcm_hw_params_dump
= NULL
;
65 dyn_snd_pcm_hw_params_set_rate_resample
* d_snd_pcm_hw_params_set_rate_resample
= NULL
;
66 dyn_snd_pcm_hw_params_test_access
* d_snd_pcm_hw_params_test_access
= NULL
;
67 dyn_snd_pcm_hw_params_set_access
* d_snd_pcm_hw_params_set_access
= NULL
;
68 dyn_snd_pcm_hw_params_set_format
* d_snd_pcm_hw_params_set_format
= NULL
;
69 dyn_snd_pcm_hw_params_set_channels
* d_snd_pcm_hw_params_set_channels
= NULL
;
70 dyn_snd_pcm_hw_params_set_rate_near
* d_snd_pcm_hw_params_set_rate_near
= NULL
;
71 dyn_snd_pcm_hw_params_set_buffer_time_near
* d_snd_pcm_hw_params_set_buffer_time_near
= NULL
;
72 dyn_snd_pcm_hw_params
* d_snd_pcm_hw_params
= NULL
;
73 dyn_snd_pcm_hw_params_can_pause
* d_snd_pcm_hw_params_can_pause
= NULL
;
74 dyn_snd_pcm_hw_params_free
* d_snd_pcm_hw_params_free
= NULL
;
75 dyn_snd_pcm_state
* d_snd_pcm_state
= NULL
;
76 dyn_snd_pcm_state_name
* d_snd_pcm_state_name
= NULL
;
77 dyn_snd_pcm_drop
* d_snd_pcm_drop
= NULL
;
78 dyn_snd_pcm_writei
* d_snd_pcm_writei
= NULL
;
79 dyn_snd_pcm_mmap_begin
* d_snd_pcm_mmap_begin
= NULL
;
80 dyn_snd_pcm_mmap_commit
* d_snd_pcm_mmap_commit
= NULL
;
81 dyn_snd_pcm_prepare
* d_snd_pcm_prepare
= NULL
;
82 dyn_snd_pcm_resume
* d_snd_pcm_resume
= NULL
;
83 dyn_snd_pcm_avail_update
* d_snd_pcm_avail_update
= NULL
;
84 dyn_snd_pcm_start
* d_snd_pcm_start
= NULL
;
85 dyn_snd_pcm_delay
* d_snd_pcm_delay
= NULL
;
86 dyn_snd_asoundlib_version
* d_snd_asoundlib_version
= NULL
;
88 #define snd_pcm_open d_snd_pcm_open
89 #define snd_pcm_close d_snd_pcm_close
90 #define snd_pcm_get_params d_snd_pcm_get_params
91 #define snd_pcm_poll_descriptors_count d_snd_pcm_poll_descriptors_count
92 #define snd_pcm_poll_descriptors d_snd_pcm_poll_descriptors
93 #define snd_output_stdio_attach d_snd_output_stdio_attach
94 #define snd_strerror d_snd_strerror
95 #define snd_pcm_hw_params_malloc d_snd_pcm_hw_params_malloc
96 #define snd_pcm_hw_params_any d_snd_pcm_hw_params_any
97 #define snd_pcm_hw_params_dump d_snd_pcm_hw_params_dump
98 #define snd_pcm_hw_params_set_rate_resample d_snd_pcm_hw_params_set_rate_resample
99 #define snd_pcm_hw_params_test_access d_snd_pcm_hw_params_test_access
100 #define snd_pcm_hw_params_test_access d_snd_pcm_hw_params_test_access
101 #define snd_pcm_hw_params_set_access d_snd_pcm_hw_params_set_access
102 #define snd_pcm_hw_params_set_format d_snd_pcm_hw_params_set_format
103 #define snd_pcm_hw_params_set_channels d_snd_pcm_hw_params_set_channels
104 #define snd_pcm_hw_params_set_rate_near d_snd_pcm_hw_params_set_rate_near
105 #define snd_pcm_hw_params_set_buffer_time_near d_snd_pcm_hw_params_set_buffer_time_near
106 #define snd_pcm_hw_params d_snd_pcm_hw_params
107 #define snd_pcm_hw_params_can_pause d_snd_pcm_hw_params_can_pause
108 #define snd_pcm_hw_params_free d_snd_pcm_hw_params_free
109 #define snd_pcm_state d_snd_pcm_state
110 #define snd_pcm_state_name d_snd_pcm_state_name
111 #define snd_pcm_drop d_snd_pcm_drop
112 #define snd_pcm_writei d_snd_pcm_writei
113 #define snd_pcm_mmap_begin d_snd_pcm_mmap_begin
114 #define snd_pcm_mmap_commit d_snd_pcm_mmap_commit
115 #define snd_pcm_prepare d_snd_pcm_prepare
116 #define snd_pcm_resume d_snd_pcm_resume
117 #define snd_pcm_avail_update d_snd_pcm_avail_update
118 #define snd_pcm_start d_snd_pcm_start
119 #define snd_pcm_delay d_snd_pcm_delay
120 #define snd_asoundlib_version d_snd_asoundlib_version
126 AlsaSource::AlsaSource (AlsaPlayer
*player
, MediaPlayer
*mplayer
, AudioStream
*stream
)
127 : AudioSource (Type::ALSASOURCE
, player
, mplayer
, stream
), mutex (true)
129 LOG_ALSA ("AlsaSource::AlsaSource (%p, %p)\n", player
, stream
);
131 this->player
= player
;
142 drop_pending
= false;
146 AlsaSource::~AlsaSource ()
148 LOG_ALSA ("AlsaSource::~AlsaSource ()\n");
154 AlsaSource::InitializeInternal ()
156 LOG_AUDIO ("AlsaSource::InitializeInternal ()\n");
157 // this is a no-op, initialization is done when needed.
162 AlsaSource::InitializeAlsa ()
166 AudioStream
*stream
= NULL
;
168 LOG_AUDIO ("AlsaSource::InitializeAlsa (%p) initialized: %i\n", this, initialized
);
177 stream
= GetStreamReffed ();
179 if (stream
== NULL
) {
180 // Shouldn't really happen, but handle this case anyway.
181 LOG_AUDIO ("AlsaSource::Initialize (): trying to initialize an audio device, but there's no audio to play.\n");
186 result
= snd_pcm_open (&pcm
, "default", SND_PCM_STREAM_PLAYBACK
, 0 /*SND_PCM_NONBLOCK*/);
188 LOG_AUDIO ("AlsaSource::Initialize (): cannot open audio device: %s\n", snd_strerror (result
));
193 // Configure the hardware
195 LOG_AUDIO ("AlsaSource::Initialize (): could not configure hardware for audio playback\n");
200 result
= snd_pcm_get_params (pcm
, &buffer_size
, &period_size
);
202 LOG_AUDIO ("AlsaSource::Initialize (): error while getting parameters: %s\n", snd_strerror (result
));
207 // Get the file descriptors to poll on
208 ndfs
= snd_pcm_poll_descriptors_count (pcm
);
210 LOG_AUDIO ("AlsaSource::Initialize(): Unable to initialize audio for playback (could not get poll descriptor count).\n");
215 udfs
= (pollfd
*) g_malloc0 (sizeof (pollfd
) * ndfs
);
216 if (snd_pcm_poll_descriptors (pcm
, udfs
, ndfs
) < 0) {
217 LOG_AUDIO ("AlsaSource::Initialize (): Unable to initialize audio for playback (could not get poll descriptors).\n");
222 LOG_AUDIO ("AlsaSource::Initialize (%p): Succeeded. Buffer size: %lu, period size: %lu\n", this, buffer_size
, period_size
);
238 AlsaSource::SetupHW ()
241 bool rw_available
= false;
242 bool mmap_available
= false;
244 bool debug
= debug_flags
& RUNTIME_DEBUG_AUDIO
;
249 snd_pcm_hw_params_t
*params
= NULL
;
250 snd_output_t
*output
= NULL
;
251 guint32 buffer_time
= 100000; // request 0.1 seconds of buffer time.
254 unsigned int rate
= GetSampleRate ();
255 unsigned int actual_rate
= rate
;
256 guint32 channels
= GetChannels ();
259 err
= snd_output_stdio_attach (&output
, stdout
, 0);
261 LOG_AUDIO ("AlsaSource::SetupHW (): Could not create alsa output: %s\n", snd_strerror (err
));
264 err
= snd_pcm_hw_params_malloc (¶ms
);
266 LOG_AUDIO ("AlsaSource::SetupHW (): Audio HW setup failed (malloc): %s\n", snd_strerror (err
));
270 // choose all parameters
271 err
= snd_pcm_hw_params_any (pcm
, params
);
273 LOG_AUDIO ("AlsaSource::SetupHW (): Audio HW setup failed (no configurations available): %s\n", snd_strerror (err
));
277 if (debug
&& output
!= NULL
) {
278 LOG_AUDIO ("AlsaSource::SetupHW (): hw configurations:\n");
279 snd_pcm_hw_params_dump (params
, output
);
282 // enable software resampling
283 err
= snd_pcm_hw_params_set_rate_resample (pcm
, params
, 1);
285 LOG_AUDIO ("AlsaSource::SetupHW (): Audio HW setup failed (could not enable resampling): %s\n", snd_strerror (err
));
289 // test for available transfer modes
290 if (!(moonlight_flags
& RUNTIME_INIT_AUDIO_ALSA_MMAP
)) {
291 err
= snd_pcm_hw_params_test_access (pcm
, params
, SND_PCM_ACCESS_RW_INTERLEAVED
);
293 LOG_AUDIO ("AlsaSource::SetupHW (): Audio HW setup: RW access mode not supported (%s).\n", snd_strerror (err
));
298 if (!(moonlight_flags
& RUNTIME_INIT_AUDIO_ALSA_RW
)) {
299 err
= snd_pcm_hw_params_test_access (pcm
, params
, SND_PCM_ACCESS_MMAP_INTERLEAVED
);
301 LOG_AUDIO ("AlsaSource::SetupHW (): Audio HW setup: MMAP access mode not supported (%s).\n", snd_strerror (err
));
303 mmap_available
= true;
306 if (mmap_available
) {
308 } else if (rw_available
) {
311 LOG_AUDIO ("AlsaSource::SetupHW (): Audio HW setup failed, no available access mode\n");
315 LOG_AUDIO ("AlsaSource::SetupHW (): Audio HW setup: using %s access mode.\n", mmap
? "MMAP" : "RW");
317 // set transfer mode (mmap or rw in our case)
318 err
= snd_pcm_hw_params_set_access (pcm
, params
, mmap
? SND_PCM_ACCESS_MMAP_INTERLEAVED
: SND_PCM_ACCESS_RW_INTERLEAVED
);
320 LOG_AUDIO ("AlsaSource::SetupHW (): Audio HW setup failed (access type not available for playback): %s\n", snd_strerror (err
));
325 switch (GetInputBytesPerSample ()) {
326 case 2: // 16 bit audio
327 err
= snd_pcm_hw_params_set_format (pcm
, params
, SND_PCM_FORMAT_S16
);
328 SetOutputBytesPerSample (2);
330 case 3: // 24 bit audio
331 // write as 32 bit audio, this is a lot easier to write to than 24 bit.
332 err
= snd_pcm_hw_params_set_format (pcm
, params
, SND_PCM_FORMAT_S32
);
333 SetOutputBytesPerSample (4);
336 LOG_AUDIO ("AlsaSource::SetupHW (): Invalid input bytes per sample, expected 2 or 3, got %i\n", GetInputBytesPerSample ());
341 LOG_AUDIO ("AlsaSource::SetupHW (): Audio HW setup failed (sample format not available for playback): %s\n", snd_strerror (err
));
346 err
= snd_pcm_hw_params_set_channels (pcm
, params
, channels
);
348 LOG_AUDIO ("AlsaSource::SetupHW (): Audio HW setup failed (channels count %i not available for playback): %s\n", channels
, snd_strerror (err
));
353 err
= snd_pcm_hw_params_set_rate_near (pcm
, params
, &actual_rate
, 0);
355 LOG_AUDIO ("AlsaSource::SetupHW (): Audio HW setup failed (sample rate %i Hz not available for playback): %s\n", rate
, snd_strerror (err
));
357 } else if (actual_rate
!= rate
) {
358 LOG_AUDIO ("AlsaSource::SetupHW (): Audio HW setup failed (sample rate %i Hz not available for playback, only got %i Hz).\n", rate
, actual_rate
);
362 // set the buffer time
363 err
= snd_pcm_hw_params_set_buffer_time_near (pcm
, params
, &buffer_time
, &dir
);
365 LOG_AUDIO ("AudioNode::SetupHW (): Audio HW setup failed (unable to set buffer time %i for playback: %s\n", buffer_time
, snd_strerror (err
));
369 // write the parameters to device
370 err
= snd_pcm_hw_params (pcm
, params
);
372 LOG_AUDIO ("AlsaSource::SetupHW (): Audio HW setup failed (unable to set hw params for playback: %s)\n", snd_strerror (err
));
373 if (debug
&& output
!= NULL
) {
374 LOG_AUDIO ("AlsaSource::SetupHW (): current hw configurations:\n");
375 snd_pcm_hw_params_dump (params
, output
);
381 LOG_AUDIO ("AlsaSource::SetupHW (): hardware pause support: %s\n", snd_pcm_hw_params_can_pause (params
) == 0 ? "no" : "yes");
382 LOG_AUDIO ("AlsaSource::SetupHW (): succeeded\n");
384 snd_pcm_hw_params_dump (params
, output
);
390 snd_pcm_hw_params_free (params
);
396 AlsaSource::StateChanged (AudioState old_state
)
398 if (GetState () == AudioPlaying
)
400 player
->UpdatePollList ();
404 AlsaSource::Played ()
407 player
->UpdatePollList ();
411 AlsaSource::Paused ()
419 AlsaSource::Stopped ()
428 AlsaSource::DropAlsa ()
432 LOG_ALSA ("AlsaSource::DropAlsa ()\n");
435 drop_pending
= false;
437 if (pcm
!= NULL
&& snd_pcm_state (pcm
) == SND_PCM_STATE_RUNNING
) {
438 err
= snd_pcm_drop (pcm
);
440 LOG_AUDIO ("AlsaSource::DropAlsa (): Could not stop/drain pcm: %s\n", snd_strerror (err
));
446 AlsaSource::CloseInternal ()
452 AlsaSource::CloseAlsa ()
469 AlsaSource::WriteRW ()
471 snd_pcm_sframes_t avail
;
472 snd_pcm_sframes_t commitres
= 0;
476 if (GetState () != AudioPlaying
) {
477 LOG_ALSA ("AlsaSource::WriteRW (): trying to write when we're not playing (state: %i)\n", GetState ());
481 if (!PreparePcm (&avail
))
484 LOG_ALSA ("AlsaSource::WriteRW (): entering play loop, avail: %" G_GINT64_FORMAT
", sample size: %i\n", (gint64
) avail
, (int) period_size
);
486 buffer
= g_malloc (avail
* GetOutputBytesPerFrame ());
488 frames
= Write (buffer
, (guint32
) avail
);
492 commitres
= snd_pcm_writei (pcm
, buffer
, frames
);
497 LOG_ALSA ("AlsaSource::WriteRW (): played %i samples, of %i available samples, result: %i.\n", (int) frames
, (int) avail
, (int) commitres
);
499 if (commitres
< 0 || (snd_pcm_uframes_t
) commitres
!= frames
) {
500 if (commitres
== -EAGAIN
)
501 LOG_AUDIO ("AlsaSource::WriteRW (): not enough space for all the data\n");
502 if (!XrunRecovery (commitres
>= 0 ? -EPIPE
: commitres
)) {
503 LOG_AUDIO ("AudioPlayer: could not write audio data: %s, commitres: %li, frames: %u\n", snd_strerror (commitres
), commitres
, frames
);
513 AlsaSource::WriteMmap ()
515 snd_pcm_channel_area_t
*areas
= NULL
;
516 snd_pcm_uframes_t offset
= 0;
517 snd_pcm_uframes_t frames
;
518 snd_pcm_sframes_t available_samples
;
519 snd_pcm_sframes_t commitres
= 0;
520 guint32 channels
= GetChannels ();
522 AudioData
*data
[channels
+ 1];
524 if (GetState () != AudioPlaying
) {
525 LOG_ALSA ("AlsaSource::WriteMmap (): trying to write when we're not playing (state: %i)\n", GetState ());
529 if (!PreparePcm (&available_samples
))
532 if (GetFlag (AudioEnded
)) {
537 LOG_ALSA_EX ("AlsaSource::WriteMmap (): entering play loop, avail: %" G_GINT64_FORMAT
", sample size: %i\n", (gint64
) available_samples
, (int) period_size
);
539 frames
= available_samples
;
545 err
= snd_pcm_mmap_begin (pcm
, (const snd_pcm_channel_area_t
** ) &areas
, &offset
, &frames
);
547 if (!XrunRecovery (err
)) {
548 LOG_AUDIO ("AudioPlayer: could not get mmapped memory: %s\n", snd_strerror (err
));
554 LOG_ALSA_EX ("AlsaSource::WriteMmap (): can write %lu frames, avail: %lu\n", frames
, available_samples
);
556 for (guint32 channel
= 0; channel
< channels
; channel
++) {
557 data
[channel
] = (AudioData
*) g_malloc (sizeof (AudioData
));
558 // pointer to the first sample to write to
559 data
[channel
]->dest
= ((gint8
*) areas
[channel
].addr
) + (areas
[channel
].first
/ 8) + offset
* areas
[channel
].step
/ 8;
560 // distance (in bytes) between samples
561 data
[channel
]->distance
= areas
[channel
].step
/ 8;
563 data
[channels
] = NULL
;
565 frames
= WriteFull (data
, frames
);
567 for (guint32 channel
= 0; channel
< channels
; channel
++) {
568 g_free (data
[channel
]);
571 commitres
= snd_pcm_mmap_commit (pcm
, offset
, frames
);
573 LOG_ALSA_EX ("AlsaSource::WriteMmap (): played %i samples, of %i available samples, result: %i.\n", (int) frames
, (int) 0, (int) commitres
);
575 if (commitres
< 0 || (snd_pcm_uframes_t
) commitres
!= frames
) {
576 if (!XrunRecovery (commitres
>= 0 ? -EPIPE
: commitres
)) {
577 LOG_AUDIO ("AudioPlayer: could not commit mmapped memory: %s\n", snd_strerror(err
));
578 commitres
= 0; // so that we end up returning false
588 return commitres
> 0;
592 AlsaSource::WriteAlsa ()
601 AlsaSource::XrunRecovery (int err
)
604 case -EPIPE
: // under-run
608 err
= snd_pcm_prepare (pcm
);
610 LOG_AUDIO ("AlsaPlayer: Can't recover from underrun, prepare failed: %s.\n", snd_strerror (err
));
613 LOG_AUDIO ("AlsaPlayer: Can't recover from underrun, pcm has been closed.\n");
620 while ((err
= snd_pcm_resume (pcm
)) == -EAGAIN
) {
621 LOG_AUDIO ("XrunRecovery: waiting for resume\n");
622 sleep (1); // wait until the suspend flag is released
625 err
= snd_pcm_prepare (pcm
);
627 LOG_AUDIO ("AlsaPlayer: Can't recover from suspend, prepare failed: %s.\n", snd_strerror (err
));
631 LOG_AUDIO ("AlsaPlayer: Can't recover from suspend, pcm has been closed.\n");
636 LOG_AUDIO ("AlsaPlayer: Can't recover from underrun: %s\n", snd_strerror (err
));
644 AlsaSource::PreparePcm (snd_pcm_sframes_t
*avail
)
648 snd_pcm_state_t state
;
652 state
= snd_pcm_state (pcm
);
654 LOG_ALSA ("AlsaSource::PreparePcm (): pcm has been closed.\n");
663 case SND_PCM_STATE_XRUN
:
664 LOG_ALSA ("AlsaSource::PreparePcm (): SND_PCM_STATE_XRUN.\n");
666 if (!XrunRecovery (-EPIPE
))
671 case SND_PCM_STATE_SUSPENDED
:
672 if (!XrunRecovery (-ESTRPIPE
))
675 case SND_PCM_STATE_SETUP
:
676 if (!XrunRecovery (-EPIPE
))
681 case SND_PCM_STATE_RUNNING
:
682 started
= true; // We might have gotten started automatically after writing a certain number of samples.
683 case SND_PCM_STATE_PREPARED
:
685 case SND_PCM_STATE_PAUSED
:
686 case SND_PCM_STATE_DRAINING
:
688 LOG_ALSA ("AlsaSource::PreparePcm (): state: %s (prepare failed)\n", snd_pcm_state_name (state
));
695 *avail
= snd_pcm_avail_update (pcm
);
705 if (!XrunRecovery (*avail
))
712 if ((snd_pcm_uframes_t
) *avail
< period_size
) {
714 LOG_ALSA ("AlsaSource::PreparePcm (): starting pcm (period size: %li, available: %li)\n", period_size
, *avail
);
718 err
= snd_pcm_start (pcm
);
728 LOG_AUDIO ("AlsaPlayer: Could not start pcm: %s\n", snd_strerror (err
));
738 LOG_ALSA ("AlsaSource::PreparePcm (): Prepared, avail: %li, started: %i\n", *avail
, (int) started
);
744 AlsaSource::GetDelayInternal ()
746 snd_pcm_sframes_t delay
;
749 bool update_error
= false;
750 bool not_initialized
= false;
754 not_initialized
= true;
756 err
= snd_pcm_avail_update (pcm
);
759 LOG_AUDIO ("AlsaSource::GetDelayInternal (): Could not update delay (%s)\n", snd_strerror (err
));
762 err
= snd_pcm_delay (pcm
, &delay
);
767 if (not_initialized
) {
768 LOG_AUDIO ("AlsaSource::GetDelayInternal (): pcm has been closed.\n");
776 LOG_AUDIO ("AlsaSource::GetDelayInternal (): Could not get delay (%s)\n", snd_strerror (err
));
777 result
= G_MAXUINT64
;
778 } else if (delay
< 0) {
779 LOG_AUDIO ("AlsaSource::GetDelayInternal (): Got negative delay (%li)\n", delay
);
780 result
= G_MAXUINT64
;
782 result
= (guint64
) TIMESPANTICKS_IN_SECOND
* (guint64
) delay
/ (guint64
) GetSampleRate ();
792 AlsaPlayer::AlsaPlayer ()
794 LOG_ALSA ("AlsaPlayer::AlsaPlayer ()\n");
798 update_poll_pending
= true;
805 AlsaPlayer::~AlsaPlayer ()
807 LOG_ALSA ("AlsaPlayer::~AlsaPlayer ()\n");
811 AlsaPlayer::Initialize ()
815 LOG_ALSA ("AlsaPlayer::Initialize ()\n");
818 if (pipe (fds
) != 0) {
819 LOG_AUDIO ("AlsaPlayer::Initialize (): Unable to create pipe (%s).\n", strerror (errno
));
823 // Make the writer pipe non-blocking.
824 fcntl (fds
[1], F_SETFL
, fcntl (fds
[1], F_GETFL
) | O_NONBLOCK
);
826 // Create the audio thread
827 audio_thread
= (pthread_t
*) g_malloc (sizeof (pthread_t
));
828 result
= pthread_create (audio_thread
, NULL
, Loop
, this);
830 LOG_AUDIO ("AlsaPlayer::Initialize (): could not create audio thread (error code: %i = '%s').\n", result
, strerror (result
));
831 g_free (audio_thread
);
836 LOG_ALSA ("AlsaPlayer::Initialize (): the audio player has been initialized.\n");
841 static int is_alsa_usable
= 0; // 0 = not tested, 1 = tested, usable, 2 = tested, not usable
842 static void *libalsa
= NULL
;
845 AlsaPlayer::IsInstalled ()
850 switch (is_alsa_usable
) {
852 libalsa
= dlopen ("libasound.so.2", RTLD_LAZY
);
853 if (libalsa
== NULL
) {
859 result
&= NULL
!= (d_snd_pcm_open
= (dyn_snd_pcm_open
*) dlsym (libalsa
, "snd_pcm_open"));
860 result
&= NULL
!= (d_snd_pcm_close
= (dyn_snd_pcm_close
*) dlsym (libalsa
, "snd_pcm_close"));
861 result
&= NULL
!= (d_snd_pcm_get_params
= (dyn_snd_pcm_get_params
*) dlsym (libalsa
, "snd_pcm_get_params"));
862 result
&= NULL
!= (d_snd_pcm_poll_descriptors_count
= (dyn_snd_pcm_poll_descriptors_count
*) dlsym (libalsa
, "snd_pcm_poll_descriptors_count"));
863 result
&= NULL
!= (d_snd_pcm_poll_descriptors
= (dyn_snd_pcm_poll_descriptors
*) dlsym (libalsa
, "snd_pcm_poll_descriptors"));
864 result
&= NULL
!= (d_snd_output_stdio_attach
= (dyn_snd_output_stdio_attach
*) dlsym (libalsa
, "snd_output_stdio_attach"));
865 result
&= NULL
!= (d_snd_pcm_hw_params_malloc
= (dyn_snd_pcm_hw_params_malloc
*) dlsym (libalsa
, "snd_pcm_hw_params_malloc"));
866 result
&= NULL
!= (d_snd_pcm_hw_params_any
= (dyn_snd_pcm_hw_params_any
*) dlsym (libalsa
, "snd_pcm_hw_params_any"));
867 result
&= NULL
!= (d_snd_pcm_hw_params_dump
= (dyn_snd_pcm_hw_params_dump
*) dlsym (libalsa
, "snd_pcm_hw_params_dump"));
868 result
&= NULL
!= (d_snd_pcm_hw_params_set_rate_resample
= (dyn_snd_pcm_hw_params_set_rate_resample
*) dlsym (libalsa
, "snd_pcm_hw_params_set_rate_resample"));
869 result
&= NULL
!= (d_snd_pcm_hw_params_test_access
= (dyn_snd_pcm_hw_params_test_access
*) dlsym (libalsa
, "snd_pcm_hw_params_test_access"));
870 result
&= NULL
!= (d_snd_pcm_hw_params_set_access
= (dyn_snd_pcm_hw_params_set_access
*) dlsym (libalsa
, "snd_pcm_hw_params_set_access"));
871 result
&= NULL
!= (d_snd_pcm_hw_params_set_format
= (dyn_snd_pcm_hw_params_set_format
*) dlsym (libalsa
, "snd_pcm_hw_params_set_format"));
872 result
&= NULL
!= (d_snd_pcm_hw_params_set_channels
= (dyn_snd_pcm_hw_params_set_channels
*) dlsym (libalsa
, "snd_pcm_hw_params_set_channels"));
873 result
&= NULL
!= (d_snd_pcm_hw_params_set_rate_near
= (dyn_snd_pcm_hw_params_set_rate_near
*) dlsym (libalsa
, "snd_pcm_hw_params_set_rate_near"));
874 result
&= NULL
!= (d_snd_pcm_hw_params_set_buffer_time_near
= (dyn_snd_pcm_hw_params_set_buffer_time_near
*) dlsym (libalsa
, "snd_pcm_hw_params_set_buffer_time_near"));
875 result
&= NULL
!= (d_snd_pcm_hw_params
= (dyn_snd_pcm_hw_params
*) dlsym (libalsa
, "snd_pcm_hw_params"));
876 result
&= NULL
!= (d_snd_pcm_hw_params_can_pause
= (dyn_snd_pcm_hw_params_can_pause
*) dlsym (libalsa
, "snd_pcm_hw_params_can_pause"));
877 result
&= NULL
!= (d_snd_pcm_hw_params_free
= (dyn_snd_pcm_hw_params_free
*) dlsym (libalsa
, "snd_pcm_hw_params_free"));
878 result
&= NULL
!= (d_snd_pcm_state
= (dyn_snd_pcm_state
*) dlsym (libalsa
, "snd_pcm_state"));
879 result
&= NULL
!= (d_snd_pcm_state_name
= (dyn_snd_pcm_state_name
*) dlsym (libalsa
, "snd_pcm_state_name"));
880 result
&= NULL
!= (d_snd_pcm_drop
= (dyn_snd_pcm_drop
*) dlsym (libalsa
, "snd_pcm_drop"));
881 result
&= NULL
!= (d_snd_pcm_writei
= (dyn_snd_pcm_writei
*) dlsym (libalsa
, "snd_pcm_writei"));
882 result
&= NULL
!= (d_snd_pcm_mmap_begin
= (dyn_snd_pcm_mmap_begin
*) dlsym (libalsa
, "snd_pcm_mmap_begin"));
883 result
&= NULL
!= (d_snd_pcm_mmap_commit
= (dyn_snd_pcm_mmap_commit
*) dlsym (libalsa
, "snd_pcm_mmap_commit"));
884 result
&= NULL
!= (d_snd_pcm_prepare
= (dyn_snd_pcm_prepare
*) dlsym (libalsa
, "snd_pcm_prepare"));
885 result
&= NULL
!= (d_snd_pcm_resume
= (dyn_snd_pcm_resume
*) dlsym (libalsa
, "snd_pcm_resume"));
886 result
&= NULL
!= (d_snd_pcm_avail_update
= (dyn_snd_pcm_avail_update
*) dlsym (libalsa
, "snd_pcm_avail_update"));
887 result
&= NULL
!= (d_snd_pcm_start
= (dyn_snd_pcm_start
*) dlsym (libalsa
, "snd_pcm_start"));
888 result
&= NULL
!= (d_snd_pcm_delay
= (dyn_snd_pcm_delay
*) dlsym (libalsa
, "snd_pcm_delay"));
889 result
&= NULL
!= (d_snd_asoundlib_version
= (dyn_snd_asoundlib_version
*) dlsym (libalsa
, "snd_asoundlib_version"));
890 result
&= NULL
!= (d_snd_strerror
= (dyn_snd_strerror
*) dlsym (libalsa
, "snd_strerror"));
892 if (d_snd_asoundlib_version
!= NULL
) {
893 version
= d_snd_asoundlib_version ();
894 LOG_AUDIO ("AlsaPlayer: Found alsa/asound version: '%s'\n", version
);
898 LOG_AUDIO ("AlsaPlayer: Failed to load one or more required functions in libasound.so.");
900 is_alsa_usable
= result
? 1 : 2;
912 AlsaPlayer::AddInternal (AudioSource
*source
)
914 update_poll_pending
= true;
919 AlsaPlayer::RemoveInternal (AudioSource
*source
)
921 update_poll_pending
= true;
926 AlsaPlayer::PrepareShutdownInternal ()
930 LOG_ALSA ("AlsaPlayer::PrepareShutdownInternal ().\n");
932 // Wait for the audio thread to finish
934 if (audio_thread
!= NULL
) {
936 result
= pthread_join (*audio_thread
, NULL
);
938 LOG_AUDIO ("AudioPlayer::Shutdown (): failed to join the audio thread (error code: %i).\n", result
);
940 // Only free the thread if we could join it.
941 g_free (audio_thread
);
948 AlsaPlayer::FinishShutdownInternal ()
950 LOG_ALSA ("AlsaPlayer::FinishShutdownInternal ().\n");
967 AlsaPlayer::UpdatePollList ()
969 update_poll_pending
= true;
974 AlsaPlayer::CreateNode (MediaPlayer
*mplayer
, AudioStream
*stream
)
976 return new AlsaSource (this, mplayer
, stream
);
980 AlsaPlayer::Loop (void *data
)
982 ((AlsaPlayer
*) data
)->Loop ();
989 AlsaSource
*source
= NULL
;
991 bool played_something
;
996 LOG_ALSA ("AlsaPlayer: entering audio loop.\n");
999 sources
.StartEnumeration ();
1001 played_something
= false;
1002 while ((source
= (AlsaSource
*) sources
.GetNext (false)) != NULL
) {
1003 if (source
->GetState () == AudioPlaying
) {
1004 if (source
->WriteAlsa ())
1005 played_something
= true;
1006 } else if (source
->IsDropPending ()) {
1007 source
->DropAlsa ();
1012 if (played_something
)
1015 // None of the audio nodes in the list played anything
1016 // (or there are no audio nodes), so wait for something
1017 // to happen. We handle spurious wakeups correctly, so
1018 // there is no find out exactly what happened.
1020 while (!shutdown
&& update_poll_pending
) {
1022 * We need to update the list of file descriptors we poll on
1023 * to only include audio nodes which are playing.
1025 update_poll_pending
= false;
1029 sources
.StartEnumeration ();
1030 while ((source
= (AlsaSource
*) sources
.GetNext (true)) != NULL
) {
1031 ndfs
+= source
->ndfs
;
1036 udfs
= (pollfd
*) g_malloc0 (sizeof (pollfd
) * ndfs
);
1037 udfs
[0].fd
= fds
[0];
1038 udfs
[0].events
= POLLIN
;
1040 sources
.StartEnumeration ();
1041 while (!update_poll_pending
&& (source
= (AlsaSource
*) sources
.GetNext (true)) != NULL
) {
1042 if (current
+ source
->ndfs
> ndfs
) {
1043 // the list of sources changed.
1044 update_poll_pending
= true;
1046 memcpy (&udfs
[current
], source
->udfs
, source
->ndfs
* sizeof (pollfd
));
1047 current
+= source
->ndfs
;
1052 if (current
!= ndfs
) {
1053 // The list of sources changed
1054 update_poll_pending
= true;
1059 udfs
[0].events
= POLLIN
;
1060 udfs
[0].revents
= 0;
1062 LOG_ALSA_EX ("AlsaPlayer::Loop (): polling... ndfs: %i\n", ndfs
);
1064 result
= poll (udfs
, ndfs
, 10000); // Have a timeout of 10 seconds, just in case something goes wrong.
1066 LOG_ALSA_EX ("AlsaPlayer::Loop (): poll result: %i, fd: %i, fd [0].revents: %i, errno: %i, err: %s, ndfs = %i, shutdown: %i\n",
1067 result
, udfs
[0].fd
, (int) udfs
[0].revents
, errno
, strerror (errno
), ndfs
, shutdown
);
1069 if (result
== 0) { // Timed out
1070 LOG_ALSA_EX ("AlsaPlayer::Loop (): poll timed out.\n");
1071 } else if (result
< 0) { // Some error poll exit condition
1072 // Doesn't matter what happened (happens quite often due to interrupts)
1073 LOG_ALSA_EX ("AlsaPlayer::Loop (): poll failed: %i (%s)\n", errno
, strerror (errno
));
1074 } else { // Something woke up the poll
1075 if (udfs
[0].revents
& POLLIN
) {
1076 // We were asked to wake up by the audio player
1077 // Read whatever was written into the pipe so that the pipe doesn't fill up.
1078 read (udfs
[0].fd
, &buffer
, sizeof (int));
1079 LOG_ALSA_EX ("AlsaPlayer::Loop (): woken up by ourselves.\n");
1081 // Something happened on any of the audio streams
1084 } while (result
== -1 && errno
== EINTR
);
1087 LOG_ALSA ("AlsaPlayer: exiting audio loop.\n");
1091 AlsaPlayer::WakeUp ()
1095 LOG_ALSA_EX ("AlsaPlayer::WakeUp ().\n");
1097 // Write until something has been written.
1099 result
= write (fds
[1], "c", 1);
1100 } while (result
== 0);
1103 LOG_AUDIO ("AlsaPlayer::WakeUp (): Could not wake up audio thread: %s\n", strerror (errno
));
1105 LOG_ALSA_EX ("AlsaPlayer::WakeUp (): thread should now wake up (or have woken up already).\n");