1d5ac70f0Sopenharmony_ci/** 2d5ac70f0Sopenharmony_ci * \file pcm/pcm_simple.c 3d5ac70f0Sopenharmony_ci * \ingroup PCM_Simple 4d5ac70f0Sopenharmony_ci * \brief PCM Simple Interface 5d5ac70f0Sopenharmony_ci * \author Jaroslav Kysela <perex@perex.cz> 6d5ac70f0Sopenharmony_ci * \date 2004 7d5ac70f0Sopenharmony_ci */ 8d5ac70f0Sopenharmony_ci/* 9d5ac70f0Sopenharmony_ci * 10d5ac70f0Sopenharmony_ci * This library is free software; you can redistribute it and/or modify 11d5ac70f0Sopenharmony_ci * it under the terms of the GNU Lesser General Public License as 12d5ac70f0Sopenharmony_ci * published by the Free Software Foundation; either version 2.1 of 13d5ac70f0Sopenharmony_ci * the License, or (at your option) any later version. 14d5ac70f0Sopenharmony_ci * 15d5ac70f0Sopenharmony_ci * This program is distributed in the hope that it will be useful, 16d5ac70f0Sopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 17d5ac70f0Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18d5ac70f0Sopenharmony_ci * GNU Lesser General Public License for more details. 19d5ac70f0Sopenharmony_ci * 20d5ac70f0Sopenharmony_ci * You should have received a copy of the GNU Lesser General Public 21d5ac70f0Sopenharmony_ci * License along with this library; if not, write to the Free Software 22d5ac70f0Sopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 23d5ac70f0Sopenharmony_ci * 24d5ac70f0Sopenharmony_ci */ 25d5ac70f0Sopenharmony_ci 26d5ac70f0Sopenharmony_ci#include "pcm_local.h" 27d5ac70f0Sopenharmony_ci 28d5ac70f0Sopenharmony_cistatic int set_buffer_time(snd_spcm_latency_t latency, 29d5ac70f0Sopenharmony_ci unsigned int *buffer_time) 30d5ac70f0Sopenharmony_ci{ 31d5ac70f0Sopenharmony_ci switch (latency) { 32d5ac70f0Sopenharmony_ci case SND_SPCM_LATENCY_STANDARD: 33d5ac70f0Sopenharmony_ci *buffer_time = 350000; 34d5ac70f0Sopenharmony_ci break; 35d5ac70f0Sopenharmony_ci case SND_SPCM_LATENCY_MEDIUM: 36d5ac70f0Sopenharmony_ci *buffer_time = 25000; 37d5ac70f0Sopenharmony_ci break; 38d5ac70f0Sopenharmony_ci case SND_SPCM_LATENCY_REALTIME: 39d5ac70f0Sopenharmony_ci *buffer_time = 2500; 40d5ac70f0Sopenharmony_ci break; 41d5ac70f0Sopenharmony_ci default: 42d5ac70f0Sopenharmony_ci return -EINVAL; 43d5ac70f0Sopenharmony_ci } 44d5ac70f0Sopenharmony_ci return 0; 45d5ac70f0Sopenharmony_ci} 46d5ac70f0Sopenharmony_ci 47d5ac70f0Sopenharmony_cistatic int set_hw_params(snd_pcm_t *pcm, 48d5ac70f0Sopenharmony_ci snd_pcm_hw_params_t *hw_params, 49d5ac70f0Sopenharmony_ci unsigned int *rate, 50d5ac70f0Sopenharmony_ci unsigned int channels, 51d5ac70f0Sopenharmony_ci snd_pcm_format_t format, 52d5ac70f0Sopenharmony_ci snd_pcm_subformat_t subformat, 53d5ac70f0Sopenharmony_ci unsigned int *buffer_time, 54d5ac70f0Sopenharmony_ci unsigned int *period_time, 55d5ac70f0Sopenharmony_ci snd_pcm_access_t access) 56d5ac70f0Sopenharmony_ci{ 57d5ac70f0Sopenharmony_ci int err; 58d5ac70f0Sopenharmony_ci 59d5ac70f0Sopenharmony_ci /* 60d5ac70f0Sopenharmony_ci * hardware parameters 61d5ac70f0Sopenharmony_ci */ 62d5ac70f0Sopenharmony_ci err = snd_pcm_hw_params_any(pcm, hw_params); 63d5ac70f0Sopenharmony_ci if (err < 0) 64d5ac70f0Sopenharmony_ci return err; 65d5ac70f0Sopenharmony_ci err = snd_pcm_hw_params_set_access(pcm, hw_params, access); 66d5ac70f0Sopenharmony_ci if (err < 0) 67d5ac70f0Sopenharmony_ci return err; 68d5ac70f0Sopenharmony_ci err = snd_pcm_hw_params_set_format(pcm, hw_params, format); 69d5ac70f0Sopenharmony_ci if (err < 0) 70d5ac70f0Sopenharmony_ci return err; 71d5ac70f0Sopenharmony_ci if (subformat != SND_PCM_SUBFORMAT_STD) { 72d5ac70f0Sopenharmony_ci err = snd_pcm_hw_params_set_subformat(pcm, hw_params, subformat); 73d5ac70f0Sopenharmony_ci if (err < 0) 74d5ac70f0Sopenharmony_ci return err; 75d5ac70f0Sopenharmony_ci } 76d5ac70f0Sopenharmony_ci err = snd_pcm_hw_params_set_channels(pcm, hw_params, channels); 77d5ac70f0Sopenharmony_ci if (err < 0) 78d5ac70f0Sopenharmony_ci return err; 79d5ac70f0Sopenharmony_ci err = INTERNAL(snd_pcm_hw_params_set_rate_near)(pcm, hw_params, rate, 0); 80d5ac70f0Sopenharmony_ci if (err < 0) 81d5ac70f0Sopenharmony_ci return err; 82d5ac70f0Sopenharmony_ci err = INTERNAL(snd_pcm_hw_params_set_buffer_time_near)(pcm, hw_params, buffer_time, NULL); 83d5ac70f0Sopenharmony_ci if (err < 0) 84d5ac70f0Sopenharmony_ci return err; 85d5ac70f0Sopenharmony_ci if (period_time == NULL || *period_time == 0) { 86d5ac70f0Sopenharmony_ci unsigned int periods = 3; 87d5ac70f0Sopenharmony_ci err = INTERNAL(snd_pcm_hw_params_set_periods_near)(pcm, hw_params, &periods, NULL); 88d5ac70f0Sopenharmony_ci if (err < 0) 89d5ac70f0Sopenharmony_ci return err; 90d5ac70f0Sopenharmony_ci if (periods == 1) 91d5ac70f0Sopenharmony_ci return -EINVAL; 92d5ac70f0Sopenharmony_ci if (period_time) { 93d5ac70f0Sopenharmony_ci err = INTERNAL(snd_pcm_hw_params_get_period_time)(hw_params, period_time, NULL); 94d5ac70f0Sopenharmony_ci if (err < 0) 95d5ac70f0Sopenharmony_ci return err; 96d5ac70f0Sopenharmony_ci } 97d5ac70f0Sopenharmony_ci } else { 98d5ac70f0Sopenharmony_ci err = snd_pcm_hw_params_set_period_time(pcm, hw_params, *period_time, 0); 99d5ac70f0Sopenharmony_ci if (err < 0) 100d5ac70f0Sopenharmony_ci return err; 101d5ac70f0Sopenharmony_ci if (*buffer_time == *period_time) 102d5ac70f0Sopenharmony_ci return -EINVAL; 103d5ac70f0Sopenharmony_ci } 104d5ac70f0Sopenharmony_ci err = snd_pcm_hw_params(pcm, hw_params); 105d5ac70f0Sopenharmony_ci if (err < 0) 106d5ac70f0Sopenharmony_ci return err; 107d5ac70f0Sopenharmony_ci return 0; 108d5ac70f0Sopenharmony_ci} 109d5ac70f0Sopenharmony_ci 110d5ac70f0Sopenharmony_cistatic int set_sw_params(snd_pcm_t *pcm, 111d5ac70f0Sopenharmony_ci snd_pcm_sw_params_t *sw_params, 112d5ac70f0Sopenharmony_ci snd_spcm_xrun_type_t xrun_type) 113d5ac70f0Sopenharmony_ci{ 114d5ac70f0Sopenharmony_ci int err; 115d5ac70f0Sopenharmony_ci 116d5ac70f0Sopenharmony_ci err = snd_pcm_sw_params_current(pcm, sw_params); 117d5ac70f0Sopenharmony_ci if (err < 0) 118d5ac70f0Sopenharmony_ci return err; 119d5ac70f0Sopenharmony_ci err = snd_pcm_sw_params_set_start_threshold(pcm, sw_params, (pcm->buffer_size / pcm->period_size) * pcm->period_size); 120d5ac70f0Sopenharmony_ci if (err < 0) 121d5ac70f0Sopenharmony_ci return err; 122d5ac70f0Sopenharmony_ci err = snd_pcm_sw_params_set_avail_min(pcm, sw_params, pcm->period_size); 123d5ac70f0Sopenharmony_ci if (err < 0) 124d5ac70f0Sopenharmony_ci return err; 125d5ac70f0Sopenharmony_ci switch (xrun_type) { 126d5ac70f0Sopenharmony_ci case SND_SPCM_XRUN_STOP: 127d5ac70f0Sopenharmony_ci err = snd_pcm_sw_params_set_stop_threshold(pcm, sw_params, pcm->buffer_size); 128d5ac70f0Sopenharmony_ci break; 129d5ac70f0Sopenharmony_ci case SND_SPCM_XRUN_IGNORE: 130d5ac70f0Sopenharmony_ci err = snd_pcm_sw_params_set_stop_threshold(pcm, sw_params, pcm->boundary); 131d5ac70f0Sopenharmony_ci break; 132d5ac70f0Sopenharmony_ci default: 133d5ac70f0Sopenharmony_ci return -EINVAL; 134d5ac70f0Sopenharmony_ci } 135d5ac70f0Sopenharmony_ci if (err < 0) 136d5ac70f0Sopenharmony_ci return err; 137d5ac70f0Sopenharmony_ci err = snd_pcm_sw_params(pcm, sw_params); 138d5ac70f0Sopenharmony_ci if (err < 0) 139d5ac70f0Sopenharmony_ci return err; 140d5ac70f0Sopenharmony_ci return 0; 141d5ac70f0Sopenharmony_ci} 142d5ac70f0Sopenharmony_ci 143d5ac70f0Sopenharmony_ci/** 144d5ac70f0Sopenharmony_ci * \brief Set up a simple PCM 145d5ac70f0Sopenharmony_ci * \param pcm PCM handle 146d5ac70f0Sopenharmony_ci * \param rate Sample rate 147d5ac70f0Sopenharmony_ci * \param channels Number of channels 148d5ac70f0Sopenharmony_ci * \param format PCM format 149d5ac70f0Sopenharmony_ci * \param subformat PCM subformat 150d5ac70f0Sopenharmony_ci * \param latency Latency type 151d5ac70f0Sopenharmony_ci * \param access PCM acceess type 152d5ac70f0Sopenharmony_ci * \param xrun_type XRUN type 153d5ac70f0Sopenharmony_ci * \return 0 if successful, or a negative error code 154d5ac70f0Sopenharmony_ci * 155d5ac70f0Sopenharmony_ci * \warning The simple PCM API may be broken in the current release. 156d5ac70f0Sopenharmony_ci */ 157d5ac70f0Sopenharmony_ciint snd_spcm_init(snd_pcm_t *pcm, 158d5ac70f0Sopenharmony_ci unsigned int rate, 159d5ac70f0Sopenharmony_ci unsigned int channels, 160d5ac70f0Sopenharmony_ci snd_pcm_format_t format, 161d5ac70f0Sopenharmony_ci snd_pcm_subformat_t subformat, 162d5ac70f0Sopenharmony_ci snd_spcm_latency_t latency, 163d5ac70f0Sopenharmony_ci snd_pcm_access_t access, 164d5ac70f0Sopenharmony_ci snd_spcm_xrun_type_t xrun_type) 165d5ac70f0Sopenharmony_ci{ 166d5ac70f0Sopenharmony_ci int err; 167d5ac70f0Sopenharmony_ci snd_pcm_hw_params_t hw_params = {0}; 168d5ac70f0Sopenharmony_ci snd_pcm_sw_params_t sw_params = {0}; 169d5ac70f0Sopenharmony_ci unsigned int rrate; 170d5ac70f0Sopenharmony_ci unsigned int buffer_time; 171d5ac70f0Sopenharmony_ci 172d5ac70f0Sopenharmony_ci assert(pcm); 173d5ac70f0Sopenharmony_ci assert(rate >= 5000 && rate <= 786000); 174d5ac70f0Sopenharmony_ci assert(channels >= 1 && channels <= 512); 175d5ac70f0Sopenharmony_ci 176d5ac70f0Sopenharmony_ci rrate = rate; 177d5ac70f0Sopenharmony_ci err = set_buffer_time(latency, &buffer_time); 178d5ac70f0Sopenharmony_ci if (err < 0) 179d5ac70f0Sopenharmony_ci return err; 180d5ac70f0Sopenharmony_ci err = set_hw_params(pcm, &hw_params, 181d5ac70f0Sopenharmony_ci &rrate, channels, format, subformat, 182d5ac70f0Sopenharmony_ci &buffer_time, NULL, access); 183d5ac70f0Sopenharmony_ci if (err < 0) 184d5ac70f0Sopenharmony_ci return err; 185d5ac70f0Sopenharmony_ci 186d5ac70f0Sopenharmony_ci err = set_sw_params(pcm, &sw_params, xrun_type); 187d5ac70f0Sopenharmony_ci if (err < 0) 188d5ac70f0Sopenharmony_ci return err; 189d5ac70f0Sopenharmony_ci 190d5ac70f0Sopenharmony_ci return 0; 191d5ac70f0Sopenharmony_ci} 192d5ac70f0Sopenharmony_ci 193d5ac70f0Sopenharmony_ci/** 194d5ac70f0Sopenharmony_ci * \brief Initialize simple PCMs in the duplex mode 195d5ac70f0Sopenharmony_ci * \param playback_pcm PCM handle for playback 196d5ac70f0Sopenharmony_ci * \param capture_pcm PCM handle for capture 197d5ac70f0Sopenharmony_ci * \param rate Sample rate 198d5ac70f0Sopenharmony_ci * \param channels Number of channels 199d5ac70f0Sopenharmony_ci * \param format PCM format 200d5ac70f0Sopenharmony_ci * \param subformat PCM subformat 201d5ac70f0Sopenharmony_ci * \param latency Latency type 202d5ac70f0Sopenharmony_ci * \param access PCM acceess type 203d5ac70f0Sopenharmony_ci * \param xrun_type XRUN type 204d5ac70f0Sopenharmony_ci * \param duplex_type Duplex mode 205d5ac70f0Sopenharmony_ci * \return 0 if successful, or a negative error code 206d5ac70f0Sopenharmony_ci * 207d5ac70f0Sopenharmony_ci * \warning The simple PCM API may be broken in the current release. 208d5ac70f0Sopenharmony_ci */ 209d5ac70f0Sopenharmony_ciint snd_spcm_init_duplex(snd_pcm_t *playback_pcm, 210d5ac70f0Sopenharmony_ci snd_pcm_t *capture_pcm, 211d5ac70f0Sopenharmony_ci unsigned int rate, 212d5ac70f0Sopenharmony_ci unsigned int channels, 213d5ac70f0Sopenharmony_ci snd_pcm_format_t format, 214d5ac70f0Sopenharmony_ci snd_pcm_subformat_t subformat, 215d5ac70f0Sopenharmony_ci snd_spcm_latency_t latency, 216d5ac70f0Sopenharmony_ci snd_pcm_access_t access, 217d5ac70f0Sopenharmony_ci snd_spcm_xrun_type_t xrun_type, 218d5ac70f0Sopenharmony_ci snd_spcm_duplex_type_t duplex_type) 219d5ac70f0Sopenharmony_ci{ 220d5ac70f0Sopenharmony_ci int err, i; 221d5ac70f0Sopenharmony_ci snd_pcm_hw_params_t hw_params = {0}; 222d5ac70f0Sopenharmony_ci snd_pcm_sw_params_t sw_params = {0}; 223d5ac70f0Sopenharmony_ci unsigned int rrate; 224d5ac70f0Sopenharmony_ci unsigned int xbuffer_time, buffer_time[2]; 225d5ac70f0Sopenharmony_ci unsigned int period_time[2]; 226d5ac70f0Sopenharmony_ci snd_pcm_t *pcms[2]; 227d5ac70f0Sopenharmony_ci 228d5ac70f0Sopenharmony_ci assert(playback_pcm); 229d5ac70f0Sopenharmony_ci assert(capture_pcm); 230d5ac70f0Sopenharmony_ci assert(rate >= 5000 && rate <= 768000); 231d5ac70f0Sopenharmony_ci assert(channels >= 1 && channels <= 512); 232d5ac70f0Sopenharmony_ci 233d5ac70f0Sopenharmony_ci pcms[0] = playback_pcm; 234d5ac70f0Sopenharmony_ci pcms[1] = capture_pcm; 235d5ac70f0Sopenharmony_ci 236d5ac70f0Sopenharmony_ci /* 237d5ac70f0Sopenharmony_ci * hardware parameters 238d5ac70f0Sopenharmony_ci */ 239d5ac70f0Sopenharmony_ci err = set_buffer_time(latency, &xbuffer_time); 240d5ac70f0Sopenharmony_ci if (err < 0) 241d5ac70f0Sopenharmony_ci return err; 242d5ac70f0Sopenharmony_ci 243d5ac70f0Sopenharmony_ci for (i = 0; i < 2; i++) { 244d5ac70f0Sopenharmony_ci buffer_time[i] = xbuffer_time; 245d5ac70f0Sopenharmony_ci period_time[i] = i > 0 ? period_time[0] : 0; 246d5ac70f0Sopenharmony_ci rrate = rate; 247d5ac70f0Sopenharmony_ci err = set_hw_params(pcms[i], &hw_params, 248d5ac70f0Sopenharmony_ci &rrate, channels, format, subformat, 249d5ac70f0Sopenharmony_ci &buffer_time[i], &period_time[i], access); 250d5ac70f0Sopenharmony_ci if (err < 0) 251d5ac70f0Sopenharmony_ci return err; 252d5ac70f0Sopenharmony_ci } 253d5ac70f0Sopenharmony_ci if (buffer_time[0] == buffer_time[1] && 254d5ac70f0Sopenharmony_ci period_time[0] == period_time[1]) 255d5ac70f0Sopenharmony_ci goto __sw_params; 256d5ac70f0Sopenharmony_ci if (duplex_type == SND_SPCM_DUPLEX_LIBERAL) 257d5ac70f0Sopenharmony_ci goto __sw_params; 258d5ac70f0Sopenharmony_ci /* FIXME: */ 259d5ac70f0Sopenharmony_ci return -EINVAL; 260d5ac70f0Sopenharmony_ci 261d5ac70f0Sopenharmony_ci /* 262d5ac70f0Sopenharmony_ci * software parameters 263d5ac70f0Sopenharmony_ci */ 264d5ac70f0Sopenharmony_ci __sw_params: 265d5ac70f0Sopenharmony_ci for (i = 0; i < 2; i++) { 266d5ac70f0Sopenharmony_ci err = set_sw_params(pcms[i], &sw_params, xrun_type); 267d5ac70f0Sopenharmony_ci if (err < 0) 268d5ac70f0Sopenharmony_ci return err; 269d5ac70f0Sopenharmony_ci } 270d5ac70f0Sopenharmony_ci 271d5ac70f0Sopenharmony_ci return 0; 272d5ac70f0Sopenharmony_ci} 273d5ac70f0Sopenharmony_ci 274d5ac70f0Sopenharmony_ci/** 275d5ac70f0Sopenharmony_ci * \brief Get the set up of simple PCM 276d5ac70f0Sopenharmony_ci * \param pcm PCM handle 277d5ac70f0Sopenharmony_ci * \param rate Pointer to store the current sample rate 278d5ac70f0Sopenharmony_ci * \param buffer_size Pointer to store the current buffer size 279d5ac70f0Sopenharmony_ci * \param period_size Pointer to store the current period size 280d5ac70f0Sopenharmony_ci * \return 0 if successful, or a negative error code 281d5ac70f0Sopenharmony_ci * 282d5ac70f0Sopenharmony_ci * \warning The simple PCM API may be broken in the current release. 283d5ac70f0Sopenharmony_ci */ 284d5ac70f0Sopenharmony_ciint snd_spcm_init_get_params(snd_pcm_t *pcm, 285d5ac70f0Sopenharmony_ci unsigned int *rate, 286d5ac70f0Sopenharmony_ci snd_pcm_uframes_t *buffer_size, 287d5ac70f0Sopenharmony_ci snd_pcm_uframes_t *period_size) 288d5ac70f0Sopenharmony_ci{ 289d5ac70f0Sopenharmony_ci assert(pcm); 290d5ac70f0Sopenharmony_ci if (!pcm->setup) 291d5ac70f0Sopenharmony_ci return -EBADFD; 292d5ac70f0Sopenharmony_ci if (rate) 293d5ac70f0Sopenharmony_ci *rate = pcm->rate; 294d5ac70f0Sopenharmony_ci if (buffer_size) 295d5ac70f0Sopenharmony_ci *buffer_size = pcm->buffer_size; 296d5ac70f0Sopenharmony_ci if (period_size) 297d5ac70f0Sopenharmony_ci *period_size = pcm->period_size; 298d5ac70f0Sopenharmony_ci return 0; 299d5ac70f0Sopenharmony_ci} 300