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

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

Unify reference counting and remove some unnecessary instances of <atomic.h>

  • 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/**
165 * Data link remaining frames getter.
166 * @param alink audio data link
167 * @return Number of remaining frames in the buffer.
168 */
169static inline size_t audio_data_link_available_frames(audio_data_link_t *alink)
170{
171 assert(alink);
172 assert(alink->adata);
173 return pcm_format_size_to_frames(audio_data_link_remain_size(alink),
174 &alink->adata->format);
175}
176
177/* Audio Pipe */
178
179/**
180 * Initialize audio pipe structure.
181 * @param pipe The pipe structure to initialize.
182 */
183void audio_pipe_init(audio_pipe_t *pipe)
184{
185 assert(pipe);
186 list_initialize(&pipe->list);
187 fibril_mutex_initialize(&pipe->guard);
188 pipe->frames = 0;
189 pipe->bytes = 0;
190}
191
192/**
193 * Destroy all data in a pipe.
194 * @param pipe The audio pipe to clean.
195 */
196void audio_pipe_fini(audio_pipe_t *pipe)
197{
198 assert(pipe);
199 while (!list_empty(&pipe->list)) {
200 audio_data_t *adata = audio_pipe_pop(pipe);
201 audio_data_unref(adata);
202 }
203}
204
205/**
206 * Add new audio data to a pipe.
207 * @param pipe The target pipe.
208 * @param data The data.
209 * @return Error code.
210 */
211errno_t audio_pipe_push(audio_pipe_t *pipe, audio_data_t *data)
212{
213 assert(pipe);
214 assert(data);
215 audio_data_link_t *alink = audio_data_link_create(data);
216 if (!alink)
217 return ENOMEM;
218
219 fibril_mutex_lock(&pipe->guard);
220 list_append(&alink->link, &pipe->list);
221 pipe->bytes += audio_data_link_remain_size(alink);
222 pipe->frames += audio_data_link_available_frames(alink);
223 fibril_mutex_unlock(&pipe->guard);
224 return EOK;
225}
226
227/**
228 * Retrieve data form a audio pipe.
229 * @param pipe THe target pipe.
230 * @return Valid pointer to audio data, NULL if the pipe was empty.
231 */
232audio_data_t *audio_pipe_pop(audio_pipe_t *pipe)
233{
234 assert(pipe);
235 fibril_mutex_lock(&pipe->guard);
236 audio_data_t *adata = NULL;
237 link_t *l = list_first(&pipe->list);
238 if (l) {
239 audio_data_link_t *alink = audio_data_link_list_instance(l);
240 list_remove(&alink->link);
241 pipe->bytes -= audio_data_link_remain_size(alink);
242 pipe->frames -= audio_data_link_available_frames(alink);
243 adata = alink->adata;
244 audio_data_addref(adata);
245 audio_data_link_destroy(alink);
246 }
247 fibril_mutex_unlock(&pipe->guard);
248 return adata;
249}
250
251
252/**
253 * Use data store in a pipe and mix it into the provided buffer.
254 * @param pipe The piep that should provide data.
255 * @param data Target buffer.
256 * @param size Target buffer size.
257 * @param format Target data format.
258 * @return Size of the target buffer used.
259 */
260size_t audio_pipe_mix_data(audio_pipe_t *pipe, void *data,
261 size_t size, const pcm_format_t *f)
262{
263 assert(pipe);
264
265 const size_t dst_frame_size = pcm_format_frame_size(f);
266 size_t needed_frames = pcm_format_size_to_frames(size, f);
267 size_t copied_size = 0;
268
269 fibril_mutex_lock(&pipe->guard);
270 while (needed_frames > 0 && !list_empty(&pipe->list)) {
271 /* Get first audio chunk */
272 link_t *l = list_first(&pipe->list);
273 audio_data_link_t *alink = audio_data_link_list_instance(l);
274
275 /* Get audio chunk metadata */
276 const size_t src_frame_size =
277 pcm_format_frame_size(&alink->adata->format);
278 const size_t available_frames =
279 audio_data_link_available_frames(alink);
280 const size_t copy_frames = min(available_frames, needed_frames);
281 const size_t dst_copy_size = copy_frames * dst_frame_size;
282 const size_t src_copy_size = copy_frames * src_frame_size;
283
284 assert(src_copy_size <= audio_data_link_remain_size(alink));
285
286 /* Copy audio data */
287 pcm_format_convert_and_mix(data, dst_copy_size,
288 audio_data_link_start(alink), src_copy_size,
289 &alink->adata->format, f);
290
291 /* Update values */
292 needed_frames -= copy_frames;
293 copied_size += dst_copy_size;
294 data += dst_copy_size;
295 alink->position += src_copy_size;
296 pipe->bytes -= src_copy_size;
297 pipe->frames -= copy_frames;
298 if (audio_data_link_remain_size(alink) == 0) {
299 list_remove(&alink->link);
300 audio_data_link_destroy(alink);
301 } else {
302 assert(needed_frames == 0);
303 }
304 }
305 fibril_mutex_unlock(&pipe->guard);
306 return copied_size;
307}
308
309/**
310 * @}
311 */
Note: See TracBrowser for help on using the repository browser.