source: mainline/uspace/srv/audio/hound/hound.c@ 6da3baec

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

hound: fix ctx removal.

warn if still connected

  • Property mode set to 100644
File size: 11.9 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 "connection.h"
46#include "log.h"
47#include "errno.h"
48#include "str_error.h"
49
50#define FIND_BY_NAME(type) \
51do { \
52 assert(list); \
53 assert(name); \
54 list_foreach(*list, it) { \
55 audio_ ## type ## _t *dev = \
56 audio_ ## type ## _list_instance(it); \
57 if (str_cmp(name, dev->name) == 0) { \
58 log_debug("%s with name '%s' is in the list", \
59 #type, name); \
60 return dev; \
61 } \
62 } \
63 return NULL; \
64} while (0)
65
66static audio_device_t * find_device_by_name(list_t *list, const char *name)
67{
68 FIND_BY_NAME(device);
69}
70static audio_source_t * find_source_by_name(list_t *list, const char *name)
71{
72 FIND_BY_NAME(source);
73}
74static audio_sink_t * find_sink_by_name(list_t *list, const char *name)
75{
76 FIND_BY_NAME(sink);
77}
78
79static int hound_disconnect_internal(hound_t *hound, const char* source_name, const char* sink_name);
80
81static void hound_remove_sink_internal(hound_t *hound, audio_sink_t *sink)
82{
83 assert(hound);
84 assert(sink);
85 log_verbose("Removing sink '%s'.", sink->name);
86 if (!list_empty(&sink->connections))
87 log_warning("Removing sink '%s' while still connected.", sink->name);
88 while (!list_empty(&sink->connections)) {
89 connection_t *conn =
90 connection_from_sink_list(list_first(&sink->connections));
91 list_remove(&conn->hound_link);
92 connection_destroy(conn);
93 }
94 list_remove(&sink->link);
95}
96
97static void hound_remove_source_internal(hound_t *hound, audio_source_t *source)
98{
99 assert(hound);
100 assert(source);
101 log_verbose("Removing source '%s'.", source->name);
102 if (!list_empty(&source->connections))
103 log_warning("Removing source '%s' while still connected.", source->name);
104 while (!list_empty(&source->connections)) {
105 connection_t *conn =
106 connection_from_source_list(list_first(&source->connections));
107 assert(conn);
108 list_remove(&conn->hound_link);
109 connection_destroy(conn);
110 }
111 list_remove(&source->link);
112}
113
114int hound_init(hound_t *hound)
115{
116 assert(hound);
117 fibril_mutex_initialize(&hound->list_guard);
118 list_initialize(&hound->devices);
119 list_initialize(&hound->contexts);
120 list_initialize(&hound->sources);
121 list_initialize(&hound->sinks);
122 list_initialize(&hound->connections);
123 return EOK;
124}
125
126int hound_add_ctx(hound_t *hound, hound_ctx_t *ctx)
127{
128 log_info("Trying to add context %p", ctx);
129 assert(hound);
130 if (!ctx)
131 return EINVAL;
132 fibril_mutex_lock(&hound->list_guard);
133 list_append(&ctx->link, &hound->contexts);
134 fibril_mutex_unlock(&hound->list_guard);
135 int ret = EOK;
136 if (ret == EOK && ctx->source)
137 ret = hound_add_source(hound, ctx->source);
138 if (ret == EOK && ctx->sink)
139 ret = hound_add_sink(hound, ctx->sink);
140 if (ret != EOK)
141 hound_ctx_destroy(ctx);
142 return ret;
143}
144
145int hound_remove_ctx(hound_t *hound, hound_ctx_t *ctx)
146{
147 assert(hound);
148 if (!ctx)
149 return EINVAL;
150 fibril_mutex_lock(&hound->list_guard);
151 list_remove(&ctx->link);
152 if (ctx->source)
153 hound_remove_source_internal(hound, ctx->source);
154 if (ctx->sink)
155 hound_remove_sink_internal(hound, ctx->sink);
156 fibril_mutex_unlock(&hound->list_guard);
157 return EOK;
158}
159
160hound_ctx_t *hound_get_ctx_by_id(hound_t *hound, hound_context_id_t id)
161{
162 assert(hound);
163
164 fibril_mutex_lock(&hound->list_guard);
165 hound_ctx_t *res = NULL;
166 list_foreach(hound->contexts, it) {
167 hound_ctx_t *ctx = hound_ctx_from_link(it);
168 if (hound_ctx_get_id(ctx) == id) {
169 res = ctx;
170 break;
171 }
172 }
173 fibril_mutex_unlock(&hound->list_guard);
174 return res;
175}
176
177int hound_add_device(hound_t *hound, service_id_t id, const char *name)
178{
179 log_verbose("Adding device \"%s\", service: %zu", name, id);
180
181 assert(hound);
182 if (!name || !id) {
183 log_debug("Incorrect parameters.");
184 return EINVAL;
185 }
186
187 list_foreach(hound->devices, it) {
188 audio_device_t *dev = audio_device_list_instance(it);
189 if (dev->id == id) {
190 log_debug("Device with id %zu is already present", id);
191 return EEXISTS;
192 }
193 }
194
195 audio_device_t *dev = find_device_by_name(&hound->devices, name);
196 if (dev) {
197 log_debug("Device with name %s is already present", name);
198 return EEXISTS;
199 }
200
201 dev = malloc(sizeof(audio_device_t));
202 if (!dev) {
203 log_debug("Failed to malloc device structure.");
204 return ENOMEM;
205 }
206
207 const int ret = audio_device_init(dev, id, name);
208 if (ret != EOK) {
209 log_debug("Failed to initialize new audio device: %s",
210 str_error(ret));
211 free(dev);
212 return ret;
213 }
214
215 list_append(&dev->link, &hound->devices);
216 log_info("Added new device: '%s'", dev->name);
217
218 audio_source_t *source = audio_device_get_source(dev);
219 if (source) {
220 const int ret = hound_add_source(hound, source);
221 if (ret != EOK) {
222 log_debug("Failed to add device source: %s",
223 str_error(ret));
224 audio_device_fini(dev);
225 return ret;
226 }
227 log_verbose("Added source: '%s'.", source->name);
228 }
229
230 audio_sink_t *sink = audio_device_get_sink(dev);
231 if (sink) {
232 const int ret = hound_add_sink(hound, sink);
233 if (ret != EOK) {
234 log_debug("Failed to add device sink: %s",
235 str_error(ret));
236 audio_device_fini(dev);
237 return ret;
238 }
239 log_verbose("Added sink: '%s'.", sink->name);
240 }
241
242 if (!source && !sink)
243 log_warning("Neither sink nor source on device '%s'.", name);
244
245 return ret;
246}
247
248int hound_add_source(hound_t *hound, audio_source_t *source)
249{
250 assert(hound);
251 if (!source || !source->name || str_cmp(source->name, "default") == 0) {
252 log_debug("Invalid source specified.");
253 return EINVAL;
254 }
255 fibril_mutex_lock(&hound->list_guard);
256 if (find_source_by_name(&hound->sources, source->name)) {
257 log_debug("Source by that name already exists");
258 fibril_mutex_unlock(&hound->list_guard);
259 return EEXISTS;
260 }
261 list_append(&source->link, &hound->sources);
262 fibril_mutex_unlock(&hound->list_guard);
263 return EOK;
264}
265
266int hound_add_sink(hound_t *hound, audio_sink_t *sink)
267{
268 assert(hound);
269 if (!sink || !sink->name || str_cmp(sink->name, "default") == 0) {
270 log_debug("Invalid source specified.");
271 return EINVAL;
272 }
273 fibril_mutex_lock(&hound->list_guard);
274 if (find_sink_by_name(&hound->sinks, sink->name)) {
275 log_debug("Sink by that name already exists");
276 fibril_mutex_unlock(&hound->list_guard);
277 return EEXISTS;
278 }
279 list_append(&sink->link, &hound->sinks);
280 fibril_mutex_unlock(&hound->list_guard);
281 return EOK;
282}
283
284int hound_remove_source(hound_t *hound, audio_source_t *source)
285{
286 assert(hound);
287 if (!source)
288 return EINVAL;
289 fibril_mutex_lock(&hound->list_guard);
290 hound_remove_source_internal(hound, source);
291 fibril_mutex_unlock(&hound->list_guard);
292 return EOK;
293}
294
295
296int hound_remove_sink(hound_t *hound, audio_sink_t *sink)
297{
298 assert(hound);
299 if (!sink)
300 return EINVAL;
301 fibril_mutex_lock(&hound->list_guard);
302 hound_remove_sink_internal(hound, sink);
303 fibril_mutex_unlock(&hound->list_guard);
304 return EOK;
305}
306
307int hound_list_sources(hound_t *hound, const char ***list, size_t *size)
308{
309 assert(hound);
310 if (!list || !size)
311 return EINVAL;
312
313 fibril_mutex_lock(&hound->list_guard);
314 const size_t count = list_count(&hound->sources);
315 if (count == 0) {
316 *list = NULL;
317 *size = 0;
318 fibril_mutex_unlock(&hound->list_guard);
319 return EOK;
320 }
321 const char **names = calloc(count, sizeof(char *));
322 int ret = names ? EOK : ENOMEM;
323 for (size_t i = 0; i < count && ret == EOK; ++i) {
324 link_t *slink = list_nth(&hound->sources, i);
325 audio_source_t *source = audio_source_list_instance(slink);
326 names[i] = str_dup(source->name);
327 if (names[i])
328 ret = ENOMEM;
329 }
330 if (ret == EOK) {
331 *size = count;
332 *list = names;
333 } else {
334 for (size_t i = 0; i < count; ++i)
335 free(names[i]);
336 free(names);
337 }
338 fibril_mutex_unlock(&hound->list_guard);
339 return ret;
340}
341
342int hound_list_sinks(hound_t *hound, const char ***list, size_t *size)
343{
344 assert(hound);
345 if (!list || !size)
346 return EINVAL;
347
348 fibril_mutex_lock(&hound->list_guard);
349 const size_t count = list_count(&hound->sinks);
350 if (count == 0) {
351 *list = NULL;
352 *size = 0;
353 fibril_mutex_unlock(&hound->list_guard);
354 return EOK;
355 }
356 const char **names = calloc(count, sizeof(char *));
357 int ret = names ? EOK : ENOMEM;
358 for (size_t i = 0; i < count && ret == EOK; ++i) {
359 link_t *slink = list_nth(&hound->sinks, i);
360 audio_sink_t *sink = audio_sink_list_instance(slink);
361 names[i] = str_dup(sink->name);
362 if (!names[i])
363 ret = ENOMEM;
364 }
365 if (ret == EOK) {
366 *size = count;
367 *list = names;
368 } else {
369 for (size_t i = 0; i < count; ++i)
370 free(names[i]);
371 free(names);
372 }
373 fibril_mutex_unlock(&hound->list_guard);
374 return ret;
375}
376
377int hound_list_connections(hound_t *hound, const char ***sources,
378 const char ***sinks, size_t *size)
379{
380 fibril_mutex_lock(&hound->list_guard);
381 fibril_mutex_unlock(&hound->list_guard);
382 return ENOTSUP;
383}
384
385int hound_connect(hound_t *hound, const char* source_name, const char* sink_name)
386{
387 assert(hound);
388 log_verbose("Connecting '%s' to '%s'.", source_name, sink_name);
389 fibril_mutex_lock(&hound->list_guard);
390
391 audio_source_t *source =
392 audio_source_list_instance(list_first(&hound->sources));
393 if (str_cmp(source_name, "default") != 0)
394 source = find_source_by_name(&hound->sources, source_name);
395
396 audio_sink_t *sink =
397 audio_sink_list_instance(list_first(&hound->sinks));
398 if (str_cmp(sink_name, "default") != 0)
399 sink = find_sink_by_name(&hound->sinks, sink_name);
400
401 if (!source || !sink) {
402 fibril_mutex_unlock(&hound->list_guard);
403 log_debug("Source (%p), or sink (%p) not found", source, sink);
404 return ENOENT;
405 }
406 connection_t *conn = connection_create(source, sink);
407 if (!conn) {
408 fibril_mutex_unlock(&hound->list_guard);
409 log_debug("Failed to create connection");
410 return ENOMEM;
411 }
412 list_append(&conn->hound_link, &hound->connections);
413 fibril_mutex_unlock(&hound->list_guard);
414 return EOK;
415}
416
417int hound_disconnect(hound_t *hound, const char* source_name, const char* sink_name)
418{
419 assert(hound);
420 fibril_mutex_lock(&hound->list_guard);
421 const int ret = hound_disconnect_internal(hound, source_name, sink_name);
422 fibril_mutex_unlock(&hound->list_guard);
423 return ret;
424}
425
426static int hound_disconnect_internal(hound_t *hound, const char* source_name,
427 const char* sink_name)
428{
429 assert(hound);
430 assert(fibril_mutex_is_locked(&hound->list_guard));
431 log_debug("Disconnecting '%s' to '%s'.", source_name, sink_name);
432
433 list_foreach_safe(hound->connections, it, next) {
434 connection_t *conn = connection_from_hound_list(it);
435 if (str_cmp(connection_source_name(conn), source_name) == 0 ||
436 str_cmp(connection_sink_name(conn), sink_name) == 0) {
437 log_debug("Removing %s -> %s", connection_source_name(conn),
438 connection_sink_name(conn));
439 list_remove(it);
440 connection_destroy(conn);
441 }
442 }
443
444 return EOK;
445}
446/**
447 * @}
448 */
Note: See TracBrowser for help on using the repository browser.