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

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

libhound: implement drain_on_exit on the client side

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