• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
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_BASE_AUDIO_SPLICER_H_
6 #define MEDIA_BASE_AUDIO_SPLICER_H_
7 
8 #include "base/memory/ref_counted.h"
9 #include "base/memory/scoped_ptr.h"
10 #include "base/time/time.h"
11 #include "media/audio/audio_parameters.h"
12 #include "media/base/buffers.h"
13 #include "media/base/media_export.h"
14 
15 namespace media {
16 
17 class AudioBuffer;
18 class AudioBus;
19 class AudioStreamSanitizer;
20 
21 // Helper class that handles filling gaps and resolving overlaps.
22 class MEDIA_EXPORT AudioSplicer {
23  public:
24   explicit AudioSplicer(int samples_per_second);
25   ~AudioSplicer();
26 
27   enum {
28     // The number of ms to crossfade before trimming when buffers overlap.
29     kCrossfadeDurationInMilliseconds = 5,
30 
31     // Largest gap or overlap allowed between buffers.  Anything larger than
32     // this will trigger an error.  This is an arbitrary value, but the initial
33     // selection of 50ms roughly represents the duration of 2 compressed AAC or
34     // MP3 frames.
35     kMaxTimeDeltaInMilliseconds = 50,
36   };
37 
38   // Resets the splicer state by clearing the output buffers queue and resetting
39   // the timestamp helper.
40   void Reset();
41 
42   // Adds a new buffer full of samples or end of stream buffer to the splicer.
43   // Returns true if the buffer was accepted.  False is returned if an error
44   // occurred.
45   bool AddInput(const scoped_refptr<AudioBuffer>& input);
46 
47   // Returns true if the splicer has a buffer to return.
48   bool HasNextBuffer() const;
49 
50   // Removes the next buffer from the output buffer queue and returns it; this
51   // should only be called if HasNextBuffer() returns true.
52   scoped_refptr<AudioBuffer> GetNextBuffer();
53 
54   // Indicates an upcoming splice point.  All buffers overlapping or after the
55   // |splice_timestamp| will be considered as "before the splice."  Clients must
56   // then call SetSpliceTimestamp(kNoTimestamp()) to signal that future buffers
57   // should be considered as "after the splice."
58   //
59   // Once |kCrossfadeDurationInMilliseconds| of buffers "after the splice" or
60   // end of stream has been received, the "after" buffers will be crossfaded
61   // with all "before" buffers which overlap them.  "before" buffers outside
62   // of the overlap range will be discarded.
63   void SetSpliceTimestamp(base::TimeDelta splice_timestamp);
64 
65  private:
66   friend class AudioSplicerTest;
67 
68   // Extracts frames to be crossfaded from |pre_splice_sanitizer_|.  Transfers
69   // all frames before |splice_timestamp_| into |output_sanitizer_| and drops
70   // frames outside of the crossfade duration.
71   //
72   // The size of the returned AudioBus is the crossfade duration in frames.
73   // Crossfade duration is calculated based on the number of frames available
74   // after |splice_timestamp_| in each sanitizer and capped by
75   // |max_crossfade_duration_|.
76   //
77   // |pre_splice_sanitizer_| will be empty after this operation.
78   scoped_ptr<AudioBus> ExtractCrossfadeFromPreSplice(
79       scoped_refptr<AudioBuffer>* crossfade_buffer);
80 
81   // Crossfades |pre_splice_bus->frames()| frames from
82   // |post_splice_sanitizer_|
83   // with those from |pre_splice_bus|.  Adds the crossfaded buffer to
84   // |output_sanitizer_| along with all buffers in |post_splice_sanitizer_|.
85   //
86   // |post_splice_sanitizer_| will be empty after this operation.
87   void CrossfadePostSplice(scoped_ptr<AudioBus> pre_splice_bus,
88                            const scoped_refptr<AudioBuffer>& crossfade_buffer);
89 
90   // Reset the splice and splice end timestamps.
reset_splice_timestamps()91   void reset_splice_timestamps() {
92     splice_timestamp_ = max_splice_end_timestamp_ = kNoTimestamp();
93   }
94 
95   const base::TimeDelta max_crossfade_duration_;
96   base::TimeDelta splice_timestamp_;
97   base::TimeDelta max_splice_end_timestamp_;
98 
99   // The various sanitizers for each stage of the crossfade process.  Buffers in
100   // |output_sanitizer_| are immediately available for consumption by external
101   // callers.
102   //
103   // Overlapped buffers go into the |pre_splice_sanitizer_| while overlapping
104   // buffers go into the |post_splice_sanitizer_|.  Once enough buffers for
105   // crossfading are received the pre and post sanitizers are drained into
106   // |output_sanitizer_| by the two ExtractCrossfadeFromXXX methods above.
107   //
108   // |pre_splice_sanitizer_| is not constructed until the first splice frame is
109   // encountered.  At which point it is constructed based on the timestamp state
110   // of |output_sanitizer_|.  It is destructed once the splice is finished.
111   scoped_ptr<AudioStreamSanitizer> output_sanitizer_;
112   scoped_ptr<AudioStreamSanitizer> pre_splice_sanitizer_;
113   scoped_ptr<AudioStreamSanitizer> post_splice_sanitizer_;
114 
115   // Whether all buffers which should go into |pre_splice_sanitizer_| have been
116   // received.  If true, buffers should now be put in |post_splice_sanitizer_|.
117   bool have_all_pre_splice_buffers_;
118 
119   DISALLOW_IMPLICIT_CONSTRUCTORS(AudioSplicer);
120 };
121 
122 }  // namespace media
123 
124 #endif
125