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
RevLine 
[76ea1b7]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
[d988ef2]36#include <macros.h>
[38d150e]37#include <stdlib.h>
[2373ba7]38
[76ea1b7]39#include "audio_data.h"
[2373ba7]40#include "log.h"
[76ea1b7]41
[c799138]42/**
43 * Create reference counted buffer out of ordinary data buffer.
[902dd4b]44 * @param data audio buffer. The memory passed will be freed eventually.
[c799138]45 * @param size Size of the @p data buffer.
[902dd4b]46 * @param format audio data format.
[5d27e5a]47 * @return pointer to valid audio data structure, NULL on failure.
[c799138]48 */
[902dd4b]49audio_data_t *audio_data_create(void *data, size_t size,
[5029c788]50 pcm_format_t format)
51{
[33b8d024]52 audio_data_t *adata = malloc(sizeof(audio_data_t) + size);
[5029c788]53 if (adata) {
[2373ba7]54 unsigned overflow = size % pcm_format_frame_size(&format);
55 if (overflow)
56 log_warning("Data not a multiple of frame size, "
57 "clipping.");
[231c770]58 adata->data = data;
[2373ba7]59 adata->size = size - overflow;
[5029c788]60 adata->format = format;
[498ced1]61 refcount_init(&adata->refcount);
[5029c788]62 }
63 return adata;
64}
65
[c799138]66/**
67 * Get a new reference to the audio data buffer.
68 * @param adata The audio data buffer.
69 */
[d988ef2]70void audio_data_addref(audio_data_t *adata)
71{
72 assert(adata);
[498ced1]73 refcount_up(&adata->refcount);
[d988ef2]74}
75
[c799138]76/**
77 * Release a reference to the audio data buffer.
78 * @param adata The audio data buffer.
79 */
[5029c788]80void audio_data_unref(audio_data_t *adata)
81{
[d988ef2]82 assert(adata);
[498ced1]83 if (refcount_down(&adata->refcount)) {
[902dd4b]84 free(adata->data);
[d988ef2]85 free(adata);
86 }
[5029c788]87}
88
[c5b8548]89/* Data link helpers */
90
[c799138]91/** Audio data buffer list helper structure. */
[c5b8548]92typedef struct {
93 link_t link;
94 audio_data_t *adata;
95 size_t position;
96} audio_data_link_t;
97
[c799138]98/** List instance helper function.
99 * @param l link
100 * @return valid pointer to data link structure, NULL on failure.
101 */
[3bacee1]102static inline audio_data_link_t *audio_data_link_list_instance(link_t *l)
[c5b8548]103{
104 return l ? list_get_instance(l, audio_data_link_t, link) : NULL;
105}
106
[c799138]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 */
[c5b8548]112static audio_data_link_t *audio_data_link_create(audio_data_t *adata)
[76ea1b7]113{
114 assert(adata);
115 audio_data_link_t *link = malloc(sizeof(audio_data_link_t));
116 if (link) {
[d988ef2]117 audio_data_addref(adata);
[76ea1b7]118 link->adata = adata;
119 link->position = 0;
120 }
121 return link;
122}
123
[c799138]124/**
125 * Destroy audio data link.
126 * @param link The link to destroy.
127 *
128 * Releases data reference.
129 */
[c5b8548]130static void audio_data_link_destroy(audio_data_link_t *link)
[76ea1b7]131{
132 assert(link);
133 assert(!link_in_use(&link->link));
[d988ef2]134 audio_data_unref(link->adata);
[76ea1b7]135 free(link);
136}
137
[c799138]138/**
139 * Data link buffer start helper function.
140 * @param alink audio data link
141 * @return pointer to the beginning of data buffer.
142 */
[3bacee1]143static inline const void *audio_data_link_start(audio_data_link_t *alink)
[c5b8548]144{
145 assert(alink);
146 assert(alink->adata);
147 return alink->adata->data + alink->position;
148}
149
[c799138]150/**
151 * Data link remaining size getter.
152 * @param alink audio data link
153 * @return Remaining size of valid data in the buffer.
154 */
[c5b8548]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
[c799138]163/**
164 * Data link remaining frames getter.
165 * @param alink audio data link
166 * @return Number of remaining frames in the buffer.
167 */
[c5b8548]168static inline size_t audio_data_link_available_frames(audio_data_link_t *alink)
[5029c788]169{
170 assert(alink);
171 assert(alink->adata);
[d988ef2]172 return pcm_format_size_to_frames(audio_data_link_remain_size(alink),
[5029c788]173 &alink->adata->format);
174}
175
[d988ef2]176/* Audio Pipe */
177
[c799138]178/**
179 * Initialize audio pipe structure.
180 * @param pipe The pipe structure to initialize.
181 */
[d988ef2]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
[c799138]191/**
192 * Destroy all data in a pipe.
193 * @param pipe The audio pipe to clean.
194 */
[d988ef2]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
[c799138]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 */
[b7fd2a0]210errno_t audio_pipe_push(audio_pipe_t *pipe, audio_data_t *data)
[d988ef2]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
[c799138]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 */
[d988ef2]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);
[f04603e]240 pipe->bytes -= audio_data_link_remain_size(alink);
241 pipe->frames -= audio_data_link_available_frames(alink);
[d988ef2]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
[c799138]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.
[541eb67]256 * @return Size of the target buffer used.
[c799138]257 */
[541eb67]258size_t audio_pipe_mix_data(audio_pipe_t *pipe, void *data,
[d988ef2]259 size_t size, const pcm_format_t *f)
260{
261 assert(pipe);
[98af9cc]262
[d988ef2]263 const size_t dst_frame_size = pcm_format_frame_size(f);
[98af9cc]264 size_t needed_frames = pcm_format_size_to_frames(size, f);
[d988ef2]265 size_t copied_size = 0;
[98af9cc]266
[d988ef2]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);
[3545c56]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));
[d988ef2]283
284 /* Copy audio data */
[3545c56]285 pcm_format_convert_and_mix(data, dst_copy_size,
286 audio_data_link_start(alink), src_copy_size,
[d988ef2]287 &alink->adata->format, f);
288
289 /* Update values */
290 needed_frames -= copy_frames;
[3545c56]291 copied_size += dst_copy_size;
292 data += dst_copy_size;
293 alink->position += src_copy_size;
294 pipe->bytes -= src_copy_size;
[f04603e]295 pipe->frames -= copy_frames;
[d988ef2]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
[76ea1b7]307/**
308 * @}
309 */
Note: See TracBrowser for help on using the repository browser.