]> code.delx.au - pulseaudio/blob - src/pacat.c
esound 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 do_write(size_t length) {
33 size_t l;
34 assert(buffer && buffer_length);
35
36 l = length;
37 if (l > buffer_length)
38 l = buffer_length;
39
40 pa_stream_write(stream, buffer+buffer_index, l);
41 buffer_length -= l;
42 buffer_index += l;
43
44 if (!buffer_length) {
45 free(buffer);
46 buffer = NULL;
47 buffer_index = buffer_length = 0;
48 }
49 }
50
51 static void stream_write_callback(struct pa_stream *s, size_t length, void *userdata) {
52 assert(s && length);
53
54 mainloop_api->enable_io(mainloop_api, stdin_source, PA_MAINLOOP_API_IO_EVENT_INPUT);
55
56 if (!buffer)
57 return;
58
59 do_write(length);
60 }
61
62 static void stream_complete_callback(struct pa_context*c, struct pa_stream *s, void *userdata) {
63 assert(c);
64
65 if (!s) {
66 fprintf(stderr, "Stream creation failed.\n");
67 mainloop_api->quit(mainloop_api, 1);
68 return;
69 }
70
71 stream = s;
72 pa_stream_set_die_callback(stream, stream_die_callback, NULL);
73 pa_stream_set_write_callback(stream, stream_write_callback, NULL);
74 }
75
76 static void context_complete_callback(struct pa_context *c, int success, void *userdata) {
77 static const struct pa_sample_spec ss = {
78 .format = PA_SAMPLE_S16NE,
79 .rate = 44100,
80 .channels = 2
81 };
82
83 assert(c && !stream);
84
85 if (!success) {
86 fprintf(stderr, "Connection failed\n");
87 goto fail;
88 }
89
90 if (pa_stream_new(c, PA_STREAM_PLAYBACK, NULL, "pacat", &ss, NULL, stream_complete_callback, NULL) < 0) {
91 fprintf(stderr, "pa_stream_new() failed.\n");
92 goto fail;
93 }
94
95 return;
96
97 fail:
98 mainloop_api->quit(mainloop_api, 1);
99 }
100
101 static void stdin_callback(struct pa_mainloop_api*a, void *id, int fd, enum pa_mainloop_api_io_events events, void *userdata) {
102 size_t l, w = 0;
103 ssize_t r;
104 assert(a == mainloop_api && id && fd == STDIN_FILENO && events == PA_MAINLOOP_API_IO_EVENT_INPUT);
105
106 if (buffer) {
107 mainloop_api->enable_io(mainloop_api, stdin_source, PA_MAINLOOP_API_IO_EVENT_NULL);
108 return;
109 }
110
111 if (!stream || !(l = w = pa_stream_writable_size(stream)))
112 l = 4096;
113 buffer = malloc(l);
114 assert(buffer);
115 if ((r = read(fd, buffer, l)) <= 0) {
116 if (r == 0)
117 mainloop_api->quit(mainloop_api, 0);
118 else {
119 fprintf(stderr, "read() failed: %s\n", strerror(errno));
120 mainloop_api->quit(mainloop_api, 1);
121 }
122
123 return;
124 }
125
126 buffer_length = r;
127 buffer_index = 0;
128
129 if (w)
130 do_write(w);
131 }
132
133 int main(int argc, char *argv[]) {
134 struct pa_mainloop* m;
135 int ret = 1;
136
137 if (!(m = pa_mainloop_new())) {
138 fprintf(stderr, "pa_mainloop_new() failed.\n");
139 goto quit;
140 }
141
142 mainloop_api = pa_mainloop_get_api(m);
143
144 if (!(stdin_source = mainloop_api->source_io(mainloop_api, STDIN_FILENO, PA_MAINLOOP_API_IO_EVENT_INPUT, stdin_callback, NULL))) {
145 fprintf(stderr, "source_io() failed.\n");
146 goto quit;
147 }
148
149 if (!(context = pa_context_new(mainloop_api, argv[0]))) {
150 fprintf(stderr, "pa_context_new() failed.\n");
151 goto quit;
152 }
153
154 if (pa_context_connect(context, NULL, context_complete_callback, NULL) < 0) {
155 fprintf(stderr, "pa_context_connext() failed.\n");
156 goto quit;
157 }
158
159 pa_context_set_die_callback(context, context_die_callback, NULL);
160
161 if (pa_mainloop_run(m, &ret) < 0) {
162 fprintf(stderr, "pa_mainloop_run() failed.\n");
163 goto quit;
164 }
165
166 quit:
167 if (stream)
168 pa_stream_free(stream);
169 if (context)
170 pa_context_free(context);
171 if (m)
172 pa_mainloop_free(m);
173 if (buffer)
174 free(buffer);
175
176 return ret;
177 }