1 /* -*- Mode: C ; c-basic-offset: 2 -*- */
2 /*****************************************************************************
4 * Player capable to send PCM sequence over ALSA
5 * This file is part of monster
7 * Copyright (C) 2006,2007 Nedko Arnaudov <nedko@arnaudov.name>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; version 2 of the License
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
22 *****************************************************************************/
24 #include <alsa/asoundlib.h>
27 #define DISABLE_DEBUG_OUTPUT
31 #include "media_source.h"
34 #include "player_alsa_pcm.h"
37 #define FEED_THREAD_STATE_INITIAL 0
38 #define FEED_THREAD_STATE_ARMED 1
39 #define FEED_THREAD_STATE_PLAY 2
40 #define FEED_THREAD_STATE_STOP_REQUESTED 3
41 #define FEED_THREAD_STATE_STOPPED 4
43 struct player_alsa_pcm
45 struct player
virtual;
47 struct media_source
* media_source_ptr
;
50 unsigned int eod_context
;
52 snd_pcm_t
* playback_handle
;
54 unsigned int rt_prio_alsa_pcm_feed
;
56 pthread_t feed_thread
;
58 pthread_mutex_t feed_mutex
;
59 pthread_cond_t feed_cond
;
60 unsigned int feed_thread_state
;
64 playback_callback(struct player_alsa_pcm
* player_ptr
)
69 //DEBUG_OUT("playback callback called");
71 if (player_ptr
->eof
== 0)
73 player_ptr
->eod(player_ptr
->eod_context
);
77 ret
= media_source_get_frame_data(player_ptr
->media_source_ptr
, &buffer_ptr
);
80 ERROR_OUT("media_source_get_frame_data() failed.");
84 if (ret
== 1 && player_ptr
->eof
== -1)
89 ret
= snd_pcm_writei(player_ptr
->playback_handle
, buffer_ptr
, WAV_DATA_CHUNK
);
92 ERROR_OUT("write failed (%s)", snd_strerror(ret
));
96 if (ret
!= WAV_DATA_CHUNK
)
98 ERROR_OUT("write accepted less data (%d)", ret
);
102 media_source_next_frame(player_ptr
->media_source_ptr
);
107 void dump_state(const char * msg
, struct player_alsa_pcm
* player_ptr
)
109 snd_pcm_state_t state
;
111 state
= snd_pcm_state(player_ptr
->playback_handle
);
115 case SND_PCM_STATE_OPEN
:
116 DEBUG_OUT("%s: Open", msg
);
118 case SND_PCM_STATE_SETUP
:
119 DEBUG_OUT("%s: Setup installed", msg
);
121 case SND_PCM_STATE_PREPARED
:
122 DEBUG_OUT("%s: Ready to start", msg
);
124 case SND_PCM_STATE_RUNNING
:
125 DEBUG_OUT("%s: Running", msg
);
127 case SND_PCM_STATE_XRUN
:
128 DEBUG_OUT("%s: Stopped: underrun (playback) or overrun (capture) detected", msg
);
130 case SND_PCM_STATE_DRAINING
:
131 DEBUG_OUT("%s: Draining: running (playback) or stopped (capture)", msg
);
133 case SND_PCM_STATE_PAUSED
:
134 DEBUG_OUT("%s: Paused", msg
);
136 case SND_PCM_STATE_SUSPENDED
:
137 DEBUG_OUT("%s: Hardware is suspended", msg
);
139 case SND_PCM_STATE_DISCONNECTED
:
140 DEBUG_OUT("%s: Hardware is disconnected ", msg
);
144 DEBUG_OUT("%s: Unknown ALSA pcm state %u", msg
, (unsigned int)state
);
147 #define player_ptr ((struct player_alsa_pcm *)context)
149 void * player_alsa_pcm_feed(void * context
)
152 snd_pcm_sframes_t frames_to_deliver
;
154 DEBUG_OUT("player_alsa_pcm_feed thread started");
157 struct sched_param param
;
160 pthread_getschedparam(pthread_self(), &policy
, ¶m
);
161 param
.sched_priority
= player_ptr
->rt_prio_alsa_pcm_feed
;
163 pthread_setschedparam(pthread_self(), policy
, ¶m
);
166 /* mark that we are ready */
167 pthread_mutex_lock(&player_ptr
->feed_mutex
);
169 player_ptr
->feed_thread_state
= FEED_THREAD_STATE_ARMED
;
171 ret
= pthread_cond_signal(&player_ptr
->feed_cond
);
174 ERROR_OUT("Failed to signal feed cond (%d)", ret
);
175 pthread_mutex_unlock(&player_ptr
->feed_mutex
);
179 pthread_mutex_unlock(&player_ptr
->feed_mutex
);
181 /* wait for play command */
182 pthread_mutex_lock(&player_ptr
->feed_mutex
);
184 while (player_ptr
->feed_thread_state
== FEED_THREAD_STATE_ARMED
)
186 pthread_cond_wait(&player_ptr
->feed_cond
, &player_ptr
->feed_mutex
);
189 if (player_ptr
->feed_thread_state
!= FEED_THREAD_STATE_PLAY
)
194 pthread_mutex_unlock(&player_ptr
->feed_mutex
);
196 dump_state("Before loop", player_ptr
);
199 /* wait till the interface is ready for data, or 1 second has elapsed. */
200 if ((ret
= snd_pcm_wait(player_ptr
->playback_handle
, 1000)) < 0)
204 /* othe thread stopped the player */
208 ERROR_OUT("poll failed (%i: %s)", errno
, strerror(errno
));
212 //DEBUG_OUT("snd_pcm_wait() returned %u", (unsigned int)ret);
214 pthread_mutex_lock(&player_ptr
->feed_mutex
);
216 if (player_ptr
->feed_thread_state
!= FEED_THREAD_STATE_PLAY
)
221 pthread_mutex_unlock(&player_ptr
->feed_mutex
);
223 /* find out how much space is available for playback data */
227 if ((frames_to_deliver
= snd_pcm_avail_update(player_ptr
->playback_handle
)) < 0)
229 if (frames_to_deliver
== -EPIPE
)
231 ERROR_OUT("an xrun occured");
236 ERROR_OUT("unknown ALSA avail update return value (%d)",
237 (int)frames_to_deliver
);
242 while (frames_to_deliver
< WAV_DATA_CHUNK
);
244 /* deliver the data */
246 if (playback_callback(player_ptr
) < 0)
248 ERROR_OUT("playback callback failed");
252 if (player_ptr
->eof
== 1)
260 pthread_mutex_lock(&player_ptr
->feed_mutex
);
263 player_ptr
->feed_thread_state
= FEED_THREAD_STATE_STOPPED
;
265 ret
= pthread_cond_signal(&player_ptr
->feed_cond
);
268 ERROR_OUT("Failed to signal feed cond (%d)", ret
);
271 pthread_mutex_unlock(&player_ptr
->feed_mutex
);
273 DEBUG_OUT("player_alsa_pcm_feed thread stopped");
279 #define player_ptr ((struct player_alsa_pcm *)virtual_ptr)
282 player_alsa_pcm_destroy(struct player
* virtual_ptr
)
286 DEBUG_OUT("player_alsa_pcm_destroy");
288 if (player_ptr
->playback_handle
!= NULL
)
290 /* signal thread that it must stop */
291 pthread_mutex_lock(&player_ptr
->feed_mutex
);
292 if (player_ptr
->feed_thread_state
!= FEED_THREAD_STATE_STOPPED
)
294 player_ptr
->feed_thread_state
= FEED_THREAD_STATE_STOP_REQUESTED
;
296 ret
= pthread_cond_signal(&player_ptr
->feed_cond
);
299 ERROR_OUT("Failed to signal feed cond (%d)", ret
);
300 pthread_mutex_unlock(&player_ptr
->feed_mutex
);
304 pthread_mutex_unlock(&player_ptr
->feed_mutex
);
306 snd_pcm_drain(player_ptr
->playback_handle
);
308 pthread_join(player_ptr
->feed_thread
, NULL
);
313 pthread_mutex_unlock(&player_ptr
->feed_mutex
);
316 ret
= pthread_cond_destroy(&player_ptr
->feed_cond
);
319 ERROR_OUT("Failed to destroy feed cond (%d)", ret
);
322 ret
= pthread_mutex_destroy(&player_ptr
->feed_mutex
);
325 ERROR_OUT("Failed to destroy feed mutex (%d)", ret
);
328 snd_pcm_close(player_ptr
->playback_handle
);
334 int player_alsa_pcm_start_prepare(struct player
* virtual_ptr
)
336 snd_pcm_hw_params_t
*hw_params
;
337 snd_pcm_sw_params_t
*sw_params
;
340 DEBUG_OUT("player_alsa_pcm_start_prepare");
342 NOTICE_OUT("Audio: Using priority %i for feed thread", player_ptr
->rt_prio_alsa_pcm_feed
);
344 if ((ret
= snd_pcm_open(&player_ptr
->playback_handle
, "default", SND_PCM_STREAM_PLAYBACK
, 0)) < 0)
346 ERROR_OUT("cannot open default audio device (%s)", snd_strerror(ret
));
351 if ((ret
= snd_pcm_hw_params_malloc(&hw_params
)) < 0)
353 ERROR_OUT("cannot allocate hardware parameter structure (%s)", snd_strerror(ret
));
358 if ((ret
= snd_pcm_hw_params_any(player_ptr
->playback_handle
, hw_params
)) < 0)
360 ERROR_OUT("cannot initialize hardware parameter structure (%s)", snd_strerror(ret
));
361 snd_pcm_hw_params_free(hw_params
);
366 if ((ret
= snd_pcm_hw_params_set_access(player_ptr
->playback_handle
, hw_params
, SND_PCM_ACCESS_RW_INTERLEAVED
)) < 0)
368 ERROR_OUT("cannot set access type (%s)", snd_strerror(ret
));
369 snd_pcm_hw_params_free(hw_params
);
374 if ((ret
= snd_pcm_hw_params_set_format(player_ptr
->playback_handle
, hw_params
, SND_PCM_FORMAT_S16_LE
)) < 0)
376 ERROR_OUT("cannot set sample format (%s)", snd_strerror(ret
));
377 snd_pcm_hw_params_free(hw_params
);
382 if ((ret
= snd_pcm_hw_params_set_rate(player_ptr
->playback_handle
, hw_params
, 48000, 0)) < 0)
384 ERROR_OUT("cannot set sample rate (%s)", snd_strerror(ret
));
385 snd_pcm_hw_params_free(hw_params
);
390 if ((ret
= snd_pcm_hw_params_set_channels(player_ptr
->playback_handle
, hw_params
, 2)) < 0)
392 ERROR_OUT("cannot set channel count (%s)", snd_strerror(ret
));
393 snd_pcm_hw_params_free(hw_params
);
398 //dump_state("Before snd_pcm_hw_params", player_ptr);
400 if ((ret
= snd_pcm_hw_params(player_ptr
->playback_handle
, hw_params
)) < 0)
402 ERROR_OUT("cannot set parameters (%s)", snd_strerror(ret
));
403 snd_pcm_hw_params_free(hw_params
);
408 //dump_state("After snd_pcm_hw_params", player_ptr);
410 snd_pcm_hw_params_free(hw_params
);
412 /* tell ALSA to wake us up whenever 4096 or more frames
413 of playback data can be delivered. Also, tell
414 ALSA that we'll start the device ourselves.
417 if ((ret
= snd_pcm_sw_params_malloc(&sw_params
)) < 0)
419 ERROR_OUT("cannot allocate software parameters structure (%s)", snd_strerror(ret
));
423 if ((ret
= snd_pcm_sw_params_current(player_ptr
->playback_handle
, sw_params
)) < 0)
425 ERROR_OUT("cannot initialize software parameters structure (%s)", snd_strerror(ret
));
429 if ((ret
= snd_pcm_sw_params_set_avail_min(player_ptr
->playback_handle
, sw_params
, 4096)) < 0)
431 ERROR_OUT("cannot set minimum available count (%s)", snd_strerror(ret
));
435 if ((ret
= snd_pcm_sw_params_set_start_threshold(player_ptr
->playback_handle
, sw_params
, 0U)) < 0)
437 ERROR_OUT("cannot set start mode (%s)", snd_strerror(ret
));
442 //dump_state("Before snd_pcm_sw_params", player_ptr);
444 if ((ret
= snd_pcm_sw_params(player_ptr
->playback_handle
, sw_params
)) < 0)
446 ERROR_OUT("cannot set software parameters (%s)", snd_strerror(ret
));
451 //dump_state("Before prepare", player_ptr);
453 /* the interface will interrupt the kernel every 4096 frames, and ALSA
454 will wake up this program very soon after that.
457 /* if ((ret = snd_pcm_prepare(player_ptr->playback_handle)) < 0) */
459 /* ERROR_OUT("cannot prepare audio interface for use (%s)", snd_strerror(ret)); */
461 /* goto exit_close_pcm; */
464 ret
= pthread_mutex_init(&player_ptr
->feed_mutex
, NULL
);
467 ERROR_OUT("Failed to init feed mutex (%d)", ret
);
472 ret
= pthread_cond_init(&player_ptr
->feed_cond
, NULL
);
475 ERROR_OUT("Failed to init feed cond (%d)", ret
);
477 goto exit_destroy_mutex
;
480 player_ptr
->feed_thread_state
= FEED_THREAD_STATE_INITIAL
;
482 ret
= pthread_create(&player_ptr
->feed_thread
, NULL
, player_alsa_pcm_feed
, player_ptr
);
485 ERROR_OUT("Failed to start feed thread (%d)", ret
);
487 goto exit_destroy_cond
;
490 /* Wait feed thread to fill kernel buffers */
491 DEBUG_OUT("Waiting feed thread to fill kernel buffers...");
492 pthread_mutex_lock(&player_ptr
->feed_mutex
);
493 while (player_ptr
->feed_thread_state
== FEED_THREAD_STATE_INITIAL
)
495 pthread_cond_wait(&player_ptr
->feed_cond
, &player_ptr
->feed_mutex
);
498 if (player_ptr
->feed_thread_state
!= FEED_THREAD_STATE_ARMED
)
500 ERROR_OUT("Feed thread failed to prefill kernel buffers");
501 pthread_mutex_unlock(&player_ptr
->feed_mutex
);
505 pthread_mutex_unlock(&player_ptr
->feed_mutex
);
511 /* signal thread that it must stop */
512 pthread_mutex_lock(&player_ptr
->feed_mutex
);
513 if (player_ptr
->feed_thread_state
!= FEED_THREAD_STATE_STOPPED
)
515 player_ptr
->feed_thread_state
= FEED_THREAD_STATE_STOP_REQUESTED
;
517 ret
= pthread_cond_signal(&player_ptr
->feed_cond
);
520 ERROR_OUT("Failed to signal feed cond (%d)", ret
);
521 pthread_mutex_unlock(&player_ptr
->feed_mutex
);
522 goto exit_destroy_cond
;
525 pthread_mutex_unlock(&player_ptr
->feed_mutex
);
527 ret
= pthread_join(player_ptr
->feed_thread
, NULL
);
530 ERROR_OUT("Failed to join feed thread (%d)", ret
);
534 ret
= pthread_cond_destroy(&player_ptr
->feed_cond
);
537 ERROR_OUT("Failed to destroy feed cond (%d)", ret
);
541 ret
= pthread_mutex_destroy(&player_ptr
->feed_mutex
);
544 ERROR_OUT("Failed to destroy feed mutex (%d)", ret
);
548 snd_pcm_close(player_ptr
->playback_handle
);
549 player_ptr
->playback_handle
= NULL
;
555 int player_alsa_pcm_start(struct player
* virtual_ptr
)
559 DEBUG_OUT("player_alsa_pcm_start");
561 /* signal thread that it must start play */
563 pthread_mutex_lock(&player_ptr
->feed_mutex
);
565 if (player_ptr
->feed_thread_state
!= FEED_THREAD_STATE_ARMED
)
567 ERROR_OUT("Feed thread is not armed");
572 player_ptr
->feed_thread_state
= FEED_THREAD_STATE_PLAY
;
574 ret
= pthread_cond_signal(&player_ptr
->feed_cond
);
577 ERROR_OUT("Failed to signal feed cond (%d)", ret
);
585 pthread_mutex_unlock(&player_ptr
->feed_mutex
);
594 struct media_source
* media_source_ptr
,
596 unsigned int eod_context
,
597 struct player
** player_ptr_ptr
)
600 struct player_alsa_pcm
* player_ptr
;
602 unsigned int rt_prio_alsa_pcm_feed
;
604 DEBUG_OUT("player_alsa_pcm");
606 ret
= media_source_format_query(media_source_ptr
, &format
);
612 if (format
!= MEDIA_FORMAT_PCM_16_STEREO_48
)
614 ERROR_OUT("player_alsa_pcm cannot handle format %u", format
);
618 ret
= conf_file_get_uint("/conf/realtime_priorities/alsa_pcm_feed", &rt_prio_alsa_pcm_feed
);
621 ERROR_OUT("failed to read from configuration what realtime priority to use for ALSA PCM feed thread");
625 player_ptr
= malloc(sizeof(struct player_alsa_pcm
));
626 if (player_ptr
== NULL
)
628 ERROR_OUT("malloc() failed.");
632 player_ptr
->virtual.destroy
= player_alsa_pcm_destroy
;
633 player_ptr
->virtual.start_prepare
= player_alsa_pcm_start_prepare
;
634 player_ptr
->virtual.start
= player_alsa_pcm_start
;
636 player_ptr
->media_source_ptr
= media_source_ptr
;
638 player_ptr
->eod
= eod
;
639 player_ptr
->eod_context
= eod_context
;
640 player_ptr
->eof
= -1;
642 player_ptr
->rt_prio_alsa_pcm_feed
= rt_prio_alsa_pcm_feed
;
644 player_ptr
->playback_handle
= NULL
;
646 strcpy(player_ptr
->virtual.name
, "ALSA PCM");
648 *player_ptr_ptr
= &player_ptr
->virtual;