source: mainline/uspace/srv/audio/hound/audio_data.c@ 38d150e

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

Prefer to get memory allocation functions through the standard stdlib header.

  • 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
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));
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
59 adata->data = data;
60 adata->size = size - overflow;
61 adata->format = format;
62 atomic_set(&adata->refcount, 1);
63 }
64 return adata;
65}
66
67/**
68 * Get a new reference to the audio data buffer.
69 * @param adata The audio data buffer.
70 */
71void audio_data_addref(audio_data_t *adata)
72{
73 assert(adata);
74 assert(atomic_get(&adata->refcount) > 0);
75 atomic_inc(&adata->refcount);
76}
77
78/**
79 * Release a reference to the audio data buffer.
80 * @param adata The audio data buffer.
81 */
82void audio_data_unref(audio_data_t *adata)
83{
84 assert(adata);
85 assert(atomic_get(&adata->refcount) > 0);
86 atomic_count_t refc = atomic_predec(&adata->refcount);
87 if (refc == 0) {
88 free(adata->data);
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 */
215int 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, Error code on failure.
263 */
264ssize_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.