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