2 This file is part of PulseAudio.
4 Copyright 2004-2006 Lennart Poettering
5 Copyright 2011 George Boutsioukis for Xen
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.
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.
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
35 #include <sys/ioctl.h>
39 #include <pulse/xmalloc.h>
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>
51 #include <sys/select.h>
56 #include "module-xenpv-sink-symdef.h"
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);
65 "sink_name=<name for the sink> "
66 "sink_properties=<properties for the sink> "
67 "format=<sample format> "
69 "channels=<number of channels> "
70 "channel_map=<channel map>");
72 #define DEFAULT_SINK_NAME "xenpv_output"
73 #define DEFAULT_FILE_NAME "xenpv_output"
75 #define STATE_UNDEFINED 9999
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
90 static const char* xenbus_names
[] = {
92 "XenbusStateInitialising",
93 "XenbusStateInitWait",
94 "XenbusStateInitialised",
95 "XenbusStateConnected",
98 "XenbusStateReconfiguring",
99 "XenbusStateReconfigured"
108 pa_thread_mq thread_mq
;
111 pa_memchunk memchunk
;
113 pa_rtpoll_item
*rtpoll_item
;
121 /* just to test non- frame-aligned size */
125 uint32_t cons_indx
, prod_indx
;
126 uint32_t usable_buffer_space
; /* kept here for convenience */
127 uint8_t buffer
[BUFSIZE
];
130 static const char* const valid_modargs
[] = {
144 evtchn_port_or_error_t xen_evtchn_port
;
145 static struct xs_handle
*xsh
;
146 struct ioctl_gntalloc_alloc_gref gref
;
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
);
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
]);
163 publish_param_int("state", state
);
164 current_state
= state
;
167 #define NEGOTIATION_ERROR 2
168 #define NEGOTIATION_OK 1
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
);
178 static int state_initialising_cb() {
179 pa_log_debug("Xen audio sink: Backend state was XenbusStateInitialising\n");
180 set_state(XenbusStateInitialised
);
184 static int state_initwait_cb() {
185 pa_log_debug("Xen audio sink: Backend state was XenbusStateInitWait\n");
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
);
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
;
203 static int state_closing_cb() {
204 pa_log_debug("Xen audio sink: Backend state was XenbusStateClosing\n");
208 static int state_closed_cb() {
209 pa_log_debug("Xen audio sink: Backend state was XenbusStateClosed\n");
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 */
220 set_state(XenbusStateInitialised
);
224 static int state_reconfigured_cb() {
225 pa_log_debug("Xen audio sink: Backend state was XenbusStateReconfigured\n");
229 int (*state_callbacks
[9])(void) = {
231 state_initialising_cb
,
233 state_initialised_cb
,
237 state_reconfiguring_cb
,
238 state_reconfigured_cb
241 static void xen_cleanup() {
244 munmap((void*)gref
.index
, 4096);
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
);
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
);
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
;
265 case PA_SINK_MESSAGE_GET_LATENCY
: {
268 n
+= u
->memchunk
.length
;
270 *((pa_usec_t
*) data
) = pa_bytes_to_usec(n
, &u
->sink
->sample_spec
);
275 return pa_sink_process_msg(o
, code
, data
, offset
, chunk
);
278 static int process_render(struct userdata
*u
) {
281 if (u
->memchunk
.length
<= 0)
282 pa_sink_render(u
->sink
, ioring
->usable_buffer_space
, &u
->memchunk
);
284 pa_assert(u
->memchunk
.length
> 0);
286 xc_evtchn_notify(xce
, xen_evtchn_port
);
291 p
= pa_memblock_acquire(u
->memchunk
.memblock
);
292 /* xen: write data to ring buffer & notify backend */
293 l
= ring_write(ioring
, (uint8_t*)p
+ u
->memchunk
.index
, u
->memchunk
.length
);
295 pa_memblock_release(u
->memchunk
.memblock
);
302 else if (errno
== EAGAIN
)
305 pa_log("Failed to write data to FIFO: %s", pa_cstrerror(errno
));
311 u
->memchunk
.index
+= (size_t) l
;
312 u
->memchunk
.length
-= (size_t) l
;
314 if (u
->memchunk
.length
<= 0) {
315 pa_memblock_unref(u
->memchunk
.memblock
);
316 pa_memchunk_reset(&u
->memchunk
);
324 static void thread_func(void *userdata
) {
325 struct userdata
*u
= userdata
;
329 pa_log_debug("Thread starting up");
331 pa_thread_mq_install(&u
->thread_mq
);
334 struct pollfd
*pollfd
;
337 pollfd
= pa_rtpoll_item_get_pollfd(u
->rtpoll_item
, NULL
);
339 if (PA_UNLIKELY(u
->sink
->thread_info
.rewind_requested
))
340 pa_sink_process_rewind(u
->sink
, 0);
342 /* Render some data and write it to the fifo */
343 if (PA_SINK_IS_OPENED(u
->sink
->thread_info
.state
)) {
344 if (pollfd
->revents
) {
345 if (process_render(u
) < 0)
352 /* Hmm, nothing to do. Let's sleep */
354 pollfd
->events
= (short) (u
->sink
->thread_info
.state
== PA_SINK_RUNNING
? POLLOUT
: 0);
356 if ((ret
= pa_rtpoll_run(u
->rtpoll
, true)) < 0)
362 pollfd
= pa_rtpoll_item_get_pollfd(u
->rtpoll_item
, NULL
);
364 if (pollfd
->revents
& ~POLLOUT
) {
365 pa_log("FIFO shutdown.");
371 /* If this was no regular exit from the loop we have to continue
372 * processing messages until we received PA_MESSAGE_SHUTDOWN */
373 pa_asyncmsgq_post(u
->thread_mq
.outq
, PA_MSGOBJECT(u
->core
), PA_CORE_MESSAGE_UNLOAD_MODULE
, u
->module
, 0, NULL
, NULL
);
374 pa_asyncmsgq_wait_for(u
->thread_mq
.inq
, PA_MESSAGE_SHUTDOWN
);
375 pa_log_debug("Shutting down Xen...");
378 pa_log_debug("Thread shutting down");
381 int pa__init(pa_module
*m
) {
385 pa_sink_new_data data
;
392 if (!(ma
= pa_modargs_new(m
->argument
, valid_modargs
))) {
393 pa_log("Failed to parse module arguments.");
397 ss
= m
->core
->default_sample_spec
;
398 map
= m
->core
->default_channel_map
;
400 /* user arguments override these */
401 if (pa_modargs_get_sample_spec_and_channel_map(ma
, &ss
, &map
, PA_CHANNEL_MAP_DEFAULT
) < 0) {
402 pa_log("Invalid sample format specification or channel map");
407 xsh
= xs_domain_open();
409 pa_log("xs_domain_open failed");
412 set_state(XenbusStateUnknown
);
414 xch
= xc_interface_open(NULL
, NULL
, 0);
416 pa_log("xc_interface_open failed");
420 xce
= xc_evtchn_open(NULL
, 0);
422 pa_log("xc_evtchn_open failed");
426 /* use only dom0 as the backend for now */
427 xen_evtchn_port
= xc_evtchn_bind_unbound_port(xce
, 0);
428 if (xen_evtchn_port
== 0) {
429 pa_log("xc_evtchn_bind_unbound_port failed");
432 /* get grant reference & map locally */
433 if (alloc_gref(&gref
, (void**)&ioring
)) {
434 pa_log("alloc_gref failed");
436 device_id
= 0; /* hardcoded for now */
438 if (register_backend_state_watch()) {
439 pa_log("Xen sink: register xenstore watch failed");
442 publish_param_int("event-channel", xen_evtchn_port
);
443 publish_param_int("ring-ref", gref
.gref_ids
[0]);
445 /* let's ask for something absurd and deal with rejection */
452 backend_state
= wait_for_backend_state_change();
453 if (backend_state
== STATE_UNDEFINED
) {
454 pa_log("Xen Backend is taking long to respond, still waiting...");
456 } else if (backend_state
== -1) {
457 pa_log("Error while waiting for backend: %s", strerror(errno
));
461 ret
= state_callbacks
[backend_state
]();
463 if (ret
!=NEGOTIATION_OK
) {
464 pa_log("Negotiation with Xen backend failed!");
468 pa_sample_spec_snprint(strbuf
, 100, &ss
);
469 pa_log_debug("Negotiation ended, the result was: %s", strbuf
);
471 /* End of Phase 2, begin playback cycle */
473 u
= pa_xnew0(struct userdata
, 1);
477 pa_memchunk_reset(&u
->memchunk
);
478 u
->rtpoll
= pa_rtpoll_new();
479 pa_thread_mq_init(&u
->thread_mq
, m
->core
->mainloop
, u
->rtpoll
);
482 /* init ring buffer */
483 ioring
->prod_indx
= ioring
->cons_indx
= 0;
484 ioring
->usable_buffer_space
= BUFSIZE
- BUFSIZE
% pa_frame_size(&ss
);
486 pa_sink_new_data_init(&data
);
487 data
.driver
= __FILE__
;
489 pa_sink_new_data_set_name(&data
, pa_modargs_get_value(ma
, "sink_name", DEFAULT_SINK_NAME
));
490 pa_proplist_sets(data
.proplist
, PA_PROP_DEVICE_STRING
, "xensink");
491 pa_proplist_setf(data
.proplist
, PA_PROP_DEVICE_DESCRIPTION
, "Xen PV audio sink");
492 pa_sink_new_data_set_sample_spec(&data
, &ss
);
493 pa_sink_new_data_set_channel_map(&data
, &map
);
495 if (pa_modargs_get_proplist(ma
, "sink_properties", data
.proplist
, PA_UPDATE_REPLACE
) < 0) {
496 pa_log("Invalid properties");
497 pa_sink_new_data_done(&data
);
501 u
->sink
= pa_sink_new(m
->core
, &data
, PA_SINK_LATENCY
);
502 pa_sink_new_data_done(&data
);
505 pa_log("Failed to create sink.");
509 u
->sink
->parent
.process_msg
= sink_process_msg
;
510 u
->sink
->userdata
= u
;
512 pa_sink_set_asyncmsgq(u
->sink
, u
->thread_mq
.inq
);
513 pa_sink_set_rtpoll(u
->sink
, u
->rtpoll
);
514 pa_sink_set_max_request(u
->sink
, ioring
->usable_buffer_space
);
515 pa_sink_set_fixed_latency(u
->sink
, pa_bytes_to_usec(ioring
->usable_buffer_space
, &u
->sink
->sample_spec
));
517 u
->rtpoll_item
= pa_rtpoll_item_new(u
->rtpoll
, PA_RTPOLL_NEVER
, 1);
519 if (!(u
->thread
= pa_thread_new("xenpv-sink", thread_func
, u
))) {
520 pa_log("Failed to create thread.");
524 pa_sink_put(u
->sink
);
539 int pa__get_n_used(pa_module
*m
) {
543 pa_assert_se(u
= m
->userdata
);
545 return pa_sink_linked_by(u
->sink
);
548 void pa__done(pa_module
*m
) {
553 if (!(u
= m
->userdata
))
557 pa_sink_unlink(u
->sink
);
560 pa_asyncmsgq_send(u
->thread_mq
.inq
, NULL
, PA_MESSAGE_SHUTDOWN
, NULL
, 0, NULL
);
561 pa_thread_free(u
->thread
);
564 pa_thread_mq_done(&u
->thread_mq
);
567 pa_sink_unref(u
->sink
);
569 if (u
->memchunk
.memblock
)
570 pa_memblock_unref(u
->memchunk
.memblock
);
573 pa_rtpoll_item_free(u
->rtpoll_item
);
576 pa_rtpoll_free(u
->rtpoll
);
584 static int alloc_gref(struct ioctl_gntalloc_alloc_gref
*gref_
, void **addr
) {
585 int alloc_fd
, dev_fd
, rv
;
587 alloc_fd
= open("/dev/xen/gntalloc", O_RDWR
);
589 perror("Could not open /dev/xen/gntalloc! Have you loaded the xen_gntalloc module?");
593 dev_fd
= open("/dev/xen/gntdev", O_RDWR
);
595 perror("Could not open /dev/xen/gntdev! Have you loaded the xen_gntdev module?");
601 gref_
->flags
= GNTALLOC_FLAG_WRITABLE
;
604 rv
= ioctl(alloc_fd
, IOCTL_GNTALLOC_ALLOC_GREF
, gref_
);
606 pa_log_debug("Xen audio sink: src-add error: %s (rv=%d)\n", strerror(errno
), rv
);
610 /*addr=NULL(default),length, prot, flags, fd, offset*/
611 *addr
= mmap(0, 4096, PROT_READ
|PROT_WRITE
, MAP_SHARED
, alloc_fd
, gref_
->index
);
612 if (*addr
== MAP_FAILED
) {
614 pa_log_debug("Xen audio sink: mmap'ing shared page failed\n");
618 pa_log_debug("Xen audio sink: Got grant #%d. Mapped locally at %Ld=%p\n",
619 gref_
->gref_ids
[0], (long long)gref_
->index
, *addr
);
622 struct ioctl_gntalloc_unmap_notify uarg = {
623 .index = gref->index + offsetof(struct shr_page, notifies[0]),
624 .action = UNMAP_NOTIFY_CLEAR_BYTE
627 rv = ioctl(a_fd, IOCTL_GNTALLOC_SET_UNMAP_NOTIFY, &uarg);
629 pa_log_debug("gntalloc unmap notify error: %s (rv=%d)\n", strerror(errno), rv);
638 #define RING_FREE_BYTES ((r->usable_buffer_space - (r->prod_indx-r->cons_indx) -1) % r->usable_buffer_space)
639 static int ring_write(struct ring
*r
, void *src
, int length
) {
642 /* free space may be split over the end of the buffer */
643 int first_chunk_size
= (r
->usable_buffer_space
-r
->prod_indx
);
644 int second_chunk_size
= (r
->cons_indx
>=r
->prod_indx
)? (r
->cons_indx
) : 0;
648 if (RING_FREE_BYTES
==0) {
656 /* should return in 100ms max; definitely not midstream */
661 /* calculate lengths in case of a split buffer */
662 l
= PA_MIN((int)RING_FREE_BYTES
, length
);
663 fl
= PA_MIN(l
, first_chunk_size
);
664 sl
= PA_MIN(l
-fl
, second_chunk_size
);
666 memcpy(r
->buffer
+r
->prod_indx
, src
, fl
);
668 memcpy(r
->buffer
, ((char*)src
)+fl
, sl
);
669 r
->prod_indx
= (r
->prod_indx
+fl
+sl
) % r
->usable_buffer_space
;
675 static int publish_param(const char *paramname
, const char *value
) {
676 char keybuf
[128], valbuf
[32];
678 snprintf(keybuf
, sizeof keybuf
, "device/audio/%d/%s", device_id
, paramname
);
679 snprintf(valbuf
, sizeof valbuf
, "%s", value
);
680 return xs_write(xsh
, 0, keybuf
, valbuf
, strlen(valbuf
));
683 static int publish_param_int(const char *paramname
, const int value
) {
684 char keybuf
[128], valbuf
[32];
685 snprintf(keybuf
, sizeof keybuf
, "device/audio/%d/%s", device_id
, paramname
);
686 snprintf(valbuf
, sizeof valbuf
, "%d", value
);
687 return xs_write(xsh
, 0, keybuf
, valbuf
, strlen(valbuf
));
690 static char* read_param(const char *paramname
) {
695 my_domid
= atoi(xs_read(xsh
, 0, "domid", &len
));
696 snprintf(keybuf
, sizeof(keybuf
), "/local/domain/0/backend/audio/%d/%d/%s", my_domid
, device_id
, paramname
);
697 /* remember to free lvalue! */
698 return xs_read(xsh
, 0, keybuf
, &len
);
701 static int publish_spec(pa_sample_spec
*sample_spec
) {
702 /* Publish spec and set state to XenbusStateInitWait*/
705 ret
= publish_param("format", pa_sample_format_to_string(sample_spec
->format
));
706 ret
+= publish_param_int("rate", sample_spec
->rate
);
707 ret
+= publish_param_int("channels", sample_spec
->channels
);
712 static int read_backend_default_spec(pa_sample_spec
*sample_spec
) {
713 /* Read spec from backend */
716 out
= read_param("default-format");
717 sample_spec
->format
= pa_parse_sample_format(out
);
720 out
= read_param("default-rate");
721 sample_spec
->rate
= atoi(out
);
724 out
= read_param("default-channels");
725 sample_spec
->channels
= atoi(out
);
731 static int register_backend_state_watch() {
736 my_domid
= atoi(xs_read(xsh
, 0, "domid", &len
));
737 snprintf(keybuf
, sizeof(keybuf
), "/local/domain/0/backend/audio/%d/%d/state", my_domid
, device_id
);
738 if (!xs_watch(xsh
, keybuf
, "xenpvaudiofrontendsinktoken")) {
739 perror("xs_watch failed");
745 static int wait_for_backend_state_change() {
760 backend_state
= STATE_UNDEFINED
;
761 xs_fd
= xs_fileno(xsh
);
762 start
= now
= time(NULL
);
764 my_domid
= atoi(xs_read(xsh
, 0, "domid", &len
));
765 snprintf(keybuf
, sizeof(keybuf
), "/local/domain/0/backend/audio/%d/%d/state", my_domid
, device_id
);
771 tv
.tv_sec
= (start
+ seconds
) - now
;
772 FD_ZERO(&watch_fdset
);
773 FD_SET(xs_fd
, &watch_fdset
);
774 ret
=select(xs_fd
+ 1, &watch_fdset
, NULL
, NULL
, &tv
);
781 /* Read the watch to drain the buffer */
782 vec
= xs_read_watch(xsh
, &len
);
784 buf
= xs_read(xsh
, XBT_NULL
, vec
[0], &len
);
786 /* usually means that the backend isn't there yet */
789 backend_state
= atoi(buf
);
795 } while (backend_state
== STATE_UNDEFINED
&& \
796 (now
= time(NULL
)) < start
+ seconds
);
798 return backend_state
;