| 1 | /*
 | 
|---|
| 2 |  * Copyright (c) 2013 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 <errno.h>
 | 
|---|
| 38 | #include <hound/protocol.h>
 | 
|---|
| 39 | #include <inttypes.h>
 | 
|---|
| 40 | 
 | 
|---|
| 41 | #include "hound.h"
 | 
|---|
| 42 | #include "hound_ctx.h"
 | 
|---|
| 43 | #include "log.h"
 | 
|---|
| 44 | 
 | 
|---|
| 45 | static errno_t iface_add_context(void *server, hound_context_id_t *id,
 | 
|---|
| 46 |     const char *name, bool record)
 | 
|---|
| 47 | {
 | 
|---|
| 48 |         assert(server);
 | 
|---|
| 49 |         assert(id);
 | 
|---|
| 50 |         assert(name);
 | 
|---|
| 51 | 
 | 
|---|
| 52 |         hound_ctx_t *ctx = record ? hound_record_ctx_get(name) :
 | 
|---|
| 53 |             hound_playback_ctx_get(name);
 | 
|---|
| 54 |         if (!ctx)
 | 
|---|
| 55 |                 return ENOMEM;
 | 
|---|
| 56 | 
 | 
|---|
| 57 |         const errno_t ret = hound_add_ctx(server, ctx);
 | 
|---|
| 58 |         if (ret != EOK)
 | 
|---|
| 59 |                 hound_ctx_destroy(ctx);
 | 
|---|
| 60 |         else
 | 
|---|
| 61 |                 *id = hound_ctx_get_id(ctx);
 | 
|---|
| 62 |         return ret;
 | 
|---|
| 63 | }
 | 
|---|
| 64 | 
 | 
|---|
| 65 | static errno_t iface_rem_context(void *server, hound_context_id_t id)
 | 
|---|
| 66 | {
 | 
|---|
| 67 |         assert(server);
 | 
|---|
| 68 |         hound_ctx_t *ctx = hound_get_ctx_by_id(server, id);
 | 
|---|
| 69 |         if (!ctx)
 | 
|---|
| 70 |                 return EINVAL;
 | 
|---|
| 71 |         const errno_t ret = hound_remove_ctx(server, ctx);
 | 
|---|
| 72 |         if (ret == EOK) {
 | 
|---|
| 73 |                 hound_ctx_destroy(ctx);
 | 
|---|
| 74 |                 log_info("%s: %p, %p", __FUNCTION__, server, id);
 | 
|---|
| 75 |         }
 | 
|---|
| 76 |         return ret;
 | 
|---|
| 77 | }
 | 
|---|
| 78 | 
 | 
|---|
| 79 | static bool iface_is_record_context(void *server, hound_context_id_t id)
 | 
|---|
| 80 | {
 | 
|---|
| 81 |         assert(server);
 | 
|---|
| 82 |         hound_ctx_t *ctx = hound_get_ctx_by_id(server, id);
 | 
|---|
| 83 |         if (!ctx)
 | 
|---|
| 84 |                 return false;
 | 
|---|
| 85 |         return hound_ctx_is_record(ctx);
 | 
|---|
| 86 | }
 | 
|---|
| 87 | 
 | 
|---|
| 88 | static errno_t iface_get_list(void *server, char ***list, size_t *size,
 | 
|---|
| 89 |     const char *connection, int flags)
 | 
|---|
| 90 | {
 | 
|---|
| 91 |         log_info("%s: %p, %zu, %s, %#x\n", __FUNCTION__, server, *size,
 | 
|---|
| 92 |             connection, flags);
 | 
|---|
| 93 |         if ((flags & (HOUND_SINK_DEVS | HOUND_SINK_APPS)) != 0)
 | 
|---|
| 94 |                 return hound_list_sinks(server, list, size);
 | 
|---|
| 95 |         if ((flags & (HOUND_SOURCE_DEVS | HOUND_SOURCE_APPS)) != 0)
 | 
|---|
| 96 |                 return hound_list_sources(server, list, size);
 | 
|---|
| 97 |         return ENOTSUP;
 | 
|---|
| 98 | }
 | 
|---|
| 99 | 
 | 
|---|
| 100 | static errno_t iface_connect(void *server, const char *source, const char *sink)
 | 
|---|
| 101 | {
 | 
|---|
| 102 |         log_info("%s: %p, %s -> %s", __FUNCTION__, server, source, sink);
 | 
|---|
| 103 |         return hound_connect(server, source, sink);
 | 
|---|
| 104 | }
 | 
|---|
| 105 | 
 | 
|---|
| 106 | static errno_t iface_disconnect(void *server, const char *source, const char *sink)
 | 
|---|
| 107 | {
 | 
|---|
| 108 |         log_info("%s: %p, %s -> %s", __FUNCTION__, server, source, sink);
 | 
|---|
| 109 |         return hound_disconnect(server, source, sink);
 | 
|---|
| 110 | }
 | 
|---|
| 111 | 
 | 
|---|
| 112 | static errno_t iface_add_stream(void *server, hound_context_id_t id, int flags,
 | 
|---|
| 113 |     pcm_format_t format, size_t size, void **data)
 | 
|---|
| 114 | {
 | 
|---|
| 115 |         assert(data);
 | 
|---|
| 116 |         assert(server);
 | 
|---|
| 117 | 
 | 
|---|
| 118 |         log_verbose("%s: %p, %p %x ch:%u r:%u f:%s", __FUNCTION__, server, id,
 | 
|---|
| 119 |             flags, format.channels, format.sampling_rate,
 | 
|---|
| 120 |             pcm_sample_format_str(format.sample_format));
 | 
|---|
| 121 |         hound_ctx_t *ctx = hound_get_ctx_by_id(server, id);
 | 
|---|
| 122 |         if (!ctx)
 | 
|---|
| 123 |                 return ENOENT;
 | 
|---|
| 124 |         hound_ctx_stream_t *stream =
 | 
|---|
| 125 |             hound_ctx_create_stream(ctx, flags, format, size);
 | 
|---|
| 126 |         if (!stream)
 | 
|---|
| 127 |                 return ENOMEM;
 | 
|---|
| 128 |         *data = stream;
 | 
|---|
| 129 |         return EOK;
 | 
|---|
| 130 | }
 | 
|---|
| 131 | 
 | 
|---|
| 132 | static errno_t iface_rem_stream(void *server, void *stream)
 | 
|---|
| 133 | {
 | 
|---|
| 134 |         hound_ctx_destroy_stream(stream);
 | 
|---|
| 135 |         return EOK;
 | 
|---|
| 136 | }
 | 
|---|
| 137 | 
 | 
|---|
| 138 | static errno_t iface_drain_stream(void *stream)
 | 
|---|
| 139 | {
 | 
|---|
| 140 |         hound_ctx_stream_drain(stream);
 | 
|---|
| 141 |         return EOK;
 | 
|---|
| 142 | }
 | 
|---|
| 143 | 
 | 
|---|
| 144 | static errno_t iface_stream_data_read(void *stream, void *buffer, size_t size)
 | 
|---|
| 145 | {
 | 
|---|
| 146 |         return hound_ctx_stream_read(stream, buffer, size);
 | 
|---|
| 147 | }
 | 
|---|
| 148 | 
 | 
|---|
| 149 | static errno_t iface_stream_data_write(void *stream, const void *buffer, size_t size)
 | 
|---|
| 150 | {
 | 
|---|
| 151 |         return hound_ctx_stream_write(stream, buffer, size);
 | 
|---|
| 152 | }
 | 
|---|
| 153 | 
 | 
|---|
| 154 | hound_server_iface_t hound_iface = {
 | 
|---|
| 155 |         .add_context = iface_add_context,
 | 
|---|
| 156 |         .rem_context = iface_rem_context,
 | 
|---|
| 157 |         .is_record_context = iface_is_record_context,
 | 
|---|
| 158 |         .get_list = iface_get_list,
 | 
|---|
| 159 |         .connect = iface_connect,
 | 
|---|
| 160 |         .disconnect = iface_disconnect,
 | 
|---|
| 161 |         .add_stream = iface_add_stream,
 | 
|---|
| 162 |         .rem_stream = iface_rem_stream,
 | 
|---|
| 163 |         .drain_stream = iface_drain_stream,
 | 
|---|
| 164 |         .stream_data_write = iface_stream_data_write,
 | 
|---|
| 165 |         .stream_data_read = iface_stream_data_read,
 | 
|---|
| 166 |         .server = NULL,
 | 
|---|
| 167 | };
 | 
|---|