source: mainline/uspace/srv/audio/hound/hound.c@ 3b6c1d4

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

hound: implement context manipulation

  • Property mode set to 100644
File size: 9.3 KB
Line 
1/*
2 * Copyright (c) 2012 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/**
30 * @addtogroup audio
31 * @brief HelenOS sound server.
32 * @{
33 */
34/** @file
35 */
36
37#include <assert.h>
38#include <stdlib.h>
39
40#include "hound.h"
41#include "audio_client.h"
42#include "audio_device.h"
43#include "audio_sink.h"
44#include "audio_source.h"
45#include "log.h"
46#include "errno.h"
47#include "str_error.h"
48
49#define FIND_BY_NAME(type) \
50do { \
51 assert(list); \
52 assert(name); \
53 list_foreach(*list, it) { \
54 audio_ ## type ## _t *dev = \
55 audio_ ## type ## _list_instance(it); \
56 if (str_cmp(name, dev->name) == 0) { \
57 log_debug("%s with name '%s' is in the list", \
58 #type, name); \
59 return dev; \
60 } \
61 } \
62 return NULL; \
63} while (0)
64
65static audio_device_t * find_device_by_name(list_t *list, const char *name)
66{
67 FIND_BY_NAME(device);
68}
69static audio_source_t * find_source_by_name(list_t *list, const char *name)
70{
71 FIND_BY_NAME(source);
72}
73static audio_sink_t * find_sink_by_name(list_t *list, const char *name)
74{
75 FIND_BY_NAME(sink);
76}
77
78static int hound_disconnect_internal(hound_t *hound, const char* source_name, const char* sink_name);
79
80int hound_init(hound_t *hound)
81{
82 assert(hound);
83 fibril_mutex_initialize(&hound->list_guard);
84 list_initialize(&hound->devices);
85 list_initialize(&hound->contexts);
86 list_initialize(&hound->sources);
87 list_initialize(&hound->sinks);
88 return EOK;
89}
90
91int hound_add_ctx(hound_t *hound, hound_ctx_t *ctx)
92{
93 log_info("Trying to add context %p", ctx);
94 assert(hound);
95 if (!ctx)
96 return EINVAL;
97 list_append(&ctx->link, &hound->contexts);
98 //TODO register sinks/sources
99 return EOK;
100}
101
102int hound_remove_ctx(hound_t *hound, hound_ctx_t *ctx)
103{
104 assert(hound);
105 if (!ctx)
106 return EINVAL;
107 list_remove(&ctx->link);
108 return EOK;
109}
110
111hound_ctx_t *hound_get_ctx_by_id(hound_t *hound, hound_context_id_t id)
112{
113 assert(hound);
114
115 //TODO locking
116
117 list_foreach(hound->contexts, it) {
118 hound_ctx_t *ctx = hound_ctx_from_link(it);
119 if (hound_ctx_get_id(ctx) == id)
120 return ctx;
121 }
122 return NULL;
123}
124
125int hound_add_device(hound_t *hound, service_id_t id, const char *name)
126{
127 log_verbose("Adding device \"%s\", service: %zu", name, id);
128
129 assert(hound);
130 if (!name || !id) {
131 log_debug("Incorrect parameters.");
132 return EINVAL;
133 }
134
135 list_foreach(hound->devices, it) {
136 audio_device_t *dev = audio_device_list_instance(it);
137 if (dev->id == id) {
138 log_debug("Device with id %zu is already present", id);
139 return EEXISTS;
140 }
141 }
142
143 audio_device_t *dev = find_device_by_name(&hound->devices, name);
144 if (dev) {
145 log_debug("Device with name %s is already present", name);
146 return EEXISTS;
147 }
148
149 dev = malloc(sizeof(audio_device_t));
150 if (!dev) {
151 log_debug("Failed to malloc device structure.");
152 return ENOMEM;
153 }
154
155 const int ret = audio_device_init(dev, id, name);
156 if (ret != EOK) {
157 log_debug("Failed to initialize new audio device: %s",
158 str_error(ret));
159 free(dev);
160 return ret;
161 }
162
163 list_append(&dev->link, &hound->devices);
164 log_info("Added new device: '%s'", dev->name);
165
166 audio_source_t *source = audio_device_get_source(dev);
167 if (source) {
168 const int ret = hound_add_source(hound, source);
169 if (ret != EOK) {
170 log_debug("Failed to add device source: %s",
171 str_error(ret));
172 audio_device_fini(dev);
173 return ret;
174 }
175 log_verbose("Added source: '%s'.", source->name);
176 }
177
178 audio_sink_t *sink = audio_device_get_sink(dev);
179 if (sink) {
180 const int ret = hound_add_sink(hound, sink);
181 if (ret != EOK) {
182 log_debug("Failed to add device sink: %s",
183 str_error(ret));
184 audio_device_fini(dev);
185 return ret;
186 }
187 log_verbose("Added sink: '%s'.", sink->name);
188 }
189
190 if (!source && !sink)
191 log_warning("Neither sink nor source on device '%s'.", name);
192
193 return ret;
194}
195
196int hound_add_source(hound_t *hound, audio_source_t *source)
197{
198 assert(hound);
199 if (!source || !source->name || str_cmp(source->name, "default") == 0) {
200 log_debug("Invalid source specified.");
201 return EINVAL;
202 }
203 fibril_mutex_lock(&hound->list_guard);
204 if (find_source_by_name(&hound->sources, source->name)) {
205 log_debug("Source by that name already exists");
206 fibril_mutex_unlock(&hound->list_guard);
207 return EEXISTS;
208 }
209 list_foreach(hound->sinks, it) {
210 audio_sink_t *sink = audio_sink_list_instance(it);
211 if (find_source_by_name(&sink->sources, source->name)) {
212 log_debug("Source by that name already exists");
213 fibril_mutex_unlock(&hound->list_guard);
214 return EEXISTS;
215 }
216 }
217 list_append(&source->link, &hound->sources);
218 fibril_mutex_unlock(&hound->list_guard);
219 return EOK;
220}
221
222int hound_add_sink(hound_t *hound, audio_sink_t *sink)
223{
224 assert(hound);
225 if (!sink || !sink->name || str_cmp(sink->name, "default") == 0) {
226 log_debug("Invalid source specified.");
227 return EINVAL;
228 }
229 fibril_mutex_lock(&hound->list_guard);
230 if (find_sink_by_name(&hound->sinks, sink->name)) {
231 log_debug("Sink by that name already exists");
232 fibril_mutex_unlock(&hound->list_guard);
233 return EEXISTS;
234 }
235 list_append(&sink->link, &hound->sinks);
236 fibril_mutex_unlock(&hound->list_guard);
237 return EOK;
238}
239
240int hound_remove_source(hound_t *hound, audio_source_t *source)
241{
242 assert(hound);
243 if (!source)
244 return EINVAL;
245 log_verbose("Removing source '%s'.", source->name);
246 fibril_mutex_lock(&hound->list_guard);
247 if (!list_member(&source->link, &hound->sources)) {
248 assert(source->connected_sink);
249 hound_disconnect_internal(hound, source->name,
250 source->connected_sink->name);
251 }
252 list_remove(&source->link);
253 fibril_mutex_unlock(&hound->list_guard);
254 return EOK;
255}
256
257int hound_remove_sink(hound_t *hound, audio_sink_t *sink)
258{
259 assert(hound);
260 if (!sink)
261 return EINVAL;
262 log_verbose("Removing sink '%s'.", sink->name);
263 fibril_mutex_lock(&hound->list_guard);
264
265 if (!list_empty(&sink->sources)) {
266 // TODO disconnect instead
267 fibril_mutex_unlock(&hound->list_guard);
268 return EBUSY;
269 }
270 list_remove(&sink->link);
271 fibril_mutex_unlock(&hound->list_guard);
272 return EOK;
273}
274
275int hound_connect(hound_t *hound, const char* source_name, const char* sink_name)
276{
277 assert(hound);
278 log_verbose("Connecting '%s' to '%s'.", source_name, sink_name);
279 fibril_mutex_lock(&hound->list_guard);
280
281 audio_source_t *source =
282 audio_source_list_instance(list_first(&hound->sources));
283 if (str_cmp(source_name, "default") != 0)
284 source = find_source_by_name(&hound->sources, source_name);
285
286 audio_sink_t *sink =
287 audio_sink_list_instance(list_first(&hound->sinks));
288 if (str_cmp(sink_name, "default") != 0)
289 sink = find_sink_by_name(&hound->sinks, sink_name);
290
291 if (!source || !sink) {
292 fibril_mutex_unlock(&hound->list_guard);
293 log_debug("Source (%p), or sink (%p) not found", source, sink);
294 return ENOENT;
295 }
296 list_remove(&source->link);
297 const int ret = audio_sink_add_source(sink, source);
298 if (ret != EOK) {
299 log_debug("Failed add source to sink list: %s", str_error(ret));
300 list_append(&source->link, &hound->sources);
301 }
302 fibril_mutex_unlock(&hound->list_guard);
303 return EOK;
304}
305
306int hound_disconnect(hound_t *hound, const char* source_name, const char* sink_name)
307{
308 assert(hound);
309 fibril_mutex_lock(&hound->list_guard);
310 const int ret = hound_disconnect_internal(hound, source_name, sink_name);
311 fibril_mutex_unlock(&hound->list_guard);
312 return ret;
313}
314
315static int hound_disconnect_internal(hound_t *hound, const char* source_name, const char* sink_name)
316{
317 assert(hound);
318 assert(fibril_mutex_is_locked(&hound->list_guard));
319 log_verbose("Disconnecting '%s' to '%s'.", source_name, sink_name);
320
321 audio_sink_t *sink =
322 audio_sink_list_instance(list_first(&hound->sinks));
323 if (str_cmp(sink_name, "default") != 0)
324 sink = find_sink_by_name(&hound->sinks, sink_name);
325
326 audio_source_t *source =
327 audio_source_list_instance(list_first(&hound->sources));
328 if (str_cmp(source_name, "default") != 0)
329 source = sink ? find_source_by_name(&sink->sources, source_name) : NULL;
330 if (!source || !sink) {
331 log_debug("Source (%p), or sink (%p) not found", source, sink);
332 return ENOENT;
333 }
334 const int ret = audio_sink_remove_source(sink, source);
335 if (ret != EOK) {
336 log_debug("Failed remove source to sink list: %s", str_error(ret));
337 } else {
338 list_append(&source->link, &hound->sources);
339 }
340 return EOK;
341}
342/**
343 * @}
344 */
Note: See TracBrowser for help on using the repository browser.