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 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