pacat.c

A playback and recording tool using the asynchronous API

00001 /* $Id: pacat.c 1426 2007-02-13 15:35:19Z ossman $ */
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 < 9
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 /* A shortcut for terminating the application */
00073 static void quit(int ret) {
00074     assert(mainloop_api);
00075     mainloop_api->quit(mainloop_api, ret);
00076 }
00077 
00078 /* Write some data to the stream */
00079 static void do_stream_write(size_t length) {
00080     size_t l;
00081     assert(length);
00082 
00083     if (!buffer || !buffer_length)
00084         return;
00085 
00086     l = length;
00087     if (l > buffer_length)
00088         l = buffer_length;
00089 
00090     if (pa_stream_write(stream, (uint8_t*) buffer + buffer_index, l, NULL, 0, PA_SEEK_RELATIVE) < 0) {
00091         fprintf(stderr, "pa_stream_write() failed: %s\n", pa_strerror(pa_context_errno(context)));
00092         quit(1);
00093         return;
00094     }
00095 
00096     buffer_length -= l;
00097     buffer_index += l;
00098 
00099     if (!buffer_length) {
00100         pa_xfree(buffer);
00101         buffer = NULL;
00102         buffer_index = buffer_length = 0;
00103     }
00104 }
00105 
00106 /* This is called whenever new data may be written to the stream */
00107 static void stream_write_callback(pa_stream *s, size_t length, void *userdata) {
00108     assert(s && length);
00109 
00110     if (stdio_event)
00111         mainloop_api->io_enable(stdio_event, PA_IO_EVENT_INPUT);
00112 
00113     if (!buffer)
00114         return;
00115 
00116     do_stream_write(length);
00117 }
00118 
00119 /* This is called whenever new data may is available */
00120 static void stream_read_callback(pa_stream *s, size_t length, void *userdata) {
00121     const void *data;
00122     assert(s && length);
00123 
00124     if (stdio_event)
00125         mainloop_api->io_enable(stdio_event, PA_IO_EVENT_OUTPUT);
00126 
00127     if (pa_stream_peek(s, &data, &length) < 0) {
00128         fprintf(stderr, "pa_stream_peek() failed: %s\n", pa_strerror(pa_context_errno(context)));
00129         quit(1);
00130         return;
00131     }
00132 
00133     assert(data && length);
00134 
00135     if (buffer) {
00136         fprintf(stderr, "Buffer overrun, dropping incoming data\n");
00137         if (pa_stream_drop(s) < 0) {
00138             fprintf(stderr, "pa_stream_drop() failed: %s\n", pa_strerror(pa_context_errno(context)));
00139             quit(1);
00140         }
00141         return;
00142     }
00143 
00144     buffer = pa_xmalloc(buffer_length = length);
00145     memcpy(buffer, data, length);
00146     buffer_index = 0;
00147     pa_stream_drop(s);
00148 }
00149 
00150 /* This routine is called whenever the stream state changes */
00151 static void stream_state_callback(pa_stream *s, void *userdata) {
00152     assert(s);
00153 
00154     switch (pa_stream_get_state(s)) {
00155         case PA_STREAM_CREATING:
00156         case PA_STREAM_TERMINATED:
00157             break;
00158 
00159         case PA_STREAM_READY:
00160             if (verbose) {
00161                 const pa_buffer_attr *a;
00162 
00163                 fprintf(stderr, "Stream successfully created.\n");
00164 
00165                 if (!(a = pa_stream_get_buffer_attr(s)))
00166                     fprintf(stderr, "pa_stream_get_buffer_attr() failed: %s\n", pa_strerror(pa_context_errno(pa_stream_get_context(s))));
00167                 else {
00168 
00169                     if (mode == PLAYBACK)
00170                         fprintf(stderr, "Buffer metrics: maxlength=%u, tlength=%u, prebuf=%u, minreq=%u\n", a->maxlength, a->tlength, a->prebuf, a->minreq);
00171                     else {
00172                         assert(mode == RECORD);
00173                         fprintf(stderr, "Buffer metrics: maxlength=%u, fragsize=%u\n", a->maxlength, a->fragsize);
00174                     }
00175 
00176                 }
00177 
00178             }
00179 
00180             break;
00181 
00182         case PA_STREAM_FAILED:
00183         default:
00184             fprintf(stderr, "Stream error: %s\n", pa_strerror(pa_context_errno(pa_stream_get_context(s))));
00185             quit(1);
00186     }
00187 }
00188 
00189 /* This is called whenever the context status changes */
00190 static void context_state_callback(pa_context *c, void *userdata) {
00191     assert(c);
00192 
00193     switch (pa_context_get_state(c)) {
00194         case PA_CONTEXT_CONNECTING:
00195         case PA_CONTEXT_AUTHORIZING:
00196         case PA_CONTEXT_SETTING_NAME:
00197             break;
00198 
00199         case PA_CONTEXT_READY: {
00200             int r;
00201 
00202             assert(c && !stream);
00203 
00204             if (verbose)
00205                 fprintf(stderr, "Connection established.\n");
00206 
00207             if (!(stream = pa_stream_new(c, stream_name, &sample_spec, channel_map_set ? &channel_map : NULL))) {
00208                 fprintf(stderr, "pa_stream_new() failed: %s\n", pa_strerror(pa_context_errno(c)));
00209                 goto fail;
00210             }
00211 
00212             pa_stream_set_state_callback(stream, stream_state_callback, NULL);
00213             pa_stream_set_write_callback(stream, stream_write_callback, NULL);
00214             pa_stream_set_read_callback(stream, stream_read_callback, NULL);
00215 
00216             if (mode == PLAYBACK) {
00217                 pa_cvolume cv;
00218                 if ((r = pa_stream_connect_playback(stream, device, NULL, 0, pa_cvolume_set(&cv, sample_spec.channels, volume), NULL)) < 0) {
00219                     fprintf(stderr, "pa_stream_connect_playback() failed: %s\n", pa_strerror(pa_context_errno(c)));
00220                     goto fail;
00221                 }
00222 
00223             } else {
00224                 if ((r = pa_stream_connect_record(stream, device, NULL, 0)) < 0) {
00225                     fprintf(stderr, "pa_stream_connect_record() failed: %s\n", pa_strerror(pa_context_errno(c)));
00226                     goto fail;
00227                 }
00228             }
00229 
00230             break;
00231         }
00232 
00233         case PA_CONTEXT_TERMINATED:
00234             quit(0);
00235             break;
00236 
00237         case PA_CONTEXT_FAILED:
00238         default:
00239             fprintf(stderr, "Connection failure: %s\n", pa_strerror(pa_context_errno(c)));
00240             goto fail;
00241     }
00242 
00243     return;
00244 
00245 fail:
00246     quit(1);
00247 
00248 }
00249 
00250 /* Connection draining complete */
00251 static void context_drain_complete(pa_context*c, void *userdata) {
00252     pa_context_disconnect(c);
00253 }
00254 
00255 /* Stream draining complete */
00256 static void stream_drain_complete(pa_stream*s, int success, void *userdata) {
00257     pa_operation *o;
00258 
00259     if (!success) {
00260         fprintf(stderr, "Failed to drain stream: %s\n", pa_strerror(pa_context_errno(context)));
00261         quit(1);
00262     }
00263 
00264     if (verbose)
00265         fprintf(stderr, "Playback stream drained.\n");
00266 
00267     pa_stream_disconnect(stream);
00268     pa_stream_unref(stream);
00269     stream = NULL;
00270 
00271     if (!(o = pa_context_drain(context, context_drain_complete, NULL)))
00272         pa_context_disconnect(context);
00273     else {
00274         if (verbose)
00275             fprintf(stderr, "Draining connection to server.\n");
00276     }
00277 }
00278 
00279 /* New data on STDIN **/
00280 static void stdin_callback(pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata) {
00281     size_t l, w = 0;
00282     ssize_t r;
00283     assert(a == mainloop_api && e && stdio_event == e);
00284 
00285     if (buffer) {
00286         mainloop_api->io_enable(stdio_event, PA_IO_EVENT_NULL);
00287         return;
00288     }
00289 
00290     if (!stream || pa_stream_get_state(stream) != PA_STREAM_READY || !(l = w = pa_stream_writable_size(stream)))
00291         l = 4096;
00292 
00293     buffer = pa_xmalloc(l);
00294 
00295     if ((r = read(fd, buffer, l)) <= 0) {
00296         if (r == 0) {
00297             if (verbose)
00298                 fprintf(stderr, "Got EOF.\n");
00299 
00300             if (stream) {
00301                 pa_operation *o;
00302 
00303                 if (!(o = pa_stream_drain(stream, stream_drain_complete, NULL))) {
00304                     fprintf(stderr, "pa_stream_drain(): %s\n", pa_strerror(pa_context_errno(context)));
00305                     quit(1);
00306                     return;
00307                 }
00308 
00309                 pa_operation_unref(o);
00310             } else
00311                 quit(0);
00312 
00313         } else {
00314             fprintf(stderr, "read() failed: %s\n", strerror(errno));
00315             quit(1);
00316         }
00317 
00318         mainloop_api->io_free(stdio_event);
00319         stdio_event = NULL;
00320         return;
00321     }
00322 
00323     buffer_length = r;
00324     buffer_index = 0;
00325 
00326     if (w)
00327         do_stream_write(w);
00328 }
00329 
00330 /* Some data may be written to STDOUT */
00331 static void stdout_callback(pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata) {
00332     ssize_t r;
00333     assert(a == mainloop_api && e && stdio_event == e);
00334 
00335     if (!buffer) {
00336         mainloop_api->io_enable(stdio_event, PA_IO_EVENT_NULL);
00337         return;
00338     }
00339 
00340     assert(buffer_length);
00341 
00342     if ((r = write(fd, (uint8_t*) buffer+buffer_index, buffer_length)) <= 0) {
00343         fprintf(stderr, "write() failed: %s\n", strerror(errno));
00344         quit(1);
00345 
00346         mainloop_api->io_free(stdio_event);
00347         stdio_event = NULL;
00348         return;
00349     }
00350 
00351     buffer_length -= r;
00352     buffer_index += r;
00353 
00354     if (!buffer_length) {
00355         pa_xfree(buffer);
00356         buffer = NULL;
00357         buffer_length = buffer_index = 0;
00358     }
00359 }
00360 
00361 /* UNIX signal to quit recieved */
00362 static void exit_signal_callback(pa_mainloop_api*m, pa_signal_event *e, int sig, void *userdata) {
00363     if (verbose)
00364         fprintf(stderr, "Got signal, exiting.\n");
00365     quit(0);
00366 }
00367 
00368 /* Show the current latency */
00369 static void stream_update_timing_callback(pa_stream *s, int success, void *userdata) {
00370     pa_usec_t latency, usec;
00371     int negative = 0;
00372 
00373     assert(s);
00374 
00375     if (!success ||
00376         pa_stream_get_time(s, &usec) < 0 ||
00377         pa_stream_get_latency(s, &latency, &negative) < 0) {
00378         fprintf(stderr, "Failed to get latency: %s\n", pa_strerror(pa_context_errno(context)));
00379         quit(1);
00380         return;
00381     }
00382 
00383     fprintf(stderr, "Time: %0.3f sec; Latency: %0.0f usec.  \r",
00384             (float) usec / 1000000,
00385             (float) latency * (negative?-1:1));
00386 }
00387 
00388 /* Someone requested that the latency is shown */
00389 static void sigusr1_signal_callback(pa_mainloop_api*m, pa_signal_event *e, int sig, void *userdata) {
00390 
00391     if (!stream)
00392         return;
00393 
00394     pa_operation_unref(pa_stream_update_timing_info(stream, stream_update_timing_callback, NULL));
00395 }
00396 
00397 static void time_event_callback(pa_mainloop_api*m, pa_time_event *e, const struct timeval *tv, void *userdata) {
00398     struct timeval next;
00399 
00400     if (stream && pa_stream_get_state(stream) == PA_STREAM_READY) {
00401         pa_operation *o;
00402         if (!(o = pa_stream_update_timing_info(stream, stream_update_timing_callback, NULL)))
00403             fprintf(stderr, "pa_stream_update_timing_info() failed: %s\n", pa_strerror(pa_context_errno(context)));
00404         else
00405             pa_operation_unref(o);
00406     }
00407 
00408     pa_gettimeofday(&next);
00409     pa_timeval_add(&next, TIME_EVENT_USEC);
00410 
00411     m->time_restart(e, &next);
00412 }
00413 
00414 static void help(const char *argv0) {
00415 
00416     printf("%s [options]\n\n"
00417            "  -h, --help                            Show this help\n"
00418            "      --version                         Show version\n\n"
00419            "  -r, --record                          Create a connection for recording\n"
00420            "  -p, --playback                        Create a connection for playback\n\n"
00421            "  -v, --verbose                         Enable verbose operations\n\n"
00422            "  -s, --server=SERVER                   The name of the server to connect to\n"
00423            "  -d, --device=DEVICE                   The name of the sink/source to connect to\n"
00424            "  -n, --client-name=NAME                How to call this client on the server\n"
00425            "      --stream-name=NAME                How to call this stream on the server\n"
00426            "      --volume=VOLUME                   Specify the initial (linear) volume in range 0...65536\n"
00427            "      --rate=SAMPLERATE                 The sample rate in Hz (defaults to 44100)\n"
00428            "      --format=SAMPLEFORMAT             The sample type, one of s16le, s16be, u8, float32le,\n"
00429            "                                        float32be, ulaw, alaw (defaults to s16ne)\n"
00430            "      --channels=CHANNELS               The number of channels, 1 for mono, 2 for stereo\n"
00431            "                                        (defaults to 2)\n"
00432            "      --channel-map=CHANNELMAP          Channel map to use instead of the default\n",
00433            argv0);
00434 }
00435 
00436 enum {
00437     ARG_VERSION = 256,
00438     ARG_STREAM_NAME,
00439     ARG_VOLUME,
00440     ARG_SAMPLERATE,
00441     ARG_SAMPLEFORMAT,
00442     ARG_CHANNELS,
00443     ARG_CHANNELMAP,
00444 };
00445 
00446 int main(int argc, char *argv[]) {
00447     pa_mainloop* m = NULL;
00448     int ret = 1, r, c;
00449     char *bn, *server = NULL;
00450     pa_time_event *time_event = NULL;
00451 
00452     static const struct option long_options[] = {
00453         {"record",      0, NULL, 'r'},
00454         {"playback",    0, NULL, 'p'},
00455         {"device",      1, NULL, 'd'},
00456         {"server",      1, NULL, 's'},
00457         {"client-name", 1, NULL, 'n'},
00458         {"stream-name", 1, NULL, ARG_STREAM_NAME},
00459         {"version",     0, NULL, ARG_VERSION},
00460         {"help",        0, NULL, 'h'},
00461         {"verbose",     0, NULL, 'v'},
00462         {"volume",      1, NULL, ARG_VOLUME},
00463         {"rate",        1, NULL, ARG_SAMPLERATE},
00464         {"format",      1, NULL, ARG_SAMPLEFORMAT},
00465         {"channels",    1, NULL, ARG_CHANNELS},
00466         {"channel-map", 1, NULL, ARG_CHANNELMAP},
00467         {NULL,          0, NULL, 0}
00468     };
00469 
00470     if (!(bn = strrchr(argv[0], '/')))
00471         bn = argv[0];
00472     else
00473         bn++;
00474 
00475     if (strstr(bn, "rec") || strstr(bn, "mon"))
00476         mode = RECORD;
00477     else if (strstr(bn, "cat") || strstr(bn, "play"))
00478         mode = PLAYBACK;
00479 
00480     while ((c = getopt_long(argc, argv, "rpd:s:n:hv", long_options, NULL)) != -1) {
00481 
00482         switch (c) {
00483             case 'h' :
00484                 help(bn);
00485                 ret = 0;
00486                 goto quit;
00487 
00488             case ARG_VERSION:
00489                 printf("pacat "PACKAGE_VERSION"\nCompiled with libpulse %s\nLinked with libpulse %s\n", pa_get_headers_version(), pa_get_library_version());
00490                 ret = 0;
00491                 goto quit;
00492 
00493             case 'r':
00494                 mode = RECORD;
00495                 break;
00496 
00497             case 'p':
00498                 mode = PLAYBACK;
00499                 break;
00500 
00501             case 'd':
00502                 pa_xfree(device);
00503                 device = pa_xstrdup(optarg);
00504                 break;
00505 
00506             case 's':
00507                 pa_xfree(server);
00508                 server = pa_xstrdup(optarg);
00509                 break;
00510 
00511             case 'n':
00512                 pa_xfree(client_name);
00513                 client_name = pa_xstrdup(optarg);
00514                 break;
00515 
00516             case ARG_STREAM_NAME:
00517                 pa_xfree(stream_name);
00518                 stream_name = pa_xstrdup(optarg);
00519                 break;
00520 
00521             case 'v':
00522                 verbose = 1;
00523                 break;
00524 
00525             case ARG_VOLUME: {
00526                 int v = atoi(optarg);
00527                 volume = v < 0 ? 0 : v;
00528                 break;
00529             }
00530 
00531             case ARG_CHANNELS:
00532                 sample_spec.channels = atoi(optarg);
00533                 break;
00534 
00535             case ARG_SAMPLEFORMAT:
00536                 sample_spec.format = pa_parse_sample_format(optarg);
00537                 break;
00538 
00539             case ARG_SAMPLERATE:
00540                 sample_spec.rate = atoi(optarg);
00541                 break;
00542 
00543             case ARG_CHANNELMAP:
00544                 if (!pa_channel_map_parse(&channel_map, optarg)) {
00545                     fprintf(stderr, "Invalid channel map\n");
00546                     goto quit;
00547                 }
00548 
00549                 channel_map_set = 1;
00550                 break;
00551 
00552             default:
00553                 goto quit;
00554         }
00555     }
00556 
00557     if (!pa_sample_spec_valid(&sample_spec)) {
00558         fprintf(stderr, "Invalid sample specification\n");
00559         goto quit;
00560     }
00561 
00562     if (channel_map_set && channel_map.channels != sample_spec.channels) {
00563         fprintf(stderr, "Channel map doesn't match sample specification\n");
00564         goto quit;
00565     }
00566 
00567     if (verbose) {
00568         char t[PA_SAMPLE_SPEC_SNPRINT_MAX];
00569         pa_sample_spec_snprint(t, sizeof(t), &sample_spec);
00570         fprintf(stderr, "Opening a %s stream with sample specification '%s'.\n", mode == RECORD ? "recording" : "playback", t);
00571     }
00572 
00573     if (!(optind >= argc)) {
00574         if (optind+1 == argc) {
00575             int fd;
00576 
00577             if ((fd = open(argv[optind], mode == PLAYBACK ? O_RDONLY : O_WRONLY|O_TRUNC|O_CREAT, 0666)) < 0) {
00578                 fprintf(stderr, "open(): %s\n", strerror(errno));
00579                 goto quit;
00580             }
00581 
00582             if (dup2(fd, mode == PLAYBACK ? 0 : 1) < 0) {
00583                 fprintf(stderr, "dup2(): %s\n", strerror(errno));
00584                 goto quit;
00585             }
00586 
00587             close(fd);
00588 
00589             if (!stream_name)
00590                 stream_name = pa_xstrdup(argv[optind]);
00591 
00592         } else {
00593             fprintf(stderr, "Too many arguments.\n");
00594             goto quit;
00595         }
00596     }
00597 
00598     if (!client_name)
00599         client_name = pa_xstrdup(bn);
00600 
00601     if (!stream_name)
00602         stream_name = pa_xstrdup(client_name);
00603 
00604     /* Set up a new main loop */
00605     if (!(m = pa_mainloop_new())) {
00606         fprintf(stderr, "pa_mainloop_new() failed.\n");
00607         goto quit;
00608     }
00609 
00610     mainloop_api = pa_mainloop_get_api(m);
00611 
00612     r = pa_signal_init(mainloop_api);
00613     assert(r == 0);
00614     pa_signal_new(SIGINT, exit_signal_callback, NULL);
00615     pa_signal_new(SIGTERM, exit_signal_callback, NULL);
00616 #ifdef SIGUSR1
00617     pa_signal_new(SIGUSR1, sigusr1_signal_callback, NULL);
00618 #endif
00619 #ifdef SIGPIPE
00620     signal(SIGPIPE, SIG_IGN);
00621 #endif
00622 
00623     if (!(stdio_event = mainloop_api->io_new(mainloop_api,
00624                                              mode == PLAYBACK ? STDIN_FILENO : STDOUT_FILENO,
00625                                              mode == PLAYBACK ? PA_IO_EVENT_INPUT : PA_IO_EVENT_OUTPUT,
00626                                              mode == PLAYBACK ? stdin_callback : stdout_callback, NULL))) {
00627         fprintf(stderr, "io_new() failed.\n");
00628         goto quit;
00629     }
00630 
00631     /* Create a new connection context */
00632     if (!(context = pa_context_new(mainloop_api, client_name))) {
00633         fprintf(stderr, "pa_context_new() failed.\n");
00634         goto quit;
00635     }
00636 
00637     pa_context_set_state_callback(context, context_state_callback, NULL);
00638 
00639     /* Connect the context */
00640     pa_context_connect(context, server, 0, NULL);
00641 
00642     if (verbose) {
00643         struct timeval tv;
00644 
00645         pa_gettimeofday(&tv);
00646         pa_timeval_add(&tv, TIME_EVENT_USEC);
00647 
00648         if (!(time_event = mainloop_api->time_new(mainloop_api, &tv, time_event_callback, NULL))) {
00649             fprintf(stderr, "time_new() failed.\n");
00650             goto quit;
00651         }
00652     }
00653 
00654     /* Run the main loop */
00655     if (pa_mainloop_run(m, &ret) < 0) {
00656         fprintf(stderr, "pa_mainloop_run() failed.\n");
00657         goto quit;
00658     }
00659 
00660 quit:
00661     if (stream)
00662         pa_stream_unref(stream);
00663 
00664     if (context)
00665         pa_context_unref(context);
00666 
00667     if (stdio_event) {
00668         assert(mainloop_api);
00669         mainloop_api->io_free(stdio_event);
00670     }
00671 
00672     if (time_event) {
00673         assert(mainloop_api);
00674         mainloop_api->time_free(time_event);
00675     }
00676 
00677     if (m) {
00678         pa_signal_done();
00679         pa_mainloop_free(m);
00680     }
00681 
00682     pa_xfree(buffer);
00683 
00684     pa_xfree(server);
00685     pa_xfree(device);
00686     pa_xfree(client_name);
00687     pa_xfree(stream_name);
00688 
00689     return ret;
00690 }

Generated on Sun Aug 12 20:23:27 2007 for PulseAudio by  doxygen 1.5.2