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