Index: media/audio/audio_output_mixer.cc |
diff --git a/media/audio/audio_output_mixer.cc b/media/audio/audio_output_mixer.cc |
deleted file mode 100644 |
index edce4ea11a0daa96b977abf3125642c391c56b12..0000000000000000000000000000000000000000 |
--- a/media/audio/audio_output_mixer.cc |
+++ /dev/null |
@@ -1,248 +0,0 @@ |
-// Copyright (c) 2012 The Chromium Authors. All rights reserved. |
-// Use of this source code is governed by a BSD-style license that can be |
-// found in the LICENSE file. |
- |
-#include "media/audio/audio_output_mixer.h" |
- |
-#include <algorithm> |
- |
-#include "base/bind.h" |
-#include "base/compiler_specific.h" |
-#include "base/message_loop.h" |
-#include "base/time.h" |
-#include "media/audio/audio_io.h" |
-#include "media/audio/audio_output_proxy.h" |
-#include "media/audio/audio_util.h" |
- |
-namespace media { |
- |
-AudioOutputMixer::AudioOutputMixer(AudioManager* audio_manager, |
- const AudioParameters& params, |
- const base::TimeDelta& close_delay) |
- : AudioOutputDispatcher(audio_manager, params), |
- ALLOW_THIS_IN_INITIALIZER_LIST(weak_this_(this)), |
- close_timer_(FROM_HERE, |
- close_delay, |
- weak_this_.GetWeakPtr(), |
- &AudioOutputMixer::ClosePhysicalStream), |
- pending_bytes_(0) { |
- // TODO(enal): align data. |
- mixer_data_.reset(new uint8[params_.GetBytesPerBuffer()]); |
-} |
- |
-AudioOutputMixer::~AudioOutputMixer() { |
-} |
- |
-bool AudioOutputMixer::OpenStream() { |
- DCHECK_EQ(MessageLoop::current(), message_loop_); |
- |
- if (physical_stream_.get()) |
- return true; |
- AudioOutputStream* stream = audio_manager_->MakeAudioOutputStream(params_); |
- if (!stream) |
- return false; |
- if (!stream->Open()) { |
- stream->Close(); |
- return false; |
- } |
- pending_bytes_ = 0; // Just in case. |
- physical_stream_.reset(stream); |
- close_timer_.Reset(); |
- return true; |
-} |
- |
-bool AudioOutputMixer::StartStream( |
- AudioOutputStream::AudioSourceCallback* callback, |
- AudioOutputProxy* stream_proxy) { |
- DCHECK_EQ(MessageLoop::current(), message_loop_); |
- |
- // May need to re-open the physical stream if no active proxies and |
- // enough time had pass. |
- OpenStream(); |
- if (!physical_stream_.get()) |
- return false; |
- |
- double volume = 0.0; |
- stream_proxy->GetVolume(&volume); |
- bool should_start = proxies_.empty(); |
- { |
- base::AutoLock lock(lock_); |
- ProxyData* proxy_data = &proxies_[stream_proxy]; |
- proxy_data->audio_source_callback = callback; |
- proxy_data->volume = volume; |
- proxy_data->pending_bytes = 0; |
- } |
- // We cannot start physical stream under the lock, |
- // OnMoreData() would try acquiring it... |
- if (should_start) { |
- physical_stream_->SetVolume(1.0); |
- physical_stream_->Start(this); |
- } |
- return true; |
-} |
- |
-void AudioOutputMixer::StopStream(AudioOutputProxy* stream_proxy) { |
- DCHECK_EQ(MessageLoop::current(), message_loop_); |
- |
- // Because of possible deadlock we cannot stop physical stream under the lock |
- // (physical_stream_->Stop() can call OnError(), and it acquires the lock to |
- // iterate through proxies), so acquire the lock, update proxy list, release |
- // the lock, and only then stop physical stream if necessary. |
- bool stop_physical_stream = false; |
- { |
- base::AutoLock lock(lock_); |
- ProxyMap::iterator it = proxies_.find(stream_proxy); |
- if (it != proxies_.end()) { |
- proxies_.erase(it); |
- stop_physical_stream = proxies_.empty(); |
- } |
- } |
- if (physical_stream_.get()) { |
- if (stop_physical_stream) { |
- physical_stream_->Stop(); |
- pending_bytes_ = 0; // Just in case. |
- } |
- close_timer_.Reset(); |
- } |
-} |
- |
-void AudioOutputMixer::StreamVolumeSet(AudioOutputProxy* stream_proxy, |
- double volume) { |
- DCHECK_EQ(MessageLoop::current(), message_loop_); |
- |
- ProxyMap::iterator it = proxies_.find(stream_proxy); |
- |
- // Do nothing if stream is not currently playing. |
- if (it != proxies_.end()) { |
- base::AutoLock lock(lock_); |
- it->second.volume = volume; |
- } |
-} |
- |
-void AudioOutputMixer::CloseStream(AudioOutputProxy* stream_proxy) { |
- DCHECK_EQ(MessageLoop::current(), message_loop_); |
- |
- StopStream(stream_proxy); |
-} |
- |
-void AudioOutputMixer::Shutdown() { |
- DCHECK_EQ(MessageLoop::current(), message_loop_); |
- |
- // Cancel any pending tasks to close physical stream. |
- weak_this_.InvalidateWeakPtrs(); |
- |
- while (!proxies_.empty()) { |
- CloseStream(proxies_.begin()->first); |
- } |
- ClosePhysicalStream(); |
- |
- // No AudioOutputProxy objects should hold a reference to us when we get |
- // to this stage. |
- DCHECK(HasOneRef()) << "Only the AudioManager should hold a reference"; |
-} |
- |
-void AudioOutputMixer::ClosePhysicalStream() { |
- DCHECK_EQ(MessageLoop::current(), message_loop_); |
- |
- if (proxies_.empty() && physical_stream_.get() != NULL) |
- physical_stream_.release()->Close(); |
-} |
- |
-// AudioSourceCallback implementation. |
-uint32 AudioOutputMixer::OnMoreData(uint8* dest, |
- uint32 max_size, |
- AudioBuffersState buffers_state) { |
- max_size = std::min(max_size, |
- static_cast<uint32>(params_.GetBytesPerBuffer())); |
- // TODO(enal): consider getting rid of lock as it is in time-critical code. |
- // E.g. swap |proxies_| with local variable, and merge 2 lists |
- // at the end. That would speed things up but complicate stopping |
- // the stream. |
- base::AutoLock lock(lock_); |
- |
- DCHECK_GE(pending_bytes_, buffers_state.pending_bytes); |
- if (proxies_.empty()) { |
- pending_bytes_ = buffers_state.pending_bytes; |
- return 0; |
- } |
- uint32 actual_total_size = 0; |
- uint32 bytes_per_sample = params_.bits_per_sample() >> 3; |
- |
- // Go through all the streams, getting data for every one of them |
- // and mixing it into destination. |
- // Minor optimization: for the first stream we are writing data directly into |
- // destination. This way we don't have to mix the data when there is only one |
- // active stream, and net win in other cases, too. |
- bool first_stream = true; |
- uint8* actual_dest = dest; |
- for (ProxyMap::iterator it = proxies_.begin(); it != proxies_.end(); ++it) { |
- ProxyData* proxy_data = &it->second; |
- |
- // If proxy's pending bytes are the same as pending bytes for combined |
- // stream, both are either pre-buffering or in the steady state. In either |
- // case new pending bytes for proxy is the same as new pending bytes for |
- // combined stream. |
- // Note: use >= instead of ==, that way is safer. |
- if (proxy_data->pending_bytes >= pending_bytes_) |
- proxy_data->pending_bytes = buffers_state.pending_bytes; |
- |
- // Note: there is no way we can deduce hardware_delay_bytes for the |
- // particular proxy stream. Use zero instead. |
- uint32 actual_size = proxy_data->audio_source_callback->OnMoreData( |
- actual_dest, |
- max_size, |
- AudioBuffersState(proxy_data->pending_bytes, 0)); |
- if (actual_size == 0) |
- continue; |
- double volume = proxy_data->volume; |
- |
- // Different handling for first and all subsequent streams. |
- if (first_stream) { |
- if (volume != 1.0) { |
- media::AdjustVolume(actual_dest, |
- actual_size, |
- params_.channels(), |
- bytes_per_sample, |
- volume); |
- } |
- if (actual_size < max_size) |
- memset(dest + actual_size, 0, max_size - actual_size); |
- first_stream = false; |
- actual_dest = mixer_data_.get(); |
- actual_total_size = actual_size; |
- } else { |
- media::MixStreams(dest, |
- actual_dest, |
- actual_size, |
- bytes_per_sample, |
- volume); |
- actual_total_size = std::max(actual_size, actual_total_size); |
- } |
- } |
- |
- // Now go through all proxies once again and increase pending_bytes |
- // for each proxy. Could not do it earlier because we did not know |
- // actual_total_size. |
- for (ProxyMap::iterator it = proxies_.begin(); it != proxies_.end(); ++it) { |
- it->second.pending_bytes += actual_total_size; |
- } |
- pending_bytes_ = buffers_state.pending_bytes + actual_total_size; |
- |
- return actual_total_size; |
-} |
- |
-void AudioOutputMixer::OnError(AudioOutputStream* stream, int code) { |
- base::AutoLock lock(lock_); |
- for (ProxyMap::iterator it = proxies_.begin(); it != proxies_.end(); ++it) { |
- it->second.audio_source_callback->OnError(it->first, code); |
- } |
-} |
- |
-void AudioOutputMixer::WaitTillDataReady() { |
- base::AutoLock lock(lock_); |
- for (ProxyMap::iterator it = proxies_.begin(); it != proxies_.end(); ++it) { |
- it->second.audio_source_callback->WaitTillDataReady(); |
- } |
-} |
- |
-} // namespace media |