chiark / gitweb /
yet more logging; dots at every snd_pcm_wait
[disorder] / clients / playrtp.c
1 /*
2  * This file is part of DisOrder.
3  * Copyright (C) 2007 Richard Kettlewell
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
18  * USA
19  */
20
21 #include <config.h>
22 #include "types.h"
23
24 #include <getopt.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <sys/socket.h>
28 #include <sys/types.h>
29 #include <sys/socket.h>
30 #include <netdb.h>
31 #include <pthread.h>
32 #include <locale.h>
33
34 #include "log.h"
35 #include "mem.h"
36 #include "configuration.h"
37 #include "addr.h"
38 #include "syscalls.h"
39 #include "rtp.h"
40 #include "defs.h"
41
42 #if HAVE_COREAUDIO_AUDIOHARDWARE_H
43 # include <CoreAudio/AudioHardware.h>
44 #endif
45 #if API_ALSA
46 #include <alsa/asoundlib.h>
47 #endif
48
49 #define readahead linux_headers_are_borked
50
51 /** @brief RTP socket */
52 static int rtpfd;
53
54 /** @brief Output device */
55 static const char *device;
56
57 /** @brief Maximum samples per packet we'll support
58  *
59  * NB that two channels = two samples in this program.
60  */
61 #define MAXSAMPLES 2048
62
63 /** @brief Minimum buffer size
64  *
65  * We'll stop playing if there's only this many samples in the buffer. */
66 static unsigned minbuffer = 2 * 44100 / 10;  /* 0.2 seconds */
67
68 /** @brief Maximum sample size
69  *
70  * The maximum supported size (in bytes) of one sample. */
71 #define MAXSAMPLESIZE 2
72
73 /** @brief Buffer size
74  *
75  * We'll only start playing when this many samples are available. */
76 static unsigned readahead = 2 * 2 * 44100;
77
78 /** @brief Number of samples to infill by in one go */
79 #define INFILL_SAMPLES (44100 * 2)      /* 1s */
80
81 #define MAXBUFFER (3 * 88200)           /* maximum buffer contents */
82
83 /** @brief Received packet
84  *
85  * Packets are recorded in an ordered linked list. */
86 struct packet {
87   /** @brief Pointer to next packet
88    * The next packet might not be immediately next: if packets are dropped
89    * or mis-ordered there may be gaps at any given moment. */
90   struct packet *next;
91   /** @brief Number of samples in this packet */
92   uint32_t nsamples;
93   /** @brief Timestamp from RTP packet
94    *
95    * NB that "timestamps" are really sample counters.*/
96   uint32_t timestamp;
97 #if HAVE_COREAUDIO_AUDIOHARDWARE_H
98   /** @brief Converted sample data */
99   float samples_float[MAXSAMPLES];
100 #else
101   /** @brief Raw sample data */
102   unsigned char samples_raw[MAXSAMPLES * MAXSAMPLESIZE];
103 #endif
104 };
105
106 /** @brief Total number of samples available */
107 static unsigned long nsamples;
108
109 /** @brief Linked list of packets
110  *
111  * In ascending order of timestamp. */
112 static struct packet *packets;
113
114 /** @brief Timestamp of next packet to play.
115  *
116  * This is set to the timestamp of the last packet, plus the number of
117  * samples it contained.  Only valid if @ref active is nonzero.
118  */
119 static uint32_t next_timestamp;
120
121 /** @brief True if actively playing
122  *
123  * This is true when playing and false when just buffering. */
124 static int active;
125
126 /** @brief Lock protecting @ref packets */
127 static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
128
129 /** @brief Condition variable signalled whenever @ref packets is changed */
130 static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
131
132 static const struct option options[] = {
133   { "help", no_argument, 0, 'h' },
134   { "version", no_argument, 0, 'V' },
135   { "debug", no_argument, 0, 'd' },
136   { "device", required_argument, 0, 'D' },
137   { "min", required_argument, 0, 'm' },
138   { "buffer", required_argument, 0, 'b' },
139   { 0, 0, 0, 0 }
140 };
141
142 /** @brief Return true iff a < b in sequence-space arithmetic */
143 static inline int lt(uint32_t a, uint32_t b) {
144   return (uint32_t)(a - b) & 0x80000000;
145 }
146
147 /** @brief Return true iff a >= b in sequence-space arithmetic */
148 static inline int ge(uint32_t a, uint32_t b) {
149   return !lt(a, b);
150 }
151
152 /** @brief Return true iff a > b in sequence-space arithmetic */
153 static inline int gt(uint32_t a, uint32_t b) {
154   return lt(b, a);
155 }
156
157 /** @brief Return true iff a <= b in sequence-space arithmetic */
158 static inline int le(uint32_t a, uint32_t b) {
159   return !lt(b, a);
160 }
161
162 /** @brief Background thread collecting samples
163  *
164  * This function collects samples, perhaps converts them to the target format,
165  * and adds them to the packet list. */
166 static void *listen_thread(void attribute((unused)) *arg) {
167   struct packet *p = 0, **pp;
168   int n;
169   union {
170     struct rtp_header header;
171     uint8_t bytes[sizeof(uint16_t) * MAXSAMPLES + sizeof (struct rtp_header)];
172   } packet;
173   const uint16_t *const samples = (uint16_t *)(packet.bytes
174                                                + sizeof (struct rtp_header));
175
176   for(;;) {
177     if(!p)
178       p = xmalloc(sizeof *p);
179     n = read(rtpfd, packet.bytes, sizeof packet.bytes);
180     if(n < 0) {
181       switch(errno) {
182       case EINTR:
183         continue;
184       default:
185         fatal(errno, "error reading from socket");
186       }
187     }
188     /* Ignore too-short packets */
189     if((size_t)n <= sizeof (struct rtp_header))
190       continue;
191     p->timestamp = ntohl(packet.header.timestamp);
192     /* Ignore packets in the past */
193     if(active && lt(p->timestamp, next_timestamp)) {
194       info("dropping old packet, timestamp=%"PRIx32" < %"PRIx32,
195            p->timestamp, next_timestamp);
196       continue;
197     }
198     /* Convert to target format */
199     switch(packet.header.mpt & 0x7F) {
200     case 10:
201       p->nsamples = (n - sizeof (struct rtp_header)) / sizeof(uint16_t);
202 #if HAVE_COREAUDIO_AUDIOHARDWARE_H
203       /* Convert to what Core Audio expects */
204       for(n = 0; n < p->nsamples; ++n)
205         p->samples_float[n] = (int16_t)ntohs(samples[n]) * (0.5f / 32767);
206 #else
207       /* ALSA can do any necessary conversion itself (though it might be better
208        * to do any necessary conversion in the background) */
209       memcpy(p->samples_raw, samples, n - sizeof (struct rtp_header));
210 #endif
211       break;
212       /* TODO support other RFC3551 media types (when the speaker does) */
213     default:
214       fatal(0, "unsupported RTP payload type %d",
215             packet.header.mpt & 0x7F);
216     }
217     pthread_mutex_lock(&lock);
218     /* Stop reading if we've reached the maximum.
219      *
220      * This is rather unsatisfactory: it means that if packets get heavily
221      * out of order then we guarantee dropouts.  But for now... */
222     while(nsamples >= MAXBUFFER)
223       pthread_cond_wait(&cond, &lock);
224     for(pp = &packets;
225         *pp && lt((*pp)->timestamp, p->timestamp);
226         pp = &(*pp)->next)
227       ;
228     /* So now either !*pp or *pp >= p */
229     if(*pp && p->timestamp == (*pp)->timestamp) {
230       /* *pp == p; a duplicate.  Ideally we avoid the translation step here,
231        * but we'll worry about that another time. */
232       info("dropped a duplicated");
233     } else {
234       if(*pp)
235         info("receiving packets out of order");
236       p->next = *pp;
237       *pp = p;
238       nsamples += p->nsamples;
239       pthread_cond_broadcast(&cond);
240       p = 0;                            /* we've consumed this packet */
241     }
242     pthread_mutex_unlock(&lock);
243   }
244 }
245
246 #if HAVE_COREAUDIO_AUDIOHARDWARE_H
247 /** @brief Callback from Core Audio */
248 static OSStatus adioproc(AudioDeviceID inDevice,
249                          const AudioTimeStamp *inNow,
250                          const AudioBufferList *inInputData,
251                          const AudioTimeStamp *inInputTime,
252                          AudioBufferList *outOutputData,
253                          const AudioTimeStamp *inOutputTime,
254                          void *inClientData) {
255   UInt32 nbuffers = outOutputData->mNumberBuffers;
256   AudioBuffer *ab = outOutputData->mBuffers;
257   float *samplesOut;                    /* where to write samples to */
258   size_t samplesOutLeft;                /* space left */
259   size_t samplesInLeft;
260   size_t samplesToCopy;
261
262   pthread_mutex_lock(&lock);
263   samplesOut = ab->data;
264   samplesOutLeft = ab->mDataByteSize / sizeof (float);
265   while(packets && nbuffers > 0) {
266     if(packets->used == packets->nsamples) {
267       /* TODO if we dropped a packet then we should introduce a gap here */
268       struct packet *const p = packets;
269       packets = p->next;
270       free(p);
271       pthread_cond_broadcast(&cond);
272       continue;
273     }
274     if(samplesOutLeft == 0) {
275       --nbuffers;
276       ++ab;
277       samplesOut = ab->data;
278       samplesOutLeft = ab->mDataByteSize / sizeof (float);
279       continue;
280     }
281     /* Now: (1) there is some data left to read
282      *      (2) there is some space to put it */
283     samplesInLeft = packets->nsamples - packets->used;
284     samplesToCopy = (samplesInLeft < samplesOutLeft
285                      ? samplesInLeft : samplesOutLeft);
286     memcpy(samplesOut, packet->samples + packets->used, samplesToCopy);
287     packets->used += samplesToCopy;
288     samplesOut += samplesToCopy;
289     samesOutLeft -= samplesToCopy;
290   }
291   pthread_mutex_unlock(&lock);
292   return 0;
293 }
294 #endif
295
296 /** @brief Play an RTP stream
297  *
298  * This is the guts of the program.  It is responsible for:
299  * - starting the listening thread
300  * - opening the audio device
301  * - reading ahead to build up a buffer
302  * - arranging for audio to be played
303  * - detecting when the buffer has got too small and re-buffering
304  */
305 static void play_rtp(void) {
306   pthread_t ltid;
307
308   /* We receive and convert audio data in a background thread */
309   pthread_create(&ltid, 0, listen_thread, 0);
310 #if API_ALSA
311   {
312     snd_pcm_t *pcm;
313     snd_pcm_hw_params_t *hwparams;
314     snd_pcm_sw_params_t *swparams;
315     /* Only support one format for now */
316     const int sample_format = SND_PCM_FORMAT_S16_BE;
317     unsigned rate = 44100;
318     const int channels = 2;
319     const int samplesize = channels * sizeof(uint16_t);
320     snd_pcm_uframes_t pcm_bufsize = MAXSAMPLES * samplesize * 3;
321     /* If we can write more than this many samples we'll get a wakeup */
322     const int avail_min = 256;
323     snd_pcm_sframes_t frames_written;
324     size_t samples_written;
325     int prepared = 1;
326     int err;
327     int infilling = 0, escape = 0;
328     time_t logged, now;
329     uint32_t packet_start, packet_end;
330
331     /* Open ALSA */
332     if((err = snd_pcm_open(&pcm,
333                            device ? device : "default",
334                            SND_PCM_STREAM_PLAYBACK,
335                            SND_PCM_NONBLOCK)))
336       fatal(0, "error from snd_pcm_open: %d", err);
337     /* Set up 'hardware' parameters */
338     snd_pcm_hw_params_alloca(&hwparams);
339     if((err = snd_pcm_hw_params_any(pcm, hwparams)) < 0)
340       fatal(0, "error from snd_pcm_hw_params_any: %d", err);
341     if((err = snd_pcm_hw_params_set_access(pcm, hwparams,
342                                            SND_PCM_ACCESS_RW_INTERLEAVED)) < 0)
343       fatal(0, "error from snd_pcm_hw_params_set_access: %d", err);
344     if((err = snd_pcm_hw_params_set_format(pcm, hwparams,
345                                            sample_format)) < 0)
346       fatal(0, "error from snd_pcm_hw_params_set_format (%d): %d",
347             sample_format, err);
348     if((err = snd_pcm_hw_params_set_rate_near(pcm, hwparams, &rate, 0)) < 0)
349       fatal(0, "error from snd_pcm_hw_params_set_rate (%d): %d",
350             rate, err);
351     if((err = snd_pcm_hw_params_set_channels(pcm, hwparams,
352                                              channels)) < 0)
353       fatal(0, "error from snd_pcm_hw_params_set_channels (%d): %d",
354             channels, err);
355     if((err = snd_pcm_hw_params_set_buffer_size_near(pcm, hwparams,
356                                                      &pcm_bufsize)) < 0)
357       fatal(0, "error from snd_pcm_hw_params_set_buffer_size (%d): %d",
358             MAXSAMPLES * samplesize * 3, err);
359     if((err = snd_pcm_hw_params(pcm, hwparams)) < 0)
360       fatal(0, "error calling snd_pcm_hw_params: %d", err);
361     /* Set up 'software' parameters */
362     snd_pcm_sw_params_alloca(&swparams);
363     if((err = snd_pcm_sw_params_current(pcm, swparams)) < 0)
364       fatal(0, "error calling snd_pcm_sw_params_current: %d", err);
365     if((err = snd_pcm_sw_params_set_avail_min(pcm, swparams, avail_min)) < 0)
366       fatal(0, "error calling snd_pcm_sw_params_set_avail_min %d: %d",
367             avail_min, err);
368     if((err = snd_pcm_sw_params(pcm, swparams)) < 0)
369       fatal(0, "error calling snd_pcm_sw_params: %d", err);
370
371     /* Ready to go */
372
373     time(&logged);
374     pthread_mutex_lock(&lock);
375     for(;;) {
376       /* Wait for the buffer to fill up a bit */
377       logged = now;
378       info("%lu samples in buffer (%lus)", nsamples,
379            nsamples / (44100 * 2));
380       info("Buffering...");
381       while(nsamples < readahead)
382         pthread_cond_wait(&cond, &lock);
383       if(!prepared) {
384         if((err = snd_pcm_prepare(pcm)))
385           fatal(0, "error calling snd_pcm_prepare: %d", err);
386         prepared = 1;
387       }
388       /* Start at the first available packet */
389       next_timestamp = packets->timestamp;
390       active = 1;
391       infilling = 0;
392       escape = 0;
393       logged = now;
394       info("%lu samples in buffer (%lus)", nsamples,
395            nsamples / (44100 * 2));
396       info("Playing...");
397       /* Wait until the buffer empties out */
398       while(nsamples >= minbuffer && !escape) {
399         time(&now);
400         if(now > logged + 10) {
401           logged = now;
402           info("%lu samples in buffer (%lus)", nsamples,
403                nsamples / (44100 * 2));
404         }
405         if(packets
406            && ge(next_timestamp, packets->timestamp + packets->nsamples)) {
407           struct packet *p = packets;
408           
409           info("dropping buffered past packet %"PRIx32" < %"PRIx32,
410                packets->timestamp, next_timestamp);
411           
412           packets = p->next;
413           if(packets)
414             assert(lt(p->timestamp, packets->timestamp));
415           nsamples -= p->nsamples;
416           free(p);
417           pthread_cond_broadcast(&cond);
418           continue;
419         }
420         /* Wait for ALSA to ask us for more data */
421         pthread_mutex_unlock(&lock);
422         write(2, ".", 1);               /* TODO remove me sometime */
423         switch(err = snd_pcm_wait(pcm, -1)) {
424         case 0:
425           info("snd_pcm_wait timed out");
426           break;
427         case 1:
428           break;
429         default:
430           fatal(0, "snd_pcm_wait returned %d", err);
431         }
432         pthread_mutex_lock(&lock);
433         /* ALSA is ready for more data */
434         packet_start = packets->timestamp;
435         packet_end = packets->timestamp + packets->nsamples;
436         if(ge(next_timestamp, packet_start)
437            && lt(next_timestamp, packet_end)) {
438           /* The target timestamp is somewhere in this packet */
439           const uint32_t offset = next_timestamp - packets->timestamp;
440           const uint32_t samples_available = (packets->timestamp + packets->nsamples) - next_timestamp;
441           const size_t frames_available = samples_available / 2;
442
443           frames_written = snd_pcm_writei(pcm,
444                                           packets->samples_raw + offset,
445                                           frames_available);
446           if(frames_written < 0) {
447             switch(frames_written) {
448             case -EAGAIN:
449               info("snd_pcm_wait() returned but we got -EAGAIN!");
450               break;
451             case -EPIPE:
452               error(0, "error calling snd_pcm_writei: %ld",
453                     (long)frames_written);
454               escape = 1;
455               break;
456             default:
457               fatal(0, "error calling snd_pcm_writei: %ld",
458                     (long)frames_written);
459             }
460           } else {
461             samples_written = frames_written * 2;
462             next_timestamp += samples_written;
463             if(ge(next_timestamp, packet_end)) {
464               /* We're done with this packet */
465               struct packet *p = packets;
466               
467               packets = p->next;
468               if(packets)
469                 assert(lt(p->timestamp, packets->timestamp));
470               nsamples -= p->nsamples;
471               free(p);
472               pthread_cond_broadcast(&cond);
473             }
474             infilling = 0;
475           }
476         } else {
477           /* We don't have anything to play!  We'd better play some 0s. */
478           static const uint16_t zeros[INFILL_SAMPLES];
479           size_t samples_available = INFILL_SAMPLES, frames_available;
480
481           /* If the maximum infill would take us past the start of the next
482            * packet then we truncate the infill to the right amount. */
483           if(lt(packets->timestamp,
484                 next_timestamp + samples_available))
485             samples_available = packets->timestamp - next_timestamp;
486           if((int)samples_available < 0) {
487             info("packets->timestamp: %"PRIx32"  next_timestamp: %"PRIx32"  next+max: %"PRIx32"  available: %"PRIx32,
488                  packets->timestamp, next_timestamp,
489                  next_timestamp + INFILL_SAMPLES, samples_available);
490           }
491           frames_available = samples_available / 2;
492           if(!infilling) {
493             info("Infilling %d samples, next=%"PRIx32" packet=[%"PRIx32",%"PRIx32"]",
494                  samples_available, next_timestamp,
495                  packets->timestamp, packets->timestamp + packets->nsamples);
496             //infilling++;
497           }
498           frames_written = snd_pcm_writei(pcm,
499                                           zeros,
500                                           frames_available);
501           if(frames_written < 0) {
502             switch(frames_written) {
503             case -EAGAIN:
504               info("snd_pcm_wait() returned but we got -EAGAIN!");
505               break;
506             case -EPIPE:
507               error(0, "error calling snd_pcm_writei: %ld",
508                     (long)frames_written);
509               escape = 1;
510               break;
511             default:
512               fatal(0, "error calling snd_pcm_writei: %ld",
513                     (long)frames_written);
514             }
515           } else {
516             samples_written = frames_written * 2;
517             next_timestamp += samples_written;
518           }
519         }
520       }
521       active = 0;
522       /* We stop playing for a bit until the buffer re-fills */
523       pthread_mutex_unlock(&lock);
524       if((err = snd_pcm_nonblock(pcm, 0)))
525         fatal(0, "error calling snd_pcm_nonblock: %d", err);
526       if(escape) {
527         if((err = snd_pcm_drop(pcm)))
528           fatal(0, "error calling snd_pcm_drop: %d", err);
529         escape = 0;
530       } else
531         if((err = snd_pcm_drain(pcm)))
532           fatal(0, "error calling snd_pcm_drain: %d", err);
533       if((err = snd_pcm_nonblock(pcm, 1)))
534         fatal(0, "error calling snd_pcm_nonblock: %d", err);
535       prepared = 0;
536       pthread_mutex_lock(&lock);
537     }
538
539   }
540 #elif HAVE_COREAUDIO_AUDIOHARDWARE_H
541   {
542     OSStatus status;
543     UInt32 propertySize;
544     AudioDeviceID adid;
545     AudioStreamBasicDescription asbd;
546
547     /* If this looks suspiciously like libao's macosx driver there's an
548      * excellent reason for that... */
549
550     /* TODO report errors as strings not numbers */
551     propertySize = sizeof adid;
552     status = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice,
553                                       &propertySize, &adid);
554     if(status)
555       fatal(0, "AudioHardwareGetProperty: %d", (int)status);
556     if(adid == kAudioDeviceUnknown)
557       fatal(0, "no output device");
558     propertySize = sizeof asbd;
559     status = AudioDeviceGetProperty(adid, 0, false,
560                                     kAudioDevicePropertyStreamFormat,
561                                     &propertySize, &asbd);
562     if(status)
563       fatal(0, "AudioHardwareGetProperty: %d", (int)status);
564     D(("mSampleRate       %f", asbd.mSampleRate));
565     D(("mFormatID         %08"PRIx32, asbd.mFormatID));
566     D(("mFormatFlags      %08"PRIx32, asbd.mFormatFlags));
567     D(("mBytesPerPacket   %08"PRIx32, asbd.mBytesPerPacket));
568     D(("mFramesPerPacket  %08"PRIx32, asbd.mFramesPerPacket));
569     D(("mBytesPerFrame    %08"PRIx32, asbd.mBytesPerFrame));
570     D(("mChannelsPerFrame %08"PRIx32, asbd.mChannelsPerFrame));
571     D(("mBitsPerChannel   %08"PRIx32, asbd.mBitsPerChannel));
572     D(("mReserved         %08"PRIx32, asbd.mReserved));
573     if(asbd.mFormatID != kAudioFormatLinearPCM)
574       fatal(0, "audio device does not support kAudioFormatLinearPCM");
575     status = AudioDeviceAddIOProc(adid, adioproc, 0);
576     if(status)
577       fatal(0, "AudioDeviceAddIOProc: %d", (int)status);
578     pthread_mutex_lock(&lock);
579     for(;;) {
580       /* Wait for the buffer to fill up a bit */
581       while(nsamples < readahead)
582         pthread_cond_wait(&cond, &lock);
583       /* Start playing now */
584       status = AudioDeviceStart(adid, adioproc);
585       if(status)
586         fatal(0, "AudioDeviceStart: %d", (int)status);
587       /* Wait until the buffer empties out */
588       while(nsamples >= minbuffer)
589         pthread_cond_wait(&cond, &lock);
590       /* Stop playing for a bit until the buffer re-fills */
591       status = AudioDeviceStop(adid, adioproc);
592       if(status)
593         fatal(0, "AudioDeviceStop: %d", (int)status);
594       /* Go back round */
595     }
596   }
597 #else
598 # error No known audio API
599 #endif
600 }
601
602 /* display usage message and terminate */
603 static void help(void) {
604   xprintf("Usage:\n"
605           "  disorder-playrtp [OPTIONS] ADDRESS [PORT]\n"
606           "Options:\n"
607           "  --help, -h              Display usage message\n"
608           "  --version, -V           Display version number\n"
609           "  --debug, -d             Turn on debugging\n"
610           "  --device, -D DEVICE     Output device\n"
611           "  --min, -m FRAMES        Buffer low water mark\n"
612           "  --buffer, -b FRAMES     Buffer high water mark\n");
613   xfclose(stdout);
614   exit(0);
615 }
616
617 /* display version number and terminate */
618 static void version(void) {
619   xprintf("disorder-playrtp version %s\n", disorder_version_string);
620   xfclose(stdout);
621   exit(0);
622 }
623
624 int main(int argc, char **argv) {
625   int n;
626   struct addrinfo *res;
627   struct stringlist sl;
628   char *sockname;
629
630   static const struct addrinfo prefs = {
631     AI_PASSIVE,
632     PF_INET,
633     SOCK_DGRAM,
634     IPPROTO_UDP,
635     0,
636     0,
637     0,
638     0
639   };
640
641   mem_init();
642   if(!setlocale(LC_CTYPE, "")) fatal(errno, "error calling setlocale");
643   while((n = getopt_long(argc, argv, "hVdD:m:b:", options, 0)) >= 0) {
644     switch(n) {
645     case 'h': help();
646     case 'V': version();
647     case 'd': debugging = 1; break;
648     case 'D': device = optarg; break;
649     case 'm': minbuffer = 2 * atol(optarg); break;
650     case 'b': readahead = 2 * atol(optarg); break;
651     default: fatal(0, "invalid option");
652     }
653   }
654   argc -= optind;
655   argv += optind;
656   if(argc < 1 || argc > 2)
657     fatal(0, "usage: disorder-playrtp [OPTIONS] ADDRESS [PORT]");
658   sl.n = argc;
659   sl.s = argv;
660   /* Listen for inbound audio data */
661   if(!(res = get_address(&sl, &prefs, &sockname)))
662     exit(1);
663   if((rtpfd = socket(res->ai_family,
664                      res->ai_socktype,
665                      res->ai_protocol)) < 0)
666     fatal(errno, "error creating socket");
667   if(bind(rtpfd, res->ai_addr, res->ai_addrlen) < 0)
668     fatal(errno, "error binding socket to %s", sockname);
669   play_rtp();
670   return 0;
671 }
672
673 /*
674 Local Variables:
675 c-basic-offset:2
676 comment-column:40
677 fill-column:79
678 indent-tabs-mode:nil
679 End:
680 */