chiark / gitweb /
TABLE_FIND() now uses typeof. We're committed to GCC anyway so it
[disorder] / clients / playrtp-alsa.c
1 /*
2  * This file is part of DisOrder.
3  * Copyright (C) 2008 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 /** @file clients/playrtp-alsa.c
21  * @brief RTP player - ALSA support
22  *
23  * This has been rewritten to use the @ref alsabg.h interface and is therefore
24  * now closely modelled on @ref playrtp-coreaudio.c.  Given a similar interface
25  * wrapping OSS the whole of playrtp could probably be greatly simplified.
26  */
27
28 #include <config.h>
29
30 #if HAVE_ALSA_ASOUNDLIB_H 
31 #include "types.h"
32
33 #include <poll.h>
34 #include <alsa/asoundlib.h>
35 #include <assert.h>
36 #include <pthread.h>
37 #include <arpa/inet.h>
38
39 #include "mem.h"
40 #include "log.h"
41 #include "vector.h"
42 #include "heap.h"
43 #include "playrtp.h"
44 #include "alsabg.h"
45
46 /** @brief Callback from alsa_bg_collect() */
47 static int playrtp_alsa_supply(void *dst,
48                                unsigned supply_nsamples) {
49   unsigned samples_available;
50   const struct packet *p;
51
52   pthread_mutex_lock(&lock);
53   p = playrtp_next_packet();
54   if(p && contains(p, next_timestamp)) {
55     /* This packet is ready to play */
56     const uint32_t packet_end = p->timestamp + p->nsamples;
57     const uint32_t offset = next_timestamp - p->timestamp;
58     const uint16_t *src = (void *)(p->samples_raw + offset);
59     samples_available = packet_end - next_timestamp;
60     if(samples_available > supply_nsamples)
61       samples_available = supply_nsamples;
62     next_timestamp += samples_available;
63     memcpy(dst, src, samples_available * sizeof (int16_t));
64     /* We don't bother junking the packet - that'll be dealt with next time
65      * round */
66   } else {
67     /* No packet is ready to play (and there might be no packet at all) */
68     samples_available = p ? p->timestamp - next_timestamp : supply_nsamples;
69     if(samples_available > supply_nsamples)
70       samples_available = supply_nsamples;
71     /*info("infill %d", samples_available);*/
72     next_timestamp += samples_available;
73     /* Unlike Core Audio the buffer is not guaranteed to be 0-filled */
74     memset(dst, 0, samples_available * sizeof (int16_t));
75   }
76   pthread_mutex_unlock(&lock);
77   return samples_available;
78 }
79
80 void playrtp_alsa(void) {
81   alsa_bg_init(device ? device : "default",
82                playrtp_alsa_supply);
83   pthread_mutex_lock(&lock);
84   for(;;) {
85     /* Wait for the buffer to fill up a bit */
86     playrtp_fill_buffer();
87     /* Start playing now */
88     info("Playing...");
89     next_timestamp = pheap_first(&packets)->timestamp;
90     active = 1;
91     alsa_bg_enable();
92     /* Wait until the buffer empties out */
93     while(nsamples >= minbuffer
94           || (nsamples > 0
95               && contains(pheap_first(&packets), next_timestamp))) {
96       pthread_cond_wait(&cond, &lock);
97     }
98     /* Stop playing for a bit until the buffer re-fills */
99     alsa_bg_disable();
100     active = 0;
101     /* Go back round */
102   }
103 }
104
105 #endif
106
107 /*
108 Local Variables:
109 c-basic-offset:2
110 comment-column:40
111 fill-column:79
112 indent-tabs-mode:nil
113 End:
114 */