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

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

Fix printf compile issues

  • Property mode set to 100644
File size: 13.6 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>
[e5bc912]38#include <inttypes.h>
[36774cf]39#include <loc.h>
40#include <str.h>
41#include <stdlib.h>
42#include <stdio.h>
43#include <libarch/types.h>
44
[059490c2]45#include "protocol.h"
[9e1800c]46#include "client.h"
[36774cf]47
[876f5561]48/** Stream structure */
[36774cf]49typedef struct hound_stream {
[876f5561]50 /** link in context's list */
[36774cf]51 link_t link;
[876f5561]52 /** audio data format fo the stream */
[9e1800c]53 pcm_format_t format;
[876f5561]54 /** IPC exchange representing the stream (in STREAM MODE) */
[36774cf]55 async_exch_t *exch;
[876f5561]56 /** parent context */
[9e1800c]57 hound_context_t *context;
[876f5561]58 /** Stream flags */
[c5d6f9cf]59 int flags;
[36774cf]60} hound_stream_t;
61
[876f5561]62/**
63 * Linked list isntacen helper function.
64 * @param l link
65 * @return hound stream isntance.
66 */
[cc3c27ad]67static inline hound_stream_t * hound_stream_from_link(link_t *l)
68{
69 return l ? list_get_instance(l, hound_stream_t, link) : NULL;
70}
71
[876f5561]72/** Hound client context structure */
[36774cf]73typedef struct hound_context {
[876f5561]74 /** Audio session */
[059490c2]75 hound_sess_t *session;
[876f5561]76 /** context name, reported to the daemon */
[36774cf]77 const char *name;
[876f5561]78 /** True if the instance is record context */
[36774cf]79 bool record;
[876f5561]80 /** List of associated streams */
[36774cf]81 list_t stream_list;
[876f5561]82 /** Main stream helper structure */
[36774cf]83 struct {
[9e1800c]84 hound_stream_t *stream;
85 pcm_format_t format;
[36774cf]86 size_t bsize;
[9e1800c]87 } main;
[876f5561]88 /** Assigned context id */
[9e1800c]89 hound_context_id_t id;
[36774cf]90} hound_context_t;
91
[876f5561]92/**
93 * Alloc and initialize context structure.
94 * @param name Base for the real context name, will add task id.
95 * @param record True if the new context should capture audio data.
96 * @param format PCM format of the main pipe.
97 * @param bsize Server size buffer size of the main stream.
98 * @return valid pointer to initialized structure on success, NULL on failure
99 */
[36774cf]100static hound_context_t *hound_context_create(const char *name, bool record,
[9e1800c]101 pcm_format_t format, size_t bsize)
[36774cf]102{
103 hound_context_t *new_context = malloc(sizeof(hound_context_t));
104 if (new_context) {
105 char *cont_name;
[e5bc912]106 int ret = asprintf(&cont_name, "%" PRIu64 ":%s",
107 task_get_id(), name);
[36774cf]108 if (ret < 0) {
109 free(new_context);
110 return NULL;
111 }
112 list_initialize(&new_context->stream_list);
113 new_context->name = cont_name;
114 new_context->record = record;
[059490c2]115 new_context->session = hound_service_connect(HOUND_SERVICE);
[9e1800c]116 new_context->main.stream = NULL;
117 new_context->main.format = format;
118 new_context->main.bsize = bsize;
[36774cf]119 if (!new_context->session) {
120 free(new_context->name);
121 free(new_context);
122 return NULL;
123 }
[9e1800c]124 new_context->id = hound_service_register_context(
[493817b0]125 new_context->session, new_context->name, record);
[7294b5b]126 if (hound_context_id_err(new_context->id) != EOK) {
[2ba4d45c]127 hound_service_disconnect(new_context->session);
[9e1800c]128 free(new_context->name);
129 free(new_context);
130 return NULL;
131 }
[36774cf]132 }
133 return new_context;
134}
135
[876f5561]136/**
137 * Playback context helper function.
138 * @param name Base for the real context name, will add task id.
139 * @param format PCM format of the main pipe.
140 * @param bsize Server size buffer size of the main stream.
141 * @return valid pointer to initialized structure on success, NULL on failure
142 */
[36774cf]143hound_context_t * hound_context_create_playback(const char *name,
[9e1800c]144 pcm_format_t format, size_t bsize)
[36774cf]145{
[9e1800c]146 return hound_context_create(name, false, format, bsize);
[36774cf]147}
148
[876f5561]149/**
150 * Record context helper function.
151 * @param name Base for the real context name, will add task id.
152 * @param format PCM format of the main pipe.
153 * @param bsize Server size buffer size of the main stream.
154 * @return valid pointer to initialized structure on success, NULL on failure
155 */
[36774cf]156hound_context_t * hound_context_create_capture(const char *name,
[9e1800c]157 pcm_format_t format, size_t bsize)
[36774cf]158{
[9e1800c]159 return hound_context_create(name, true, format, bsize);
[36774cf]160}
161
[876f5561]162/**
163 * Correctly dispose of the hound context structure.
164 * @param hound context to remove.
165 *
166 * The function will destroy all associated streams first. Pointers
167 * to these structures will become invalid and the function will block
168 * if any of these stream needs to be drained first.
169 */
[36774cf]170void hound_context_destroy(hound_context_t *hound)
171{
172 assert(hound);
[cc3c27ad]173
174 while (!list_empty(&hound->stream_list)) {
175 link_t *first = list_first(&hound->stream_list);
176 hound_stream_t *stream = hound_stream_from_link(first);
177 hound_stream_destroy(stream);
178 }
179
[9e1800c]180 hound_service_unregister_context(hound->session, hound->id);
181 hound_service_disconnect(hound->session);
182 free(hound->name);
183 free(hound);
[36774cf]184}
185
[876f5561]186/**
187 * Get a list of possible connection targets.
188 * @param[in] hound Hound context.
189 * @param[out] names list of target string ids.
190 * @param[out] count Number of elements in @p names list
191 * @return Error code.
192 *
193 * The function will return deice sinks or source based on the context type.
194 */
[7294b5b]195int hound_context_get_available_targets(hound_context_t *hound,
196 const char ***names, size_t *count)
[36774cf]197{
[7294b5b]198 assert(hound);
[36774cf]199 assert(names);
200 assert(count);
[7294b5b]201 return hound_service_get_list_all(hound->session, names, count,
202 hound->record ? HOUND_SOURCE_DEVS : HOUND_SINK_DEVS);
[36774cf]203}
204
[876f5561]205/**
206 * Get a list of targets connected to the context.
207 * @param[in] hound Hound context.
208 * @param[out] names list of target string ids.
209 * @param[out] count Number of elements in @p names list
210 * @return Error code.
211 */
[7294b5b]212int hound_context_get_connected_targets(hound_context_t *hound,
213 const char ***names, size_t *count)
[36774cf]214{
[7294b5b]215 assert(hound);
[36774cf]216 assert(names);
217 assert(count);
[7294b5b]218 return hound_service_get_list(hound->session, names, count,
219 HOUND_CONNECTED | (hound->record ?
220 HOUND_SOURCE_DEVS : HOUND_SINK_DEVS), hound->name);
[36774cf]221}
222
[876f5561]223/**
224 * Create a new connection to the target.
225 * @param hound Hound context.
226 * @param target String identifier of the desired target.
227 * @return Error code.
228 *
229 * The function recognizes special 'HOUND_DEFAULT_TARGET' and will
230 * connect to the first possible target if it is passed this value.
231 */
[36774cf]232int hound_context_connect_target(hound_context_t *hound, const char* target)
233{
234 assert(hound);
[ec81221]235 assert(target);
236
237 const char **tgt = NULL;
238 size_t count = 1;
239 int ret = EOK;
240 if (str_cmp(target, HOUND_DEFAULT_TARGET) == 0) {
241 ret = hound_context_get_available_targets(hound, &tgt, &count);
242 if (ret != EOK)
243 return ret;
244 target = tgt[0];
245 }
246 //TODO handle all-targets
247
248 if (hound->record) {
249 ret = hound_service_connect_source_sink(
[7294b5b]250 hound->session, target, hound->name);
[ec81221]251 } else {
252 ret = hound_service_connect_source_sink(
[7294b5b]253 hound->session, hound->name, target);
[ec81221]254 }
255 if (tgt)
256 free(tgt[0]);
257 free(tgt);
258 return ret;
[36774cf]259}
260
[876f5561]261/**
262 * Destroy a connection to the target.
263 * @param hound Hound context.
264 * @param target String identifier of the desired target.
265 * @return Error code.
266 */
[36774cf]267int hound_context_disconnect_target(hound_context_t *hound, const char* target)
268{
269 assert(hound);
[ec81221]270 assert(target);
[2ba4d45c]271 //TODO handle all-targets
[ec81221]272 if (hound->record) {
[7294b5b]273 return hound_service_disconnect_source_sink(
274 hound->session, target, hound->name);
[ec81221]275 } else {
[7294b5b]276 return hound_service_disconnect_source_sink(
277 hound->session, hound->name, target);
[ec81221]278 }
[36774cf]279}
280
[876f5561]281/**
282 * Create a new stream associated with the context.
283 * @param hound Hound context.
284 * @param flags new stream flags.
285 * @param format new stream PCM format.
286 * @param bzise new stream server side buffer size (in bytes)
287 * @return Valid pointer to a stream instance, NULL on failure.
288 */
[9e1800c]289hound_stream_t *hound_stream_create(hound_context_t *hound, unsigned flags,
290 pcm_format_t format, size_t bsize)
291{
292 assert(hound);
293 async_exch_t *stream_exch = async_exchange_begin(hound->session);
294 if (!stream_exch)
295 return NULL;
296 hound_stream_t *new_stream = malloc(sizeof(hound_stream_t));
297 if (new_stream) {
298 link_initialize(&new_stream->link);
299 new_stream->exch = stream_exch;
300 new_stream->format = format;
301 new_stream->context = hound;
[c5d6f9cf]302 new_stream->flags = flags;
[5bf4310]303 const int ret = hound_service_stream_enter(new_stream->exch,
[9e1800c]304 hound->id, flags, format, bsize);
305 if (ret != EOK) {
306 async_exchange_end(new_stream->exch);
307 free(new_stream);
308 return NULL;
309 }
310 list_append(&new_stream->link, &hound->stream_list);
311 }
312 return new_stream;
313}
314
[876f5561]315/**
316 * Destroy existing stream
317 * @param stream The stream to destroy.
318 *
319 * Function will wait until the server side buffer is empty if the
320 * HOUND_STREAM_DRAIN_ON_EXIT flag was set on creation.
321 */
[9e1800c]322void hound_stream_destroy(hound_stream_t *stream)
323{
324 if (stream) {
[c5d6f9cf]325 if (stream->flags & HOUND_STREAM_DRAIN_ON_EXIT)
326 hound_service_stream_drain(stream->exch);
[9e1800c]327 hound_service_stream_exit(stream->exch);
328 async_exchange_end(stream->exch);
329 list_remove(&stream->link);
330 free(stream);
331 }
332}
333
[876f5561]334/**
335 * Send new data to a stream.
336 * @param stream The target stream
337 * @param data data buffer
338 * @param size size of the @p data buffer.
339 * @return error code.
340 */
[9e1800c]341int hound_stream_write(hound_stream_t *stream, const void *data, size_t size)
342{
343 assert(stream);
344 if (!data || size == 0)
345 return EBADMEM;
346 return hound_service_stream_write(stream->exch, data, size);
347}
348
[876f5561]349/**
350 * Get data from a stream.
351 * @param stream The target stream.
352 * @param data data buffer.
353 * @param size size of the @p data buffer.
354 * @return error code.
355 */
[9e1800c]356int hound_stream_read(hound_stream_t *stream, void *data, size_t size)
357{
358 assert(stream);
359 if (!data || size == 0)
360 return EBADMEM;
361 return hound_service_stream_read(stream->exch, data, size);
362}
363
[4e72a4c]364/**
365 * Wait until the server side buffer is empty.
366 * @param stream The stream that shoulod be drained.
367 * @return Error code.
368 */
369int hound_stream_drain(hound_stream_t *stream)
370{
371 assert(stream);
372 return hound_service_stream_drain(stream->exch);
373}
374
[876f5561]375/**
376 * Main stream getter function.
377 * @param hound Houndcontext.
378 * @return Valid stream pointer, NULL on failure.
379 *
380 * The function will create new stream, or return a pointer to the exiting one
381 * if it exists.
382 */
[9e1800c]383static hound_stream_t * hound_get_main_stream(hound_context_t *hound)
384{
385 assert(hound);
386 if (!hound->main.stream)
[c5d6f9cf]387 hound->main.stream = hound_stream_create(hound,
388 HOUND_STREAM_DRAIN_ON_EXIT,hound->main.format,
389 hound->main.bsize);
[9e1800c]390 return hound->main.stream;
391}
392
[876f5561]393/**
394 * Send new data to the main stream.
395 * @param stream The target stream
396 * @param data data buffer
397 * @param size size of the @p data buffer.
398 * @return error code.
399 */
[36774cf]400int hound_write_main_stream(hound_context_t *hound,
[9e1800c]401 const void *data, size_t size)
402{
403 assert(hound);
[876f5561]404 if (hound->record)
405 return EINVAL;
406
[9e1800c]407 hound_stream_t *mstream = hound_get_main_stream(hound);
408 if (!mstream)
409 return ENOMEM;
410 return hound_stream_write(mstream, data, size);
411}
412
[876f5561]413/**
414 * Get data from the main stream.
415 * @param stream The target stream
416 * @param data data buffer
417 * @param size size of the @p data buffer.
418 * @return error code.
419 */
[9e1800c]420int hound_read_main_stream(hound_context_t *hound, void *data, size_t size)
421{
422 assert(hound);
[876f5561]423 if (!hound->record)
424 return EINVAL;
[9e1800c]425 hound_stream_t *mstream = hound_get_main_stream(hound);
426 if (!mstream)
427 return ENOMEM;
428 return hound_stream_read(mstream, data, size);
429}
430
[876f5561]431/**
432 * Destroy the old main stream and replace it with a new one with fresh data.
433 * @param hound Hound context.
434 * @param data data buffer.
435 * @param size size of the @p data buffer.
436 * @return error code.
437 *
438 * NOT IMPLEMENTED
439 */
[36774cf]440int hound_write_replace_main_stream(hound_context_t *hound,
[9e1800c]441 const void *data, size_t size)
442{
443 assert(hound);
444 if (!data || size == 0)
445 return EBADMEM;
446 // TODO implement
447 return ENOTSUP;
448}
449
[876f5561]450/**
451 * Destroy the old main stream and replace it with a new one using new params.
452 * @param hound Hound context.
453 * @param channels
454 * @return error code.
455 *
456 * NOT IMPLEMENTED
457 */
458int hound_context_set_main_stream_params(hound_context_t *hound,
459 pcm_format_t format, size_t bsize)
[9e1800c]460{
461 assert(hound);
462 // TODO implement
463 return ENOTSUP;
464}
465
[876f5561]466/**
467 * Write data immediately to a new stream, and wait for it to drain.
468 * @param hound Hound context.
469 * @param format pcm data format.
470 * @param data data buffer
471 * @param size @p data buffer size
472 * @return Error code.
473 *
474 * This functnion creates a new stream writes the data, ti waits for the stream
475 * to drain and destroys it before returning.
476 */
[9e1800c]477int hound_write_immediate(hound_context_t *hound, pcm_format_t format,
478 const void *data, size_t size)
479{
480 assert(hound);
[876f5561]481 if (hound->record)
482 return EINVAL;
[9e1800c]483 hound_stream_t *tmpstream = hound_stream_create(hound, 0, format, size);
484 if (!tmpstream)
485 return ENOMEM;
486 const int ret = hound_stream_write(tmpstream, data, size);
487 if (ret == EOK) {
488 //TODO drain?
489 hound_service_stream_drain(tmpstream->exch);
490 }
491 hound_stream_destroy(tmpstream);
492 return ret;
493}
[36774cf]494/**
495 * @}
496 */
Note: See TracBrowser for help on using the repository browser.