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
15namespace media {
16
17class AudioBuffer;
18class AudioBus;
19class AudioStreamSanitizer;
20
21// Helper class that handles filling gaps and resolving overlaps.
22class 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.
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