00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #ifdef HAVE_CONFIG_H
00026 #include <config.h>
00027 #endif
00028
00029 #include <signal.h>
00030 #include <string.h>
00031 #include <errno.h>
00032 #include <unistd.h>
00033 #include <assert.h>
00034 #include <stdio.h>
00035 #include <stdlib.h>
00036 #include <getopt.h>
00037 #include <fcntl.h>
00038
00039 #include <pulse/pulseaudio.h>
00040
00041 #define TIME_EVENT_USEC 50000
00042
00043 #if PA_API_VERSION < 10
00044 #error Invalid PulseAudio API version
00045 #endif
00046
00047 static enum { RECORD, PLAYBACK } mode = PLAYBACK;
00048
00049 static pa_context *context = NULL;
00050 static pa_stream *stream = NULL;
00051 static pa_mainloop_api *mainloop_api = NULL;
00052
00053 static void *buffer = NULL;
00054 static size_t buffer_length = 0, buffer_index = 0;
00055
00056 static pa_io_event* stdio_event = NULL;
00057
00058 static char *stream_name = NULL, *client_name = NULL, *device = NULL;
00059
00060 static int verbose = 0;
00061 static pa_volume_t volume = PA_VOLUME_NORM;
00062
00063 static pa_sample_spec sample_spec = {
00064 .format = PA_SAMPLE_S16LE,
00065 .rate = 44100,
00066 .channels = 2
00067 };
00068
00069 static pa_channel_map channel_map;
00070 static int channel_map_set = 0;
00071
00072 static pa_stream_flags_t flags = 0;
00073
00074
00075 static void quit(int ret) {
00076 assert(mainloop_api);
00077 mainloop_api->quit(mainloop_api, ret);
00078 }
00079
00080
00081 static void do_stream_write(size_t length) {
00082 size_t l;
00083 assert(length);
00084
00085 if (!buffer || !buffer_length)
00086 return;
00087
00088 l = length;
00089 if (l > buffer_length)
00090 l = buffer_length;
00091
00092 if (pa_stream_write(stream, (uint8_t*) buffer + buffer_index, l, NULL, 0, PA_SEEK_RELATIVE) < 0) {
00093 fprintf(stderr, "pa_stream_write() failed: %s\n", pa_strerror(pa_context_errno(context)));
00094 quit(1);
00095 return;
00096 }
00097
00098 buffer_length -= l;
00099 buffer_index += l;
00100
00101 if (!buffer_length) {
00102 pa_xfree(buffer);
00103 buffer = NULL;
00104 buffer_index = buffer_length = 0;
00105 }
00106 }
00107
00108
00109 static void stream_write_callback(pa_stream *s, size_t length, void *userdata) {
00110 assert(s);
00111 assert(length > 0);
00112
00113 if (stdio_event)
00114 mainloop_api->io_enable(stdio_event, PA_IO_EVENT_INPUT);
00115
00116 if (!buffer)
00117 return;
00118
00119 do_stream_write(length);
00120 }
00121
00122
00123 static void stream_read_callback(pa_stream *s, size_t length, void *userdata) {
00124 const void *data;
00125 assert(s);
00126 assert(length > 0);
00127
00128 if (stdio_event)
00129 mainloop_api->io_enable(stdio_event, PA_IO_EVENT_OUTPUT);
00130
00131 if (pa_stream_peek(s, &data, &length) < 0) {
00132 fprintf(stderr, "pa_stream_peek() failed: %s\n", pa_strerror(pa_context_errno(context)));
00133 quit(1);
00134 return;
00135 }
00136
00137 assert(data);
00138 assert(length > 0);
00139
00140 if (buffer) {
00141 fprintf(stderr, "Buffer overrun, dropping incoming data\n");
00142 if (pa_stream_drop(s) < 0) {
00143 fprintf(stderr, "pa_stream_drop() failed: %s\n", pa_strerror(pa_context_errno(context)));
00144 quit(1);
00145 }
00146 return;
00147 }
00148
00149 buffer = pa_xmalloc(buffer_length = length);
00150 memcpy(buffer, data, length);
00151 buffer_index = 0;
00152 pa_stream_drop(s);
00153 }
00154
00155
00156 static void stream_state_callback(pa_stream *s, void *userdata) {
00157 assert(s);
00158
00159 switch (pa_stream_get_state(s)) {
00160 case PA_STREAM_CREATING:
00161 case PA_STREAM_TERMINATED:
00162 break;
00163
00164 case PA_STREAM_READY:
00165 if (verbose) {
00166 const pa_buffer_attr *a;
00167 char cmt[PA_CHANNEL_MAP_SNPRINT_MAX], sst[PA_SAMPLE_SPEC_SNPRINT_MAX];
00168
00169 fprintf(stderr, "Stream successfully created.\n");
00170
00171 if (!(a = pa_stream_get_buffer_attr(s)))
00172 fprintf(stderr, "pa_stream_get_buffer_attr() failed: %s\n", pa_strerror(pa_context_errno(pa_stream_get_context(s))));
00173 else {
00174
00175 if (mode == PLAYBACK)
00176 fprintf(stderr, "Buffer metrics: maxlength=%u, tlength=%u, prebuf=%u, minreq=%u\n", a->maxlength, a->tlength, a->prebuf, a->minreq);
00177 else {
00178 assert(mode == RECORD);
00179 fprintf(stderr, "Buffer metrics: maxlength=%u, fragsize=%u\n", a->maxlength, a->fragsize);
00180 }
00181 }
00182
00183 fprintf(stderr, "Using sample spec '%s', channel map '%s'.\n",
00184 pa_sample_spec_snprint(sst, sizeof(sst), pa_stream_get_sample_spec(s)),
00185 pa_channel_map_snprint(cmt, sizeof(cmt), pa_stream_get_channel_map(s)));
00186
00187 fprintf(stderr, "Connected to device %s (%u, %ssuspended).\n",
00188 pa_stream_get_device_name(s),
00189 pa_stream_get_device_index(s),
00190 pa_stream_is_suspended(s) ? "" : "not ");
00191 }
00192
00193 break;
00194
00195 case PA_STREAM_FAILED:
00196 default:
00197 fprintf(stderr, "Stream error: %s\n", pa_strerror(pa_context_errno(pa_stream_get_context(s))));
00198 quit(1);
00199 }
00200 }
00201
00202 static void stream_suspended_callback(pa_stream *s, void *userdata) {
00203 assert(s);
00204
00205 if (verbose) {
00206 if (pa_stream_is_suspended(s))
00207 fprintf(stderr, "Stream device suspended.\n");
00208 else
00209 fprintf(stderr, "Stream device resumed.\n");
00210 }
00211 }
00212
00213 static void stream_moved_callback(pa_stream *s, void *userdata) {
00214 assert(s);
00215
00216 if (verbose)
00217 fprintf(stderr, "Stream moved to device %s (%u, %ssuspended).\n", pa_stream_get_device_name(s), pa_stream_get_device_index(s), pa_stream_is_suspended(s) ? "" : "not ");
00218 }
00219
00220
00221 static void context_state_callback(pa_context *c, void *userdata) {
00222 assert(c);
00223
00224 switch (pa_context_get_state(c)) {
00225 case PA_CONTEXT_CONNECTING:
00226 case PA_CONTEXT_AUTHORIZING:
00227 case PA_CONTEXT_SETTING_NAME:
00228 break;
00229
00230 case PA_CONTEXT_READY: {
00231 int r;
00232
00233 assert(c);
00234 assert(!stream);
00235
00236 if (verbose)
00237 fprintf(stderr, "Connection established.\n");
00238
00239 if (!(stream = pa_stream_new(c, stream_name, &sample_spec, channel_map_set ? &channel_map : NULL))) {
00240 fprintf(stderr, "pa_stream_new() failed: %s\n", pa_strerror(pa_context_errno(c)));
00241 goto fail;
00242 }
00243
00244 pa_stream_set_state_callback(stream, stream_state_callback, NULL);
00245 pa_stream_set_write_callback(stream, stream_write_callback, NULL);
00246 pa_stream_set_read_callback(stream, stream_read_callback, NULL);
00247 pa_stream_set_suspended_callback(stream, stream_suspended_callback, NULL);
00248 pa_stream_set_moved_callback(stream, stream_moved_callback, NULL);
00249
00250 if (mode == PLAYBACK) {
00251 pa_cvolume cv;
00252 if ((r = pa_stream_connect_playback(stream, device, NULL, flags, pa_cvolume_set(&cv, sample_spec.channels, volume), NULL)) < 0) {
00253 fprintf(stderr, "pa_stream_connect_playback() failed: %s\n", pa_strerror(pa_context_errno(c)));
00254 goto fail;
00255 }
00256
00257 } else {
00258 if ((r = pa_stream_connect_record(stream, device, NULL, flags)) < 0) {
00259 fprintf(stderr, "pa_stream_connect_record() failed: %s\n", pa_strerror(pa_context_errno(c)));
00260 goto fail;
00261 }
00262 }
00263
00264 break;
00265 }
00266
00267 case PA_CONTEXT_TERMINATED:
00268 quit(0);
00269 break;
00270
00271 case PA_CONTEXT_FAILED:
00272 default:
00273 fprintf(stderr, "Connection failure: %s\n", pa_strerror(pa_context_errno(c)));
00274 goto fail;
00275 }
00276
00277 return;
00278
00279 fail:
00280 quit(1);
00281
00282 }
00283
00284
00285 static void context_drain_complete(pa_context*c, void *userdata) {
00286 pa_context_disconnect(c);
00287 }
00288
00289
00290 static void stream_drain_complete(pa_stream*s, int success, void *userdata) {
00291 pa_operation *o;
00292
00293 if (!success) {
00294 fprintf(stderr, "Failed to drain stream: %s\n", pa_strerror(pa_context_errno(context)));
00295 quit(1);
00296 }
00297
00298 if (verbose)
00299 fprintf(stderr, "Playback stream drained.\n");
00300
00301 pa_stream_disconnect(stream);
00302 pa_stream_unref(stream);
00303 stream = NULL;
00304
00305 if (!(o = pa_context_drain(context, context_drain_complete, NULL)))
00306 pa_context_disconnect(context);
00307 else {
00308 if (verbose)
00309 fprintf(stderr, "Draining connection to server.\n");
00310 }
00311 }
00312
00313
00314 static void stdin_callback(pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata) {
00315 size_t l, w = 0;
00316 ssize_t r;
00317
00318 assert(a == mainloop_api);
00319 assert(e);
00320 assert(stdio_event == e);
00321
00322 if (buffer) {
00323 mainloop_api->io_enable(stdio_event, PA_IO_EVENT_NULL);
00324 return;
00325 }
00326
00327 if (!stream || pa_stream_get_state(stream) != PA_STREAM_READY || !(l = w = pa_stream_writable_size(stream)))
00328 l = 4096;
00329
00330 buffer = pa_xmalloc(l);
00331
00332 if ((r = read(fd, buffer, l)) <= 0) {
00333 if (r == 0) {
00334 if (verbose)
00335 fprintf(stderr, "Got EOF.\n");
00336
00337 if (stream) {
00338 pa_operation *o;
00339
00340 if (!(o = pa_stream_drain(stream, stream_drain_complete, NULL))) {
00341 fprintf(stderr, "pa_stream_drain(): %s\n", pa_strerror(pa_context_errno(context)));
00342 quit(1);
00343 return;
00344 }
00345
00346 pa_operation_unref(o);
00347 } else
00348 quit(0);
00349
00350 } else {
00351 fprintf(stderr, "read() failed: %s\n", strerror(errno));
00352 quit(1);
00353 }
00354
00355 mainloop_api->io_free(stdio_event);
00356 stdio_event = NULL;
00357 return;
00358 }
00359
00360 buffer_length = r;
00361 buffer_index = 0;
00362
00363 if (w)
00364 do_stream_write(w);
00365 }
00366
00367
00368 static void stdout_callback(pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata) {
00369 ssize_t r;
00370
00371 assert(a == mainloop_api);
00372 assert(e);
00373 assert(stdio_event == e);
00374
00375 if (!buffer) {
00376 mainloop_api->io_enable(stdio_event, PA_IO_EVENT_NULL);
00377 return;
00378 }
00379
00380 assert(buffer_length);
00381
00382 if ((r = write(fd, (uint8_t*) buffer+buffer_index, buffer_length)) <= 0) {
00383 fprintf(stderr, "write() failed: %s\n", strerror(errno));
00384 quit(1);
00385
00386 mainloop_api->io_free(stdio_event);
00387 stdio_event = NULL;
00388 return;
00389 }
00390
00391 buffer_length -= r;
00392 buffer_index += r;
00393
00394 if (!buffer_length) {
00395 pa_xfree(buffer);
00396 buffer = NULL;
00397 buffer_length = buffer_index = 0;
00398 }
00399 }
00400
00401
00402 static void exit_signal_callback(pa_mainloop_api*m, pa_signal_event *e, int sig, void *userdata) {
00403 if (verbose)
00404 fprintf(stderr, "Got signal, exiting.\n");
00405 quit(0);
00406 }
00407
00408
00409 static void stream_update_timing_callback(pa_stream *s, int success, void *userdata) {
00410 pa_usec_t latency, usec;
00411 int negative = 0;
00412
00413 assert(s);
00414
00415 if (!success ||
00416 pa_stream_get_time(s, &usec) < 0 ||
00417 pa_stream_get_latency(s, &latency, &negative) < 0) {
00418 fprintf(stderr, "Failed to get latency: %s\n", pa_strerror(pa_context_errno(context)));
00419 quit(1);
00420 return;
00421 }
00422
00423 fprintf(stderr, "Time: %0.3f sec; Latency: %0.0f usec. \r",
00424 (float) usec / 1000000,
00425 (float) latency * (negative?-1:1));
00426 }
00427
00428
00429 static void sigusr1_signal_callback(pa_mainloop_api*m, pa_signal_event *e, int sig, void *userdata) {
00430
00431 if (!stream)
00432 return;
00433
00434 pa_operation_unref(pa_stream_update_timing_info(stream, stream_update_timing_callback, NULL));
00435 }
00436
00437 static void time_event_callback(pa_mainloop_api*m, pa_time_event *e, const struct timeval *tv, void *userdata) {
00438 struct timeval next;
00439
00440 if (stream && pa_stream_get_state(stream) == PA_STREAM_READY) {
00441 pa_operation *o;
00442 if (!(o = pa_stream_update_timing_info(stream, stream_update_timing_callback, NULL)))
00443 fprintf(stderr, "pa_stream_update_timing_info() failed: %s\n", pa_strerror(pa_context_errno(context)));
00444 else
00445 pa_operation_unref(o);
00446 }
00447
00448 pa_gettimeofday(&next);
00449 pa_timeval_add(&next, TIME_EVENT_USEC);
00450
00451 m->time_restart(e, &next);
00452 }
00453
00454 static void help(const char *argv0) {
00455
00456 printf("%s [options]\n\n"
00457 " -h, --help Show this help\n"
00458 " --version Show version\n\n"
00459 " -r, --record Create a connection for recording\n"
00460 " -p, --playback Create a connection for playback\n\n"
00461 " -v, --verbose Enable verbose operations\n\n"
00462 " -s, --server=SERVER The name of the server to connect to\n"
00463 " -d, --device=DEVICE The name of the sink/source to connect to\n"
00464 " -n, --client-name=NAME How to call this client on the server\n"
00465 " --stream-name=NAME How to call this stream on the server\n"
00466 " --volume=VOLUME Specify the initial (linear) volume in range 0...65536\n"
00467 " --rate=SAMPLERATE The sample rate in Hz (defaults to 44100)\n"
00468 " --format=SAMPLEFORMAT The sample type, one of s16le, s16be, u8, float32le,\n"
00469 " float32be, ulaw, alaw (defaults to s16ne)\n"
00470 " --channels=CHANNELS The number of channels, 1 for mono, 2 for stereo\n"
00471 " (defaults to 2)\n"
00472 " --channel-map=CHANNELMAP Channel map to use instead of the default\n"
00473 " --fix-format Take the sample format from the sink the stream is\n"
00474 " being connected to.\n"
00475 " --fix-rate Take the sampling rate from the sink the stream is\n"
00476 " being connected to.\n"
00477 " --fix-channels Take the number of channels and the channel map\n"
00478 " from the sink the stream is being connected to.\n"
00479 " --no-remix Don't upmix or downmix channels.\n"
00480 " --no-remap Map channels by index instead of name.\n"
00481 ,
00482 argv0);
00483 }
00484
00485 enum {
00486 ARG_VERSION = 256,
00487 ARG_STREAM_NAME,
00488 ARG_VOLUME,
00489 ARG_SAMPLERATE,
00490 ARG_SAMPLEFORMAT,
00491 ARG_CHANNELS,
00492 ARG_CHANNELMAP,
00493 ARG_FIX_FORMAT,
00494 ARG_FIX_RATE,
00495 ARG_FIX_CHANNELS,
00496 ARG_NO_REMAP,
00497 ARG_NO_REMIX
00498 };
00499
00500 int main(int argc, char *argv[]) {
00501 pa_mainloop* m = NULL;
00502 int ret = 1, r, c;
00503 char *bn, *server = NULL;
00504 pa_time_event *time_event = NULL;
00505
00506 static const struct option long_options[] = {
00507 {"record", 0, NULL, 'r'},
00508 {"playback", 0, NULL, 'p'},
00509 {"device", 1, NULL, 'd'},
00510 {"server", 1, NULL, 's'},
00511 {"client-name", 1, NULL, 'n'},
00512 {"stream-name", 1, NULL, ARG_STREAM_NAME},
00513 {"version", 0, NULL, ARG_VERSION},
00514 {"help", 0, NULL, 'h'},
00515 {"verbose", 0, NULL, 'v'},
00516 {"volume", 1, NULL, ARG_VOLUME},
00517 {"rate", 1, NULL, ARG_SAMPLERATE},
00518 {"format", 1, NULL, ARG_SAMPLEFORMAT},
00519 {"channels", 1, NULL, ARG_CHANNELS},
00520 {"channel-map", 1, NULL, ARG_CHANNELMAP},
00521 {"fix-format", 0, NULL, ARG_FIX_FORMAT},
00522 {"fix-rate", 0, NULL, ARG_FIX_RATE},
00523 {"fix-channels",0, NULL, ARG_FIX_CHANNELS},
00524 {"no-remap", 0, NULL, ARG_NO_REMAP},
00525 {"no-remix", 0, NULL, ARG_NO_REMIX},
00526 {NULL, 0, NULL, 0}
00527 };
00528
00529 if (!(bn = strrchr(argv[0], '/')))
00530 bn = argv[0];
00531 else
00532 bn++;
00533
00534 if (strstr(bn, "rec") || strstr(bn, "mon"))
00535 mode = RECORD;
00536 else if (strstr(bn, "cat") || strstr(bn, "play"))
00537 mode = PLAYBACK;
00538
00539 while ((c = getopt_long(argc, argv, "rpd:s:n:hv", long_options, NULL)) != -1) {
00540
00541 switch (c) {
00542 case 'h' :
00543 help(bn);
00544 ret = 0;
00545 goto quit;
00546
00547 case ARG_VERSION:
00548 printf("pacat "PACKAGE_VERSION"\nCompiled with libpulse %s\nLinked with libpulse %s\n", pa_get_headers_version(), pa_get_library_version());
00549 ret = 0;
00550 goto quit;
00551
00552 case 'r':
00553 mode = RECORD;
00554 break;
00555
00556 case 'p':
00557 mode = PLAYBACK;
00558 break;
00559
00560 case 'd':
00561 pa_xfree(device);
00562 device = pa_xstrdup(optarg);
00563 break;
00564
00565 case 's':
00566 pa_xfree(server);
00567 server = pa_xstrdup(optarg);
00568 break;
00569
00570 case 'n':
00571 pa_xfree(client_name);
00572 client_name = pa_xstrdup(optarg);
00573 break;
00574
00575 case ARG_STREAM_NAME:
00576 pa_xfree(stream_name);
00577 stream_name = pa_xstrdup(optarg);
00578 break;
00579
00580 case 'v':
00581 verbose = 1;
00582 break;
00583
00584 case ARG_VOLUME: {
00585 int v = atoi(optarg);
00586 volume = v < 0 ? 0 : v;
00587 break;
00588 }
00589
00590 case ARG_CHANNELS:
00591 sample_spec.channels = atoi(optarg);
00592 break;
00593
00594 case ARG_SAMPLEFORMAT:
00595 sample_spec.format = pa_parse_sample_format(optarg);
00596 break;
00597
00598 case ARG_SAMPLERATE:
00599 sample_spec.rate = atoi(optarg);
00600 break;
00601
00602 case ARG_CHANNELMAP:
00603 if (!pa_channel_map_parse(&channel_map, optarg)) {
00604 fprintf(stderr, "Invalid channel map\n");
00605 goto quit;
00606 }
00607
00608 channel_map_set = 1;
00609 break;
00610
00611 case ARG_FIX_CHANNELS:
00612 flags |= PA_STREAM_FIX_CHANNELS;
00613 break;
00614
00615 case ARG_FIX_RATE:
00616 flags |= PA_STREAM_FIX_RATE;
00617 break;
00618
00619 case ARG_FIX_FORMAT:
00620 flags |= PA_STREAM_FIX_FORMAT;
00621 break;
00622
00623 case ARG_NO_REMIX:
00624 flags |= PA_STREAM_NO_REMIX_CHANNELS;
00625 break;
00626
00627 case ARG_NO_REMAP:
00628 flags |= PA_STREAM_NO_REMAP_CHANNELS;
00629 break;
00630
00631 default:
00632 goto quit;
00633 }
00634 }
00635
00636 if (!pa_sample_spec_valid(&sample_spec)) {
00637 fprintf(stderr, "Invalid sample specification\n");
00638 goto quit;
00639 }
00640
00641 if (channel_map_set && channel_map.channels != sample_spec.channels) {
00642 fprintf(stderr, "Channel map doesn't match sample specification\n");
00643 goto quit;
00644 }
00645
00646 if (verbose) {
00647 char t[PA_SAMPLE_SPEC_SNPRINT_MAX];
00648 pa_sample_spec_snprint(t, sizeof(t), &sample_spec);
00649 fprintf(stderr, "Opening a %s stream with sample specification '%s'.\n", mode == RECORD ? "recording" : "playback", t);
00650 }
00651
00652 if (!(optind >= argc)) {
00653 if (optind+1 == argc) {
00654 int fd;
00655
00656 if ((fd = open(argv[optind], mode == PLAYBACK ? O_RDONLY : O_WRONLY|O_TRUNC|O_CREAT, 0666)) < 0) {
00657 fprintf(stderr, "open(): %s\n", strerror(errno));
00658 goto quit;
00659 }
00660
00661 if (dup2(fd, mode == PLAYBACK ? 0 : 1) < 0) {
00662 fprintf(stderr, "dup2(): %s\n", strerror(errno));
00663 goto quit;
00664 }
00665
00666 close(fd);
00667
00668 if (!stream_name)
00669 stream_name = pa_xstrdup(argv[optind]);
00670
00671 } else {
00672 fprintf(stderr, "Too many arguments.\n");
00673 goto quit;
00674 }
00675 }
00676
00677 if (!client_name)
00678 client_name = pa_xstrdup(bn);
00679
00680 if (!stream_name)
00681 stream_name = pa_xstrdup(client_name);
00682
00683
00684 if (!(m = pa_mainloop_new())) {
00685 fprintf(stderr, "pa_mainloop_new() failed.\n");
00686 goto quit;
00687 }
00688
00689 mainloop_api = pa_mainloop_get_api(m);
00690
00691 r = pa_signal_init(mainloop_api);
00692 assert(r == 0);
00693 pa_signal_new(SIGINT, exit_signal_callback, NULL);
00694 pa_signal_new(SIGTERM, exit_signal_callback, NULL);
00695 #ifdef SIGUSR1
00696 pa_signal_new(SIGUSR1, sigusr1_signal_callback, NULL);
00697 #endif
00698 #ifdef SIGPIPE
00699 signal(SIGPIPE, SIG_IGN);
00700 #endif
00701
00702 if (!(stdio_event = mainloop_api->io_new(mainloop_api,
00703 mode == PLAYBACK ? STDIN_FILENO : STDOUT_FILENO,
00704 mode == PLAYBACK ? PA_IO_EVENT_INPUT : PA_IO_EVENT_OUTPUT,
00705 mode == PLAYBACK ? stdin_callback : stdout_callback, NULL))) {
00706 fprintf(stderr, "io_new() failed.\n");
00707 goto quit;
00708 }
00709
00710
00711 if (!(context = pa_context_new(mainloop_api, client_name))) {
00712 fprintf(stderr, "pa_context_new() failed.\n");
00713 goto quit;
00714 }
00715
00716 pa_context_set_state_callback(context, context_state_callback, NULL);
00717
00718
00719 pa_context_connect(context, server, 0, NULL);
00720
00721 if (verbose) {
00722 struct timeval tv;
00723
00724 pa_gettimeofday(&tv);
00725 pa_timeval_add(&tv, TIME_EVENT_USEC);
00726
00727 if (!(time_event = mainloop_api->time_new(mainloop_api, &tv, time_event_callback, NULL))) {
00728 fprintf(stderr, "time_new() failed.\n");
00729 goto quit;
00730 }
00731 }
00732
00733
00734 if (pa_mainloop_run(m, &ret) < 0) {
00735 fprintf(stderr, "pa_mainloop_run() failed.\n");
00736 goto quit;
00737 }
00738
00739 quit:
00740 if (stream)
00741 pa_stream_unref(stream);
00742
00743 if (context)
00744 pa_context_unref(context);
00745
00746 if (stdio_event) {
00747 assert(mainloop_api);
00748 mainloop_api->io_free(stdio_event);
00749 }
00750
00751 if (time_event) {
00752 assert(mainloop_api);
00753 mainloop_api->time_free(time_event);
00754 }
00755
00756 if (m) {
00757 pa_signal_done();
00758 pa_mainloop_free(m);
00759 }
00760
00761 pa_xfree(buffer);
00762
00763 pa_xfree(server);
00764 pa_xfree(device);
00765 pa_xfree(client_name);
00766 pa_xfree(stream_name);
00767
00768 return ret;
00769 }