Commit | Line | Data |
---|---|---|
ec57f6c9 RK |
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 | */ |