xref: /aosp_15_r20/external/tinyalsa_new/examples/plugins/sample_pcm_plugin.c (revision 02e95f1a335b55495d41ca67eaf42361f13704fa)
1 /* sample_mixer_plugin.c
2 **
3 ** Copyright (c) 2021, The Linux Foundation. All rights reserved.
4 **
5 ** Redistribution and use in source and binary forms, with or without
6 ** modification, are permitted provided that the following conditions are
7 ** met:
8 **   * Redistributions of source code must retain the above copyright
9 **     notice, this list of conditions and the following disclaimer.
10 **   * Redistributions in binary form must reproduce the above
11 **     copyright notice, this list of conditions and the following
12 **     disclaimer in the documentation and/or other materials provided
13 **     with the distribution.
14 **   * Neither the name of The Linux Foundation nor the names of its
15 **     contributors may be used to endorse or promote products derived
16 **     from this software without specific prior written permission.
17 **
18 ** THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
19 ** WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
20 ** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
21 ** ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
22 ** BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 ** CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 ** SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
25 ** BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
26 ** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
27 ** OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
28 ** IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 **/
30 
31 #include <errno.h>
32 #include <limits.h>
33 #include <sys/time.h>
34 #include <sys/mman.h>
35 #include <sound/asound.h>
36 #include <stdint.h>
37 #include <stdlib.h>
38 #include <strings.h>
39 #include <stdio.h>
40 #include <unistd.h>
41 #include <tinyalsa/plugin.h>
42 #include <tinyalsa/asoundlib.h>
43 
44 /* 2 words of uint32_t = 64 bits of mask */
45 #define PCM_MASK_SIZE (2)
46 #define PCM_FORMAT_BIT(x) (1ULL << x)
47 
48 struct sample_pcm_priv {
49     FILE *fptr;
50     int session_id;
51     int channels;
52     int bitwidth;
53     int sample_rate;
54     unsigned int period_size;
55     snd_pcm_uframes_t total_size_frames;
56 };
57 
58 struct pcm_plugin_hw_constraints sample_pcm_constrs = {
59     .access = 0,
60     .format = 0,
61     .bit_width = {
62         .min = 16,
63         .max = 32,
64     },
65     .channels = {
66         .min = 1,
67         .max = 8,
68     },
69     .rate = {
70         .min = 8000,
71         .max = 384000,
72     },
73     .periods = {
74         .min = 1,
75         .max = 8,
76     },
77     .period_bytes = {
78         .min = 96,
79         .max = 122880,
80     },
81 };
82 
param_to_interval(struct snd_pcm_hw_params * p,int n)83 static inline struct snd_interval *param_to_interval(struct snd_pcm_hw_params *p,
84                                                   int n)
85 {
86     return &(p->intervals[n - SNDRV_PCM_HW_PARAM_FIRST_INTERVAL]);
87 }
88 
param_is_interval(int p)89 static inline int param_is_interval(int p)
90 {
91     return (p >= SNDRV_PCM_HW_PARAM_FIRST_INTERVAL) &&
92         (p <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL);
93 }
94 
param_get_int(struct snd_pcm_hw_params * p,int n)95 static unsigned int param_get_int(struct snd_pcm_hw_params *p, int n)
96 {
97     if (param_is_interval(n)) {
98         struct snd_interval *i = param_to_interval(p, n);
99         if (i->integer)
100             return i->max;
101     }
102     return 0;
103 }
104 
param_to_mask(struct snd_pcm_hw_params * p,int n)105 static inline struct snd_mask *param_to_mask(struct snd_pcm_hw_params *p, int n)
106 {
107     return &(p->masks[n - SNDRV_PCM_HW_PARAM_FIRST_MASK]);
108 }
109 
param_is_mask(int p)110 static inline int param_is_mask(int p)
111 {
112     return (p >= SNDRV_PCM_HW_PARAM_FIRST_MASK) &&
113         (p <= SNDRV_PCM_HW_PARAM_LAST_MASK);
114 }
115 
snd_mask_val(const struct snd_mask * mask)116 static inline int snd_mask_val(const struct snd_mask *mask)
117 {
118     int i;
119     for (i = 0; i < PCM_MASK_SIZE; i++) {
120         if (mask->bits[i])
121             return ffs(mask->bits[i]) + (i << 5) - 1;
122     }
123     return 0;
124 }
125 
alsaformat_to_bitwidth(int format)126 static int alsaformat_to_bitwidth(int format)
127 {
128     switch (format) {
129     case SNDRV_PCM_FORMAT_S32_LE:
130     case SNDRV_PCM_FORMAT_S24_LE:
131         return 32;
132     case SNDRV_PCM_FORMAT_S8:
133         return 8;
134     case SNDRV_PCM_FORMAT_S24_3LE:
135         return 24;
136     default:
137     case SNDRV_PCM_FORMAT_S16_LE:
138         return 16;
139     };
140 }
141 
param_get_mask_val(struct snd_pcm_hw_params * p,int n)142 static int param_get_mask_val(struct snd_pcm_hw_params *p,
143                                         int n)
144 {
145     if (param_is_mask(n)) {
146         struct snd_mask *m = param_to_mask(p, n);
147         int val = snd_mask_val(m);
148 
149         return alsaformat_to_bitwidth(val);
150     }
151     return 0;
152 }
153 
sample_session_open(int sess_id,unsigned int mode,struct sample_pcm_priv * priv)154 static int sample_session_open(int sess_id, unsigned int mode, struct sample_pcm_priv *priv)
155 {
156      char fname[128];
157 
158      snprintf(fname, 128, "sample_pcm_data_%d.raw", sess_id);
159      priv->fptr = fopen(fname,"rwb+");
160      if (priv->fptr == NULL) {
161          return -EIO;
162      }
163      rewind(priv->fptr);
164      return 0;
165 }
166 
167 
sample_session_write(struct sample_pcm_priv * priv,void * buff,size_t count)168 static int sample_session_write(struct sample_pcm_priv *priv, void *buff, size_t count)
169 {
170     uint8_t *data = (uint8_t *)buff;
171     size_t len;
172 
173     len  = fwrite(buff, 1, count, priv->fptr);
174 
175     if (len != count)
176         return -EIO;
177 
178     return 0;
179 }
180 
sample_pcm_hw_params(struct pcm_plugin * plugin,struct snd_pcm_hw_params * params)181 static int sample_pcm_hw_params(struct pcm_plugin *plugin,
182                              struct snd_pcm_hw_params *params)
183 {
184     struct sample_pcm_priv *priv = plugin->priv;
185 
186     priv->sample_rate = param_get_int(params, SNDRV_PCM_HW_PARAM_RATE);
187     priv->channels = param_get_int(params, SNDRV_PCM_HW_PARAM_CHANNELS);
188     priv->bitwidth = param_get_mask_val(params, SNDRV_PCM_HW_PARAM_FORMAT);
189 
190     return 0;
191 }
192 
sample_pcm_sw_params(struct pcm_plugin * plugin,struct snd_pcm_sw_params * sparams)193 static int sample_pcm_sw_params(struct pcm_plugin *plugin,
194                              struct snd_pcm_sw_params *sparams)
195 {
196     return 0;
197 }
198 
sample_pcm_sync_ptr(struct pcm_plugin * plugin,struct snd_pcm_sync_ptr * sync_ptr)199 static int sample_pcm_sync_ptr(struct pcm_plugin *plugin,
200                             struct snd_pcm_sync_ptr *sync_ptr)
201 {
202     return 0;
203 }
204 
sample_pcm_writei_frames(struct pcm_plugin * plugin,struct snd_xferi * x)205 static int sample_pcm_writei_frames(struct pcm_plugin *plugin, struct snd_xferi *x)
206 {
207     struct sample_pcm_priv *priv = plugin->priv;
208     void *buff;
209     size_t count;
210 
211     buff = x->buf;
212     count = x->frames * (priv->channels * (priv->bitwidth) / 8);
213 
214     return sample_session_write(priv, buff, count);
215 }
216 
sample_pcm_readi_frames(struct pcm_plugin * plugin,struct snd_xferi * x)217 static int sample_pcm_readi_frames(struct pcm_plugin *plugin, struct snd_xferi *x)
218 {
219     return 0;
220 }
221 
sample_pcm_ttstamp(struct pcm_plugin * plugin,int * tstamp)222 static int sample_pcm_ttstamp(struct pcm_plugin *plugin, int *tstamp)
223 {
224     return 0;
225 }
226 
sample_pcm_prepare(struct pcm_plugin * plugin)227 static int sample_pcm_prepare(struct pcm_plugin *plugin)
228 {
229     return 0;
230 }
231 
sample_pcm_start(struct pcm_plugin * plugin)232 static int sample_pcm_start(struct pcm_plugin *plugin)
233 {
234     return 0;
235 }
236 
sample_pcm_drop(struct pcm_plugin * plugin)237 static int sample_pcm_drop(struct pcm_plugin *plugin)
238 {
239     return 0;
240 }
241 
sample_pcm_close(struct pcm_plugin * plugin)242 static int sample_pcm_close(struct pcm_plugin *plugin)
243 {
244     struct sample_pcm_priv *priv = plugin->priv;
245     int ret = 0;
246 
247     fclose(priv->fptr);
248     free(plugin->priv);
249     free(plugin);
250 
251     return ret;
252 }
253 
sample_pcm_poll(struct pcm_plugin * plugin,struct pollfd * pfd,nfds_t nfds,int timeout)254 static int sample_pcm_poll(struct pcm_plugin *plugin, struct pollfd *pfd,
255         nfds_t nfds, int timeout)
256 {
257     return 0;
258 }
259 
sample_pcm_mmap(struct pcm_plugin * plugin,void * addr,size_t length,int prot,int flags,off_t offset)260 static void* sample_pcm_mmap(struct pcm_plugin *plugin, void *addr, size_t length, int prot,
261                                int flags, off_t offset)
262 {
263     return MAP_FAILED;
264 }
265 
sample_pcm_munmap(struct pcm_plugin * plugin,void * addr,size_t length)266 static int sample_pcm_munmap(struct pcm_plugin *plugin, void *addr, size_t length)
267 {
268     return 0;
269 }
270 
sample_pcm_open(struct pcm_plugin ** plugin,unsigned int card,unsigned int device,unsigned int mode)271 int sample_pcm_open(struct pcm_plugin **plugin, unsigned int card,
272                     unsigned int device, unsigned int mode)
273 {
274     struct pcm_plugin *sample_pcm_plugin;
275     struct sample_pcm_priv *priv;
276     int ret = 0, session_id = device;
277 
278     sample_pcm_plugin = calloc(1, sizeof(struct pcm_plugin));
279     if (!sample_pcm_plugin)
280         return -ENOMEM;
281 
282     priv = calloc(1, sizeof(struct sample_pcm_priv));
283     if (!priv) {
284         ret = -ENOMEM;
285         goto err_plugin_free;
286     }
287 
288     sample_pcm_constrs.access = (PCM_FORMAT_BIT(SNDRV_PCM_ACCESS_RW_INTERLEAVED) |
289                               PCM_FORMAT_BIT(SNDRV_PCM_ACCESS_RW_NONINTERLEAVED));
290     sample_pcm_constrs.format = (PCM_FORMAT_BIT(SNDRV_PCM_FORMAT_S16_LE) |
291                               PCM_FORMAT_BIT(SNDRV_PCM_FORMAT_S24_LE) |
292                               PCM_FORMAT_BIT(SNDRV_PCM_FORMAT_S24_3LE) |
293                               PCM_FORMAT_BIT(SNDRV_PCM_FORMAT_S32_LE));
294 
295     sample_pcm_plugin->card = card;
296     sample_pcm_plugin->mode = mode;
297     sample_pcm_plugin->constraints = &sample_pcm_constrs;
298     sample_pcm_plugin->priv = priv;
299 
300     priv->session_id = session_id;
301 
302     ret = sample_session_open(session_id, mode, priv);
303     if (ret) {
304         errno = -ret;
305         goto err_priv_free;
306     }
307     *plugin = sample_pcm_plugin;
308     return 0;
309 
310 err_priv_free:
311     free(priv);
312 err_plugin_free:
313     free(sample_pcm_plugin);
314     return ret;
315 }
316 
317 struct pcm_plugin_ops pcm_plugin_ops = {
318     .open = sample_pcm_open,
319     .close = sample_pcm_close,
320     .hw_params = sample_pcm_hw_params,
321     .sw_params = sample_pcm_sw_params,
322     .sync_ptr = sample_pcm_sync_ptr,
323     .writei_frames = sample_pcm_writei_frames,
324     .readi_frames = sample_pcm_readi_frames,
325     .ttstamp = sample_pcm_ttstamp,
326     .prepare = sample_pcm_prepare,
327     .start = sample_pcm_start,
328     .drop = sample_pcm_drop,
329     .mmap = sample_pcm_mmap,
330     .munmap = sample_pcm_munmap,
331     .poll = sample_pcm_poll,
332 };
333