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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since eca79ff was 2373ba7, checked in by Jan Vesely <jano.vesely@…>, 13 years ago

hound: warn and clip if data size is not a multiple of framesize

  • Property mode set to 100644
File size: 6.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 <malloc.h>
38
39#include "audio_data.h"
40#include "log.h"
41
42audio_data_t *audio_data_create(const void *data, size_t size,
43 pcm_format_t format)
44{
45 audio_data_t *adata = malloc(sizeof(audio_data_t));
46 if (adata) {
47 unsigned overflow = size % pcm_format_frame_size(&format);
48 if (overflow)
49 log_warning("Data not a multiple of frame size, "
50 "clipping.");
51
52 adata->data = data;
53 adata->size = size - overflow;
54 adata->format = format;
55 atomic_set(&adata->refcount, 1);
56 }
57 return adata;
58}
59
60void audio_data_addref(audio_data_t *adata)
61{
62 assert(adata);
63 assert(atomic_get(&adata->refcount) > 0);
64 atomic_inc(&adata->refcount);
65}
66
67void audio_data_unref(audio_data_t *adata)
68{
69 assert(adata);
70 assert(atomic_get(&adata->refcount) > 0);
71 atomic_count_t refc = atomic_predec(&adata->refcount);
72 if (refc == 0) {
73 free(adata->data);
74 free(adata);
75 }
76}
77
78/* Data link helpers */
79
80typedef struct {
81 link_t link;
82 audio_data_t *adata;
83 size_t position;
84} audio_data_link_t;
85
86static inline audio_data_link_t * audio_data_link_list_instance(link_t *l)
87{
88 return l ? list_get_instance(l, audio_data_link_t, link) : NULL;
89}
90
91static audio_data_link_t *audio_data_link_create(audio_data_t *adata)
92{
93 assert(adata);
94 audio_data_link_t *link = malloc(sizeof(audio_data_link_t));
95 if (link) {
96 audio_data_addref(adata);
97 link->adata = adata;
98 link->position = 0;
99 }
100 return link;
101}
102
103static void audio_data_link_destroy(audio_data_link_t *link)
104{
105 assert(link);
106 assert(!link_in_use(&link->link));
107 audio_data_unref(link->adata);
108 free(link);
109}
110
111static inline const void * audio_data_link_start(audio_data_link_t *alink)
112{
113 assert(alink);
114 assert(alink->adata);
115 return alink->adata->data + alink->position;
116}
117
118static inline size_t audio_data_link_remain_size(audio_data_link_t *alink)
119{
120 assert(alink);
121 assert(alink->adata);
122 assert(alink->position <= alink->adata->size);
123 return alink->adata->size - alink->position;
124}
125
126
127static inline size_t audio_data_link_available_frames(audio_data_link_t *alink)
128{
129 assert(alink);
130 assert(alink->adata);
131 return pcm_format_size_to_frames(audio_data_link_remain_size(alink),
132 &alink->adata->format);
133}
134
135/* Audio Pipe */
136
137
138void audio_pipe_init(audio_pipe_t *pipe)
139{
140 assert(pipe);
141 list_initialize(&pipe->list);
142 fibril_mutex_initialize(&pipe->guard);
143 pipe->frames = 0;
144 pipe->bytes = 0;
145}
146
147
148
149void audio_pipe_fini(audio_pipe_t *pipe)
150{
151 assert(pipe);
152 while (!list_empty(&pipe->list)) {
153 audio_data_t *adata = audio_pipe_pop(pipe);
154 audio_data_unref(adata);
155 }
156}
157
158int audio_pipe_push(audio_pipe_t *pipe, audio_data_t *data)
159{
160 assert(pipe);
161 assert(data);
162 audio_data_link_t *alink = audio_data_link_create(data);
163 if (!alink)
164 return ENOMEM;
165
166 fibril_mutex_lock(&pipe->guard);
167 list_append(&alink->link, &pipe->list);
168 pipe->bytes += audio_data_link_remain_size(alink);
169 pipe->frames += audio_data_link_available_frames(alink);
170 fibril_mutex_unlock(&pipe->guard);
171 return EOK;
172}
173
174audio_data_t *audio_pipe_pop(audio_pipe_t *pipe)
175{
176 assert(pipe);
177 fibril_mutex_lock(&pipe->guard);
178 audio_data_t *adata = NULL;
179 link_t *l = list_first(&pipe->list);
180 if (l) {
181 audio_data_link_t *alink = audio_data_link_list_instance(l);
182 list_remove(&alink->link);
183 pipe->bytes -= audio_data_link_remain_size(alink);
184 pipe->frames -= audio_data_link_available_frames(alink);
185 adata = alink->adata;
186 audio_data_addref(adata);
187 audio_data_link_destroy(alink);
188 }
189 fibril_mutex_unlock(&pipe->guard);
190 return adata;
191}
192
193ssize_t audio_pipe_mix_data(audio_pipe_t *pipe, void *data,
194 size_t size, const pcm_format_t *f)
195{
196 assert(pipe);
197 const size_t dst_frame_size = pcm_format_frame_size(f);
198 size_t needed_frames = size / dst_frame_size;
199 size_t copied_size = 0;
200 fibril_mutex_lock(&pipe->guard);
201 while (needed_frames > 0 && !list_empty(&pipe->list)) {
202 /* Get first audio chunk */
203 link_t *l = list_first(&pipe->list);
204 audio_data_link_t *alink = audio_data_link_list_instance(l);
205
206 /* Get audio chunk metadata */
207 const size_t src_frame_size =
208 pcm_format_frame_size(&alink->adata->format);
209 const size_t available_frames =
210 audio_data_link_available_frames(alink);
211 const size_t copy_frames = min(available_frames, needed_frames);
212 const size_t copy_size = copy_frames * dst_frame_size;
213
214 /* Copy audio data */
215 pcm_format_convert_and_mix(data, copy_size,
216 audio_data_link_start(alink),
217 audio_data_link_remain_size(alink),
218 &alink->adata->format, f);
219
220 /* Update values */
221 copied_size += copy_size;
222 needed_frames -= copy_frames;
223 data += copy_size;
224 alink->position += (copy_frames * src_frame_size);
225 pipe->bytes -= (copy_frames * src_frame_size);
226 pipe->frames -= copy_frames;
227 if (audio_data_link_remain_size(alink) == 0) {
228 list_remove(&alink->link);
229 audio_data_link_destroy(alink);
230 } else {
231 assert(needed_frames == 0);
232 }
233 }
234 fibril_mutex_unlock(&pipe->guard);
235 return copied_size;
236}
237
238/**
239 * @}
240 */
Note: See TracBrowser for help on using the repository browser.