]> code.delx.au - pulseaudio/blob - src/modules/xen/module-xenpv-sink.c
66630176d055c51b09b06575fcd8111d161bdbbb
[pulseaudio] / src / modules / xen / module-xenpv-sink.c
1 /***
2 This file is part of PulseAudio.
3
4 Copyright 2004-2006 Lennart Poettering
5 Copyright 2011 George Boutsioukis for Xen
6
7 PulseAudio is free software; you can redistribute it and/or modify
8 it under the terms of the GNU Lesser General Public License as published
9 by the Free Software Foundation; either version 2.1 of the License,
10 or (at your option) any later version.
11
12 PulseAudio is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with PulseAudio; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
20 USA.
21 ***/
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <stdlib.h>
28 #include <sys/stat.h>
29 #include <stdio.h>
30 #include <errno.h>
31 #include <string.h>
32 #include <fcntl.h>
33 #include <unistd.h>
34 #include <limits.h>
35 #include <sys/ioctl.h>
36 #include <poll.h>
37 #include <time.h>
38
39 #include <pulse/xmalloc.h>
40
41 #include <pulsecore/core-error.h>
42 #include <pulsecore/sink.h>
43 #include <pulsecore/module.h>
44 #include <pulsecore/core-util.h>
45 #include <pulsecore/modargs.h>
46 #include <pulsecore/log.h>
47 #include <pulsecore/thread.h>
48 #include <pulsecore/thread-mq.h>
49 #include <pulsecore/rtpoll.h>
50
51 #include <sys/select.h>
52 #include <sys/mman.h>
53 #include <xenctrl.h>
54 #include <xs.h>
55
56 #include "module-xenpv-sink-symdef.h"
57 #include "gntalloc.h"
58 #include "gntdev.h"
59
60 PA_MODULE_AUTHOR("Giorgos Boutsioukis");
61 PA_MODULE_DESCRIPTION("Xen PV audio sink");
62 PA_MODULE_VERSION(PACKAGE_VERSION);
63 PA_MODULE_LOAD_ONCE(FALSE);
64 PA_MODULE_USAGE(
65 "sink_name=<name for the sink> "
66 "sink_properties=<properties for the sink> "
67 "format=<sample format> "
68 "rate=<sample rate>"
69 "channels=<number of channels> "
70 "channel_map=<channel map>");
71
72 #define DEFAULT_SINK_NAME "xenpv_output"
73 #define DEFAULT_FILE_NAME "xenpv_output"
74
75 #define STATE_UNDEFINED 9999
76
77 int device_id = -1;
78 enum xenbus_state {
79 XenbusStateUnknown = 0,
80 XenbusStateInitialising = 1,
81 XenbusStateInitWait = 2,
82 XenbusStateInitialised = 3,
83 XenbusStateConnected = 4,
84 XenbusStateClosing = 5,
85 XenbusStateClosed = 6,
86 XenbusStateReconfiguring = 7,
87 XenbusStateReconfigured = 8
88 };
89
90 static const char* xenbus_names[] = {
91 "XenbusStateUnknown",
92 "XenbusStateInitialising",
93 "XenbusStateInitWait",
94 "XenbusStateInitialised",
95 "XenbusStateConnected",
96 "XenbusStateClosing",
97 "XenbusStateClosed",
98 "XenbusStateReconfiguring",
99 "XenbusStateReconfigured"
100 };
101
102 struct userdata {
103 pa_core *core;
104 pa_module *module;
105 pa_sink *sink;
106
107 pa_thread *thread;
108 pa_thread_mq thread_mq;
109 pa_rtpoll *rtpoll;
110
111 pa_memchunk memchunk;
112
113 pa_rtpoll_item *rtpoll_item;
114
115 int write_type;
116 };
117
118 pa_sample_spec ss;
119 pa_channel_map map;
120
121 /* just to test non- frame-aligned size */
122 #define BUFSIZE 2047
123
124 struct ring {
125 uint32_t cons_indx, prod_indx;
126 uint32_t usable_buffer_space; /* kept here for convenience */
127 uint8_t buffer[BUFSIZE];
128 } *ioring;
129
130 static const char* const valid_modargs[] = {
131 "sink_name",
132 "sink_properties",
133 "file",
134 "format",
135 "rate",
136 "channels",
137 "channel_map",
138 NULL
139 };
140
141 /* Xen globals*/
142 xc_interface* xch;
143 xc_evtchn* xce;
144 evtchn_port_or_error_t xen_evtchn_port;
145 static struct xs_handle *xsh;
146 struct ioctl_gntalloc_alloc_gref gref;
147
148 static int register_backend_state_watch(void);
149 static int wait_for_backend_state_change(void);
150 static int alloc_gref(struct ioctl_gntalloc_alloc_gref *gref, void **addr);
151 static int ring_write(struct ring *r, void *src, int length);
152 static int publish_spec(pa_sample_spec *ss);
153 static int read_backend_default_spec(pa_sample_spec *ss);
154 static int publish_param(const char *paramname, const char *value);
155 static int publish_param_int(const char *paramname, const int value);
156 static char* read_param(const char *paramname);
157
158 static int set_state(int state) {
159 static int current_state = 0;
160 pa_log_debug("State transition %s->%s\n",
161 xenbus_names[current_state], xenbus_names[state]);
162
163 publish_param_int("state", state);
164 current_state = state;
165 return state;
166 }
167 #define NEGOTIATION_ERROR 2
168 #define NEGOTIATION_OK 1
169
170 /* negotiation callbacks */
171 static int state_unknown_cb() {
172 pa_log_debug("Xen audio sink: Backend state was XenbusStateUnknown\n");
173 set_state(XenbusStateInitialising);
174
175 return 0;
176 }
177
178 static int state_initialising_cb() {
179 pa_log_debug("Xen audio sink: Backend state was XenbusStateInitialising\n");
180 set_state(XenbusStateInitialised);
181 return 0;
182 }
183
184 static int state_initwait_cb() {
185 pa_log_debug("Xen audio sink: Backend state was XenbusStateInitWait\n");
186 return 0;
187 }
188
189 static int state_initialised_cb() {
190 pa_log_debug("Xen audio sink: Backend state was XenbusStateInitialised\n");
191 /*Remind the backend we are ready*/
192 set_state(XenbusStateInitialised);
193 return 0;
194 }
195
196 static int state_connected_cb() {
197 /* The backend accepted our parameters, sweet! */
198 set_state(XenbusStateConnected);
199 pa_log_debug("Xen audio sink: Backend state was XenbusStateConnected\n");
200 return NEGOTIATION_OK;
201 }
202
203 static int state_closing_cb() {
204 pa_log_debug("Xen audio sink: Backend state was XenbusStateClosing\n");
205 return 0;
206 }
207
208 static int state_closed_cb() {
209 pa_log_debug("Xen audio sink: Backend state was XenbusStateClosed\n");
210 return 0;
211 }
212
213 static int state_reconfiguring_cb() {
214 /* The backend rejected our sample spec */
215 pa_log_debug("Xen audio sink: Backend state was XenbusStateReconfiguring\n");
216 /* fall back to the backend's default parameters*/
217 read_backend_default_spec(&ss);
218 /* backend should accept these now */
219 publish_spec(&ss);
220 set_state(XenbusStateInitialised);
221 return 0;
222 }
223
224 static int state_reconfigured_cb() {
225 pa_log_debug("Xen audio sink: Backend state was XenbusStateReconfigured\n");
226 return 0;
227 }
228
229 int (*state_callbacks[9])(void) = {
230 state_unknown_cb,
231 state_initialising_cb,
232 state_initwait_cb,
233 state_initialised_cb,
234 state_connected_cb,
235 state_closing_cb,
236 state_closed_cb,
237 state_reconfiguring_cb,
238 state_reconfigured_cb
239 };
240
241 static void xen_cleanup() {
242 char keybuf[64];
243 /*XXX hardcoded*/
244 munmap((void*)gref.index, 4096);
245
246 set_state(XenbusStateClosing);
247 /* send one last event to unblock the backend */
248 xc_evtchn_notify(xce, xen_evtchn_port);
249 /* close xen interfaces */
250 xc_evtchn_close(xce);
251 xc_interface_close(xch);
252
253 /* delete xenstore keys */
254 publish_param_int("state", XenbusStateClosed);
255 snprintf(keybuf, sizeof(keybuf), "device/audio/%d", device_id);
256 xs_rm(xsh, 0, keybuf);
257 xs_daemon_close(xsh);
258 }
259
260 static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) {
261 struct userdata *u = PA_SINK(o)->userdata;
262
263 switch (code) {
264
265 case PA_SINK_MESSAGE_GET_LATENCY: {
266 size_t n = 0;
267
268 n += u->memchunk.length;
269
270 *((pa_usec_t*) data) = pa_bytes_to_usec(n, &u->sink->sample_spec);
271 return 0;
272 }
273 }
274
275 return pa_sink_process_msg(o, code, data, offset, chunk);
276 }
277
278 static int process_render(struct userdata *u) {
279 pa_assert(u);
280
281
282 if (u->memchunk.length <= 0)
283 pa_sink_render(u->sink, ioring->usable_buffer_space, &u->memchunk);
284
285
286 pa_assert(u->memchunk.length > 0);
287
288 xc_evtchn_notify(xce, xen_evtchn_port);
289 for (;;) {
290 ssize_t l;
291 void *p;
292
293 p = pa_memblock_acquire(u->memchunk.memblock);
294 /* xen: write data to ring buffer & notify backend */
295 l = ring_write(ioring, (uint8_t*)p + u->memchunk.index, u->memchunk.length);
296
297 pa_memblock_release(u->memchunk.memblock);
298
299 pa_assert(l != 0);
300
301 if (l < 0) {
302 if (errno == EINTR)
303 continue;
304 else if (errno == EAGAIN)
305 return 0;
306 else {
307 pa_log("Failed to write data to FIFO: %s", pa_cstrerror(errno));
308 return -1;
309 }
310
311 } else {
312
313 u->memchunk.index += (size_t) l;
314 u->memchunk.length -= (size_t) l;
315
316 if (u->memchunk.length <= 0) {
317 pa_memblock_unref(u->memchunk.memblock);
318 pa_memchunk_reset(&u->memchunk);
319 }
320 }
321
322 return 0;
323 }
324 }
325
326 static void thread_func(void *userdata) {
327 struct userdata *u = userdata;
328
329 pa_assert(u);
330
331 pa_log_debug("Thread starting up");
332
333 pa_thread_mq_install(&u->thread_mq);
334
335 for(;;) {
336 struct pollfd *pollfd;
337 int ret;
338
339 pollfd = pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL);
340
341 if (PA_UNLIKELY(u->sink->thread_info.rewind_requested))
342 pa_sink_process_rewind(u->sink, 0);
343
344 /* Render some data and write it to the fifo */
345 if (PA_SINK_IS_OPENED(u->sink->thread_info.state)) {
346 if (pollfd->revents) {
347 if (process_render(u) < 0)
348 goto fail;
349
350 pollfd->revents = 0;
351 }
352 }
353
354 /* Hmm, nothing to do. Let's sleep */
355
356 pollfd->events = (short) (u->sink->thread_info.state == PA_SINK_RUNNING ? POLLOUT : 0);
357
358 if ((ret = pa_rtpoll_run(u->rtpoll, TRUE)) < 0)
359 goto fail;
360
361 if (ret == 0)
362 goto finish;
363
364 pollfd = pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL);
365
366 if (pollfd->revents & ~POLLOUT) {
367 pa_log("FIFO shutdown.");
368 goto fail;
369 }
370 }
371
372 fail:
373 /* If this was no regular exit from the loop we have to continue
374 * processing messages until we received PA_MESSAGE_SHUTDOWN */
375 pa_asyncmsgq_post(u->thread_mq.outq, PA_MSGOBJECT(u->core), PA_CORE_MESSAGE_UNLOAD_MODULE, u->module, 0, NULL, NULL);
376 pa_asyncmsgq_wait_for(u->thread_mq.inq, PA_MESSAGE_SHUTDOWN);
377 pa_log_debug("Shutting down Xen...");
378 xen_cleanup();
379 finish:
380 pa_log_debug("Thread shutting down");
381 }
382
383 int pa__init(pa_module*m) {
384
385 struct userdata *u;
386 pa_modargs *ma;
387 pa_sink_new_data data;
388 int backend_state;
389 int ret;
390 char strbuf[100];
391
392 pa_assert(m);
393
394 if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
395 pa_log("Failed to parse module arguments.");
396 goto fail;
397 }
398
399 ss = m->core->default_sample_spec;
400 map = m->core->default_channel_map;
401
402 /* user arguments override these */
403 if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_DEFAULT) < 0) {
404 pa_log("Invalid sample format specification or channel map");
405 return 1;
406 }
407
408 /* Xen Basic init */
409 xsh = xs_domain_open();
410 if (xsh==NULL) {
411 pa_log("xs_domain_open failed");
412 goto fail;
413 }
414 set_state(XenbusStateUnknown);
415
416 xch = xc_interface_open(NULL, NULL, 0);
417 if (xch==0) {
418 pa_log("xc_interface_open failed");
419 goto fail;
420 }
421
422 xce = xc_evtchn_open(NULL, 0);
423 if (xce==0) {
424 pa_log("xc_evtchn_open failed");
425 goto fail;
426 }
427
428 /* use only dom0 as the backend for now */
429 xen_evtchn_port = xc_evtchn_bind_unbound_port(xce, 0);
430 if (xen_evtchn_port == 0) {
431 pa_log("xc_evtchn_bind_unbound_port failed");
432 }
433
434 /* get grant reference & map locally */
435 if (alloc_gref(&gref, (void**)&ioring)) {
436 pa_log("alloc_gref failed");
437 };
438 device_id = 0; /* hardcoded for now */
439
440 if (register_backend_state_watch()) {
441 pa_log("Xen sink: register xenstore watch failed");
442 };
443
444 publish_param_int("event-channel", xen_evtchn_port);
445 publish_param_int("ring-ref", gref.gref_ids[0]);
446
447 /* let's ask for something absurd and deal with rejection */
448 ss.rate = 192000;
449
450 publish_spec(&ss);
451
452 ret=0;
453 while (!ret) {
454 backend_state = wait_for_backend_state_change();
455 if (backend_state == STATE_UNDEFINED) {
456 pa_log("Xen Backend is taking long to respond, still waiting...");
457 continue;
458 } else if (backend_state == -1) {
459 pa_log("Error while waiting for backend: %s", strerror(errno));
460 break;
461 goto fail;
462 }
463 ret = state_callbacks[backend_state]();
464 }
465 if (ret!=NEGOTIATION_OK) {
466 pa_log("Negotiation with Xen backend failed!");
467 return 1;
468 }
469
470 pa_sample_spec_snprint(strbuf, 100, &ss);
471 pa_log_debug("Negotiation ended, the result was: %s", strbuf);
472
473 /* End of Phase 2, begin playback cycle */
474
475 u = pa_xnew0(struct userdata, 1);
476 u->core = m->core;
477 u->module = m;
478 m->userdata = u;
479 pa_memchunk_reset(&u->memchunk);
480 u->rtpoll = pa_rtpoll_new();
481 pa_thread_mq_init(&u->thread_mq, m->core->mainloop, u->rtpoll);
482 u->write_type = 0;
483
484 /* init ring buffer */
485 ioring->prod_indx = ioring->cons_indx = 0;
486 ioring->usable_buffer_space = BUFSIZE - BUFSIZE % pa_frame_size(&ss);
487
488 pa_sink_new_data_init(&data);
489 data.driver = __FILE__;
490 data.module = m;
491 pa_sink_new_data_set_name(&data, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME));
492 pa_proplist_sets(data.proplist, PA_PROP_DEVICE_STRING, "xensink");
493 pa_proplist_setf(data.proplist, PA_PROP_DEVICE_DESCRIPTION, "Xen PV audio sink");
494 pa_sink_new_data_set_sample_spec(&data, &ss);
495 pa_sink_new_data_set_channel_map(&data, &map);
496
497 if (pa_modargs_get_proplist(ma, "sink_properties", data.proplist, PA_UPDATE_REPLACE) < 0) {
498 pa_log("Invalid properties");
499 pa_sink_new_data_done(&data);
500 goto fail;
501 }
502
503 u->sink = pa_sink_new(m->core, &data, PA_SINK_LATENCY);
504 pa_sink_new_data_done(&data);
505
506 if (!u->sink) {
507 pa_log("Failed to create sink.");
508 goto fail;
509 }
510
511 u->sink->parent.process_msg = sink_process_msg;
512 u->sink->userdata = u;
513
514 pa_sink_set_asyncmsgq(u->sink, u->thread_mq.inq);
515 pa_sink_set_rtpoll(u->sink, u->rtpoll);
516 pa_sink_set_max_request(u->sink, ioring->usable_buffer_space);
517 pa_sink_set_fixed_latency(u->sink, pa_bytes_to_usec(ioring->usable_buffer_space, &u->sink->sample_spec));
518
519 u->rtpoll_item = pa_rtpoll_item_new(u->rtpoll, PA_RTPOLL_NEVER, 1);
520
521 if (!(u->thread = pa_thread_new("xenpv-sink", thread_func, u))) {
522 pa_log("Failed to create thread.");
523 goto fail;
524 }
525
526 pa_sink_put(u->sink);
527
528 pa_modargs_free(ma);
529
530 return 0;
531
532 fail:
533 if (ma)
534 pa_modargs_free(ma);
535
536 pa__done(m);
537
538 return -1;
539 }
540
541 int pa__get_n_used(pa_module *m) {
542 struct userdata *u;
543
544 pa_assert(m);
545 pa_assert_se(u = m->userdata);
546
547 return pa_sink_linked_by(u->sink);
548 }
549
550 void pa__done(pa_module*m) {
551 struct userdata *u;
552
553 pa_assert(m);
554
555 if (!(u = m->userdata))
556 return;
557
558 if (u->sink)
559 pa_sink_unlink(u->sink);
560
561 if (u->thread) {
562 pa_asyncmsgq_send(u->thread_mq.inq, NULL, PA_MESSAGE_SHUTDOWN, NULL, 0, NULL);
563 pa_thread_free(u->thread);
564 }
565
566 pa_thread_mq_done(&u->thread_mq);
567
568 if (u->sink)
569 pa_sink_unref(u->sink);
570
571 if (u->memchunk.memblock)
572 pa_memblock_unref(u->memchunk.memblock);
573
574 if (u->rtpoll_item)
575 pa_rtpoll_item_free(u->rtpoll_item);
576
577 if (u->rtpoll)
578 pa_rtpoll_free(u->rtpoll);
579
580 pa_xfree(u);
581
582 xen_cleanup();
583
584 }
585
586
587 static int alloc_gref(struct ioctl_gntalloc_alloc_gref *gref_, void **addr) {
588 int alloc_fd, dev_fd, rv;
589
590 alloc_fd = open("/dev/xen/gntalloc", O_RDWR);
591 if (alloc_fd<=0) {
592 perror("Could not open /dev/xen/gntalloc! Have you loaded the xen_gntalloc module?");
593 return 1;
594 }
595
596 dev_fd = open("/dev/xen/gntdev", O_RDWR);
597 if (dev_fd<=0) {
598 perror("Could not open /dev/xen/gntdev! Have you loaded the xen_gntdev module?");
599 return 1;
600 }
601
602 /* use dom0 */
603 gref_->domid = 0;
604 gref_->flags = GNTALLOC_FLAG_WRITABLE;
605 gref_->count = 1;
606
607 rv = ioctl(alloc_fd, IOCTL_GNTALLOC_ALLOC_GREF, gref_);
608 if (rv) {
609 pa_log_debug("Xen audio sink: src-add error: %s (rv=%d)\n", strerror(errno), rv);
610 return rv;
611 }
612
613 /*addr=NULL(default),length, prot, flags, fd, offset*/
614 *addr = mmap(0, 4096, PROT_READ|PROT_WRITE, MAP_SHARED, alloc_fd, gref_->index);
615 if (*addr == MAP_FAILED) {
616 *addr = 0;
617 pa_log_debug("Xen audio sink: mmap'ing shared page failed\n");
618 return rv;
619 }
620
621 pa_log_debug("Xen audio sink: Got grant #%d. Mapped locally at %Ld=%p\n",
622 gref_->gref_ids[0], (long long)gref_->index, *addr);
623
624 /* skip this for now
625 struct ioctl_gntalloc_unmap_notify uarg = {
626 .index = gref->index + offsetof(struct shr_page, notifies[0]),
627 .action = UNMAP_NOTIFY_CLEAR_BYTE
628 };
629
630 rv = ioctl(a_fd, IOCTL_GNTALLOC_SET_UNMAP_NOTIFY, &uarg);
631 if (rv)
632 pa_log_debug("gntalloc unmap notify error: %s (rv=%d)\n", strerror(errno), rv);
633 */
634
635 close(alloc_fd);
636 close(dev_fd);
637
638 return rv;
639 }
640
641 #define RING_FREE_BYTES ((r->usable_buffer_space - (r->prod_indx-r->cons_indx) -1) % r->usable_buffer_space)
642 static int ring_write(struct ring *r, void *src, int length) {
643 int full = 0;
644 for (;;) {
645 /* free space may be split over the end of the buffer */
646 int first_chunk_size = (r->usable_buffer_space-r->prod_indx);
647 int second_chunk_size = (r->cons_indx>=r->prod_indx)? (r->cons_indx) : 0;
648 int l, fl, sl;
649
650 /* full? */
651 if (RING_FREE_BYTES==0) {
652 /*XXX hardcoded*/
653 if (full>=100) {
654 errno = EINTR;
655 return -1;
656 }
657 /*XXX hardcoded */
658 usleep(1000);
659 /* should return in 100ms max; definitely not midstream */
660 full++;
661 continue;
662 }
663
664 /* calculate lengths in case of a split buffer */
665 l = PA_MIN((int)RING_FREE_BYTES, length);
666 fl = PA_MIN(l, first_chunk_size);
667 sl = PA_MIN(l-fl, second_chunk_size);
668
669 memcpy(r->buffer+r->prod_indx, src, fl);
670 if (sl)
671 memcpy(r->buffer, ((char*)src)+fl, sl);
672 r->prod_indx = (r->prod_indx+fl+sl) % r->usable_buffer_space;
673
674 return sl+fl;
675 }
676 }
677
678 static int publish_param(const char *paramname, const char *value) {
679 char keybuf[128], valbuf[32];
680
681 snprintf(keybuf, sizeof keybuf, "device/audio/%d/%s", device_id, paramname);
682 snprintf(valbuf, sizeof valbuf, "%s", value);
683 return xs_write(xsh, 0, keybuf, valbuf, strlen(valbuf));
684 }
685
686 static int publish_param_int(const char *paramname, const int value) {
687 char keybuf[128], valbuf[32];
688 snprintf(keybuf, sizeof keybuf, "device/audio/%d/%s", device_id, paramname);
689 snprintf(valbuf, sizeof valbuf, "%d", value);
690 return xs_write(xsh, 0, keybuf, valbuf, strlen(valbuf));
691 }
692
693 static char* read_param(const char *paramname) {
694 char keybuf[128];
695 unsigned int len;
696 int my_domid;
697
698 my_domid = atoi(xs_read(xsh, 0, "domid", &len));
699 snprintf(keybuf, sizeof(keybuf), "/local/domain/0/backend/audio/%d/%d/%s", my_domid, device_id, paramname);
700 /* remember to free lvalue! */
701 return xs_read(xsh, 0, keybuf, &len);
702 }
703
704
705 static int publish_spec(pa_sample_spec *sample_spec) {
706 /* Publish spec and set state to XenbusStateInitWait*/
707 int ret;
708
709 ret = publish_param("format", pa_sample_format_to_string(sample_spec->format));
710 ret += publish_param_int("rate", sample_spec->rate);
711 ret += publish_param_int("channels", sample_spec->channels);
712
713 return ret;
714 }
715
716
717 static int read_backend_default_spec(pa_sample_spec *sample_spec) {
718 /* Read spec from backend */
719 char *out;
720
721 out = read_param("default-format");
722 sample_spec->format = pa_parse_sample_format(out);
723 free(out);
724
725 out = read_param("default-rate");
726 sample_spec->rate = atoi(out);
727 free(out);
728
729 out = read_param("default-channels");
730 sample_spec->channels = atoi(out);
731 free(out);
732
733 return 0;
734 }
735
736 static int register_backend_state_watch() {
737 char keybuf[128];
738 int my_domid;
739 unsigned int len;
740
741 my_domid = atoi(xs_read(xsh, 0, "domid", &len));
742 snprintf(keybuf, sizeof(keybuf), "/local/domain/0/backend/audio/%d/%d/state", my_domid, device_id);
743 if (!xs_watch(xsh, keybuf, "xenpvaudiofrontendsinktoken")) {
744 perror("xs_watch failed");
745 return -EINVAL;
746 }
747 return 0;
748 }
749
750 static int wait_for_backend_state_change() {
751 char keybuf[128];
752 int my_domid;
753 unsigned int len;
754
755 int backend_state;
756 int seconds;
757 char *buf, **vec;
758 int ret;
759
760 int xs_fd;
761 struct timeval tv;
762 fd_set watch_fdset;
763 int start, now;
764
765 backend_state = STATE_UNDEFINED;
766 xs_fd = xs_fileno(xsh);
767 start = now = time(NULL);
768
769 my_domid = atoi(xs_read(xsh, 0, "domid", &len));
770 snprintf(keybuf, sizeof(keybuf), "/local/domain/0/backend/audio/%d/%d/state", my_domid, device_id);
771
772 /*XXX: hardcoded */
773 seconds = 10;
774 do {
775 tv.tv_usec = 0;
776 tv.tv_sec = (start + seconds) - now;
777 FD_ZERO(&watch_fdset);
778 FD_SET(xs_fd, &watch_fdset);
779 ret=select(xs_fd + 1, &watch_fdset, NULL, NULL, &tv);
780
781 if (ret==-1)
782 /* error */
783 return -1;
784 else if (ret) {
785
786 /* Read the watch to drain the buffer */
787 vec = xs_read_watch(xsh, &len);
788
789 buf = xs_read(xsh, XBT_NULL, vec[0], &len);
790 if (buf == 0) {
791 /* usually means that the backend isn't there yet */
792 continue;
793 };
794 backend_state = atoi(buf);
795
796 free(buf);
797 free(vec);
798 }
799 /* else: timeout */
800 } while (backend_state == STATE_UNDEFINED && \
801 (now = time(NULL)) < start + seconds);
802
803 return backend_state;
804 }