chiark / gitweb /
disorder-playrtp now includes timestamps in its log output (which
[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
32 #include "common.h"
33
34 #include <unistd.h>
35 #include <gcrypt.h>
36
37 #include "uaudio.h"
38 #include "mem.h"
39 #include "log.h"
40 #include "syscalls.h"
41 #include "timeval.h"
42
43 /** @brief Sample timestamp
44  *
45  * This is the timestamp that will be used on the next outbound packet.
46  *
47  * The timestamp in an RTP packet header is only 32 bits wide.  With 44100Hz
48  * stereo, that only gives about half a day before wrapping, which is not
49  * particularly convenient for certain debugging purposes.  Therefore the
50  * timestamp is maintained as a 64-bit integer, giving around six million years
51  * before wrapping, and truncated to 32 bits when transmitting.
52  */
53 uint64_t uaudio_schedule_timestamp;
54
55 /** @brief Actual time corresponding to @ref uaudio_schedule_timestamp
56  *
57  * This is the time, on this machine, at which the sample at @ref
58  * uaudio_schedule_timestamp ought to be sent, interpreted as the time the last
59  * packet was sent plus the time length of the packet. */
60 static struct timeval uaudio_schedule_timeval;
61
62 /** @brief Set when we (re-)activate, to provoke timestamp resync */
63 int uaudio_schedule_reactivated;
64
65 /** @brief Delay threshold in microseconds
66  *
67  * uaudio_schedule_play() never attempts to introduce a delay shorter than this.
68  */
69 static int64_t uaudio_schedule_delay_threshold;
70
71 /** @brief Time for current packet */
72 static struct timeval uaudio_schedule_now;
73
74 /** @brief Synchronize playback operations against real time
75  *
76  * This function sleeps as necessary to rate-limit playback operations to match
77  * the actual playback rate.  It also maintains @ref uaudio_schedule_timestamp
78  * as an arbitrarily-based sample counter, for use by RTP.
79  *
80  * You should call this in your API's @ref uaudio_playcallback before writing
81  * and call uaudio_schedule_update() afterwards.
82  */
83 void uaudio_schedule_synchronize(void) {
84 retry:
85   xgettimeofday(&uaudio_schedule_now, NULL);
86   if(uaudio_schedule_reactivated) {
87     /* We've been deactivated for some unknown interval.  We need to advance
88      * rtp_timestamp to account for the dead air. */
89     /* On the first run through we'll set the start time. */
90     if(!uaudio_schedule_timeval.tv_sec)
91       uaudio_schedule_timeval = uaudio_schedule_now;
92     /* See how much time we missed.
93      *
94      * This will be 0 on the first run through, in which case we'll not modify
95      * anything.
96      *
97      * It'll be negative in the (rare) situation where the deactivation
98      * interval is shorter than the last packet we sent.  In this case we wait
99      * for that much time and then return having sent no samples, which will
100      * cause uaudio_play_thread_fn() to retry.
101      *
102      * In the normal case it will be positive.
103      */
104     const int64_t delay = tvsub_us(uaudio_schedule_now,
105                                    uaudio_schedule_timeval); /* microseconds */
106     if(delay < 0) {
107       usleep(-delay);
108       goto retry;
109     }
110     /* Advance the RTP timestamp to the present.  With 44.1KHz stereo this will
111      * overflow the intermediate value with a delay of a bit over 6 years.
112      * This seems acceptable. */
113     uint64_t update = (delay * uaudio_rate * uaudio_channels) / 1000000;
114     /* Don't throw off channel synchronization */
115     update -= update % uaudio_channels;
116     /* We log nontrivial changes */
117     if(update)
118       info("advancing uaudio_schedule_timeval by %"PRIu64" samples", update);
119     uaudio_schedule_timestamp += update;
120     uaudio_schedule_timeval = uaudio_schedule_now;
121     uaudio_schedule_reactivated = 0;
122   } else {
123     /* Chances are we've been called right on the heels of the previous packet.
124      * If we just sent packets as fast as we got audio data we'd get way ahead
125      * of the player and some buffer somewhere would fill (or at least become
126      * unreasonably large).
127      *
128      * First find out how far ahead of the target time we are.
129      */
130     const int64_t ahead = tvsub_us(uaudio_schedule_timeval,
131                                    uaudio_schedule_now); /* microseconds */
132     /* Only delay at all if we are nontrivially ahead. */
133     if(ahead > uaudio_schedule_delay_threshold) {
134       /* Don't delay by the full amount */
135       usleep(ahead - uaudio_schedule_delay_threshold / 2);
136       /* Refetch time (so we don't get out of step with reality) */
137       xgettimeofday(&uaudio_schedule_now, NULL);
138     }
139   }
140 }
141
142 /** @brief Update schedule after writing
143  *
144  * Called by your API's @ref uaudio_playcallback after sending audio data (to a
145  * subprocess or network or whatever).  A separate function so that the caller
146  * doesn't have to know how many samples they're going to write until they've
147  * done so.
148  */
149 void uaudio_schedule_update(size_t written_samples) {
150   /* uaudio_schedule_timestamp and uaudio_schedule_timestamp are supposed to
151    * refer to the first sample of the next packet */
152   uaudio_schedule_timestamp += written_samples;
153   const unsigned usec = (uaudio_schedule_timeval.tv_usec
154                          + 1000000 * written_samples / (uaudio_rate
155                                                             * uaudio_channels));
156   /* ...will only overflow 32 bits if one packet is more than about half an
157    * hour long, which is not plausible. */
158   uaudio_schedule_timeval.tv_sec += usec / 1000000;
159   uaudio_schedule_timeval.tv_usec = usec % 1000000;
160 }
161
162 /** @brief Initialize audio scheduling
163  *
164  * Should be called from your API's @c start callback.
165  */
166 void uaudio_schedule_init(void) {
167   gcry_create_nonce(&uaudio_schedule_timestamp,
168                     sizeof uaudio_schedule_timestamp);
169   /* uaudio_schedule_play() will spot this and choose an initial value */
170   uaudio_schedule_timeval.tv_sec = 0;
171 }
172
173 /*
174 Local Variables:
175 c-basic-offset:2
176 comment-column:40
177 fill-column:79
178 indent-tabs-mode:nil
179 End:
180 */