OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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 "content/renderer/media/media_stream_audio_processor.h" | 5 #include "content/renderer/media/media_stream_audio_processor.h" |
6 | 6 |
7 #include "base/command_line.h" | 7 #include "base/command_line.h" |
8 #include "base/debug/trace_event.h" | 8 #include "base/debug/trace_event.h" |
9 #if defined(OS_MACOSX) | 9 #if defined(OS_MACOSX) |
10 #include "base/metrics/field_trial.h" | 10 #include "base/metrics/field_trial.h" |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
42 case media::CHANNEL_LAYOUT_STEREO: | 42 case media::CHANNEL_LAYOUT_STEREO: |
43 return AudioProcessing::kStereo; | 43 return AudioProcessing::kStereo; |
44 case media::CHANNEL_LAYOUT_STEREO_AND_KEYBOARD_MIC: | 44 case media::CHANNEL_LAYOUT_STEREO_AND_KEYBOARD_MIC: |
45 return AudioProcessing::kStereoAndKeyboard; | 45 return AudioProcessing::kStereoAndKeyboard; |
46 default: | 46 default: |
47 NOTREACHED() << "Layout not supported: " << media_layout; | 47 NOTREACHED() << "Layout not supported: " << media_layout; |
48 return AudioProcessing::kMono; | 48 return AudioProcessing::kMono; |
49 } | 49 } |
50 } | 50 } |
51 | 51 |
| 52 // This is only used for playout data where only max two channels is supported. |
52 AudioProcessing::ChannelLayout ChannelsToLayout(int num_channels) { | 53 AudioProcessing::ChannelLayout ChannelsToLayout(int num_channels) { |
53 switch (num_channels) { | 54 switch (num_channels) { |
54 case 1: | 55 case 1: |
55 return AudioProcessing::kMono; | 56 return AudioProcessing::kMono; |
56 case 2: | 57 case 2: |
57 return AudioProcessing::kStereo; | 58 return AudioProcessing::kStereo; |
58 default: | 59 default: |
59 NOTREACHED() << "Channels not supported: " << num_channels; | 60 NOTREACHED() << "Channels not supported: " << num_channels; |
60 return AudioProcessing::kMono; | 61 return AudioProcessing::kMono; |
61 } | 62 } |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
106 } | 107 } |
107 | 108 |
108 private: | 109 private: |
109 base::ThreadChecker thread_checker_; | 110 base::ThreadChecker thread_checker_; |
110 scoped_ptr<media::AudioBus> bus_; | 111 scoped_ptr<media::AudioBus> bus_; |
111 scoped_ptr<float*[]> channel_ptrs_; | 112 scoped_ptr<float*[]> channel_ptrs_; |
112 }; | 113 }; |
113 | 114 |
114 // Wraps AudioFifo to provide a cleaner interface to MediaStreamAudioProcessor. | 115 // Wraps AudioFifo to provide a cleaner interface to MediaStreamAudioProcessor. |
115 // It avoids the FIFO when the source and destination frames match. All methods | 116 // It avoids the FIFO when the source and destination frames match. All methods |
116 // are called on one of the capture or render audio threads exclusively. | 117 // are called on one of the capture or render audio threads exclusively. If |
| 118 // |source_channels| is larger than |destination_channels|, only the first |
| 119 // |destination_channels| are kept from the source. |
117 class MediaStreamAudioFifo { | 120 class MediaStreamAudioFifo { |
118 public: | 121 public: |
119 MediaStreamAudioFifo(int channels, int source_frames, | 122 MediaStreamAudioFifo(int source_channels, |
| 123 int destination_channels, |
| 124 int source_frames, |
120 int destination_frames) | 125 int destination_frames) |
121 : source_frames_(source_frames), | 126 : source_channels_(source_channels), |
122 destination_(new MediaStreamAudioBus(channels, destination_frames)), | 127 source_frames_(source_frames), |
| 128 destination_( |
| 129 new MediaStreamAudioBus(destination_channels, destination_frames)), |
123 data_available_(false) { | 130 data_available_(false) { |
| 131 DCHECK_GE(source_channels, destination_channels); |
| 132 |
| 133 if (source_channels > destination_channels) { |
| 134 audio_source_intermediate_ = |
| 135 media::AudioBus::CreateWrapper(destination_channels); |
| 136 } |
| 137 |
124 if (source_frames != destination_frames) { | 138 if (source_frames != destination_frames) { |
125 // Since we require every Push to be followed by as many Consumes as | 139 // Since we require every Push to be followed by as many Consumes as |
126 // possible, twice the larger of the two is a (probably) loose upper bound | 140 // possible, twice the larger of the two is a (probably) loose upper bound |
127 // on the FIFO size. | 141 // on the FIFO size. |
128 const int fifo_frames = 2 * std::max(source_frames, destination_frames); | 142 const int fifo_frames = 2 * std::max(source_frames, destination_frames); |
129 fifo_.reset(new media::AudioFifo(channels, fifo_frames)); | 143 fifo_.reset(new media::AudioFifo(destination_channels, fifo_frames)); |
130 } | 144 } |
131 | 145 |
132 // May be created in the main render thread and used in the audio threads. | 146 // May be created in the main render thread and used in the audio threads. |
133 thread_checker_.DetachFromThread(); | 147 thread_checker_.DetachFromThread(); |
134 } | 148 } |
135 | 149 |
136 void Push(const media::AudioBus* source) { | 150 void Push(const media::AudioBus* source) { |
137 DCHECK(thread_checker_.CalledOnValidThread()); | 151 DCHECK(thread_checker_.CalledOnValidThread()); |
138 DCHECK_EQ(source->channels(), destination_->bus()->channels()); | 152 DCHECK_EQ(source->channels(), source_channels_); |
139 DCHECK_EQ(source->frames(), source_frames_); | 153 DCHECK_EQ(source->frames(), source_frames_); |
140 | 154 |
| 155 const media::AudioBus* source_to_push = source; |
| 156 |
| 157 if (audio_source_intermediate_) { |
| 158 for (int i = 0; i < destination_->bus()->channels(); ++i) { |
| 159 audio_source_intermediate_->SetChannelData( |
| 160 i, |
| 161 const_cast<float*>(source->channel(i))); |
| 162 } |
| 163 audio_source_intermediate_->set_frames(source->frames()); |
| 164 source_to_push = audio_source_intermediate_.get(); |
| 165 } |
| 166 |
141 if (fifo_) { | 167 if (fifo_) { |
142 fifo_->Push(source); | 168 fifo_->Push(source_to_push); |
143 } else { | 169 } else { |
144 source->CopyTo(destination_->bus()); | 170 source_to_push->CopyTo(destination_->bus()); |
145 data_available_ = true; | 171 data_available_ = true; |
146 } | 172 } |
147 } | 173 } |
148 | 174 |
149 // Returns true if there are destination_frames() of data available to be | 175 // Returns true if there are destination_frames() of data available to be |
150 // consumed, and otherwise false. | 176 // consumed, and otherwise false. |
151 bool Consume(MediaStreamAudioBus** destination) { | 177 bool Consume(MediaStreamAudioBus** destination) { |
152 DCHECK(thread_checker_.CalledOnValidThread()); | 178 DCHECK(thread_checker_.CalledOnValidThread()); |
153 | 179 |
154 if (fifo_) { | 180 if (fifo_) { |
155 if (fifo_->frames() < destination_->bus()->frames()) | 181 if (fifo_->frames() < destination_->bus()->frames()) |
156 return false; | 182 return false; |
157 | 183 |
158 fifo_->Consume(destination_->bus(), 0, destination_->bus()->frames()); | 184 fifo_->Consume(destination_->bus(), 0, destination_->bus()->frames()); |
159 } else { | 185 } else { |
160 if (!data_available_) | 186 if (!data_available_) |
161 return false; | 187 return false; |
162 | 188 |
163 // The data was already copied to |destination_| in this case. | 189 // The data was already copied to |destination_| in this case. |
164 data_available_ = false; | 190 data_available_ = false; |
165 } | 191 } |
166 | 192 |
167 *destination = destination_.get(); | 193 *destination = destination_.get(); |
168 return true; | 194 return true; |
169 } | 195 } |
170 | 196 |
171 private: | 197 private: |
172 base::ThreadChecker thread_checker_; | 198 base::ThreadChecker thread_checker_; |
| 199 const int source_channels_; // For a DCHECK. |
173 const int source_frames_; // For a DCHECK. | 200 const int source_frames_; // For a DCHECK. |
| 201 scoped_ptr<media::AudioBus> audio_source_intermediate_; |
174 scoped_ptr<MediaStreamAudioBus> destination_; | 202 scoped_ptr<MediaStreamAudioBus> destination_; |
175 scoped_ptr<media::AudioFifo> fifo_; | 203 scoped_ptr<media::AudioFifo> fifo_; |
176 // Only used when the FIFO is disabled; | 204 // Only used when the FIFO is disabled; |
177 bool data_available_; | 205 bool data_available_; |
178 }; | 206 }; |
179 | 207 |
180 bool MediaStreamAudioProcessor::IsAudioTrackProcessingEnabled() { | 208 bool MediaStreamAudioProcessor::IsAudioTrackProcessingEnabled() { |
181 return !CommandLine::ForCurrentProcess()->HasSwitch( | 209 return !CommandLine::ForCurrentProcess()->HasSwitch( |
182 switches::kDisableAudioTrackProcessing); | 210 switches::kDisableAudioTrackProcessing); |
183 } | 211 } |
(...skipping 274 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
458 DCHECK(input_format.IsValid()); | 486 DCHECK(input_format.IsValid()); |
459 input_format_ = input_format; | 487 input_format_ = input_format; |
460 | 488 |
461 // TODO(ajm): For now, we assume fixed parameters for the output when audio | 489 // TODO(ajm): For now, we assume fixed parameters for the output when audio |
462 // processing is enabled, to match the previous behavior. We should either | 490 // processing is enabled, to match the previous behavior. We should either |
463 // use the input parameters (in which case, audio processing will convert | 491 // use the input parameters (in which case, audio processing will convert |
464 // at output) or ideally, have a backchannel from the sink to know what | 492 // at output) or ideally, have a backchannel from the sink to know what |
465 // format it would prefer. | 493 // format it would prefer. |
466 const int output_sample_rate = audio_processing_ ? | 494 const int output_sample_rate = audio_processing_ ? |
467 kAudioProcessingSampleRate : input_format.sample_rate(); | 495 kAudioProcessingSampleRate : input_format.sample_rate(); |
468 const media::ChannelLayout output_channel_layout = audio_processing_ ? | 496 media::ChannelLayout output_channel_layout = audio_processing_ ? |
469 media::GuessChannelLayout(kAudioProcessingNumberOfChannels) : | 497 media::GuessChannelLayout(kAudioProcessingNumberOfChannels) : |
470 input_format.channel_layout(); | 498 input_format.channel_layout(); |
471 | 499 |
| 500 // The output channels from the fifo is normally the same as input. |
| 501 int fifo_output_channels = input_format.channels(); |
| 502 |
| 503 // Special case for if we have a keyboard mic channel on the input and no |
| 504 // audio processing is used. We will then have the fifo strip away that |
| 505 // channel. So we use stereo as output layout, and also change the output |
| 506 // channels for the fifo. |
| 507 if (input_format.channel_layout() == |
| 508 media::CHANNEL_LAYOUT_STEREO_AND_KEYBOARD_MIC && |
| 509 !audio_processing_) { |
| 510 output_channel_layout = media::CHANNEL_LAYOUT_STEREO; |
| 511 fifo_output_channels = ChannelLayoutToChannelCount(output_channel_layout); |
| 512 } |
| 513 |
472 // webrtc::AudioProcessing requires a 10 ms chunk size. We use this native | 514 // webrtc::AudioProcessing requires a 10 ms chunk size. We use this native |
473 // size when processing is enabled. When disabled we use the same size as | 515 // size when processing is enabled. When disabled we use the same size as |
474 // the source if less than 10 ms. | 516 // the source if less than 10 ms. |
475 // | 517 // |
476 // TODO(ajm): This conditional buffer size appears to be assuming knowledge of | 518 // TODO(ajm): This conditional buffer size appears to be assuming knowledge of |
477 // the sink based on the source parameters. PeerConnection sinks seem to want | 519 // the sink based on the source parameters. PeerConnection sinks seem to want |
478 // 10 ms chunks regardless, while WebAudio sinks want less, and we're assuming | 520 // 10 ms chunks regardless, while WebAudio sinks want less, and we're assuming |
479 // we can identify WebAudio sinks by the input chunk size. Less fragile would | 521 // we can identify WebAudio sinks by the input chunk size. Less fragile would |
480 // be to have the sink actually tell us how much it wants (as in the above | 522 // be to have the sink actually tell us how much it wants (as in the above |
481 // TODO). | 523 // TODO). |
482 int processing_frames = input_format.sample_rate() / 100; | 524 int processing_frames = input_format.sample_rate() / 100; |
483 int output_frames = output_sample_rate / 100; | 525 int output_frames = output_sample_rate / 100; |
484 if (!audio_processing_ && input_format.frames_per_buffer() < output_frames) { | 526 if (!audio_processing_ && input_format.frames_per_buffer() < output_frames) { |
485 processing_frames = input_format.frames_per_buffer(); | 527 processing_frames = input_format.frames_per_buffer(); |
486 output_frames = processing_frames; | 528 output_frames = processing_frames; |
487 } | 529 } |
488 | 530 |
489 output_format_ = media::AudioParameters( | 531 output_format_ = media::AudioParameters( |
490 media::AudioParameters::AUDIO_PCM_LOW_LATENCY, | 532 media::AudioParameters::AUDIO_PCM_LOW_LATENCY, |
491 output_channel_layout, | 533 output_channel_layout, |
492 output_sample_rate, | 534 output_sample_rate, |
493 16, | 535 16, |
494 output_frames); | 536 output_frames); |
495 | 537 |
496 capture_fifo_.reset( | 538 capture_fifo_.reset( |
497 new MediaStreamAudioFifo(input_format.channels(), | 539 new MediaStreamAudioFifo(input_format.channels(), |
| 540 fifo_output_channels, |
498 input_format.frames_per_buffer(), | 541 input_format.frames_per_buffer(), |
499 processing_frames)); | 542 processing_frames)); |
500 | 543 |
501 if (audio_processing_) { | 544 if (audio_processing_) { |
502 output_bus_.reset(new MediaStreamAudioBus(output_format_.channels(), | 545 output_bus_.reset(new MediaStreamAudioBus(output_format_.channels(), |
503 output_frames)); | 546 output_frames)); |
504 } | 547 } |
505 output_data_.reset(new int16[output_format_.GetBytesPerBuffer() / | 548 output_data_.reset(new int16[output_format_.GetBytesPerBuffer() / |
506 sizeof(int16)]); | 549 sizeof(int16)]); |
507 } | 550 } |
(...skipping 12 matching lines...) Expand all Loading... |
520 render_format_ = media::AudioParameters( | 563 render_format_ = media::AudioParameters( |
521 media::AudioParameters::AUDIO_PCM_LOW_LATENCY, | 564 media::AudioParameters::AUDIO_PCM_LOW_LATENCY, |
522 media::GuessChannelLayout(number_of_channels), | 565 media::GuessChannelLayout(number_of_channels), |
523 sample_rate, | 566 sample_rate, |
524 16, | 567 16, |
525 frames_per_buffer); | 568 frames_per_buffer); |
526 | 569 |
527 const int analysis_frames = sample_rate / 100; // 10 ms chunks. | 570 const int analysis_frames = sample_rate / 100; // 10 ms chunks. |
528 render_fifo_.reset( | 571 render_fifo_.reset( |
529 new MediaStreamAudioFifo(number_of_channels, | 572 new MediaStreamAudioFifo(number_of_channels, |
| 573 number_of_channels, |
530 frames_per_buffer, | 574 frames_per_buffer, |
531 analysis_frames)); | 575 analysis_frames)); |
532 } | 576 } |
533 | 577 |
534 int MediaStreamAudioProcessor::ProcessData(const float* const* process_ptrs, | 578 int MediaStreamAudioProcessor::ProcessData(const float* const* process_ptrs, |
535 int process_frames, | 579 int process_frames, |
536 base::TimeDelta capture_delay, | 580 base::TimeDelta capture_delay, |
537 int volume, | 581 int volume, |
538 bool key_pressed, | 582 bool key_pressed, |
539 float* const* output_ptrs) { | 583 float* const* output_ptrs) { |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
579 vad->stream_has_voice()); | 623 vad->stream_has_voice()); |
580 base::subtle::Release_Store(&typing_detected_, detected); | 624 base::subtle::Release_Store(&typing_detected_, detected); |
581 } | 625 } |
582 | 626 |
583 // Return 0 if the volume hasn't been changed, and otherwise the new volume. | 627 // Return 0 if the volume hasn't been changed, and otherwise the new volume. |
584 return (agc->stream_analog_level() == volume) ? | 628 return (agc->stream_analog_level() == volume) ? |
585 0 : agc->stream_analog_level(); | 629 0 : agc->stream_analog_level(); |
586 } | 630 } |
587 | 631 |
588 } // namespace content | 632 } // namespace content |
OLD | NEW |