source: mainline/uspace/srv/audio/hound/audio_data.c@ 3bacee1

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 3bacee1 was 3bacee1, checked in by Jiri Svoboda <jiri@…>, 7 years ago

Make ccheck-fix again and commit more good files.

  • Property mode set to 100644
File size: 8.3 KB
Line 
1/*
2 * Copyright (c) 2013 Jan Vesely
3 * 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
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup audio
30 * @brief HelenOS sound server
31 * @{
32 */
33/** @file
34 */
35
36#include <macros.h>
37#include <stdlib.h>
38
39#include "audio_data.h"
40#include "log.h"
41
42/**
43 * Create reference counted buffer out of ordinary data buffer.
44 * @param data audio buffer
45 * @param size Size of the @p data buffer.
46 * @param fomart audio data format.
47 * @return pointer to valid audio data structure, NULL on failure.
48 */
49audio_data_t *audio_data_create(const void *data, size_t size,
50 pcm_format_t format)
51{
52 audio_data_t *adata = malloc(sizeof(audio_data_t) + size);
53 if (adata) {
54 unsigned overflow = size % pcm_format_frame_size(&format);
55 if (overflow)
56 log_warning("Data not a multiple of frame size, "
57 "clipping.");
58 adata->data = data;
59 adata->size = size - overflow;
60 adata->format = format;
61 atomic_set(&adata->refcount, 1);
62 }
63 return adata;
64}
65
66/**
67 * Get a new reference to the audio data buffer.
68 * @param adata The audio data buffer.
69 */
70void audio_data_addref(audio_data_t *adata)
71{
72 assert(adata);
73 assert(atomic_get(&adata->refcount) > 0);
74 atomic_inc(&adata->refcount);
75}
76
77/**
78 * Release a reference to the audio data buffer.
79 * @param adata The audio data buffer.
80 */
81void audio_data_unref(audio_data_t *adata)
82{
83 assert(adata);
84 assert(atomic_get(&adata->refcount) > 0);
85 atomic_count_t refc = atomic_predec(&adata->refcount);
86 if (refc == 0) {
87 free((void *) adata->data);
88 free(adata);
89 }
90}
91
92/* Data link helpers */
93
94/** Audio data buffer list helper structure. */
95typedef struct {
96 link_t link;
97 audio_data_t *adata;
98 size_t position;
99} audio_data_link_t;
100
101/** List instance helper function.
102 * @param l link
103 * @return valid pointer to data link structure, NULL on failure.
104 */
105static inline audio_data_link_t *audio_data_link_list_instance(link_t *l)
106{
107 return l ? list_get_instance(l, audio_data_link_t, link) : NULL;
108}
109
110/**
111 * Create a new audio data link.
112 * @param adata Audio data to store.
113 * @return Valid pointer to a new audio data link structure, NULL on failure.
114 */
115static audio_data_link_t *audio_data_link_create(audio_data_t *adata)
116{
117 assert(adata);
118 audio_data_link_t *link = malloc(sizeof(audio_data_link_t));
119 if (link) {
120 audio_data_addref(adata);
121 link->adata = adata;
122 link->position = 0;
123 }
124 return link;
125}
126
127/**
128 * Destroy audio data link.
129 * @param link The link to destroy.
130 *
131 * Releases data reference.
132 */
133static void audio_data_link_destroy(audio_data_link_t *link)
134{
135 assert(link);
136 assert(!link_in_use(&link->link));
137 audio_data_unref(link->adata);
138 free(link);
139}
140
141/**
142 * Data link buffer start helper function.
143 * @param alink audio data link
144 * @return pointer to the beginning of data buffer.
145 */
146static inline const void *audio_data_link_start(audio_data_link_t *alink)
147{
148 assert(alink);
149 assert(alink->adata);
150 return alink->adata->data + alink->position;
151}
152
153/**
154 * Data link remaining size getter.
155 * @param alink audio data link
156 * @return Remaining size of valid data in the buffer.
157 */
158static inline size_t audio_data_link_remain_size(audio_data_link_t *alink)
159{
160 assert(alink);
161 assert(alink->adata);
162 assert(alink->position <= alink->adata->size);
163 return alink->adata->size - alink->position;
164}
165
166
167/**
168 * Data link remaining frames getter.
169 * @param alink audio data link
170 * @return Number of remaining frames in the buffer.
171 */
172static inline size_t audio_data_link_available_frames(audio_data_link_t *alink)
173{
174 assert(alink);
175 assert(alink->adata);
176 return pcm_format_size_to_frames(audio_data_link_remain_size(alink),
177 &alink->adata->format);
178}
179
180/* Audio Pipe */
181
182/**
183 * Initialize audio pipe structure.
184 * @param pipe The pipe structure to initialize.
185 */
186void audio_pipe_init(audio_pipe_t *pipe)
187{
188 assert(pipe);
189 list_initialize(&pipe->list);
190 fibril_mutex_initialize(&pipe->guard);
191 pipe->frames = 0;
192 pipe->bytes = 0;
193}
194
195/**
196 * Destroy all data in a pipe.
197 * @param pipe The audio pipe to clean.
198 */
199void audio_pipe_fini(audio_pipe_t *pipe)
200{
201 assert(pipe);
202 while (!list_empty(&pipe->list)) {
203 audio_data_t *adata = audio_pipe_pop(pipe);
204 audio_data_unref(adata);
205 }
206}
207
208/**
209 * Add new audio data to a pipe.
210 * @param pipe The target pipe.
211 * @param data The data.
212 * @return Error code.
213 */
214errno_t audio_pipe_push(audio_pipe_t *pipe, audio_data_t *data)
215{
216 assert(pipe);
217 assert(data);
218 audio_data_link_t *alink = audio_data_link_create(data);
219 if (!alink)
220 return ENOMEM;
221
222 fibril_mutex_lock(&pipe->guard);
223 list_append(&alink->link, &pipe->list);
224 pipe->bytes += audio_data_link_remain_size(alink);
225 pipe->frames += audio_data_link_available_frames(alink);
226 fibril_mutex_unlock(&pipe->guard);
227 return EOK;
228}
229
230/**
231 * Retrieve data form a audio pipe.
232 * @param pipe THe target pipe.
233 * @return Valid pointer to audio data, NULL if the pipe was empty.
234 */
235audio_data_t *audio_pipe_pop(audio_pipe_t *pipe)
236{
237 assert(pipe);
238 fibril_mutex_lock(&pipe->guard);
239 audio_data_t *adata = NULL;
240 link_t *l = list_first(&pipe->list);
241 if (l) {
242 audio_data_link_t *alink = audio_data_link_list_instance(l);
243 list_remove(&alink->link);
244 pipe->bytes -= audio_data_link_remain_size(alink);
245 pipe->frames -= audio_data_link_available_frames(alink);
246 adata = alink->adata;
247 audio_data_addref(adata);
248 audio_data_link_destroy(alink);
249 }
250 fibril_mutex_unlock(&pipe->guard);
251 return adata;
252}
253
254
255/**
256 * Use data store in a pipe and mix it into the provided buffer.
257 * @param pipe The piep that should provide data.
258 * @param data Target buffer.
259 * @param size Target buffer size.
260 * @param format Target data format.
261 * @return Size of the target buffer used.
262 */
263size_t audio_pipe_mix_data(audio_pipe_t *pipe, void *data,
264 size_t size, const pcm_format_t *f)
265{
266 assert(pipe);
267
268 const size_t dst_frame_size = pcm_format_frame_size(f);
269 size_t needed_frames = pcm_format_size_to_frames(size, f);
270 size_t copied_size = 0;
271
272 fibril_mutex_lock(&pipe->guard);
273 while (needed_frames > 0 && !list_empty(&pipe->list)) {
274 /* Get first audio chunk */
275 link_t *l = list_first(&pipe->list);
276 audio_data_link_t *alink = audio_data_link_list_instance(l);
277
278 /* Get audio chunk metadata */
279 const size_t src_frame_size =
280 pcm_format_frame_size(&alink->adata->format);
281 const size_t available_frames =
282 audio_data_link_available_frames(alink);
283 const size_t copy_frames = min(available_frames, needed_frames);
284 const size_t dst_copy_size = copy_frames * dst_frame_size;
285 const size_t src_copy_size = copy_frames * src_frame_size;
286
287 assert(src_copy_size <= audio_data_link_remain_size(alink));
288
289 /* Copy audio data */
290 pcm_format_convert_and_mix(data, dst_copy_size,
291 audio_data_link_start(alink), src_copy_size,
292 &alink->adata->format, f);
293
294 /* Update values */
295 needed_frames -= copy_frames;
296 copied_size += dst_copy_size;
297 data += dst_copy_size;
298 alink->position += src_copy_size;
299 pipe->bytes -= src_copy_size;
300 pipe->frames -= copy_frames;
301 if (audio_data_link_remain_size(alink) == 0) {
302 list_remove(&alink->link);
303 audio_data_link_destroy(alink);
304 } else {
305 assert(needed_frames == 0);
306 }
307 }
308 fibril_mutex_unlock(&pipe->guard);
309 return copied_size;
310}
311
312/**
313 * @}
314 */
Note: See TracBrowser for help on using the repository browser.