source: mainline/uspace/srv/audio/hound/main.c@ f3fced0

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

hound: Implement connect code.

  • Property mode set to 100644
File size: 7.6 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/**
30 * @addtogroup audio
31 * @brief HelenOS sound server.
32 * @{
33 */
34/** @file
35 */
36
37#include <async.h>
38#include <bool.h>
39#include <errno.h>
40#include <loc.h>
41#include <stdio.h>
42#include <stdlib.h>
43#include <str_error.h>
44
45#include "hound.h"
46
47#define NAMESPACE "audio"
48#define NAME "hound"
49#define CATEGORY "audio-pcm"
50
51#include "audio_client.h"
52#include "log.h"
53#include "protocol.h"
54
55static hound_t hound;
56
57static inline audio_format_t read_format(const ipc_call_t *call)
58{
59 audio_format_t format = {
60 .channels = IPC_GET_ARG1(*call),
61 .sampling_rate = IPC_GET_ARG2(*call),
62 .sample_format = IPC_GET_ARG3(*call),
63 };
64 return format;
65}
66static inline const char *get_name()
67{
68 size_t size = 0;
69 ipc_callid_t callid;
70 async_data_write_receive(&callid, &size);
71 char *buffer = malloc(size);
72 if (buffer) {
73 async_data_write_finalize(callid, buffer, size);
74 buffer[size - 1] = 0;
75 log_verbose("Got name from client: %s", buffer);
76 }
77 return buffer;
78}
79static inline async_sess_t *get_session()
80{
81 ipc_call_t call;
82 ipc_callid_t callid = async_get_call(&call);
83 async_sess_t *s = async_callback_receive_start(EXCHANGE_ATOMIC, &call);
84 async_answer_0(callid, s ? EOK : ENOMEM);
85 if (s) {
86 log_verbose("Received callback session");
87 } else
88 log_debug("Failed to receive callback session");
89 return s;
90}
91
92
93static void scan_for_devices(void)
94{
95 static bool cat_resolved = false;
96 static category_id_t cat;
97
98 if (!cat_resolved) {
99 log_verbose("Resolving category \"%s\".", CATEGORY);
100 const int ret = loc_category_get_id(CATEGORY, &cat,
101 IPC_FLAG_BLOCKING);
102 if (ret != EOK) {
103 log_error("Failed to get category: %s", str_error(ret));
104 return;
105 }
106 cat_resolved = true;
107 }
108
109 log_verbose("Getting available services in category.");
110
111 service_id_t *svcs = NULL;
112 size_t count = 0;
113 const int ret = loc_category_get_svcs(cat, &svcs, &count);
114 if (ret != EOK) {
115 log_error("Failed to get audio devices: %s", str_error(ret));
116 return;
117 }
118
119 for (unsigned i = 0; i < count; ++i) {
120 char *name = NULL;
121 int ret = loc_service_get_name(svcs[i], &name);
122 if (ret != EOK) {
123 log_error("Failed to get dev name: %s", str_error(ret));
124 continue;
125 }
126 ret = hound_add_device(&hound, svcs[i], name);
127 if (ret != EOK && ret != EEXISTS) {
128 log_error("Failed to add audio device \"%s\": %s",
129 name, str_error(ret));
130 }
131 free(name);
132 }
133
134 free(svcs);
135}
136
137static void client_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
138{
139 async_answer_0(iid, EOK);
140
141 LIST_INITIALIZE(local_playback);
142 LIST_INITIALIZE(local_recording);
143
144 while (1) {
145 ipc_call_t call;
146 ipc_callid_t callid = async_get_call(&call);
147 switch (IPC_GET_IMETHOD(call)) {
148 case HOUND_REGISTER_PLAYBACK: {
149 const audio_format_t format = read_format(&call);
150 const char *name = get_name();
151 async_sess_t *sess = get_session();
152 audio_client_t *client =
153 audio_client_get_playback(name, &format, sess);
154 free(name);
155 if (!client) {
156 log_error("Failed to create playback client");
157 async_answer_0(callid, ENOMEM);
158 break;
159 }
160 int ret = hound_add_source(&hound, &client->source);
161 if (ret != EOK){
162 audio_client_destroy(client);
163 log_error("Failed to add audio source: %s",
164 str_error(ret));
165 async_answer_0(callid, ret);
166 break;
167 }
168 log_info("Added audio client %p '%s'",
169 client, client->name);
170 async_answer_0(callid, EOK);
171 list_append(&client->link, &local_playback);
172 break;
173 }
174 case HOUND_REGISTER_RECORDING: {
175 const audio_format_t format = read_format(&call);
176 const char *name = get_name();
177 async_sess_t *sess = get_session();
178 audio_client_t * client =
179 audio_client_get_recording(name, &format, sess);
180 if (!client) {
181 log_error("Failed to create recording client");
182 async_answer_0(callid, ENOMEM);
183 break;
184 }
185 int ret = hound_add_sink(&hound, &client->sink);
186 if (ret != EOK){
187 audio_client_destroy(client);
188 log_error("Failed to add audio sink: %s",
189 str_error(ret));
190 async_answer_0(callid, ret);
191 break;
192 }
193 async_answer_0(callid, EOK);
194 list_append(&client->link, &local_recording);
195 break;
196 }
197 case HOUND_UNREGISTER_PLAYBACK: {
198 //const char *name = get_name();
199 //TODO unregister in hound
200 //TODO remove from local
201 break;
202 }
203 case HOUND_UNREGISTER_RECORDING: {
204 //TODO Get Name
205 //TODO unregister in hound
206 //TODO remove from local
207 break;
208 }
209 case HOUND_CONNECT: {
210 const char *name_a = get_name();
211 const char *name_b = get_name();
212 const int ret = hound_connect(&hound, name_a, name_b);
213 if (ret != EOK)
214 log_error("Failed to connect '%s' to '%s': %s",
215 name_a, name_b, str_error(ret));
216 free(name_a);
217 free(name_b);
218 async_answer_0(callid, ret);
219 break;
220 }
221 case HOUND_DISCONNECT: {
222 const char *name_a = get_name();
223 const char *name_b = get_name();
224 const int ret = hound_disconnect(&hound, name_a, name_b);
225 if (ret != EOK)
226 log_error("Failed to disconnect '%s' from '%s'"
227 ": %s", name_a, name_b, str_error(ret));
228 free(name_a);
229 free(name_b);
230 async_answer_0(callid, ret);
231 break;
232 }
233 default:
234 log_debug("Got unknown method %u",
235 IPC_GET_IMETHOD(call));
236 async_answer_0(callid, ENOTSUP);
237 break;
238 case 0:
239 //TODO remove all clients
240 return;
241 }
242 }
243}
244
245int main(int argc, char **argv)
246{
247 printf("%s: HelenOS sound service\n", NAME);
248
249 int ret = hound_init(&hound);
250 if (ret != EOK) {
251 log_fatal("Failed to initialize hound structure: %s",
252 str_error(ret));
253 return -ret;
254 }
255
256 async_set_client_connection(client_connection);
257 ret = loc_server_register(NAME);
258 if (ret != EOK) {
259 log_fatal("Failed to register sound server: %s",
260 str_error(ret));
261 return -ret;
262 }
263
264 char fqdn[LOC_NAME_MAXLEN + 1];
265 snprintf(fqdn, LOC_NAME_MAXLEN, "%s/%s", NAMESPACE, NAME);
266 service_id_t id = 0;
267 ret = loc_service_register(fqdn, &id);
268 if (ret != EOK) {
269 log_fatal("Failed to register sound service: %s",
270 str_error(ret));
271 return -ret;
272 }
273
274 ret = loc_register_cat_change_cb(scan_for_devices);
275 if (ret != EOK) {
276 log_fatal("Failed to register for category changes: %s",
277 str_error(ret));
278 loc_service_unregister(id);
279 return -ret;
280 }
281 log_info("Running with service id %u", id);
282
283 scan_for_devices();
284
285 async_manager();
286 return 0;
287}
288
289/**
290 * @}
291 */
Note: See TracBrowser for help on using the repository browser.