source: mainline/uspace/lib/hound/src/client.c@ 9e40d443

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

libhound: Destroy streams on stream_exit

  • Property mode set to 100644
File size: 8.3 KB
RevLine 
[36774cf]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/** @addtogroup libhound
30 * @addtogroup audio
31 * @{
32 */
33/** @file
34 * Common USB functions.
35 */
36#include <adt/list.h>
37#include <errno.h>
38#include <loc.h>
39#include <str.h>
40#include <stdlib.h>
41#include <stdio.h>
42#include <libarch/types.h>
43
[059490c2]44#include "protocol.h"
[9e1800c]45#include "client.h"
[36774cf]46
47/***
48 * CLIENT SIDE
49 ***/
50
51typedef struct hound_stream {
52 link_t link;
[9e1800c]53 pcm_format_t format;
[36774cf]54 async_exch_t *exch;
[9e1800c]55 hound_context_t *context;
[36774cf]56} hound_stream_t;
57
[cc3c27ad]58static inline hound_stream_t * hound_stream_from_link(link_t *l)
59{
60 return l ? list_get_instance(l, hound_stream_t, link) : NULL;
61}
62
[36774cf]63typedef struct hound_context {
[059490c2]64 hound_sess_t *session;
[36774cf]65 const char *name;
66 bool record;
67 list_t stream_list;
68 struct {
[9e1800c]69 hound_stream_t *stream;
70 pcm_format_t format;
[36774cf]71 size_t bsize;
[9e1800c]72 } main;
73 hound_context_id_t id;
[36774cf]74} hound_context_t;
75
76
77static hound_context_t *hound_context_create(const char *name, bool record,
[9e1800c]78 pcm_format_t format, size_t bsize)
[36774cf]79{
80 hound_context_t *new_context = malloc(sizeof(hound_context_t));
81 if (new_context) {
82 char *cont_name;
83 int ret = asprintf(&cont_name, "%llu:%s", task_get_id(), name);
84 if (ret < 0) {
85 free(new_context);
86 return NULL;
87 }
88 list_initialize(&new_context->stream_list);
89 new_context->name = cont_name;
90 new_context->record = record;
[059490c2]91 new_context->session = hound_service_connect(HOUND_SERVICE);
[9e1800c]92 new_context->main.stream = NULL;
93 new_context->main.format = format;
94 new_context->main.bsize = bsize;
[36774cf]95 if (!new_context->session) {
96 free(new_context->name);
97 free(new_context);
98 return NULL;
99 }
[9e1800c]100 new_context->id = hound_service_register_context(
[493817b0]101 new_context->session, new_context->name, record);
[7294b5b]102 if (hound_context_id_err(new_context->id) != EOK) {
[2ba4d45]103 hound_service_disconnect(new_context->session);
[9e1800c]104 free(new_context->name);
105 free(new_context);
106 return NULL;
107 }
[36774cf]108 }
109 return new_context;
110}
111
112hound_context_t * hound_context_create_playback(const char *name,
[9e1800c]113 pcm_format_t format, size_t bsize)
[36774cf]114{
[9e1800c]115 return hound_context_create(name, false, format, bsize);
[36774cf]116}
117
118hound_context_t * hound_context_create_capture(const char *name,
[9e1800c]119 pcm_format_t format, size_t bsize)
[36774cf]120{
[9e1800c]121 return hound_context_create(name, true, format, bsize);
[36774cf]122}
123
124void hound_context_destroy(hound_context_t *hound)
125{
126 assert(hound);
[cc3c27ad]127
128 while (!list_empty(&hound->stream_list)) {
129 link_t *first = list_first(&hound->stream_list);
130 hound_stream_t *stream = hound_stream_from_link(first);
131 hound_stream_destroy(stream);
132 }
133
[9e1800c]134 hound_service_unregister_context(hound->session, hound->id);
135 hound_service_disconnect(hound->session);
136 free(hound->name);
137 free(hound);
[36774cf]138}
139
[7294b5b]140int hound_context_get_available_targets(hound_context_t *hound,
141 const char ***names, size_t *count)
[36774cf]142{
[7294b5b]143 assert(hound);
[36774cf]144 assert(names);
145 assert(count);
[7294b5b]146 return hound_service_get_list_all(hound->session, names, count,
147 hound->record ? HOUND_SOURCE_DEVS : HOUND_SINK_DEVS);
[36774cf]148}
149
[7294b5b]150int hound_context_get_connected_targets(hound_context_t *hound,
151 const char ***names, size_t *count)
[36774cf]152{
[7294b5b]153 assert(hound);
[36774cf]154 assert(names);
155 assert(count);
[7294b5b]156 return hound_service_get_list(hound->session, names, count,
157 HOUND_CONNECTED | (hound->record ?
158 HOUND_SOURCE_DEVS : HOUND_SINK_DEVS), hound->name);
[36774cf]159}
160
161int hound_context_connect_target(hound_context_t *hound, const char* target)
162{
163 assert(hound);
[ec81221]164 assert(target);
165
166 const char **tgt = NULL;
167 size_t count = 1;
168 int ret = EOK;
169 if (str_cmp(target, HOUND_DEFAULT_TARGET) == 0) {
170 ret = hound_context_get_available_targets(hound, &tgt, &count);
171 if (ret != EOK)
172 return ret;
173 target = tgt[0];
174 }
175 //TODO handle all-targets
176
177 if (hound->record) {
178 ret = hound_service_connect_source_sink(
[7294b5b]179 hound->session, target, hound->name);
[ec81221]180 } else {
181 ret = hound_service_connect_source_sink(
[7294b5b]182 hound->session, hound->name, target);
[ec81221]183 }
184 if (tgt)
185 free(tgt[0]);
186 free(tgt);
187 return ret;
[36774cf]188}
189
190int hound_context_disconnect_target(hound_context_t *hound, const char* target)
191{
192 assert(hound);
[ec81221]193 assert(target);
[2ba4d45]194 //TODO handle all-targets
[ec81221]195 if (hound->record) {
[7294b5b]196 return hound_service_disconnect_source_sink(
197 hound->session, target, hound->name);
[ec81221]198 } else {
[7294b5b]199 return hound_service_disconnect_source_sink(
200 hound->session, hound->name, target);
[ec81221]201 }
[36774cf]202}
203
[9e1800c]204hound_stream_t *hound_stream_create(hound_context_t *hound, unsigned flags,
205 pcm_format_t format, size_t bsize)
206{
207 assert(hound);
208 async_exch_t *stream_exch = async_exchange_begin(hound->session);
209 if (!stream_exch)
210 return NULL;
211 hound_stream_t *new_stream = malloc(sizeof(hound_stream_t));
212 if (new_stream) {
213 link_initialize(&new_stream->link);
214 new_stream->exch = stream_exch;
215 new_stream->format = format;
216 new_stream->context = hound;
[5bf4310]217 const int ret = hound_service_stream_enter(new_stream->exch,
[9e1800c]218 hound->id, flags, format, bsize);
219 if (ret != EOK) {
220 async_exchange_end(new_stream->exch);
221 free(new_stream);
222 return NULL;
223 }
224 list_append(&new_stream->link, &hound->stream_list);
225 }
226 return new_stream;
227}
228
229void hound_stream_destroy(hound_stream_t *stream)
230{
231 if (stream) {
232 // TODO drain?
233 hound_service_stream_exit(stream->exch);
234 async_exchange_end(stream->exch);
235 list_remove(&stream->link);
236 free(stream);
237 }
238}
239
240int hound_stream_write(hound_stream_t *stream, const void *data, size_t size)
241{
242 assert(stream);
243 if (!data || size == 0)
244 return EBADMEM;
245 return hound_service_stream_write(stream->exch, data, size);
246}
247
248int hound_stream_read(hound_stream_t *stream, void *data, size_t size)
249{
250 assert(stream);
251 if (!data || size == 0)
252 return EBADMEM;
253 return hound_service_stream_read(stream->exch, data, size);
254}
255
256static hound_stream_t * hound_get_main_stream(hound_context_t *hound)
257{
258 assert(hound);
259 if (!hound->main.stream)
260 hound->main.stream = hound_stream_create(hound, 0,
261 hound->main.format, hound->main.bsize);
262 return hound->main.stream;
263}
264
[36774cf]265int hound_write_main_stream(hound_context_t *hound,
[9e1800c]266 const void *data, size_t size)
267{
268 assert(hound);
269 hound_stream_t *mstream = hound_get_main_stream(hound);
270 if (!mstream)
271 return ENOMEM;
272 return hound_stream_write(mstream, data, size);
273}
274
275int hound_read_main_stream(hound_context_t *hound, void *data, size_t size)
276{
277 assert(hound);
278 hound_stream_t *mstream = hound_get_main_stream(hound);
279 if (!mstream)
280 return ENOMEM;
281 return hound_stream_read(mstream, data, size);
282}
283
[36774cf]284int hound_write_replace_main_stream(hound_context_t *hound,
[9e1800c]285 const void *data, size_t size)
286{
287 assert(hound);
288 if (!data || size == 0)
289 return EBADMEM;
290 // TODO implement
291 return ENOTSUP;
292}
293
294int hound_context_set_main_stream_format(hound_context_t *hound,
295 unsigned channels, unsigned rate, pcm_sample_format_t format)
296{
297 assert(hound);
298 // TODO implement
299 return ENOTSUP;
300}
301
302int hound_write_immediate(hound_context_t *hound, pcm_format_t format,
303 const void *data, size_t size)
304{
305 assert(hound);
306 hound_stream_t *tmpstream = hound_stream_create(hound, 0, format, size);
307 if (!tmpstream)
308 return ENOMEM;
309 const int ret = hound_stream_write(tmpstream, data, size);
310 if (ret == EOK) {
311 //TODO drain?
312 hound_service_stream_drain(tmpstream->exch);
313 }
314 hound_stream_destroy(tmpstream);
315 return ret;
316}
317
[36774cf]318
319/**
320 * @}
321 */
Note: See TracBrowser for help on using the repository browser.