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