OSDN Git Service

axfer: add missing header file of unit test to distribution
[android-x86/external-alsa-utils.git] / axfer / mapper-multiple.c
1 // SPDX-License-Identifier: GPL-2.0
2 //
3 // mapper-multiple.c - a muxer/demuxer for multiple containers.
4 //
5 // Copyright (c) 2018 Takashi Sakamoto <o-takashi@sakamocchi.jp>
6 //
7 // Licensed under the terms of the GNU General Public License, version 2.
8
9 #include "mapper.h"
10 #include "misc.h"
11
12 struct multiple_state {
13         void (*align_frames)(void *frame_buf, unsigned int frame_count,
14                              char **buf, unsigned int bytes_per_sample,
15                              struct container_context *cntrs,
16                              unsigned int cntr_count);
17         char **bufs;
18         unsigned int cntr_count;
19 };
20
21 static void align_to_i(void *frame_buf, unsigned int frame_count,
22                        char **src_bufs, unsigned int bytes_per_sample,
23                        struct container_context *cntrs, unsigned int cntr_count)
24 {
25         char *dst = frame_buf;
26         char *src;
27         unsigned int dst_pos;
28         unsigned int src_pos;
29         struct container_context *cntr;
30         int i, j;
31
32         // src: first channel in each of interleaved buffers in containers =>
33         // dst:interleaved.
34         for (i = 0; i < cntr_count; ++i) {
35                 src = src_bufs[i];
36                 cntr = cntrs + i;
37
38                 for (j = 0; j < frame_count; ++j) {
39                         // Use first src channel for each of dst channel.
40                         src_pos = bytes_per_sample * cntr->samples_per_frame * j;
41                         dst_pos = bytes_per_sample * (cntr_count * j + i);
42
43                         memcpy(dst + dst_pos, src + src_pos, bytes_per_sample);
44                 }
45         }
46 }
47
48 static void align_from_i(void *frame_buf, unsigned int frame_count,
49                          char **dst_bufs, unsigned int bytes_per_sample,
50                          struct container_context *cntrs,
51                          unsigned int cntr_count)
52 {
53         char *src = frame_buf;
54         char *dst;
55         unsigned int src_pos;
56         unsigned int dst_pos;
57         struct container_context *cntr;
58         int i, j;
59
60         for (i = 0; i < cntr_count; ++i) {
61                 dst = dst_bufs[i];
62                 cntr = cntrs + i;
63
64                 for (j = 0; j < frame_count; ++j) {
65                         // Use first src channel for each of dst channel.
66                         src_pos = bytes_per_sample * (cntr_count * j + i);
67                         dst_pos = bytes_per_sample * cntr->samples_per_frame * j;
68
69                         memcpy(dst + dst_pos, src + src_pos, bytes_per_sample);
70                 }
71         }
72 }
73
74 static int multiple_pre_process(struct mapper_context *mapper,
75                                 struct container_context *cntrs,
76                                 unsigned int cntr_count)
77 {
78         struct multiple_state *state = mapper->private_data;
79         struct container_context *cntr;
80         int i;
81
82         // Additionally, format of samples in the containers should be the same
83         // as the format in PCM substream.
84         for (i = 0; i < cntr_count; ++i) {
85                 cntr = cntrs + i;
86                 if (mapper->bytes_per_sample != cntr->bytes_per_sample)
87                         return -EINVAL;
88         }
89         state->cntr_count = cntr_count;
90
91         // Decide method to align frames.
92         if (mapper->type == MAPPER_TYPE_DEMUXER) {
93                 if (mapper->access == SND_PCM_ACCESS_RW_INTERLEAVED ||
94                     mapper->access == SND_PCM_ACCESS_MMAP_INTERLEAVED)
95                         state->align_frames = align_from_i;
96                 else if (mapper->access == SND_PCM_ACCESS_RW_NONINTERLEAVED ||
97                          mapper->access == SND_PCM_ACCESS_MMAP_NONINTERLEAVED)
98                         state->align_frames = NULL;
99                 else
100                         return -EINVAL;
101         } else {
102                 if (mapper->access == SND_PCM_ACCESS_RW_INTERLEAVED ||
103                     mapper->access == SND_PCM_ACCESS_MMAP_INTERLEAVED)
104                         state->align_frames = align_to_i;
105                 else if (mapper->access == SND_PCM_ACCESS_RW_NONINTERLEAVED ||
106                          mapper->access == SND_PCM_ACCESS_MMAP_NONINTERLEAVED)
107                         state->align_frames = NULL;
108                 else
109                         return -EINVAL;
110         }
111
112         if (state->align_frames) {
113                 // Furthermore, in demuxer case, each container should be
114                 // configured to store one sample per frame.
115                 if (mapper->type == MAPPER_TYPE_DEMUXER) {
116                         for (i = 0; i < cntr_count; ++i) {
117                                 cntr = cntrs + i;
118                                 if (cntrs->samples_per_frame != 1)
119                                         return -EINVAL;
120                         }
121                 }
122
123                 state->bufs = calloc(cntr_count, sizeof(char *));
124                 if (state->bufs == NULL)
125                         return -ENOMEM;
126
127                 for (i = 0; i < cntr_count; ++i) {
128                         unsigned int bytes_per_buffer;
129
130                         // Allocate intermediate buffer as the same size as a
131                         // period for each of containers.
132                         cntr = cntrs + i;
133
134                         bytes_per_buffer = mapper->bytes_per_sample *
135                                            cntr->samples_per_frame *
136                                            mapper->frames_per_buffer;
137
138                         state->bufs[i] = malloc(bytes_per_buffer);
139                         if (state->bufs[i] == NULL)
140                                 return -ENOMEM;
141                         memset(state->bufs[i], 0, bytes_per_buffer);
142                 }
143         }
144
145         return 0;
146 }
147
148 static int process_containers(char **src_bufs, unsigned int *frame_count,
149                               struct container_context *cntrs,
150                               unsigned int cntr_count)
151 {
152         struct container_context *cntr;
153         char *src;
154         int i;
155         int err = 0;
156
157         // TODO: arrangement for *frame_count.
158         for (i = 0; i < cntr_count; ++i) {
159                 cntr = &cntrs[i];
160                 src = src_bufs[i];
161
162                 err = container_context_process_frames(cntr, src, frame_count);
163                 if (err < 0)
164                         break;
165         }
166
167         return err;
168 }
169
170 static int multiple_muxer_process_frames(struct mapper_context *mapper,
171                                          void *frame_buf,
172                                          unsigned int *frame_count,
173                                          struct container_context *cntrs,
174                                          unsigned int cntr_count)
175 {
176         struct multiple_state *state = mapper->private_data;
177         char **src_bufs;
178         int err;
179
180         // If need to align PCM frames, process PCM frames to the intermediate
181         // buffer once.
182         if (!state->align_frames) {
183                 // The most likely.
184                 src_bufs = frame_buf;
185         } else {
186                 src_bufs = state->bufs;
187         }
188         err = process_containers(src_bufs, frame_count, cntrs, cntr_count);
189         if (err < 0)
190                 return err;
191
192         // Unlikely.
193         if (src_bufs != frame_buf && *frame_count > 0) {
194                 state->align_frames(frame_buf, *frame_count, src_bufs,
195                                     mapper->bytes_per_sample, cntrs,
196                                     cntr_count);
197         }
198
199         return 0;
200 }
201
202 static int multiple_demuxer_process_frames(struct mapper_context *mapper,
203                                            void *frame_buf,
204                                            unsigned int *frame_count,
205                                            struct container_context *cntrs,
206                                            unsigned int cntr_count)
207 {
208         struct multiple_state *state = mapper->private_data;
209         char **dst_bufs;
210
211         // If need to align PCM frames, process PCM frames to the intermediate
212         // buffer once.
213         if (!state->align_frames) {
214                 // The most likely.
215                 dst_bufs = frame_buf;
216         } else {
217                 dst_bufs = state->bufs;
218                 state->align_frames(frame_buf, *frame_count, dst_bufs,
219                                     mapper->bytes_per_sample, cntrs,
220                                     cntr_count);
221         }
222
223         return process_containers(dst_bufs, frame_count, cntrs, cntr_count);
224 }
225
226 static void multiple_post_process(struct mapper_context *mapper)
227 {
228         struct multiple_state *state = mapper->private_data;
229         int i;
230
231         if (state->bufs) {
232                 for (i = 0; i < state->cntr_count; ++i) {
233                         if (state->bufs[i])
234                                 free(state->bufs[i]);
235                 }
236                 free(state->bufs);
237         }
238
239         state->bufs = NULL;
240         state->align_frames = NULL;
241 }
242
243 const struct mapper_data mapper_muxer_multiple = {
244         .ops = {
245                 .pre_process = multiple_pre_process,
246                 .process_frames = multiple_muxer_process_frames,
247                 .post_process = multiple_post_process,
248         },
249         .private_size = sizeof(struct multiple_state),
250 };
251
252 const struct mapper_data mapper_demuxer_multiple = {
253         .ops = {
254                 .pre_process = multiple_pre_process,
255                 .process_frames = multiple_demuxer_process_frames,
256                 .post_process = multiple_post_process,
257         },
258         .private_size = sizeof(struct multiple_state),
259 };