OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include <stdint.h> | 5 #include <stdint.h> |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 | 8 |
9 #include "media/base/audio_block_fifo.h" | 9 #include "media/base/audio_block_fifo.h" |
10 | 10 |
11 #include "base/logging.h" | 11 #include "base/logging.h" |
12 | 12 |
13 namespace media { | 13 namespace media { |
14 | 14 |
15 AudioBlockFifo::AudioBlockFifo(int channels, int frames, int blocks) | 15 AudioBlockFifo::AudioBlockFifo(int channels, int frames, int blocks) |
16 : channels_(channels), | 16 : channels_(channels), |
17 block_frames_(frames), | 17 block_frames_(frames), |
18 write_block_(0), | 18 write_block_(0), |
19 read_block_(0), | 19 read_block_(0), |
20 available_blocks_(0), | 20 available_blocks_(0), |
21 write_pos_(0) { | 21 write_pos_(0) { |
22 IncreaseCapacity(blocks); | 22 IncreaseCapacity(blocks); |
23 } | 23 } |
24 | 24 |
25 AudioBlockFifo::~AudioBlockFifo() {} | 25 AudioBlockFifo::~AudioBlockFifo() {} |
26 | 26 |
27 void AudioBlockFifo::Push(const void* source, | 27 void AudioBlockFifo::Push(const void* source, |
28 int frames, | 28 int frames, |
29 int bytes_per_sample) { | 29 int bytes_per_sample) { |
30 DCHECK(source); | 30 PushInternal(source, frames, bytes_per_sample); |
31 DCHECK_GT(frames, 0); | 31 } |
32 DCHECK_GT(bytes_per_sample, 0); | |
33 DCHECK_LT(available_blocks_, static_cast<int>(audio_blocks_.size())); | |
34 CHECK_LE(frames, GetUnfilledFrames()); | |
35 | 32 |
36 const uint8_t* source_ptr = static_cast<const uint8_t*>(source); | 33 void AudioBlockFifo::PushSilence(int frames) { |
37 int frames_to_push = frames; | 34 PushInternal(nullptr, frames, 0); |
38 while (frames_to_push) { | |
39 // Get the current write block. | |
40 AudioBus* current_block = audio_blocks_[write_block_]; | |
41 | |
42 // Figure out what segment sizes we need when adding the new content to | |
43 // the FIFO. | |
44 const int push_frames = | |
45 std::min(block_frames_ - write_pos_, frames_to_push); | |
46 | |
47 // Deinterleave the content to the FIFO and update the |write_pos_|. | |
48 current_block->FromInterleavedPartial( | |
49 source_ptr, write_pos_, push_frames, bytes_per_sample); | |
50 write_pos_ = (write_pos_ + push_frames) % block_frames_; | |
51 if (!write_pos_) { | |
52 // The current block is completely filled, increment |write_block_| and | |
53 // |available_blocks_|. | |
54 write_block_ = (write_block_ + 1) % audio_blocks_.size(); | |
55 ++available_blocks_; | |
56 } | |
57 | |
58 source_ptr += push_frames * bytes_per_sample * channels_; | |
59 frames_to_push -= push_frames; | |
60 DCHECK_GE(frames_to_push, 0); | |
61 } | |
62 } | 35 } |
63 | 36 |
64 const AudioBus* AudioBlockFifo::Consume() { | 37 const AudioBus* AudioBlockFifo::Consume() { |
65 DCHECK(available_blocks_); | 38 DCHECK(available_blocks_); |
66 AudioBus* audio_bus = audio_blocks_[read_block_]; | 39 AudioBus* audio_bus = audio_blocks_[read_block_]; |
67 read_block_ = (read_block_ + 1) % audio_blocks_.size(); | 40 read_block_ = (read_block_ + 1) % audio_blocks_.size(); |
68 --available_blocks_; | 41 --available_blocks_; |
69 return audio_bus; | 42 return audio_bus; |
70 } | 43 } |
71 | 44 |
(...skipping 24 matching lines...) Expand all Loading... |
96 const int original_size = audio_blocks_.size(); | 69 const int original_size = audio_blocks_.size(); |
97 for (int i = 0; i < blocks; ++i) { | 70 for (int i = 0; i < blocks; ++i) { |
98 audio_blocks_.push_back( | 71 audio_blocks_.push_back( |
99 AudioBus::Create(channels_, block_frames_).release()); | 72 AudioBus::Create(channels_, block_frames_).release()); |
100 } | 73 } |
101 | 74 |
102 if (!original_size) | 75 if (!original_size) |
103 return; | 76 return; |
104 | 77 |
105 std::rotate(audio_blocks_.begin() + read_block_, | 78 std::rotate(audio_blocks_.begin() + read_block_, |
106 audio_blocks_.begin() + original_size, | 79 audio_blocks_.begin() + original_size, audio_blocks_.end()); |
107 audio_blocks_.end()); | |
108 | 80 |
109 // Update the write pointer if it is on top of the new inserted blocks. | 81 // Update the write pointer if it is on top of the new inserted blocks. |
110 if (write_block_ >= read_block_) | 82 if (write_block_ >= read_block_) |
111 write_block_ += blocks; | 83 write_block_ += blocks; |
112 | 84 |
113 // Update the read pointers correspondingly. | 85 // Update the read pointers correspondingly. |
114 read_block_ += blocks; | 86 read_block_ += blocks; |
115 | 87 |
116 DCHECK_LT(read_block_, static_cast<int>(audio_blocks_.size())); | 88 DCHECK_LT(read_block_, static_cast<int>(audio_blocks_.size())); |
117 DCHECK_LT(write_block_, static_cast<int>(audio_blocks_.size())); | 89 DCHECK_LT(write_block_, static_cast<int>(audio_blocks_.size())); |
118 } | 90 } |
119 | 91 |
| 92 void AudioBlockFifo::PushInternal(const void* source, |
| 93 int frames, |
| 94 int bytes_per_sample) { |
| 95 // |source| may be nullptr if bytes_per_sample is 0. In that case, |
| 96 // we inject silence. |
| 97 DCHECK((source && bytes_per_sample > 0) || (!source && !bytes_per_sample)); |
| 98 DCHECK_GT(frames, 0); |
| 99 DCHECK_LT(available_blocks_, static_cast<int>(audio_blocks_.size())); |
| 100 CHECK_LE(frames, GetUnfilledFrames()); |
| 101 |
| 102 const uint8_t* source_ptr = static_cast<const uint8_t*>(source); |
| 103 int frames_to_push = frames; |
| 104 while (frames_to_push) { |
| 105 // Get the current write block. |
| 106 AudioBus* current_block = audio_blocks_[write_block_]; |
| 107 |
| 108 // Figure out what segment sizes we need when adding the new content to |
| 109 // the FIFO. |
| 110 const int push_frames = |
| 111 std::min(block_frames_ - write_pos_, frames_to_push); |
| 112 |
| 113 if (source) { |
| 114 // Deinterleave the content to the FIFO and update the |write_pos_|. |
| 115 current_block->FromInterleavedPartial(source_ptr, write_pos_, push_frames, |
| 116 bytes_per_sample); |
| 117 } else { |
| 118 current_block->ZeroFramesPartial(write_pos_, push_frames); |
| 119 } |
| 120 write_pos_ = (write_pos_ + push_frames) % block_frames_; |
| 121 if (!write_pos_) { |
| 122 // The current block is completely filled, increment |write_block_| and |
| 123 // |available_blocks_|. |
| 124 write_block_ = (write_block_ + 1) % audio_blocks_.size(); |
| 125 ++available_blocks_; |
| 126 } |
| 127 |
| 128 if (source_ptr) |
| 129 source_ptr += push_frames * bytes_per_sample * channels_; |
| 130 frames_to_push -= push_frames; |
| 131 DCHECK_GE(frames_to_push, 0); |
| 132 } |
| 133 } |
| 134 |
120 } // namespace media | 135 } // namespace media |
OLD | NEW |