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
) {
282 if (u
->memchunk
.length
<= 0)
283 pa_sink_render(u
->sink
, ioring
->usable_buffer_space
, &u
->memchunk
);
286 pa_assert(u
->memchunk
.length
> 0);
288 xc_evtchn_notify(xce
, xen_evtchn_port
);
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
);
297 pa_memblock_release(u
->memchunk
.memblock
);
304 else if (errno
== EAGAIN
)
307 pa_log("Failed to write data to FIFO: %s", pa_cstrerror(errno
));
313 u
->memchunk
.index
+= (size_t) l
;
314 u
->memchunk
.length
-= (size_t) l
;
316 if (u
->memchunk
.length
<= 0) {
317 pa_memblock_unref(u
->memchunk
.memblock
);
318 pa_memchunk_reset(&u
->memchunk
);
326 static void thread_func(void *userdata
) {
327 struct userdata
*u
= userdata
;
331 pa_log_debug("Thread starting up");
333 pa_thread_mq_install(&u
->thread_mq
);
336 struct pollfd
*pollfd
;
339 pollfd
= pa_rtpoll_item_get_pollfd(u
->rtpoll_item
, NULL
);
341 if (PA_UNLIKELY(u
->sink
->thread_info
.rewind_requested
))
342 pa_sink_process_rewind(u
->sink
, 0);
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)
354 /* Hmm, nothing to do. Let's sleep */
356 pollfd
->events
= (short) (u
->sink
->thread_info
.state
== PA_SINK_RUNNING
? POLLOUT
: 0);
358 if ((ret
= pa_rtpoll_run(u
->rtpoll
, TRUE
)) < 0)
364 pollfd
= pa_rtpoll_item_get_pollfd(u
->rtpoll_item
, NULL
);
366 if (pollfd
->revents
& ~POLLOUT
) {
367 pa_log("FIFO shutdown.");
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...");
380 pa_log_debug("Thread shutting down");
383 int pa__init(pa_module
*m
) {
387 pa_sink_new_data data
;
394 if (!(ma
= pa_modargs_new(m
->argument
, valid_modargs
))) {
395 pa_log("Failed to parse module arguments.");
399 ss
= m
->core
->default_sample_spec
;
400 map
= m
->core
->default_channel_map
;
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");
409 xsh
= xs_domain_open();
411 pa_log("xs_domain_open failed");
414 set_state(XenbusStateUnknown
);
416 xch
= xc_interface_open(NULL
, NULL
, 0);
418 pa_log("xc_interface_open failed");
422 xce
= xc_evtchn_open(NULL
, 0);
424 pa_log("xc_evtchn_open failed");
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");
434 /* get grant reference & map locally */
435 if (alloc_gref(&gref
, (void**)&ioring
)) {
436 pa_log("alloc_gref failed");
438 device_id
= 0; /* hardcoded for now */
440 if (register_backend_state_watch()) {
441 pa_log("Xen sink: register xenstore watch failed");
444 publish_param_int("event-channel", xen_evtchn_port
);
445 publish_param_int("ring-ref", gref
.gref_ids
[0]);
447 /* let's ask for something absurd and deal with rejection */
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...");
458 } else if (backend_state
== -1) {
459 pa_log("Error while waiting for backend: %s", strerror(errno
));
463 ret
= state_callbacks
[backend_state
]();
465 if (ret
!=NEGOTIATION_OK
) {
466 pa_log("Negotiation with Xen backend failed!");
470 pa_sample_spec_snprint(strbuf
, 100, &ss
);
471 pa_log_debug("Negotiation ended, the result was: %s", strbuf
);
473 /* End of Phase 2, begin playback cycle */
475 u
= pa_xnew0(struct userdata
, 1);
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
);
484 /* init ring buffer */
485 ioring
->prod_indx
= ioring
->cons_indx
= 0;
486 ioring
->usable_buffer_space
= BUFSIZE
- BUFSIZE
% pa_frame_size(&ss
);
488 pa_sink_new_data_init(&data
);
489 data
.driver
= __FILE__
;
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
);
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
);
503 u
->sink
= pa_sink_new(m
->core
, &data
, PA_SINK_LATENCY
);
504 pa_sink_new_data_done(&data
);
507 pa_log("Failed to create sink.");
511 u
->sink
->parent
.process_msg
= sink_process_msg
;
512 u
->sink
->userdata
= u
;
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
));
519 u
->rtpoll_item
= pa_rtpoll_item_new(u
->rtpoll
, PA_RTPOLL_NEVER
, 1);
521 if (!(u
->thread
= pa_thread_new("xenpv-sink", thread_func
, u
))) {
522 pa_log("Failed to create thread.");
526 pa_sink_put(u
->sink
);
541 int pa__get_n_used(pa_module
*m
) {
545 pa_assert_se(u
= m
->userdata
);
547 return pa_sink_linked_by(u
->sink
);
550 void pa__done(pa_module
*m
) {
555 if (!(u
= m
->userdata
))
559 pa_sink_unlink(u
->sink
);
562 pa_asyncmsgq_send(u
->thread_mq
.inq
, NULL
, PA_MESSAGE_SHUTDOWN
, NULL
, 0, NULL
);
563 pa_thread_free(u
->thread
);
566 pa_thread_mq_done(&u
->thread_mq
);
569 pa_sink_unref(u
->sink
);
571 if (u
->memchunk
.memblock
)
572 pa_memblock_unref(u
->memchunk
.memblock
);
575 pa_rtpoll_item_free(u
->rtpoll_item
);
578 pa_rtpoll_free(u
->rtpoll
);
587 static int alloc_gref(struct ioctl_gntalloc_alloc_gref
*gref_
, void **addr
) {
588 int alloc_fd
, dev_fd
, rv
;
590 alloc_fd
= open("/dev/xen/gntalloc", O_RDWR
);
592 perror("Could not open /dev/xen/gntalloc! Have you loaded the xen_gntalloc module?");
596 dev_fd
= open("/dev/xen/gntdev", O_RDWR
);
598 perror("Could not open /dev/xen/gntdev! Have you loaded the xen_gntdev module?");
604 gref_
->flags
= GNTALLOC_FLAG_WRITABLE
;
607 rv
= ioctl(alloc_fd
, IOCTL_GNTALLOC_ALLOC_GREF
, gref_
);
609 pa_log_debug("Xen audio sink: src-add error: %s (rv=%d)\n", strerror(errno
), rv
);
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
) {
617 pa_log_debug("Xen audio sink: mmap'ing shared page failed\n");
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
);
625 struct ioctl_gntalloc_unmap_notify uarg = {
626 .index = gref->index + offsetof(struct shr_page, notifies[0]),
627 .action = UNMAP_NOTIFY_CLEAR_BYTE
630 rv = ioctl(a_fd, IOCTL_GNTALLOC_SET_UNMAP_NOTIFY, &uarg);
632 pa_log_debug("gntalloc unmap notify error: %s (rv=%d)\n", strerror(errno), rv);
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
) {
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;
651 if (RING_FREE_BYTES
==0) {
659 /* should return in 100ms max; definitely not midstream */
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
);
669 memcpy(r
->buffer
+r
->prod_indx
, src
, fl
);
671 memcpy(r
->buffer
, ((char*)src
)+fl
, sl
);
672 r
->prod_indx
= (r
->prod_indx
+fl
+sl
) % r
->usable_buffer_space
;
678 static int publish_param(const char *paramname
, const char *value
) {
679 char keybuf
[128], valbuf
[32];
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
));
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
));
693 static char* read_param(const char *paramname
) {
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
);
705 static int publish_spec(pa_sample_spec
*sample_spec
) {
706 /* Publish spec and set state to XenbusStateInitWait*/
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
);
717 static int read_backend_default_spec(pa_sample_spec
*sample_spec
) {
718 /* Read spec from backend */
721 out
= read_param("default-format");
722 sample_spec
->format
= pa_parse_sample_format(out
);
725 out
= read_param("default-rate");
726 sample_spec
->rate
= atoi(out
);
729 out
= read_param("default-channels");
730 sample_spec
->channels
= atoi(out
);
736 static int register_backend_state_watch() {
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");
750 static int wait_for_backend_state_change() {
765 backend_state
= STATE_UNDEFINED
;
766 xs_fd
= xs_fileno(xsh
);
767 start
= now
= time(NULL
);
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
);
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
);
786 /* Read the watch to drain the buffer */
787 vec
= xs_read_watch(xsh
, &len
);
789 buf
= xs_read(xsh
, XBT_NULL
, vec
[0], &len
);
791 /* usually means that the backend isn't there yet */
794 backend_state
= atoi(buf
);
800 } while (backend_state
== STATE_UNDEFINED
&& \
801 (now
= time(NULL
)) < start
+ seconds
);
803 return backend_state
;