]>
Commit | Line | Data |
---|---|---|
a2fb5d21 JL |
1 | #ifndef _PLAYER_H |
2 | #define _PLAYER_H | |
3 | ||
e4d5570e | 4 | #include <arpa/inet.h> |
d4065149 | 5 | #include <pthread.h> |
e4d5570e | 6 | |
7d672bcf | 7 | #include "config.h" |
88c55066 | 8 | #include "definitions.h" |
7d672bcf | 9 | |
c9b3d2a2 | 10 | #ifdef CONFIG_MBEDTLS |
7d672bcf MB |
11 | #include <mbedtls/aes.h> |
12 | #include <mbedtls/havege.h> | |
13 | #endif | |
14 | ||
c9b3d2a2 | 15 | #ifdef CONFIG_POLARSSL |
7d672bcf MB |
16 | #include <polarssl/aes.h> |
17 | #include <polarssl/havege.h> | |
18 | #endif | |
19 | ||
c9b3d2a2 | 20 | #ifdef CONFIG_OPENSSL |
7d672bcf MB |
21 | #include <openssl/aes.h> |
22 | #endif | |
23 | ||
8a73d597 | 24 | #ifdef CONFIG_AIRPLAY_2 |
493e9604 | 25 | #include "pair_ap/pair.h" |
f8b91e9b | 26 | #include <plist/plist.h> |
8a73d597 MB |
27 | #endif |
28 | ||
05305e15 | 29 | #include "alac.h" |
e513e533 | 30 | #include "audio.h" |
a2fb5d21 | 31 | |
efec3cc7 | 32 | #define time_ping_history_power_of_two 7 |
14bfba27 | 33 | // this must now be zero, otherwise bad things will happen |
ca562872 MB |
34 | #define time_ping_history \ |
35 | (1 << time_ping_history_power_of_two) // 2^7 is 128. At 1 per three seconds, approximately six | |
36 | // minutes of records | |
e4d5570e | 37 | typedef struct time_ping_record { |
e4d5570e MB |
38 | uint64_t dispersion; |
39 | uint64_t local_time; | |
40 | uint64_t remote_time; | |
3870195c MB |
41 | int sequence_number; |
42 | int chosen; | |
e4d5570e MB |
43 | } time_ping_record; |
44 | ||
04c7f845 MB |
45 | // these are for reporting the status of the clock |
46 | typedef enum { | |
47 | clock_no_anchor_info, | |
48 | clock_ok, | |
49 | clock_service_unavailable, | |
50 | clock_access_error, | |
51 | clock_data_unavailable, | |
52 | clock_no_master, | |
53 | clock_version_mismatch, | |
54 | clock_not_synchronised, | |
637c8132 MB |
55 | clock_not_valid, |
56 | clock_not_ready, | |
04c7f845 MB |
57 | } clock_status_t; |
58 | ||
498c1d6e MB |
59 | typedef uint16_t seq_t; |
60 | ||
61 | typedef struct audio_buffer_entry { // decoded audio packets | |
686fc2a5 MB |
62 | uint8_t ready; |
63 | uint8_t status; // flags | |
64 | uint16_t resend_request_number; | |
65 | signed short *data; | |
66 | seq_t sequence_number; | |
54d761ff MB |
67 | uint64_t initialisation_time; // the time the packet was added or the time it was noticed the |
68 | // packet was missing | |
69 | uint64_t resend_time; // time of last resend request or zero | |
70 | uint32_t given_timestamp; // for debugging and checking | |
71 | int length; // the length of the decoded data | |
498c1d6e MB |
72 | } abuf_t; |
73 | ||
759b87f2 MB |
74 | typedef struct stats { // statistics for running averages |
75 | int64_t sync_error, correction, drift; | |
76 | } stats_t; | |
77 | ||
498c1d6e | 78 | // default buffer size |
5a7b7c01 | 79 | // This needs to be a power of 2 because of the way BUFIDX(seqno) works. |
b9d3a036 MB |
80 | // 512 is the minimum for normal operation -- it gives 512*352/44100 or just over 4 seconds of |
81 | // buffers. | |
82 | // For at least 10 seconds, you need to go to 2048. | |
83 | // Resend requests will be spaced out evenly in the latency period, subject to a minimum interval of | |
84 | // about 0.25 seconds. | |
85 | // Each buffer occupies 352*4 bytes plus about, say, 64 bytes of overhead in various places, say | |
b9cf91b2 | 86 | // roughly 1,500 bytes per buffer. |
b9d3a036 MB |
87 | // Thus, 2048 buffers will occupy about 3 megabytes -- no big deal in a normal machine but maybe a |
88 | // problem in an embedded device. | |
89 | ||
8bf83c14 | 90 | #define BUFFER_FRAMES 1024 |
498c1d6e | 91 | |
f7717745 | 92 | typedef enum { |
5a7b7c01 MB |
93 | ast_unknown, |
94 | ast_uncompressed, // L16/44100/2 | |
95 | ast_apple_lossless, | |
f7717745 | 96 | } audio_stream_type; |
5a7b7c01 | 97 | |
a2fb5d21 | 98 | typedef struct { |
2a1fe7af | 99 | int encrypted; |
87a0475c MB |
100 | uint8_t aesiv[16], aeskey[16]; |
101 | int32_t fmtp[12]; | |
f7717745 | 102 | audio_stream_type type; |
a2fb5d21 JL |
103 | } stream_cfg; |
104 | ||
2e123cf3 | 105 | // the following is used even when not built for AirPlay 2 |
ae1c4f1d | 106 | typedef enum { |
1fc00e13 | 107 | unspecified_stream_category = 0, |
ae1c4f1d MB |
108 | ptp_stream, |
109 | ntp_stream, | |
986f9587 MB |
110 | remote_control_stream, |
111 | classic_airplay_stream | |
ae1c4f1d | 112 | } airplay_stream_c; // "c" for category |
2e123cf3 | 113 | |
2e123cf3 MB |
114 | #ifdef CONFIG_AIRPLAY_2 |
115 | typedef enum { ts_ntp, ts_ptp } timing_t; | |
116 | typedef enum { ap_1, ap_2 } airplay_t; | |
ae1c4f1d | 117 | typedef enum { realtime_stream, buffered_stream } airplay_stream_t; |
c2940eb2 | 118 | |
493e9604 | 119 | typedef struct { |
120 | uint8_t *data; | |
d36decbd | 121 | size_t length; |
493e9604 | 122 | size_t size; |
d36decbd | 123 | } sized_buffer; |
493e9604 | 124 | |
125 | typedef struct { | |
d36decbd MB |
126 | struct pair_cipher_context *cipher_ctx; |
127 | sized_buffer encrypted_read_buffer; | |
128 | sized_buffer plaintext_read_buffer; | |
493e9604 | 129 | int is_encrypted; |
d36decbd MB |
130 | } pair_cipher_bundle; // cipher context and buffers |
131 | ||
d36decbd | 132 | typedef struct { |
493e9604 | 133 | struct pair_setup_context *setup_ctx; |
134 | struct pair_verify_context *verify_ctx; | |
d36decbd | 135 | pair_cipher_bundle control_cipher_bundle; |
493e9604 | 136 | } ap2_pairing; |
137 | ||
a109b587 MB |
138 | // flush requests are stored in order of flushFromSeq |
139 | // on the basis that block numbers are monotonic modulo 2^24 | |
140 | typedef struct flush_request_t { | |
141 | int flushNow; // if true, the flushFrom stuff is invalid | |
142 | uint32_t flushFromSeq; | |
143 | uint32_t flushFromTS; | |
144 | uint32_t flushUntilSeq; | |
145 | uint32_t flushUntilTS; | |
146 | struct flush_request_t *next; | |
147 | } flush_request_t; | |
148 | ||
8a73d597 MB |
149 | #endif |
150 | ||
7d672bcf | 151 | typedef struct { |
deb11654 MB |
152 | int connection_number; // for debug ID purposes, nothing else... |
153 | int resend_interval; // this is really just for debugging | |
fd880056 | 154 | int rtsp_link_is_idle; // if true, this indicates if the client asleep |
deb11654 MB |
155 | char *UserAgent; // free this on teardown |
156 | int AirPlayVersion; // zero if not an AirPlay session. Used to help calculate latency | |
157 | int latency_warning_issued; | |
c5ff0dfe MB |
158 | uint32_t latency; // the actual latency used for this play session |
159 | uint32_t minimum_latency; // set if an a=min-latency: line appears in the ANNOUNCE message; zero | |
160 | // otherwise | |
161 | uint32_t maximum_latency; // set if an a=max-latency: line appears in the ANNOUNCE message; zero | |
162 | // otherwise | |
163 | int software_mute_enabled; // if we don't have a real mute that we can use | |
7d672bcf | 164 | int fd; |
c8c70b60 | 165 | int authorized; // set if a password is required and has been supplied |
a4eaace7 | 166 | char *auth_nonce; // the session nonce, if needed |
7d672bcf MB |
167 | stream_cfg stream; |
168 | SOCKADDR remote, local; | |
78da7c45 MB |
169 | volatile int stop; |
170 | volatile int running; | |
277d401d | 171 | volatile uint64_t watchdog_bark_time; |
d6536a8e | 172 | volatile int watchdog_barks; // number of times the watchdog has timed out and done something |
277d401d | 173 | |
4fa06bed MB |
174 | uint64_t playstart; |
175 | uint64_t connection_start_time; // the time the device is selected, which could be a long time | |
176 | // before a play | |
76ee6d5e MB |
177 | pthread_t thread, timer_requester, rtp_audio_thread, rtp_control_thread, rtp_timing_thread, |
178 | player_watchdog_thread; | |
7d672bcf | 179 | |
c85e7e05 | 180 | // buffers to delete on exit |
c0a3dacf | 181 | int32_t *tbuf; |
d3b79b96 MB |
182 | int32_t *sbuf; |
183 | char *outbuf; | |
76c5dd92 | 184 | |
759b87f2 MB |
185 | // for generating running statistics... |
186 | ||
187 | stats_t *statistics; | |
188 | ||
b75c82d1 | 189 | // for holding the output rate information until printed out at the end of a session |
56bef8e7 MB |
190 | double raw_frame_rate; |
191 | double corrected_frame_rate; | |
99c66385 | 192 | int frame_rate_valid; |
5141e2f5 | 193 | |
b75c82d1 | 194 | // for holding input rate information until printed out at the end of a session |
5141e2f5 | 195 | |
b75c82d1 | 196 | double input_frame_rate; |
51913573 | 197 | int input_frame_rate_starting_point_is_valid; |
5141e2f5 | 198 | |
b75c82d1 | 199 | uint64_t frames_inward_measurement_start_time; |
de071aef | 200 | uint32_t frames_inward_frames_received_at_measurement_start_time; |
b75c82d1 MB |
201 | |
202 | uint64_t frames_inward_measurement_time; | |
de071aef | 203 | uint32_t frames_inward_frames_received_at_measurement_time; |
b75c82d1 MB |
204 | |
205 | // other stuff... | |
06fa3485 | 206 | pthread_t *player_thread; |
498c1d6e | 207 | abuf_t audio_buffer[BUFFER_FRAMES]; |
e5259e87 | 208 | unsigned int max_frames_per_packet, input_num_channels, input_bit_depth, input_rate; |
e513e533 | 209 | int input_bytes_per_frame, output_bytes_per_frame, output_sample_ratio; |
05305e15 | 210 | int max_frame_size_change; |
600cebac | 211 | int64_t previous_random_number; |
05305e15 | 212 | alac_file *decoder_info; |
7d672bcf | 213 | uint64_t packet_count; |
f6b3c420 | 214 | uint64_t packet_count_since_flush; |
05305e15 | 215 | int connection_state_to_output; |
8991f342 MB |
216 | uint64_t first_packet_time_to_play; |
217 | int64_t time_since_play_started; // nanoseconds | |
7970a54b | 218 | // stats |
e513e533 MB |
219 | uint64_t missing_packets, late_packets, too_late_packets, resend_requests; |
220 | int decoder_in_use; | |
221 | // debug variables | |
222 | int32_t last_seqno_read; | |
223 | // mutexes and condition variables | |
224 | pthread_cond_t flowcontrol; | |
986f9587 | 225 | pthread_mutex_t ab_mutex, flush_mutex, volume_control_mutex, player_create_delete_mutex; |
c645a039 | 226 | |
e513e533 | 227 | int fix_volume; |
8201903a MB |
228 | double own_airplay_volume; |
229 | int own_airplay_volume_set; | |
26ce13d5 | 230 | |
e513e533 MB |
231 | uint32_t timestamp_epoch, last_timestamp, |
232 | maximum_timestamp_interval; // timestamp_epoch of zero means not initialised, could start at 2 | |
233 | // or 1. | |
234 | int ab_buffering, ab_synced; | |
235 | int64_t first_packet_timestamp; | |
236 | int flush_requested; | |
f8c24c5f | 237 | int flush_output_flushed; // true if the output device has been flushed. |
de071aef | 238 | uint32_t flush_rtp_timestamp; |
e513e533 MB |
239 | uint64_t time_of_last_audio_packet; |
240 | seq_t ab_read, ab_write; | |
05305e15 | 241 | |
c9b3d2a2 | 242 | #ifdef CONFIG_MBEDTLS |
7d672bcf MB |
243 | mbedtls_aes_context dctx; |
244 | #endif | |
245 | ||
c9b3d2a2 | 246 | #ifdef CONFIG_POLARSSL |
7d672bcf MB |
247 | aes_context dctx; |
248 | #endif | |
249 | ||
e513e533 | 250 | int amountStuffed; |
bbf7857f MB |
251 | |
252 | int32_t framesProcessedInThisEpoch; | |
253 | int32_t framesGeneratedInThisEpoch; | |
254 | int32_t correctionsRequestedInThisEpoch; | |
255 | int64_t syncErrorsInThisEpoch; | |
256 | ||
257 | // RTP stuff | |
258 | // only one RTP session can be active at a time. | |
259 | int rtp_running; | |
40289ca6 | 260 | uint64_t rtp_time_of_last_resend_request_error_ns; |
f94d6a5d | 261 | |
9ae4dee5 | 262 | char client_ip_string[INET6_ADDRSTRLEN]; // the ip string of the client |
6760bab4 | 263 | uint16_t client_rtsp_port; |
a68f28ac MB |
264 | char self_ip_string[INET6_ADDRSTRLEN]; // the ip string being used by this program -- it |
265 | uint16_t self_rtsp_port; // could be one of many, so we need to know it | |
6760bab4 | 266 | |
a68f28ac MB |
267 | uint32_t self_scope_id; // if it's an ipv6 connection, this will be its scope |
268 | short connection_ip_family; // AF_INET / AF_INET6 | |
bbf7857f MB |
269 | |
270 | SOCKADDR rtp_client_control_socket; // a socket pointing to the control port of the client | |
271 | SOCKADDR rtp_client_timing_socket; // a socket pointing to the timing port of the client | |
272 | int audio_socket; // our local [server] audio socket | |
273 | int control_socket; // our local [server] control socket | |
274 | int timing_socket; // local timing socket | |
275 | ||
665a53a8 MB |
276 | uint16_t remote_control_port; |
277 | uint16_t remote_timing_port; | |
278 | uint16_t local_audio_port; | |
279 | uint16_t local_control_port; | |
280 | uint16_t local_timing_port; | |
281 | ||
d3e2cb5d | 282 | int64_t latency_delayed_timestamp; // this is for debugging only... |
3870195c MB |
283 | |
284 | // this is what connects an rtp timestamp to the remote time | |
285 | ||
fd880056 MB |
286 | int udp_clock_is_initialised; |
287 | int udp_clock_sender_is_initialised; | |
288 | ||
8a73d597 | 289 | int anchor_remote_info_is_valid; |
c5dafbd2 MB |
290 | |
291 | // these can be modified if the master clock changes over time | |
8a73d597 MB |
292 | uint64_t anchor_clock; |
293 | uint64_t anchor_time; // this is the time according to the clock | |
294 | uint32_t anchor_rtptime; | |
295 | ||
c5dafbd2 MB |
296 | // these are used to identify when the master clock becomes equal to the |
297 | // actual anchor clock information, so it can be used to avoid accumulating errors | |
298 | uint64_t actual_anchor_clock; | |
299 | uint64_t actual_anchor_time; | |
300 | uint32_t actual_anchor_rtptime; | |
301 | ||
04c7f845 MB |
302 | clock_status_t clock_status; |
303 | ||
2e123cf3 | 304 | airplay_stream_c |
04240708 MB |
305 | airplay_stream_category; // is it a remote control stream or a normal "full service" stream? |
306 | // (will be unspecified if not build for AirPlay 2) | |
2e123cf3 | 307 | |
8a73d597 | 308 | #ifdef CONFIG_AIRPLAY_2 |
fcd57227 MB |
309 | char *airplay_gid; // UUID in the Bonjour advertisement -- if NULL, the group UUID is the same as |
310 | // the pi UUID | |
c2940eb2 | 311 | airplay_t airplay_type; // are we using AirPlay 1 or AirPlay 2 protocol on this connection? |
953ad8ac MB |
312 | airplay_stream_t airplay_stream_type; // is it realtime audio or buffered audio... |
313 | timing_t timing_type; // are we using NTP or PTP on this connection? | |
c2940eb2 | 314 | |
4a827455 | 315 | pthread_t *rtp_event_thread; |
fb151915 | 316 | pthread_t *rtp_data_thread; |
8a73d597 MB |
317 | pthread_t rtp_ap2_control_thread; |
318 | pthread_t rtp_realtime_audio_thread; | |
319 | pthread_t rtp_buffered_audio_thread; | |
320 | ||
8a73d597 | 321 | int last_anchor_info_is_valid; |
26ce13d5 MB |
322 | uint32_t last_anchor_rtptime; |
323 | uint64_t last_anchor_local_time; | |
8a73d597 | 324 | uint64_t last_anchor_time_of_update; |
ac515bbf | 325 | uint64_t last_anchor_validity_start_time; |
8a73d597 | 326 | |
8a73d597 | 327 | ssize_t ap2_audio_buffer_size; |
08afa822 | 328 | ssize_t ap2_audio_buffer_minimum_size; |
a109b587 | 329 | flush_request_t *flush_requests; // if non-null, there are flush requests, mutex protected |
8a73d597 | 330 | int ap2_flush_requested; |
e258cca3 MB |
331 | int ap2_flush_from_valid; |
332 | uint32_t ap2_flush_from_rtp_timestamp; | |
333 | uint32_t ap2_flush_from_sequence_number; | |
334 | uint32_t ap2_flush_until_rtp_timestamp; | |
335 | uint32_t ap2_flush_until_sequence_number; | |
8a73d597 MB |
336 | int ap2_rate; // protect with flush mutex, 0 means don't play, 1 means play |
337 | int ap2_play_enabled; // protect with flush mutex | |
338 | ||
d36decbd | 339 | ap2_pairing ap2_pairing_context; |
493e9604 | 340 | |
8a73d597 | 341 | int event_socket; |
fb151915 | 342 | int data_socket; |
8a73d597 MB |
343 | SOCKADDR ap2_remote_control_socket_addr; // a socket pointing to the control port of the client |
344 | socklen_t ap2_remote_control_socket_addr_length; | |
345 | int ap2_control_socket; | |
346 | int realtime_audio_socket; | |
347 | int buffered_audio_socket; | |
348 | ||
fb151915 | 349 | uint16_t local_data_port; |
8a73d597 MB |
350 | uint16_t local_event_port; |
351 | uint16_t local_ap2_control_port; | |
352 | uint16_t local_realtime_audio_port; | |
353 | uint16_t local_buffered_audio_port; | |
354 | ||
8a73d597 MB |
355 | uint64_t audio_format; |
356 | uint64_t compression; | |
357 | unsigned char *session_key; // needs to be free'd at the end | |
358 | uint64_t frames_packet; | |
359 | uint64_t type; | |
d703314c MB |
360 | uint64_t networkTimeTimelineID; // the clock ID used by the player |
361 | uint8_t groupContainsGroupLeader; // information coming from the SETUP | |
8a73d597 | 362 | #endif |
bbf7857f | 363 | |
5141e2f5 MB |
364 | // used as the initials values for calculating the rate at which the source thinks it's sending |
365 | // frames | |
de071aef | 366 | uint32_t initial_reference_timestamp; |
2f588562 MB |
367 | uint64_t initial_reference_time; |
368 | double remote_frame_rate; | |
369 | ||
3870195c MB |
370 | // the ratio of the following should give us the operating rate, nominally 44,100 |
371 | int64_t reference_to_previous_frame_difference; | |
372 | uint64_t reference_to_previous_time_difference; | |
5141e2f5 | 373 | |
bbf7857f MB |
374 | // debug variables |
375 | int request_sent; | |
376 | ||
3870195c | 377 | int time_ping_count; |
bbf7857f MB |
378 | struct time_ping_record time_pings[time_ping_history]; |
379 | ||
380 | uint64_t departure_time; // dangerous -- this assumes that there will never be two timing | |
381 | // request in flight at the same time | |
382 | ||
383 | pthread_mutex_t reference_time_mutex; | |
76ee6d5e | 384 | pthread_mutex_t watchdog_mutex; |
bbf7857f | 385 | |
5141e2f5 MB |
386 | double local_to_remote_time_gradient; // if no drift, this would be exactly 1.0; likely it's |
387 | // slightly above or below. | |
388 | int local_to_remote_time_gradient_sample_count; // the number of samples used to calculate the | |
389 | // gradient | |
3cb359c7 MB |
390 | // add the following to the local time to get the remote time modulo 2^64 |
391 | uint64_t local_to_remote_time_difference; // used to switch between local and remote clocks | |
3870195c | 392 | uint64_t local_to_remote_time_difference_measurement_time; // when the above was calculated |
bbf7857f | 393 | |
bbf7857f | 394 | int last_stuff_request; |
e513e533 | 395 | |
3870195c MB |
396 | // int64_t play_segment_reference_frame; |
397 | // uint64_t play_segment_reference_frame_remote_time; | |
e513e533 | 398 | |
bbf7857f MB |
399 | int32_t buffer_occupancy; // allow it to be negative because seq_diff may be negative |
400 | int64_t session_corrections; | |
e513e533 | 401 | |
bbf7857f | 402 | int play_number_after_flush; |
d343a851 MB |
403 | |
404 | // remote control stuff. The port to which to send commands is not specified, so you have to use | |
405 | // mdns to find it. | |
139c18bf | 406 | // at present, only avahi can do this |
d343a851 | 407 | |
32c7a535 MB |
408 | char *dacp_id; // id of the client -- used to find the port to be used |
409 | // uint16_t dacp_port; // port on the client to send remote control messages to, else | |
410 | // zero | |
3fc95704 MB |
411 | char *dacp_active_remote; // key to send to the remote controller |
412 | void *dapo_private_storage; // this is used for compatibility, if dacp stuff isn't enabled. | |
4046c0e7 MB |
413 | |
414 | int enable_dither; // needed for filling silences before play actually starts | |
034dd53a | 415 | uint64_t dac_buffer_queue_minimum_length; |
7d672bcf MB |
416 | } rtsp_conn_info; |
417 | ||
e3faba14 | 418 | extern int statistics_row; // will be reset to zero when debug level changes or statistics enabled |
25a13032 | 419 | |
2ea28c06 MB |
420 | void reset_buffer(rtsp_conn_info *conn); |
421 | ||
6760bab4 MB |
422 | void get_audio_buffer_size_and_occupancy(unsigned int *size, unsigned int *occupancy, |
423 | rtsp_conn_info *conn); | |
424 | ||
bdfb1c6e | 425 | int32_t modulo_32_offset(uint32_t from, uint32_t to); |
d2dba7cd | 426 | |
fd880056 MB |
427 | void ab_resync(rtsp_conn_info *conn); |
428 | ||
1464c4ed | 429 | int player_prepare_to_play(rtsp_conn_info *conn); |
06fa3485 | 430 | int player_play(rtsp_conn_info *conn); |
418b1ba7 | 431 | int player_stop(rtsp_conn_info *conn); |
a2fb5d21 | 432 | |
e513e533 | 433 | void player_volume(double f, rtsp_conn_info *conn); |
1e07e1e0 | 434 | void player_volume_without_notification(double f, rtsp_conn_info *conn); |
de071aef | 435 | void player_flush(uint32_t timestamp, rtsp_conn_info *conn); |
1464c4ed | 436 | // void player_full_flush(rtsp_conn_info *conn); |
a68f28ac MB |
437 | void player_put_packet(int original_format, seq_t seqno, uint32_t actual_timestamp, uint8_t *data, |
438 | int len, rtsp_conn_info *conn); | |
e513e533 MB |
439 | int64_t monotonic_timestamp(uint32_t timestamp, |
440 | rtsp_conn_info *conn); // add an epoch to the timestamp. The monotonic | |
441 | // timestamp guaranteed to start between 2^32 2^33 | |
442 | // frames and continue up to 2^64 frames | |
ef851a92 | 443 | // which is about 2*10^8 * 1,000 seconds at 384,000 frames per second -- about 2 trillion seconds. |
064bd293 MB |
444 | // assumes, without checking, that successive timestamps in a series always span an interval of less |
445 | // than one minute. | |
7f6f4f44 | 446 | |
8201903a MB |
447 | double suggested_volume(rtsp_conn_info *conn); // volume suggested for the connection |
448 | ||
a2fb5d21 | 449 | #endif //_PLAYER_H |