Upload upstream chromium 108.0.5359.1
[platform/framework/web/chromium-efl.git] / media / filters / audio_clock.h
1 // Copyright 2014 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #ifndef MEDIA_FILTERS_AUDIO_CLOCK_H_
6 #define MEDIA_FILTERS_AUDIO_CLOCK_H_
7
8 #include <stdint.h>
9
10 #include <cmath>
11
12 #include "base/containers/circular_deque.h"
13 #include "base/time/time.h"
14 #include "media/base/media_export.h"
15
16 namespace media {
17
18 // Models a queue of buffered audio in a playback pipeline for use with
19 // estimating the amount of delay in wall clock time. Takes changes in playback
20 // rate into account to handle scenarios where multiple rates may be present in
21 // a playback pipeline with large delay.
22 //
23 //
24 // USAGE
25 //
26 // Prior to starting audio playback, construct an AudioClock with an initial
27 // media timestamp and a sample rate matching the sample rate the audio device
28 // was opened at.
29 //
30 // Each time the audio rendering callback is executed, call WroteAudio() once
31 // (and only once!) containing information on what was written:
32 //   1) How many frames of audio data requested
33 //   2) How many frames of audio data provided
34 //   3) The playback rate of the audio data provided
35 //   4) The current amount of delay
36 //
37 // After a call to WroteAudio(), clients can inspect the resulting media
38 // timestamp. This can be used for UI purposes, synchronizing video, etc...
39 //
40 //
41 // DETAILS
42 //
43 // Silence (whether caused by the initial audio delay or failing to write the
44 // amount of requested frames due to underflow) is also modeled and will cause
45 // the media timestamp to stop increasing until all known silence has been
46 // played. AudioClock's model is initialized with silence during the first call
47 // to WroteAudio() using the delay value.
48 //
49 // Playback rates are tracked for translating frame durations into media
50 // durations. Since silence doesn't affect media timestamps, it also isn't
51 // affected by playback rates.
52 class MEDIA_EXPORT AudioClock {
53  public:
54   AudioClock(base::TimeDelta start_timestamp, int sample_rate);
55
56   AudioClock(const AudioClock&) = delete;
57   AudioClock& operator=(const AudioClock&) = delete;
58
59   ~AudioClock();
60
61   // |frames_written| amount of audio data scaled to |playback_rate| written.
62   // |frames_requested| amount of audio data requested by hardware.
63   // |delay_frames| is the current amount of hardware delay.
64   void WroteAudio(int frames_written,
65                   int frames_requested,
66                   int delay_frames,
67                   double playback_rate);
68
69   // If WroteAudio() calls are suspended (i.e. due to playback being paused) the
70   // AudioClock will not properly advance time (even though all data up until
71   // back_timestamp() will playout on the physical device).
72   //
73   // To compensate for this, when calls resume, before the next WroteAudio(),
74   // callers should call CompensateForSuspendedWrites() to advance the clock for
75   // audio which continued playing out while WroteAudio() calls were suspended.
76   //
77   // |delay_frames| must be provided to properly prime the clock to compensate
78   // for a new initial delay.
79   void CompensateForSuspendedWrites(base::TimeDelta elapsed, int delay_frames);
80
81   // Returns the bounds of media data currently buffered by the audio hardware,
82   // taking silence and changes in playback rate into account. Buffered audio
83   // structure and timestamps are updated with every call to WroteAudio().
84   //
85   //  start_timestamp = 1000 ms                           sample_rate = 40 Hz
86   // +-----------------------+-----------------------+-----------------------+
87   // |   10 frames silence   |   20 frames @ 1.0x    |   20 frames @ 0.5x    |
88   // |      = 250 ms (wall)  |      = 500 ms (wall)  |      = 500 ms (wall)  |
89   // |      =   0 ms (media) |      = 500 ms (media) |      = 250 ms (media) |
90   // +-----------------------+-----------------------+-----------------------+
91   // ^                                                                       ^
92   // front_timestamp() is equal to               back_timestamp() is equal to
93   // |start_timestamp| since no                  amount of media frames tracked
94   // media data has been played yet.             by AudioClock, which would be
95   //                                             1000 + 500 + 250 = 1750 ms.
96   base::TimeDelta front_timestamp() const {
97     return base::Microseconds(std::round(front_timestamp_micros_));
98   }
99   base::TimeDelta back_timestamp() const {
100     return base::Microseconds(std::round(back_timestamp_micros_));
101   }
102
103   // Returns the amount of wall time until |timestamp| will be played by the
104   // audio hardware.
105   //
106   // |timestamp| must be within front_timestamp() and back_timestamp().
107   base::TimeDelta TimeUntilPlayback(base::TimeDelta timestamp) const;
108
109   void ContiguousAudioDataBufferedForTesting(
110       base::TimeDelta* total,
111       base::TimeDelta* same_rate_total) const;
112
113  private:
114   // Even with a ridiculously high sample rate of 256kHz, using 64 bits will
115   // permit tracking up to 416999965 days worth of time (that's 1141 millenia).
116   //
117   // 32 bits on the other hand would top out at measly 2 hours and 20 minutes.
118   struct AudioData {
119     AudioData(int64_t frames, double playback_rate);
120
121     int64_t frames;
122     double playback_rate;
123   };
124
125   // Helpers for operating on |buffered_|.
126   void PushBufferedAudioData(int64_t frames, double playback_rate);
127   void PopBufferedAudioData(int64_t frames);
128   double ComputeBufferedMediaDurationMicros() const;
129
130   const base::TimeDelta start_timestamp_;
131   const double microseconds_per_frame_;
132
133   base::circular_deque<AudioData> buffered_;
134   int64_t total_buffered_frames_;
135
136   // Use double rather than TimeDelta to avoid loss of partial microseconds when
137   // converting between frames-written/delayed and time-passed (see conversion
138   // in WroteAudio()). Particularly for |back_timestamp|, which accumulates more
139   // time with each call to WroteAudio(), the loss of precision can accumulate
140   // to create noticeable audio/video sync drift for longer (2-3 hr) videos.
141   // See http://crbug.com/564604.
142   double front_timestamp_micros_;
143   double back_timestamp_micros_;
144 };
145
146 }  // namespace media
147
148 #endif  // MEDIA_FILTERS_AUDIO_CLOCK_H_