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

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

hound: Fix few leaks and memory corruption bugs.

  • Property mode set to 100644
File size: 7.0 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 log_debug("Got method %u", IPC_GET_IMETHOD(call));
148 switch (IPC_GET_IMETHOD(call)) {
149 case HOUND_REGISTER_PLAYBACK: {
150 const audio_format_t format = read_format(&call);
151 const char *name = get_name();
152 async_sess_t *sess = get_session();
153 audio_client_t *client =
154 audio_client_get_playback(name, &format, sess);
155 free(name);
156 if (!client) {
157 log_error("Failed to create playback client");
158 async_answer_0(callid, ENOMEM);
159 break;
160 }
161 int ret = hound_add_source(&hound, &client->source);
162 if (ret != EOK){
163 audio_client_destroy(client);
164 log_error("Failed to add audio source: %s",
165 str_error(ret));
166 async_answer_0(callid, ret);
167 break;
168 }
169 log_info("Added audio client %p '%s'",
170 client, client->name);
171 async_answer_0(callid, EOK);
172 list_append(&client->link, &local_playback);
173 break;
174 }
175 case HOUND_REGISTER_RECORDING: {
176 const audio_format_t format = read_format(&call);
177 const char *name = get_name();
178 async_sess_t *sess = get_session();
179 audio_client_t * client =
180 audio_client_get_recording(name, &format, sess);
181 if (!client) {
182 log_error("Failed to create recording client");
183 async_answer_0(callid, ENOMEM);
184 break;
185 }
186 int ret = hound_add_sink(&hound, &client->sink);
187 if (ret != EOK){
188 audio_client_destroy(client);
189 log_error("Failed to add audio sink: %s",
190 str_error(ret));
191 async_answer_0(callid, ret);
192 break;
193 }
194 async_answer_0(callid, EOK);
195 list_append(&client->link, &local_recording);
196 break;
197 }
198 case HOUND_UNREGISTER_PLAYBACK: {
199 //const char *name = get_name();
200 //TODO unregister in hound
201 //TODO remove from local
202 break;
203 }
204 case HOUND_UNREGISTER_RECORDING: {
205 //TODO Get Name
206 //TODO unregister in hound
207 //TODO remove from local
208 break;
209 }
210 case HOUND_CONNECT: {
211 //TODO Get Name
212 //TODO Get Name
213 //TODO connect in hound
214 break;
215 }
216 case HOUND_DISCONNECT: {
217 //TODO Get Name
218 //TODO Get Name
219 //TODO disconnect in hound
220 break;
221 }
222 default:
223 async_answer_0(callid, ENOTSUP);
224 break;
225 case 0:
226 return;
227 }
228 }
229}
230
231int main(int argc, char **argv)
232{
233 printf("%s: HelenOS sound service\n", NAME);
234
235 int ret = hound_init(&hound);
236 if (ret != EOK) {
237 log_fatal("Failed to initialize hound structure: %s",
238 str_error(ret));
239 return -ret;
240 }
241
242 async_set_client_connection(client_connection);
243 ret = loc_server_register(NAME);
244 if (ret != EOK) {
245 log_fatal("Failed to register sound server: %s",
246 str_error(ret));
247 return -ret;
248 }
249
250 char fqdn[LOC_NAME_MAXLEN + 1];
251 snprintf(fqdn, LOC_NAME_MAXLEN, "%s/%s", NAMESPACE, NAME);
252 service_id_t id = 0;
253 ret = loc_service_register(fqdn, &id);
254 if (ret != EOK) {
255 log_fatal("Failed to register sound service: %s",
256 str_error(ret));
257 return -ret;
258 }
259
260 ret = loc_register_cat_change_cb(scan_for_devices);
261 if (ret != EOK) {
262 log_fatal("Failed to register for category changes: %s",
263 str_error(ret));
264 loc_service_unregister(id);
265 return -ret;
266 }
267 log_info("Running with service id %u", id);
268
269 scan_for_devices();
270
271 async_manager();
272 return 0;
273}
274
275/**
276 * @}
277 */
Note: See TracBrowser for help on using the repository browser.