chiark / gitweb /
More comments
[disorder] / lib / uaudio-schedule.c
1 /*
2  * This file is part of DisOrder.
3  * Copyright (C) 2009 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 lib/uaudio-schedule.c
19  * @brief Scheduler for RTP and command backends
20  *
21  * These functions ensure that audio is only written at approximately the rate
22  * it should play at, allowing pause to function properly.
23  *
24  * OSS and ALSA we expect to be essentially synchronous (though we could use
25  * this code if they don't play nicely).  Core Audio sorts out its own timing
26  * issues itself.
27  *
28  * The sequence numbers are intended for RTP's use but it's more convenient to
29  * maintain them here.
30  *
31  * The basic idea:
32  * - we maintain a base time
33  * - we calculate from this how many samples SHOULD have been sent by now
34  * - we compare this with the number of samples sent so far
35  * - we use this to wait until we're ready to send something
36  * - it's up to the caller to send nothing, or send 0s, if it's supposed to
37  *   be paused
38  *
39  * An implication of this is that the caller must still call
40  * uaudio_schedule_sync() when deactivated (paused) and pretend to send 0s.
41  */
42
43 #include "common.h"
44
45 #include <unistd.h>
46 #include <time.h>
47 #include <errno.h>
48
49 #include "uaudio.h"
50 #include "mem.h"
51 #include "log.h"
52 #include "syscalls.h"
53 #include "timeval.h"
54
55 /** @brief Sample timestamp
56  *
57  * This is the timestamp that will be used on the next outbound packet.
58  *
59  * The timestamp in an RTP packet header is only 32 bits wide.  With 44100Hz
60  * stereo, that only gives about half a day before wrapping, which is not
61  * particularly convenient for certain debugging purposes.  Therefore the
62  * timestamp is maintained as a 64-bit integer, giving around six million years
63  * before wrapping, and truncated to 32 bits when transmitting.
64  */
65 static uint64_t timestamp;
66
67 /** @brief Base time
68  *
69  * This is the base time that corresponds to a timestamp of 0.
70  */
71 struct timeval base;
72
73 /** @brief Synchronize playback operations against real time
74  * @return Sample number
75  *
76  */
77 uint32_t uaudio_schedule_sync(void) {
78   const unsigned rate = uaudio_rate * uaudio_channels;
79   struct timeval now;
80
81   xgettimeofday(&now, NULL);
82   /* If we're just starting then we might as well send as much as possible
83    * straight away. */
84   if(!base.tv_sec) {
85     base = now;
86     return timestamp;
87   }
88   /* Calculate how many microseconds ahead of the base time we are */
89   uint64_t us = tvsub_us(now, base);
90   /* Calculate how many samples that is */
91   uint64_t samples = us * rate / 1000000;
92   /* So...
93    *
94    * We've actually sent 'timestamp' samples so far.
95    *
96    * We OUGHT to have sent 'samples' samples so far.
97    *
98    * Suppose it's the SECOND call.  timestamp will be (say) 716.  'samples'
99    * will be (say) 10 - there's been a bit of scheduling delay.  So in that
100    * case we should wait for 716-10=706 samples worth of time before we can
101    * even send one sample.
102    *
103    * So we wait that long and send our 716 samples.
104    *
105    * On the next call we'll have timestamp=1432 and samples=726, say.  So we
106    * wait and send again.
107    *
108    * On the next call there's been a bit of a delay.  timestamp=2148 but
109    * samples=2200.  So we send our 716 samples immediately.
110    *
111    * If the delay had been longer we might sent further packets back to back to
112    * make up for it.
113    *
114    * Now timestamp=2864 and samples=2210 (say).  Now we're back to waiting.
115    */
116   if(samples < timestamp) {
117     /* We should delay a bit */
118     int64_t wait_samples = timestamp - samples;
119     int64_t wait_ns = wait_samples * 1000000000 / rate;
120     
121     struct timespec ts[1];
122     ts->tv_sec = wait_ns / 1000000000;
123     ts->tv_nsec = wait_ns % 1000000000;
124 #if 0
125     fprintf(stderr,
126             "samples=%8"PRIu64" timestamp=%8"PRIu64" wait=%"PRId64" (%"PRId64"ns)\n",
127             samples, timestamp, wait_samples, wait_ns);
128 #endif
129     while(nanosleep(ts, ts) < 0 && errno == EINTR)
130       ;
131   } else {
132 #if 0
133     fprintf(stderr, "samples=%8"PRIu64" timestamp=%8"PRIu64"\n",
134             samples, timestamp);
135 #endif
136   }
137   /* If samples >= timestamp then it's time, or gone time, to play the
138    * timestamp'th sample.  So we return immediately. */
139   return timestamp;
140 }
141
142 /** @brief Report how many samples we actually sent
143  * @param nsamples_sent Number of samples sent
144  */
145 void uaudio_schedule_sent(size_t nsamples_sent) {
146   timestamp += nsamples_sent;
147 }
148
149 /** @brief Initialize audio scheduling
150  *
151  * Should be called from your API's @c start callback.
152  */
153 void uaudio_schedule_init(void) {
154   /* uaudio_schedule_play() will spot this and choose an initial value */
155   base.tv_sec = 0;
156 }
157
158 /*
159 Local Variables:
160 c-basic-offset:2
161 comment-column:40
162 fill-column:79
163 indent-tabs-mode:nil
164 End:
165 */