source: mainline/uspace/srv/audio/hound/audio_data.c

Last change on this file was 09ab0a9a, checked in by Jiri Svoboda <jiri@…>, 7 years ago

Fix vertical spacing with new Ccheck revision.

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