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
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/** @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
44#include "protocol.h"
45#include "client.h"
46
47/***
48 * CLIENT SIDE
49 ***/
50
51typedef struct hound_stream {
52 link_t link;
53 pcm_format_t format;
54 async_exch_t *exch;
55 hound_context_t *context;
56} hound_stream_t;
57
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
63typedef struct hound_context {
64 hound_sess_t *session;
65 const char *name;
66 bool record;
67 list_t stream_list;
68 struct {
69 hound_stream_t *stream;
70 pcm_format_t format;
71 size_t bsize;
72 } main;
73 hound_context_id_t id;
74} hound_context_t;
75
76
77static hound_context_t *hound_context_create(const char *name, bool record,
78 pcm_format_t format, size_t bsize)
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;
91 new_context->session = hound_service_connect(HOUND_SERVICE);
92 new_context->main.stream = NULL;
93 new_context->main.format = format;
94 new_context->main.bsize = bsize;
95 if (!new_context->session) {
96 free(new_context->name);
97 free(new_context);
98 return NULL;
99 }
100 new_context->id = hound_service_register_context(
101 new_context->session, new_context->name, record);
102 if (hound_context_id_err(new_context->id) != EOK) {
103 hound_service_disconnect(new_context->session);
104 free(new_context->name);
105 free(new_context);
106 return NULL;
107 }
108 }
109 return new_context;
110}
111
112hound_context_t * hound_context_create_playback(const char *name,
113 pcm_format_t format, size_t bsize)
114{
115 return hound_context_create(name, false, format, bsize);
116}
117
118hound_context_t * hound_context_create_capture(const char *name,
119 pcm_format_t format, size_t bsize)
120{
121 return hound_context_create(name, true, format, bsize);
122}
123
124void hound_context_destroy(hound_context_t *hound)
125{
126 assert(hound);
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
134 hound_service_unregister_context(hound->session, hound->id);
135 hound_service_disconnect(hound->session);
136 free(hound->name);
137 free(hound);
138}
139
140int hound_context_get_available_targets(hound_context_t *hound,
141 const char ***names, size_t *count)
142{
143 assert(hound);
144 assert(names);
145 assert(count);
146 return hound_service_get_list_all(hound->session, names, count,
147 hound->record ? HOUND_SOURCE_DEVS : HOUND_SINK_DEVS);
148}
149
150int hound_context_get_connected_targets(hound_context_t *hound,
151 const char ***names, size_t *count)
152{
153 assert(hound);
154 assert(names);
155 assert(count);
156 return hound_service_get_list(hound->session, names, count,
157 HOUND_CONNECTED | (hound->record ?
158 HOUND_SOURCE_DEVS : HOUND_SINK_DEVS), hound->name);
159}
160
161int hound_context_connect_target(hound_context_t *hound, const char* target)
162{
163 assert(hound);
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(
179 hound->session, target, hound->name);
180 } else {
181 ret = hound_service_connect_source_sink(
182 hound->session, hound->name, target);
183 }
184 if (tgt)
185 free(tgt[0]);
186 free(tgt);
187 return ret;
188}
189
190int hound_context_disconnect_target(hound_context_t *hound, const char* target)
191{
192 assert(hound);
193 assert(target);
194 //TODO handle all-targets
195 if (hound->record) {
196 return hound_service_disconnect_source_sink(
197 hound->session, target, hound->name);
198 } else {
199 return hound_service_disconnect_source_sink(
200 hound->session, hound->name, target);
201 }
202}
203
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;
217 const int ret = hound_service_stream_enter(new_stream->exch,
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
265int hound_write_main_stream(hound_context_t *hound,
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
284int hound_write_replace_main_stream(hound_context_t *hound,
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
318
319/**
320 * @}
321 */
Note: See TracBrowser for help on using the repository browser.