| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 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 "media/audio/audio_output_dispatcher_impl.h" | 5 #include "media/audio/audio_output_dispatcher_impl.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 | 8 |
| 9 #include "base/bind.h" | 9 #include "base/bind.h" |
| 10 #include "base/compiler_specific.h" | 10 #include "base/compiler_specific.h" |
| 11 #include "base/message_loop/message_loop.h" | 11 #include "base/single_thread_task_runner.h" |
| 12 #include "base/time/time.h" | 12 #include "base/time/time.h" |
| 13 #include "media/audio/audio_io.h" | 13 #include "media/audio/audio_io.h" |
| 14 #include "media/audio/audio_output_proxy.h" | 14 #include "media/audio/audio_output_proxy.h" |
| 15 | 15 |
| 16 namespace media { | 16 namespace media { |
| 17 | 17 |
| 18 AudioOutputDispatcherImpl::AudioOutputDispatcherImpl( | 18 AudioOutputDispatcherImpl::AudioOutputDispatcherImpl( |
| 19 AudioManager* audio_manager, | 19 AudioManager* audio_manager, |
| 20 const AudioParameters& params, | 20 const AudioParameters& params, |
| 21 const std::string& output_device_id, | 21 const std::string& output_device_id, |
| (...skipping 12 matching lines...) Expand all Loading... |
| 34 audio_manager->CreateAudioLog(AudioLogFactory::AUDIO_OUTPUT_STREAM)), | 34 audio_manager->CreateAudioLog(AudioLogFactory::AUDIO_OUTPUT_STREAM)), |
| 35 audio_stream_id_(0) {} | 35 audio_stream_id_(0) {} |
| 36 | 36 |
| 37 AudioOutputDispatcherImpl::~AudioOutputDispatcherImpl() { | 37 AudioOutputDispatcherImpl::~AudioOutputDispatcherImpl() { |
| 38 DCHECK_EQ(idle_proxies_, 0u); | 38 DCHECK_EQ(idle_proxies_, 0u); |
| 39 DCHECK(proxy_to_physical_map_.empty()); | 39 DCHECK(proxy_to_physical_map_.empty()); |
| 40 DCHECK(idle_streams_.empty()); | 40 DCHECK(idle_streams_.empty()); |
| 41 } | 41 } |
| 42 | 42 |
| 43 bool AudioOutputDispatcherImpl::OpenStream() { | 43 bool AudioOutputDispatcherImpl::OpenStream() { |
| 44 DCHECK(message_loop_->BelongsToCurrentThread()); | 44 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 45 | 45 |
| 46 // Ensure that there is at least one open stream. | 46 // Ensure that there is at least one open stream. |
| 47 if (idle_streams_.empty() && !CreateAndOpenStream()) | 47 if (idle_streams_.empty() && !CreateAndOpenStream()) |
| 48 return false; | 48 return false; |
| 49 | 49 |
| 50 ++idle_proxies_; | 50 ++idle_proxies_; |
| 51 close_timer_.Reset(); | 51 close_timer_.Reset(); |
| 52 return true; | 52 return true; |
| 53 } | 53 } |
| 54 | 54 |
| 55 bool AudioOutputDispatcherImpl::StartStream( | 55 bool AudioOutputDispatcherImpl::StartStream( |
| 56 AudioOutputStream::AudioSourceCallback* callback, | 56 AudioOutputStream::AudioSourceCallback* callback, |
| 57 AudioOutputProxy* stream_proxy) { | 57 AudioOutputProxy* stream_proxy) { |
| 58 DCHECK(message_loop_->BelongsToCurrentThread()); | 58 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 59 DCHECK(proxy_to_physical_map_.find(stream_proxy) == | 59 DCHECK(proxy_to_physical_map_.find(stream_proxy) == |
| 60 proxy_to_physical_map_.end()); | 60 proxy_to_physical_map_.end()); |
| 61 | 61 |
| 62 if (idle_streams_.empty() && !CreateAndOpenStream()) | 62 if (idle_streams_.empty() && !CreateAndOpenStream()) |
| 63 return false; | 63 return false; |
| 64 | 64 |
| 65 AudioOutputStream* physical_stream = idle_streams_.back(); | 65 AudioOutputStream* physical_stream = idle_streams_.back(); |
| 66 idle_streams_.pop_back(); | 66 idle_streams_.pop_back(); |
| 67 | 67 |
| 68 DCHECK_GT(idle_proxies_, 0u); | 68 DCHECK_GT(idle_proxies_, 0u); |
| 69 --idle_proxies_; | 69 --idle_proxies_; |
| 70 | 70 |
| 71 double volume = 0; | 71 double volume = 0; |
| 72 stream_proxy->GetVolume(&volume); | 72 stream_proxy->GetVolume(&volume); |
| 73 physical_stream->SetVolume(volume); | 73 physical_stream->SetVolume(volume); |
| 74 const int stream_id = audio_stream_ids_[physical_stream]; | 74 const int stream_id = audio_stream_ids_[physical_stream]; |
| 75 audio_log_->OnSetVolume(stream_id, volume); | 75 audio_log_->OnSetVolume(stream_id, volume); |
| 76 physical_stream->Start(callback); | 76 physical_stream->Start(callback); |
| 77 audio_log_->OnStarted(stream_id); | 77 audio_log_->OnStarted(stream_id); |
| 78 proxy_to_physical_map_[stream_proxy] = physical_stream; | 78 proxy_to_physical_map_[stream_proxy] = physical_stream; |
| 79 | 79 |
| 80 close_timer_.Reset(); | 80 close_timer_.Reset(); |
| 81 return true; | 81 return true; |
| 82 } | 82 } |
| 83 | 83 |
| 84 void AudioOutputDispatcherImpl::StopStream(AudioOutputProxy* stream_proxy) { | 84 void AudioOutputDispatcherImpl::StopStream(AudioOutputProxy* stream_proxy) { |
| 85 DCHECK(message_loop_->BelongsToCurrentThread()); | 85 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 86 | 86 |
| 87 AudioStreamMap::iterator it = proxy_to_physical_map_.find(stream_proxy); | 87 AudioStreamMap::iterator it = proxy_to_physical_map_.find(stream_proxy); |
| 88 DCHECK(it != proxy_to_physical_map_.end()); | 88 DCHECK(it != proxy_to_physical_map_.end()); |
| 89 AudioOutputStream* physical_stream = it->second; | 89 AudioOutputStream* physical_stream = it->second; |
| 90 proxy_to_physical_map_.erase(it); | 90 proxy_to_physical_map_.erase(it); |
| 91 | 91 |
| 92 physical_stream->Stop(); | 92 physical_stream->Stop(); |
| 93 audio_log_->OnStopped(audio_stream_ids_[physical_stream]); | 93 audio_log_->OnStopped(audio_stream_ids_[physical_stream]); |
| 94 ++idle_proxies_; | 94 ++idle_proxies_; |
| 95 idle_streams_.push_back(physical_stream); | 95 idle_streams_.push_back(physical_stream); |
| 96 | 96 |
| 97 close_timer_.Reset(); | 97 close_timer_.Reset(); |
| 98 } | 98 } |
| 99 | 99 |
| 100 void AudioOutputDispatcherImpl::StreamVolumeSet(AudioOutputProxy* stream_proxy, | 100 void AudioOutputDispatcherImpl::StreamVolumeSet(AudioOutputProxy* stream_proxy, |
| 101 double volume) { | 101 double volume) { |
| 102 DCHECK(message_loop_->BelongsToCurrentThread()); | 102 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 103 AudioStreamMap::iterator it = proxy_to_physical_map_.find(stream_proxy); | 103 AudioStreamMap::iterator it = proxy_to_physical_map_.find(stream_proxy); |
| 104 if (it != proxy_to_physical_map_.end()) { | 104 if (it != proxy_to_physical_map_.end()) { |
| 105 AudioOutputStream* physical_stream = it->second; | 105 AudioOutputStream* physical_stream = it->second; |
| 106 physical_stream->SetVolume(volume); | 106 physical_stream->SetVolume(volume); |
| 107 audio_log_->OnSetVolume(audio_stream_ids_[physical_stream], volume); | 107 audio_log_->OnSetVolume(audio_stream_ids_[physical_stream], volume); |
| 108 } | 108 } |
| 109 } | 109 } |
| 110 | 110 |
| 111 void AudioOutputDispatcherImpl::CloseStream(AudioOutputProxy* stream_proxy) { | 111 void AudioOutputDispatcherImpl::CloseStream(AudioOutputProxy* stream_proxy) { |
| 112 DCHECK(message_loop_->BelongsToCurrentThread()); | 112 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 113 | 113 |
| 114 DCHECK_GT(idle_proxies_, 0u); | 114 DCHECK_GT(idle_proxies_, 0u); |
| 115 --idle_proxies_; | 115 --idle_proxies_; |
| 116 | 116 |
| 117 // Leave at least a single stream running until the close timer fires to help | 117 // Leave at least a single stream running until the close timer fires to help |
| 118 // cycle time when streams are opened and closed repeatedly. | 118 // cycle time when streams are opened and closed repeatedly. |
| 119 CloseIdleStreams(std::max(idle_proxies_, static_cast<size_t>(1))); | 119 CloseIdleStreams(std::max(idle_proxies_, static_cast<size_t>(1))); |
| 120 close_timer_.Reset(); | 120 close_timer_.Reset(); |
| 121 } | 121 } |
| 122 | 122 |
| 123 void AudioOutputDispatcherImpl::Shutdown() { | 123 void AudioOutputDispatcherImpl::Shutdown() { |
| 124 DCHECK(message_loop_->BelongsToCurrentThread()); | 124 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 125 | 125 |
| 126 // Close all idle streams immediately. The |close_timer_| will handle | 126 // Close all idle streams immediately. The |close_timer_| will handle |
| 127 // invalidating any outstanding tasks upon its destruction. | 127 // invalidating any outstanding tasks upon its destruction. |
| 128 CloseAllIdleStreams(); | 128 CloseAllIdleStreams(); |
| 129 } | 129 } |
| 130 | 130 |
| 131 bool AudioOutputDispatcherImpl::CreateAndOpenStream() { | 131 bool AudioOutputDispatcherImpl::CreateAndOpenStream() { |
| 132 DCHECK(message_loop_->BelongsToCurrentThread()); | 132 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 133 AudioOutputStream* stream = audio_manager_->MakeAudioOutputStream( | 133 AudioOutputStream* stream = audio_manager_->MakeAudioOutputStream( |
| 134 params_, output_device_id_, input_device_id_); | 134 params_, output_device_id_, input_device_id_); |
| 135 if (!stream) | 135 if (!stream) |
| 136 return false; | 136 return false; |
| 137 | 137 |
| 138 if (!stream->Open()) { | 138 if (!stream->Open()) { |
| 139 stream->Close(); | 139 stream->Close(); |
| 140 return false; | 140 return false; |
| 141 } | 141 } |
| 142 | 142 |
| 143 const int stream_id = audio_stream_id_++; | 143 const int stream_id = audio_stream_id_++; |
| 144 audio_stream_ids_[stream] = stream_id; | 144 audio_stream_ids_[stream] = stream_id; |
| 145 audio_log_->OnCreated( | 145 audio_log_->OnCreated( |
| 146 stream_id, params_, input_device_id_, output_device_id_); | 146 stream_id, params_, input_device_id_, output_device_id_); |
| 147 | 147 |
| 148 idle_streams_.push_back(stream); | 148 idle_streams_.push_back(stream); |
| 149 return true; | 149 return true; |
| 150 } | 150 } |
| 151 | 151 |
| 152 void AudioOutputDispatcherImpl::CloseAllIdleStreams() { | 152 void AudioOutputDispatcherImpl::CloseAllIdleStreams() { |
| 153 DCHECK(message_loop_->BelongsToCurrentThread()); | 153 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 154 CloseIdleStreams(0); | 154 CloseIdleStreams(0); |
| 155 } | 155 } |
| 156 | 156 |
| 157 void AudioOutputDispatcherImpl::CloseIdleStreams(size_t keep_alive) { | 157 void AudioOutputDispatcherImpl::CloseIdleStreams(size_t keep_alive) { |
| 158 DCHECK(message_loop_->BelongsToCurrentThread()); | 158 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 159 if (idle_streams_.size() <= keep_alive) | 159 if (idle_streams_.size() <= keep_alive) |
| 160 return; | 160 return; |
| 161 for (size_t i = keep_alive; i < idle_streams_.size(); ++i) { | 161 for (size_t i = keep_alive; i < idle_streams_.size(); ++i) { |
| 162 AudioOutputStream* stream = idle_streams_[i]; | 162 AudioOutputStream* stream = idle_streams_[i]; |
| 163 stream->Close(); | 163 stream->Close(); |
| 164 | 164 |
| 165 AudioStreamIDMap::iterator it = audio_stream_ids_.find(stream); | 165 AudioStreamIDMap::iterator it = audio_stream_ids_.find(stream); |
| 166 DCHECK(it != audio_stream_ids_.end()); | 166 DCHECK(it != audio_stream_ids_.end()); |
| 167 audio_log_->OnClosed(it->second); | 167 audio_log_->OnClosed(it->second); |
| 168 audio_stream_ids_.erase(it); | 168 audio_stream_ids_.erase(it); |
| 169 } | 169 } |
| 170 idle_streams_.erase(idle_streams_.begin() + keep_alive, idle_streams_.end()); | 170 idle_streams_.erase(idle_streams_.begin() + keep_alive, idle_streams_.end()); |
| 171 } | 171 } |
| 172 | 172 |
| 173 void AudioOutputDispatcherImpl::CloseStreamsForWedgeFix() { | 173 void AudioOutputDispatcherImpl::CloseStreamsForWedgeFix() { |
| 174 DCHECK(message_loop_->BelongsToCurrentThread()); | 174 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 175 CloseAllIdleStreams(); | 175 CloseAllIdleStreams(); |
| 176 } | 176 } |
| 177 | 177 |
| 178 void AudioOutputDispatcherImpl::RestartStreamsForWedgeFix() { | 178 void AudioOutputDispatcherImpl::RestartStreamsForWedgeFix() { |
| 179 DCHECK(message_loop_->BelongsToCurrentThread()); | 179 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 180 | 180 |
| 181 // Should only be called when the dispatcher is used with fake streams which | 181 // Should only be called when the dispatcher is used with fake streams which |
| 182 // don't need to be shutdown or restarted. | 182 // don't need to be shutdown or restarted. |
| 183 CHECK_EQ(params_.format(), AudioParameters::AUDIO_FAKE); | 183 CHECK_EQ(params_.format(), AudioParameters::AUDIO_FAKE); |
| 184 } | 184 } |
| 185 | 185 |
| 186 } // namespace media | 186 } // namespace media |
| OLD | NEW |