pacat.c

A playback and recording tool using the asynchronous API

00001 /* $Id: pacat.c 2067 2007-11-21 01:30:40Z lennart $ */
00002 
00003 /***
00004   This file is part of PulseAudio.
00005 
00006   Copyright 2004-2006 Lennart Poettering
00007   Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
00008 
00009   PulseAudio is free software; you can redistribute it and/or modify
00010   it under the terms of the GNU Lesser General Public License as published
00011   by the Free Software Foundation; either version 2 of the License,
00012   or (at your option) any later version.
00013 
00014   PulseAudio is distributed in the hope that it will be useful, but
00015   WITHOUT ANY WARRANTY; without even the implied warranty of
00016   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00017   General Public License for more details.
00018 
00019   You should have received a copy of the GNU Lesser General Public License
00020   along with PulseAudio; if not, write to the Free Software
00021   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
00022   USA.
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 /* A shortcut for terminating the application */
00075 static void quit(int ret) {
00076     assert(mainloop_api);
00077     mainloop_api->quit(mainloop_api, ret);
00078 }
00079 
00080 /* Write some data to the stream */
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 /* This is called whenever new data may be written to the stream */
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 /* This is called whenever new data may is available */
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 /* This routine is called whenever the stream state changes */
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 /* This is called whenever the context status changes */
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 /* Connection draining complete */
00285 static void context_drain_complete(pa_context*c, void *userdata) {
00286     pa_context_disconnect(c);
00287 }
00288 
00289 /* Stream draining complete */
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 /* New data on STDIN **/
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 /* Some data may be written to STDOUT */
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 /* UNIX signal to quit recieved */
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 /* Show the current latency */
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 /* Someone requested that the latency is shown */
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     /* Set up a new main loop */
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     /* Create a new connection context */
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     /* Connect the context */
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     /* Run the main loop */
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 }

Generated on Tue Apr 24 02:06:15 2012 for PulseAudio by  doxygen 1.4.7