]> code.delx.au - pulseaudio/blob - src/pacat.c
main part of the native protocol
[pulseaudio] / src / pacat.c
1 #include <string.h>
2 #include <errno.h>
3 #include <unistd.h>
4 #include <assert.h>
5 #include <stdio.h>
6 #include <stdlib.h>
7
8 #include "polyp.h"
9 #include "mainloop.h"
10
11 static struct pa_context *context = NULL;
12 static struct pa_stream *stream = NULL;
13 static struct pa_mainloop_api *mainloop_api = NULL;
14
15 static void *buffer = NULL;
16 static size_t buffer_length = 0, buffer_index = 0;
17
18 static void* stdin_source = NULL;
19
20 static void context_die_callback(struct pa_context *c, void *userdata) {
21 assert(c);
22 fprintf(stderr, "Connection to server shut down, exiting.\n");
23 mainloop_api->quit(mainloop_api, 1);
24 }
25
26 static void stream_die_callback(struct pa_stream *s, void *userdata) {
27 assert(s);
28 fprintf(stderr, "Stream deleted, exiting.\n");
29 mainloop_api->quit(mainloop_api, 1);
30 }
31
32 static void stream_write_callback(struct pa_stream *s, size_t length, void *userdata) {
33 size_t l;
34 assert(s && length);
35
36 mainloop_api->enable_io(mainloop_api, stdin_source, PA_STREAM_PLAYBACK);
37
38 if (!buffer)
39 return;
40
41 assert(buffer_length);
42
43 l = length;
44 if (l > buffer_length)
45 l = buffer_length;
46
47 pa_stream_write(s, buffer+buffer_index, l);
48 buffer_length -= l;
49 buffer_index += l;
50
51 if (!buffer_length) {
52 free(buffer);
53 buffer = NULL;
54 buffer_index = buffer_length = 0;
55 }
56 }
57
58 static void stream_complete_callback(struct pa_context*c, struct pa_stream *s, void *userdata) {
59 assert(c);
60
61 if (!s) {
62 fprintf(stderr, "Stream creation failed.\n");
63 mainloop_api->quit(mainloop_api, 1);
64 }
65
66 stream = s;
67 pa_stream_set_die_callback(stream, stream_die_callback, NULL);
68 pa_stream_set_write_callback(stream, stream_write_callback, NULL);
69 }
70
71 static void context_complete_callback(struct pa_context *c, int success, void *userdata) {
72 static const struct pa_sample_spec ss = {
73 .format = SAMPLE_S16NE,
74 .rate = 44100,
75 .channels = 2
76 };
77
78 assert(c && !stream);
79
80 if (!success) {
81 fprintf(stderr, "Connection failed\n");
82 goto fail;
83 }
84
85 if (pa_stream_new(c, PA_STREAM_PLAYBACK, NULL, "pacat", &ss, NULL, stream_complete_callback, NULL) < 0) {
86 fprintf(stderr, "pa_stream_new() failed.\n");
87 goto fail;
88 }
89
90 return;
91
92 fail:
93 mainloop_api->quit(mainloop_api, 1);
94 }
95
96 static void stdin_callback(struct pa_mainloop_api*a, void *id, int fd, enum pa_mainloop_api_io_events events, void *userdata) {
97 size_t l;
98 ssize_t r;
99 assert(a == mainloop_api && id && fd == STDIN_FILENO && events == PA_MAINLOOP_API_IO_EVENT_INPUT);
100
101 if (buffer) {
102 mainloop_api->enable_io(mainloop_api, stdin_source, PA_MAINLOOP_API_IO_EVENT_NULL);
103 return;
104 }
105
106 if (!(l = pa_stream_writable_size(stream)))
107 l = 4096;
108 buffer = malloc(l);
109 assert(buffer);
110 if ((r = read(fd, buffer, l)) <= 0) {
111 if (r == 0)
112 mainloop_api->quit(mainloop_api, 0);
113 else {
114 fprintf(stderr, "read() failed: %s\n", strerror(errno));
115 mainloop_api->quit(mainloop_api, 1);
116 }
117
118 return;
119 }
120
121 buffer_length = r;
122 buffer_index = 0;
123 }
124
125 int main(int argc, char *argv[]) {
126 struct pa_mainloop* m;
127 int ret = 1;
128
129 if (!(m = pa_mainloop_new())) {
130 fprintf(stderr, "pa_mainloop_new() failed.\n");
131 goto quit;
132 }
133
134 mainloop_api = pa_mainloop_get_api(m);
135
136 if (!(stdin_source = mainloop_api->source_io(mainloop_api, STDIN_FILENO, PA_MAINLOOP_API_IO_EVENT_INPUT, stdin_callback, NULL))) {
137 fprintf(stderr, "source_io() failed.\n");
138 goto quit;
139 }
140
141 if (!(context = pa_context_new(mainloop_api, argv[0]))) {
142 fprintf(stderr, "pa_context_new() failed.\n");
143 goto quit;
144 }
145
146 if (pa_context_connect(context, NULL, context_complete_callback, NULL) < 0) {
147 fprintf(stderr, "pa_context_connext() failed.\n");
148 goto quit;
149 }
150
151 pa_context_set_die_callback(context, context_die_callback, NULL);
152
153 if (pa_mainloop_run(m, &ret) < 0) {
154 fprintf(stderr, "pa_mainloop_run() failed.\n");
155 goto quit;
156 }
157
158 quit:
159 if (stream)
160 pa_stream_free(stream);
161 if (context)
162 pa_context_free(context);
163 if (m)
164 pa_mainloop_free(m);
165 if (buffer)
166 free(buffer);
167
168 return ret;
169 }