Home | History | Annotate | Download | only in base
      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.
     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