2 Copyright (C) 2009 Red Hat, Inc.
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
14 You should have received a copy of the GNU Lesser General Public
15 License along with this library; if not, see <http://www.gnu.org/licenses/>.
25 #define REING_SIZE_MS 300
27 WavePlayer::WavePlayer(uint32_t sampels_per_sec, uint32_t bits_per_sample, uint32_t channels)
32 if (!init(sampels_per_sec, bits_per_sample, channels)) {
38 void WavePlayer::cleanup()
45 snd_pcm_hw_params_free(_hw_params);
49 snd_pcm_sw_params_free(_sw_params);
53 WavePlayer::~WavePlayer()
58 bool WavePlayer::init(uint32_t sampels_per_sec,
59 uint32_t bits_per_sample,
62 const int frame_size = WavePlaybackAbstract::FRAME_SIZE;
63 const char* pcm_device = "default";
64 snd_pcm_format_t format;
67 switch (bits_per_sample) {
69 format = SND_PCM_FORMAT_S8;
72 format = SND_PCM_FORMAT_S16_LE;
77 _sampels_per_ms = sampels_per_sec / 1000;
79 if ((err = snd_pcm_open(&_pcm, pcm_device, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK)) < 0) {
80 LOG_ERROR("cannot open audio playback device %s %s", pcm_device, snd_strerror(err));
84 if ((err = snd_pcm_hw_params_malloc(&_hw_params)) < 0) {
85 LOG_ERROR("cannot allocate hardware parameter structure %s", snd_strerror(err));
89 if ((err = snd_pcm_sw_params_malloc(&_sw_params)) < 0) {
90 LOG_ERROR("cannot allocate software parameter structure %s", snd_strerror(err));
94 if ((err = snd_pcm_hw_params_any(_pcm, _hw_params)) < 0) {
95 LOG_ERROR("cannot initialize hardware parameter structure %s", snd_strerror(err));
99 if ((err = snd_pcm_hw_params_set_rate_resample(_pcm, _hw_params, 1)) < 0) {
100 LOG_ERROR("cannot set rate resample %s", snd_strerror(err));
104 if ((err = snd_pcm_hw_params_set_access(_pcm, _hw_params,
105 SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {
106 LOG_ERROR("cannot set access type %s", snd_strerror(err));
110 if ((err = snd_pcm_hw_params_set_rate(_pcm, _hw_params, sampels_per_sec, 0)) < 0) {
111 LOG_ERROR("cannot set sample rate %s", snd_strerror(err));
115 if ((err = snd_pcm_hw_params_set_channels(_pcm, _hw_params, channels)) < 0) {
116 LOG_ERROR("cannot set channel count %s", snd_strerror(err));
120 if ((err = snd_pcm_hw_params_set_format(_pcm, _hw_params, format)) < 0) {
121 LOG_ERROR("cannot set sample format %s", snd_strerror(err));
125 snd_pcm_uframes_t buffer_size;
126 buffer_size = (sampels_per_sec * REING_SIZE_MS / 1000) / frame_size * frame_size;
128 if ((err = snd_pcm_hw_params_set_buffer_size_near(_pcm, _hw_params, &buffer_size)) < 0) {
129 LOG_ERROR("cannot set buffer size %s", snd_strerror(err));
134 snd_pcm_uframes_t period_size = (sampels_per_sec * 20 / 1000) / frame_size * frame_size;
135 if ((err = snd_pcm_hw_params_set_period_size_near(_pcm, _hw_params, &period_size,
137 LOG_ERROR("cannot set period size %s", snd_strerror(err));
141 if ((err = snd_pcm_hw_params(_pcm, _hw_params)) < 0) {
142 LOG_ERROR("cannot set parameters %s", snd_strerror(err));
146 if ((err = snd_pcm_sw_params_current(_pcm, _sw_params)) < 0) {
147 LOG_ERROR("cannot obtain sw parameters %s", snd_strerror(err));
151 err = snd_pcm_hw_params_get_buffer_size(_hw_params, &buffer_size);
153 LOG_ERROR("unable to get buffer size for playback: %s", snd_strerror(err));
158 err = snd_pcm_hw_params_get_period_size(_hw_params, &period_size, &direction);
160 LOG_ERROR("unable to get period size for playback: %s", snd_strerror(err));
164 err = snd_pcm_sw_params_set_start_threshold(_pcm, _sw_params,
165 (buffer_size / period_size) * period_size);
167 LOG_ERROR("unable to set start threshold mode for playback: %s", snd_strerror(err));
171 if ((err = snd_pcm_sw_params(_pcm, _sw_params)) < 0) {
172 LOG_ERROR("cannot set software parameters %s", snd_strerror(err));
176 if ((err = snd_pcm_prepare(_pcm)) < 0) {
177 LOG_ERROR("cannot prepare pcm device %s", snd_strerror(err));
184 bool WavePlayer::write(uint8_t* frame)
186 snd_pcm_sframes_t ret = snd_pcm_writei(_pcm, frame, WavePlaybackAbstract::FRAME_SIZE);
188 if (ret == -EAGAIN) {
191 DBG(0, "err %s", snd_strerror(-ret));
192 if (snd_pcm_recover(_pcm, ret, 1) == 0) {
193 snd_pcm_writei(_pcm, frame, WavePlaybackAbstract::FRAME_SIZE);
199 void WavePlayer::stop()
202 snd_pcm_prepare(_pcm);
205 bool WavePlayer::abort()
210 uint32_t WavePlayer::get_delay_ms()
214 snd_pcm_sframes_t delay;
216 if (snd_pcm_delay(_pcm, &delay) < 0) {
219 return delay / _sampels_per_ms;