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 (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;
477 if (GetState () != AudioPlaying
) {
478 LOG_ALSA ("AlsaSource::WriteRW (): trying to write when we're not playing (state: %i)\n", GetState ());
482 if (!PreparePcm (&avail
))
485 LOG_ALSA ("AlsaSource::WriteRW (): entering play loop, avail: %lld, sample size: %i\n", (gint64
) avail
, (int) period_size
);
487 buffer
= g_malloc (avail
* GetOutputBytesPerFrame ());
489 frames
= Write (buffer
, (guint32
) avail
);
493 commitres
= snd_pcm_writei (pcm
, buffer
, frames
);
498 LOG_ALSA ("AlsaSource::WriteRW (): played %i samples, of %i available samples, result: %i.\n", (int) frames
, (int) avail
, (int) commitres
);
500 if (commitres
< 0 || (snd_pcm_uframes_t
) commitres
!= frames
) {
501 if (commitres
== -EAGAIN
)
502 LOG_AUDIO ("AlsaSource::WriteRW (): not enough space for all the data\n");
503 if (!XrunRecovery (commitres
>= 0 ? -EPIPE
: commitres
)) {
504 LOG_AUDIO ("AudioPlayer: could not write audio data: %s, commitres: %li, frames: %u\n", snd_strerror(err
), commitres
, frames
);
514 AlsaSource::WriteMmap ()
516 snd_pcm_channel_area_t
*areas
= NULL
;
517 snd_pcm_uframes_t offset
= 0;
518 snd_pcm_uframes_t frames
;
519 snd_pcm_sframes_t available_samples
;
520 snd_pcm_sframes_t commitres
= 0;
521 guint32 channels
= GetChannels ();
523 AudioData
*data
[channels
+ 1];
525 if (GetState () != AudioPlaying
) {
526 LOG_ALSA ("AlsaSource::WriteMmap (): trying to write when we're not playing (state: %i)\n", GetState ());
530 if (!PreparePcm (&available_samples
))
533 if (GetFlag (AudioEnded
)) {
538 LOG_ALSA_EX ("AlsaSource::WriteMmap (): entering play loop, avail: %lld, sample size: %i\n", (gint64
) available_samples
, (int) period_size
);
540 frames
= available_samples
;
546 err
= snd_pcm_mmap_begin (pcm
, (const snd_pcm_channel_area_t
** ) &areas
, &offset
, &frames
);
548 if (!XrunRecovery (err
)) {
549 LOG_AUDIO ("AudioPlayer: could not get mmapped memory: %s\n", snd_strerror (err
));
555 LOG_ALSA_EX ("AlsaSource::WriteMmap (): can write %lu frames, avail: %lu\n", frames
, available_samples
);
557 for (guint32 channel
= 0; channel
< channels
; channel
++) {
558 data
[channel
] = (AudioData
*) g_malloc (sizeof (AudioData
));
559 // pointer to the first sample to write to
560 data
[channel
]->dest
= ((gint8
*) areas
[channel
].addr
) + (areas
[channel
].first
/ 8) + offset
* areas
[channel
].step
/ 8;
561 // distance (in bytes) between samples
562 data
[channel
]->distance
= areas
[channel
].step
/ 8;
564 data
[channels
] = NULL
;
566 frames
= WriteFull (data
, frames
);
568 for (guint32 channel
= 0; channel
< channels
; channel
++) {
569 g_free (data
[channel
]);
572 commitres
= snd_pcm_mmap_commit (pcm
, offset
, frames
);
574 LOG_ALSA_EX ("AlsaSource::WriteMmap (): played %i samples, of %i available samples, result: %i.\n", (int) frames
, (int) 0, (int) commitres
);
576 if (commitres
< 0 || (snd_pcm_uframes_t
) commitres
!= frames
) {
577 if (!XrunRecovery (commitres
>= 0 ? -EPIPE
: commitres
)) {
578 LOG_AUDIO ("AudioPlayer: could not commit mmapped memory: %s\n", snd_strerror(err
));
579 commitres
= 0; // so that we end up returning false
589 return commitres
> 0;
593 AlsaSource::WriteAlsa ()
602 AlsaSource::XrunRecovery (int err
)
605 case -EPIPE
: // under-run
609 err
= snd_pcm_prepare (pcm
);
611 LOG_AUDIO ("AlsaPlayer: Can't recover from underrun, prepare failed: %s.\n", snd_strerror (err
));
614 LOG_AUDIO ("AlsaPlayer: Can't recover from underrun, pcm has been closed.\n");
621 while ((err
= snd_pcm_resume (pcm
)) == -EAGAIN
) {
622 LOG_AUDIO ("XrunRecovery: waiting for resume\n");
623 sleep (1); // wait until the suspend flag is released
626 err
= snd_pcm_prepare (pcm
);
628 LOG_AUDIO ("AlsaPlayer: Can't recover from suspend, prepare failed: %s.\n", snd_strerror (err
));
632 LOG_AUDIO ("AlsaPlayer: Can't recover from suspend, pcm has been closed.\n");
637 LOG_AUDIO ("AlsaPlayer: Can't recover from underrun: %s\n", snd_strerror (err
));
645 AlsaSource::PreparePcm (snd_pcm_sframes_t
*avail
)
649 snd_pcm_state_t state
;
653 state
= snd_pcm_state (pcm
);
655 LOG_ALSA ("AlsaSource::PreparePcm (): pcm has been closed.\n");
664 case SND_PCM_STATE_XRUN
:
665 LOG_ALSA ("AlsaSource::PreparePcm (): SND_PCM_STATE_XRUN.\n");
667 if (!XrunRecovery (-EPIPE
))
672 case SND_PCM_STATE_SUSPENDED
:
673 if (!XrunRecovery (-ESTRPIPE
))
676 case SND_PCM_STATE_SETUP
:
677 if (!XrunRecovery (-EPIPE
))
682 case SND_PCM_STATE_RUNNING
:
683 started
= true; // We might have gotten started automatically after writing a certain number of samples.
684 case SND_PCM_STATE_PREPARED
:
686 case SND_PCM_STATE_PAUSED
:
687 case SND_PCM_STATE_DRAINING
:
689 LOG_ALSA ("AlsaSource::PreparePcm (): state: %s (prepare failed)\n", snd_pcm_state_name (state
));
696 *avail
= snd_pcm_avail_update (pcm
);
706 if (!XrunRecovery (*avail
))
713 if ((snd_pcm_uframes_t
) *avail
< period_size
) {
715 LOG_ALSA ("AlsaSource::PreparePcm (): starting pcm (period size: %li, available: %li)\n", period_size
, *avail
);
719 err
= snd_pcm_start (pcm
);
729 LOG_AUDIO ("AlsaPlayer: Could not start pcm: %s\n", snd_strerror (err
));
739 LOG_ALSA ("AlsaSource::PreparePcm (): Prepared, avail: %li, started: %i\n", *avail
, (int) started
);
745 AlsaSource::GetDelayInternal ()
747 snd_pcm_sframes_t delay
;
750 bool update_error
= false;
751 bool not_initialized
= false;
755 not_initialized
= true;
757 err
= snd_pcm_avail_update (pcm
);
760 LOG_AUDIO ("AlsaSource::GetDelayInternal (): Could not update delay (%s)\n", snd_strerror (err
));
763 err
= snd_pcm_delay (pcm
, &delay
);
768 if (not_initialized
) {
769 LOG_AUDIO ("AlsaSource::GetDelayInternal (): pcm has been closed.\n");
777 LOG_AUDIO ("AlsaSource::GetDelayInternal (): Could not get delay (%s)\n", snd_strerror (err
));
778 result
= G_MAXUINT64
;
779 } else if (delay
< 0) {
780 LOG_AUDIO ("AlsaSource::GetDelayInternal (): Got negative delay (%li)\n", delay
);
781 result
= G_MAXUINT64
;
783 result
= (guint64
) TIMESPANTICKS_IN_SECOND
* (guint64
) delay
/ (guint64
) GetSampleRate ();
793 AlsaPlayer::AlsaPlayer ()
795 LOG_ALSA ("AlsaPlayer::AlsaPlayer ()\n");
799 update_poll_pending
= true;
806 AlsaPlayer::~AlsaPlayer ()
808 LOG_ALSA ("AlsaPlayer::~AlsaPlayer ()\n");
812 AlsaPlayer::Initialize ()
816 LOG_ALSA ("AlsaPlayer::Initialize ()\n");
819 if (pipe (fds
) != 0) {
820 LOG_AUDIO ("AlsaPlayer::Initialize (): Unable to create pipe (%s).\n", strerror (errno
));
824 // Make the writer pipe non-blocking.
825 fcntl (fds
[1], F_SETFL
, fcntl (fds
[1], F_GETFL
) | O_NONBLOCK
);
827 // Create the audio thread
828 audio_thread
= (pthread_t
*) g_malloc (sizeof (pthread_t
));
829 result
= pthread_create (audio_thread
, NULL
, Loop
, this);
831 LOG_AUDIO ("AlsaPlayer::Initialize (): could not create audio thread (error code: %i = '%s').\n", result
, strerror (result
));
832 g_free (audio_thread
);
837 LOG_ALSA ("AlsaPlayer::Initialize (): the audio player has been initialized.\n");
842 static int is_alsa_usable
= 0; // 0 = not tested, 1 = tested, usable, 2 = tested, not usable
843 static void *libalsa
= NULL
;
846 AlsaPlayer::IsInstalled ()
851 switch (is_alsa_usable
) {
853 libalsa
= dlopen ("libasound.so.2", RTLD_LAZY
);
854 if (libalsa
== NULL
) {
860 result
&= NULL
!= (d_snd_pcm_open
= (dyn_snd_pcm_open
*) dlsym (libalsa
, "snd_pcm_open"));
861 result
&= NULL
!= (d_snd_pcm_close
= (dyn_snd_pcm_close
*) dlsym (libalsa
, "snd_pcm_close"));
862 result
&= NULL
!= (d_snd_pcm_get_params
= (dyn_snd_pcm_get_params
*) dlsym (libalsa
, "snd_pcm_get_params"));
863 result
&= NULL
!= (d_snd_pcm_poll_descriptors_count
= (dyn_snd_pcm_poll_descriptors_count
*) dlsym (libalsa
, "snd_pcm_poll_descriptors_count"));
864 result
&= NULL
!= (d_snd_pcm_poll_descriptors
= (dyn_snd_pcm_poll_descriptors
*) dlsym (libalsa
, "snd_pcm_poll_descriptors"));
865 result
&= NULL
!= (d_snd_output_stdio_attach
= (dyn_snd_output_stdio_attach
*) dlsym (libalsa
, "snd_output_stdio_attach"));
866 result
&= NULL
!= (d_snd_pcm_hw_params_malloc
= (dyn_snd_pcm_hw_params_malloc
*) dlsym (libalsa
, "snd_pcm_hw_params_malloc"));
867 result
&= NULL
!= (d_snd_pcm_hw_params_any
= (dyn_snd_pcm_hw_params_any
*) dlsym (libalsa
, "snd_pcm_hw_params_any"));
868 result
&= NULL
!= (d_snd_pcm_hw_params_dump
= (dyn_snd_pcm_hw_params_dump
*) dlsym (libalsa
, "snd_pcm_hw_params_dump"));
869 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"));
870 result
&= NULL
!= (d_snd_pcm_hw_params_test_access
= (dyn_snd_pcm_hw_params_test_access
*) dlsym (libalsa
, "snd_pcm_hw_params_test_access"));
871 result
&= NULL
!= (d_snd_pcm_hw_params_set_access
= (dyn_snd_pcm_hw_params_set_access
*) dlsym (libalsa
, "snd_pcm_hw_params_set_access"));
872 result
&= NULL
!= (d_snd_pcm_hw_params_set_format
= (dyn_snd_pcm_hw_params_set_format
*) dlsym (libalsa
, "snd_pcm_hw_params_set_format"));
873 result
&= NULL
!= (d_snd_pcm_hw_params_set_channels
= (dyn_snd_pcm_hw_params_set_channels
*) dlsym (libalsa
, "snd_pcm_hw_params_set_channels"));
874 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"));
875 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"));
876 result
&= NULL
!= (d_snd_pcm_hw_params
= (dyn_snd_pcm_hw_params
*) dlsym (libalsa
, "snd_pcm_hw_params"));
877 result
&= NULL
!= (d_snd_pcm_hw_params_can_pause
= (dyn_snd_pcm_hw_params_can_pause
*) dlsym (libalsa
, "snd_pcm_hw_params_can_pause"));
878 result
&= NULL
!= (d_snd_pcm_hw_params_free
= (dyn_snd_pcm_hw_params_free
*) dlsym (libalsa
, "snd_pcm_hw_params_free"));
879 result
&= NULL
!= (d_snd_pcm_state
= (dyn_snd_pcm_state
*) dlsym (libalsa
, "snd_pcm_state"));
880 result
&= NULL
!= (d_snd_pcm_state_name
= (dyn_snd_pcm_state_name
*) dlsym (libalsa
, "snd_pcm_state_name"));
881 result
&= NULL
!= (d_snd_pcm_drop
= (dyn_snd_pcm_drop
*) dlsym (libalsa
, "snd_pcm_drop"));
882 result
&= NULL
!= (d_snd_pcm_writei
= (dyn_snd_pcm_writei
*) dlsym (libalsa
, "snd_pcm_writei"));
883 result
&= NULL
!= (d_snd_pcm_mmap_begin
= (dyn_snd_pcm_mmap_begin
*) dlsym (libalsa
, "snd_pcm_mmap_begin"));
884 result
&= NULL
!= (d_snd_pcm_mmap_commit
= (dyn_snd_pcm_mmap_commit
*) dlsym (libalsa
, "snd_pcm_mmap_commit"));
885 result
&= NULL
!= (d_snd_pcm_prepare
= (dyn_snd_pcm_prepare
*) dlsym (libalsa
, "snd_pcm_prepare"));
886 result
&= NULL
!= (d_snd_pcm_resume
= (dyn_snd_pcm_resume
*) dlsym (libalsa
, "snd_pcm_resume"));
887 result
&= NULL
!= (d_snd_pcm_avail_update
= (dyn_snd_pcm_avail_update
*) dlsym (libalsa
, "snd_pcm_avail_update"));
888 result
&= NULL
!= (d_snd_pcm_start
= (dyn_snd_pcm_start
*) dlsym (libalsa
, "snd_pcm_start"));
889 result
&= NULL
!= (d_snd_pcm_delay
= (dyn_snd_pcm_delay
*) dlsym (libalsa
, "snd_pcm_delay"));
890 result
&= NULL
!= (d_snd_asoundlib_version
= (dyn_snd_asoundlib_version
*) dlsym (libalsa
, "snd_asoundlib_version"));
891 result
&= NULL
!= (d_snd_strerror
= (dyn_snd_strerror
*) dlsym (libalsa
, "snd_strerror"));
893 if (d_snd_asoundlib_version
!= NULL
) {
894 version
= d_snd_asoundlib_version ();
895 LOG_AUDIO ("AlsaPlayer: Found alsa/asound version: '%s'\n", version
);
899 LOG_AUDIO ("AlsaPlayer: Failed to load one or more required functions in libasound.so.");
901 is_alsa_usable
= result
? 1 : 2;
913 AlsaPlayer::AddInternal (AudioSource
*source
)
915 update_poll_pending
= true;
920 AlsaPlayer::RemoveInternal (AudioSource
*source
)
922 update_poll_pending
= true;
927 AlsaPlayer::PrepareShutdownInternal ()
931 LOG_ALSA ("AlsaPlayer::PrepareShutdownInternal ().\n");
933 // Wait for the audio thread to finish
935 if (audio_thread
!= NULL
) {
937 result
= pthread_join (*audio_thread
, NULL
);
939 LOG_AUDIO ("AudioPlayer::Shutdown (): failed to join the audio thread (error code: %i).\n", result
);
941 // Only free the thread if we could join it.
942 g_free (audio_thread
);
949 AlsaPlayer::FinishShutdownInternal ()
951 LOG_ALSA ("AlsaPlayer::FinishShutdownInternal ().\n");
968 AlsaPlayer::UpdatePollList ()
970 update_poll_pending
= true;
975 AlsaPlayer::CreateNode (MediaPlayer
*mplayer
, AudioStream
*stream
)
977 return new AlsaSource (this, mplayer
, stream
);
981 AlsaPlayer::Loop (void *data
)
983 ((AlsaPlayer
*) data
)->Loop ();
990 AlsaSource
*source
= NULL
;
992 bool played_something
;
997 LOG_ALSA ("AlsaPlayer: entering audio loop.\n");
1000 sources
.StartEnumeration ();
1002 played_something
= false;
1003 while ((source
= (AlsaSource
*) sources
.GetNext (false)) != NULL
) {
1004 if (source
->GetState () == AudioPlaying
) {
1005 if (source
->WriteAlsa ())
1006 played_something
= true;
1007 } else if (source
->IsDropPending ()) {
1008 source
->DropAlsa ();
1013 if (played_something
)
1016 // None of the audio nodes in the list played anything
1017 // (or there are no audio nodes), so wait for something
1018 // to happen. We handle spurious wakeups correctly, so
1019 // there is no find out exactly what happened.
1021 while (!shutdown
&& update_poll_pending
) {
1023 * We need to update the list of file descriptors we poll on
1024 * to only include audio nodes which are playing.
1026 update_poll_pending
= false;
1030 sources
.StartEnumeration ();
1031 while ((source
= (AlsaSource
*) sources
.GetNext (true)) != NULL
) {
1032 ndfs
+= source
->ndfs
;
1037 udfs
= (pollfd
*) g_malloc0 (sizeof (pollfd
) * ndfs
);
1038 udfs
[0].fd
= fds
[0];
1039 udfs
[0].events
= POLLIN
;
1041 sources
.StartEnumeration ();
1042 while (!update_poll_pending
&& (source
= (AlsaSource
*) sources
.GetNext (true)) != NULL
) {
1043 if (current
+ source
->ndfs
> ndfs
) {
1044 // the list of sources changed.
1045 update_poll_pending
= true;
1047 memcpy (&udfs
[current
], source
->udfs
, source
->ndfs
* sizeof (pollfd
));
1048 current
+= source
->ndfs
;
1053 if (current
!= ndfs
) {
1054 // The list of sources changed
1055 update_poll_pending
= true;
1060 udfs
[0].events
= POLLIN
;
1061 udfs
[0].revents
= 0;
1063 LOG_ALSA_EX ("AlsaPlayer::Loop (): polling... ndfs: %i\n", ndfs
);
1065 result
= poll (udfs
, ndfs
, 10000); // Have a timeout of 10 seconds, just in case something goes wrong.
1067 LOG_ALSA_EX ("AlsaPlayer::Loop (): poll result: %i, fd: %i, fd [0].revents: %i, errno: %i, err: %s, ndfs = %i, shutdown: %i\n",
1068 result
, udfs
[0].fd
, (int) udfs
[0].revents
, errno
, strerror (errno
), ndfs
, shutdown
);
1070 if (result
== 0) { // Timed out
1071 LOG_ALSA_EX ("AlsaPlayer::Loop (): poll timed out.\n");
1072 } else if (result
< 0) { // Some error poll exit condition
1073 // Doesn't matter what happened (happens quite often due to interrupts)
1074 LOG_ALSA_EX ("AlsaPlayer::Loop (): poll failed: %i (%s)\n", errno
, strerror (errno
));
1075 } else { // Something woke up the poll
1076 if (udfs
[0].revents
& POLLIN
) {
1077 // We were asked to wake up by the audio player
1078 // Read whatever was written into the pipe so that the pipe doesn't fill up.
1079 read (udfs
[0].fd
, &buffer
, sizeof (int));
1080 LOG_ALSA_EX ("AlsaPlayer::Loop (): woken up by ourselves.\n");
1082 // Something happened on any of the audio streams
1085 } while (result
== -1 && errno
== EINTR
);
1088 LOG_ALSA ("AlsaPlayer: exiting audio loop.\n");
1092 AlsaPlayer::WakeUp ()
1096 LOG_ALSA_EX ("AlsaPlayer::WakeUp ().\n");
1098 // Write until something has been written.
1100 result
= write (fds
[1], "c", 1);
1101 } while (result
== 0);
1104 LOG_AUDIO ("AlsaPlayer::WakeUp (): Could not wake up audio thread: %s\n", strerror (errno
));
1106 LOG_ALSA_EX ("AlsaPlayer::WakeUp (): thread should now wake up (or have woken up already).\n");