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