source: mainline/uspace/srv/audio/hound/audio_data.c@ 850fd32

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 850fd32 was 33b8d024, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 8 years ago

Remove const qualifier from the argument of free() and realloc(),
as well as in numerous other variables that hold ownership of memory.

By convention, a pointer that holds ownership is _never_ qualified by const.
This is reflected in the standard type signature of free() and realloc().
Allowing const pointers to hold ownership may seem superficially convenient,
but is actually quite confusing to experienced C programmers.

  • Property mode set to 100644
File size: 8.4 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#include <str.h>
39
40#include "audio_data.h"
41#include "log.h"
42
43/**
44 * Create reference counted buffer out of ordinary data buffer.
45 * @param data audio buffer
46 * @param size Size of the @p data buffer.
47 * @param fomart audio data format.
48 * @return pointer to valid audio data structure, NULL on failure.
49 */
50audio_data_t *audio_data_create(const void *data, size_t size,
51 pcm_format_t format)
52{
53 audio_data_t *adata = malloc(sizeof(audio_data_t) + size);
54 if (adata) {
55 unsigned overflow = size % pcm_format_frame_size(&format);
56 if (overflow)
57 log_warning("Data not a multiple of frame size, "
58 "clipping.");
59 uint8_t *d = ((uint8_t *)adata) + offsetof(audio_data_t, data);
60 memcpy(d, data, size);
61 adata->size = size - overflow;
62 adata->format = format;
63 atomic_set(&adata->refcount, 1);
64 }
65 return adata;
66}
67
68/**
69 * Get a new reference to the audio data buffer.
70 * @param adata The audio data buffer.
71 */
72void audio_data_addref(audio_data_t *adata)
73{
74 assert(adata);
75 assert(atomic_get(&adata->refcount) > 0);
76 atomic_inc(&adata->refcount);
77}
78
79/**
80 * Release a reference to the audio data buffer.
81 * @param adata The audio data buffer.
82 */
83void audio_data_unref(audio_data_t *adata)
84{
85 assert(adata);
86 assert(atomic_get(&adata->refcount) > 0);
87 atomic_count_t refc = atomic_predec(&adata->refcount);
88 if (refc == 0) {
89 free(adata);
90 }
91}
92
93/* Data link helpers */
94
95/** Audio data buffer list helper structure. */
96typedef struct {
97 link_t link;
98 audio_data_t *adata;
99 size_t position;
100} audio_data_link_t;
101
102/** List instance helper function.
103 * @param l link
104 * @return valid pointer to data link structure, NULL on failure.
105 */
106static inline audio_data_link_t * audio_data_link_list_instance(link_t *l)
107{
108 return l ? list_get_instance(l, audio_data_link_t, link) : NULL;
109}
110
111/**
112 * Create a new audio data link.
113 * @param adata Audio data to store.
114 * @return Valid pointer to a new audio data link structure, NULL on failure.
115 */
116static audio_data_link_t *audio_data_link_create(audio_data_t *adata)
117{
118 assert(adata);
119 audio_data_link_t *link = malloc(sizeof(audio_data_link_t));
120 if (link) {
121 audio_data_addref(adata);
122 link->adata = adata;
123 link->position = 0;
124 }
125 return link;
126}
127
128/**
129 * Destroy audio data link.
130 * @param link The link to destroy.
131 *
132 * Releases data reference.
133 */
134static void audio_data_link_destroy(audio_data_link_t *link)
135{
136 assert(link);
137 assert(!link_in_use(&link->link));
138 audio_data_unref(link->adata);
139 free(link);
140}
141
142/**
143 * Data link buffer start helper function.
144 * @param alink audio data link
145 * @return pointer to the beginning of data buffer.
146 */
147static inline const void * audio_data_link_start(audio_data_link_t *alink)
148{
149 assert(alink);
150 assert(alink->adata);
151 return alink->adata->data + alink->position;
152}
153
154/**
155 * Data link remaining size getter.
156 * @param alink audio data link
157 * @return Remaining size of valid data in the buffer.
158 */
159static inline size_t audio_data_link_remain_size(audio_data_link_t *alink)
160{
161 assert(alink);
162 assert(alink->adata);
163 assert(alink->position <= alink->adata->size);
164 return alink->adata->size - alink->position;
165}
166
167
168/**
169 * Data link remaining frames getter.
170 * @param alink audio data link
171 * @return Number of remaining frames in the buffer.
172 */
173static inline size_t audio_data_link_available_frames(audio_data_link_t *alink)
174{
175 assert(alink);
176 assert(alink->adata);
177 return pcm_format_size_to_frames(audio_data_link_remain_size(alink),
178 &alink->adata->format);
179}
180
181/* Audio Pipe */
182
183/**
184 * Initialize audio pipe structure.
185 * @param pipe The pipe structure to initialize.
186 */
187void audio_pipe_init(audio_pipe_t *pipe)
188{
189 assert(pipe);
190 list_initialize(&pipe->list);
191 fibril_mutex_initialize(&pipe->guard);
192 pipe->frames = 0;
193 pipe->bytes = 0;
194}
195
196/**
197 * Destroy all data in a pipe.
198 * @param pipe The audio pipe to clean.
199 */
200void audio_pipe_fini(audio_pipe_t *pipe)
201{
202 assert(pipe);
203 while (!list_empty(&pipe->list)) {
204 audio_data_t *adata = audio_pipe_pop(pipe);
205 audio_data_unref(adata);
206 }
207}
208
209/**
210 * Add new audio data to a pipe.
211 * @param pipe The target pipe.
212 * @param data The data.
213 * @return Error code.
214 */
215errno_t audio_pipe_push(audio_pipe_t *pipe, audio_data_t *data)
216{
217 assert(pipe);
218 assert(data);
219 audio_data_link_t *alink = audio_data_link_create(data);
220 if (!alink)
221 return ENOMEM;
222
223 fibril_mutex_lock(&pipe->guard);
224 list_append(&alink->link, &pipe->list);
225 pipe->bytes += audio_data_link_remain_size(alink);
226 pipe->frames += audio_data_link_available_frames(alink);
227 fibril_mutex_unlock(&pipe->guard);
228 return EOK;
229}
230
231/**
232 * Retrieve data form a audio pipe.
233 * @param pipe THe target pipe.
234 * @return Valid pointer to audio data, NULL if the pipe was empty.
235 */
236audio_data_t *audio_pipe_pop(audio_pipe_t *pipe)
237{
238 assert(pipe);
239 fibril_mutex_lock(&pipe->guard);
240 audio_data_t *adata = NULL;
241 link_t *l = list_first(&pipe->list);
242 if (l) {
243 audio_data_link_t *alink = audio_data_link_list_instance(l);
244 list_remove(&alink->link);
245 pipe->bytes -= audio_data_link_remain_size(alink);
246 pipe->frames -= audio_data_link_available_frames(alink);
247 adata = alink->adata;
248 audio_data_addref(adata);
249 audio_data_link_destroy(alink);
250 }
251 fibril_mutex_unlock(&pipe->guard);
252 return adata;
253}
254
255
256/**
257 * Use data store in a pipe and mix it into the provided buffer.
258 * @param pipe The piep that should provide data.
259 * @param data Target buffer.
260 * @param size Target buffer size.
261 * @param format Target data format.
262 * @return Size of the target buffer used.
263 */
264size_t audio_pipe_mix_data(audio_pipe_t *pipe, void *data,
265 size_t size, const pcm_format_t *f)
266{
267 assert(pipe);
268
269 const size_t dst_frame_size = pcm_format_frame_size(f);
270 size_t needed_frames = pcm_format_size_to_frames(size, f);
271 size_t copied_size = 0;
272
273 fibril_mutex_lock(&pipe->guard);
274 while (needed_frames > 0 && !list_empty(&pipe->list)) {
275 /* Get first audio chunk */
276 link_t *l = list_first(&pipe->list);
277 audio_data_link_t *alink = audio_data_link_list_instance(l);
278
279 /* Get audio chunk metadata */
280 const size_t src_frame_size =
281 pcm_format_frame_size(&alink->adata->format);
282 const size_t available_frames =
283 audio_data_link_available_frames(alink);
284 const size_t copy_frames = min(available_frames, needed_frames);
285 const size_t dst_copy_size = copy_frames * dst_frame_size;
286 const size_t src_copy_size = copy_frames * src_frame_size;
287
288 assert(src_copy_size <= audio_data_link_remain_size(alink));
289
290 /* Copy audio data */
291 pcm_format_convert_and_mix(data, dst_copy_size,
292 audio_data_link_start(alink), src_copy_size,
293 &alink->adata->format, f);
294
295 /* Update values */
296 needed_frames -= copy_frames;
297 copied_size += dst_copy_size;
298 data += dst_copy_size;
299 alink->position += src_copy_size;
300 pipe->bytes -= src_copy_size;
301 pipe->frames -= copy_frames;
302 if (audio_data_link_remain_size(alink) == 0) {
303 list_remove(&alink->link);
304 audio_data_link_destroy(alink);
305 } else {
306 assert(needed_frames == 0);
307 }
308 }
309 fibril_mutex_unlock(&pipe->guard);
310 return copied_size;
311}
312
313/**
314 * @}
315 */
Note: See TracBrowser for help on using the repository browser.