| 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/message_loop/message_loop.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 #include "content/browser/media/media_internals.h" |
| 17 |
| 16 namespace media { | 18 namespace media { |
| 17 | 19 |
| 20 static int g_stream_id = 0; |
| 21 static std::map<void*, int> g_stream_id_map; |
| 22 |
| 18 AudioOutputDispatcherImpl::AudioOutputDispatcherImpl( | 23 AudioOutputDispatcherImpl::AudioOutputDispatcherImpl( |
| 19 AudioManager* audio_manager, | 24 AudioManager* audio_manager, |
| 20 const AudioParameters& params, | 25 const AudioParameters& params, |
| 21 const std::string& output_device_id, | 26 const std::string& output_device_id, |
| 22 const std::string& input_device_id, | 27 const std::string& input_device_id, |
| 23 const base::TimeDelta& close_delay) | 28 const base::TimeDelta& close_delay) |
| 24 : AudioOutputDispatcher(audio_manager, params, output_device_id, | 29 : AudioOutputDispatcher(audio_manager, params, output_device_id, |
| 25 input_device_id), | 30 input_device_id), |
| 26 pause_delay_(base::TimeDelta::FromMicroseconds( | 31 pause_delay_(base::TimeDelta::FromMicroseconds( |
| 27 2 * params.frames_per_buffer() * base::Time::kMicrosecondsPerSecond / | 32 2 * params.frames_per_buffer() * base::Time::kMicrosecondsPerSecond / |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 70 DCHECK_GT(paused_proxies_, 0u); | 75 DCHECK_GT(paused_proxies_, 0u); |
| 71 --paused_proxies_; | 76 --paused_proxies_; |
| 72 | 77 |
| 73 close_timer_.Reset(); | 78 close_timer_.Reset(); |
| 74 | 79 |
| 75 double volume = 0; | 80 double volume = 0; |
| 76 stream_proxy->GetVolume(&volume); | 81 stream_proxy->GetVolume(&volume); |
| 77 physical_stream->SetVolume(volume); | 82 physical_stream->SetVolume(volume); |
| 78 physical_stream->Start(callback); | 83 physical_stream->Start(callback); |
| 79 proxy_to_physical_map_[stream_proxy] = physical_stream; | 84 proxy_to_physical_map_[stream_proxy] = physical_stream; |
| 85 |
| 86 audio_manager_->GetMediaInternals()->OnSetAudioStreamPlaying( |
| 87 this, g_stream_id_map[physical_stream], true); |
| 88 |
| 80 return true; | 89 return true; |
| 81 } | 90 } |
| 82 | 91 |
| 83 void AudioOutputDispatcherImpl::StopStream(AudioOutputProxy* stream_proxy) { | 92 void AudioOutputDispatcherImpl::StopStream(AudioOutputProxy* stream_proxy) { |
| 84 DCHECK(message_loop_->BelongsToCurrentThread()); | 93 DCHECK(message_loop_->BelongsToCurrentThread()); |
| 85 | 94 |
| 86 AudioStreamMap::iterator it = proxy_to_physical_map_.find(stream_proxy); | 95 AudioStreamMap::iterator it = proxy_to_physical_map_.find(stream_proxy); |
| 87 DCHECK(it != proxy_to_physical_map_.end()); | 96 DCHECK(it != proxy_to_physical_map_.end()); |
| 88 AudioOutputStream* physical_stream = it->second; | 97 AudioOutputStream* physical_stream = it->second; |
| 89 proxy_to_physical_map_.erase(it); | 98 proxy_to_physical_map_.erase(it); |
| 90 | 99 |
| 91 physical_stream->Stop(); | 100 physical_stream->Stop(); |
| 92 | 101 |
| 93 ++paused_proxies_; | 102 ++paused_proxies_; |
| 94 | 103 |
| 95 pausing_streams_.push_front(physical_stream); | 104 pausing_streams_.push_front(physical_stream); |
| 96 | 105 |
| 106 audio_manager_->GetMediaInternals()->OnSetAudioStreamPlaying( |
| 107 this, g_stream_id_map[physical_stream], false); |
| 108 |
| 97 // Don't recycle stream until two buffers worth of time has elapsed. | 109 // Don't recycle stream until two buffers worth of time has elapsed. |
| 98 message_loop_->PostDelayedTask( | 110 message_loop_->PostDelayedTask( |
| 99 FROM_HERE, | 111 FROM_HERE, |
| 100 base::Bind(&AudioOutputDispatcherImpl::StopStreamTask, | 112 base::Bind(&AudioOutputDispatcherImpl::StopStreamTask, |
| 101 weak_this_.GetWeakPtr()), | 113 weak_this_.GetWeakPtr()), |
| 102 pause_delay_); | 114 pause_delay_); |
| 103 } | 115 } |
| 104 | 116 |
| 105 void AudioOutputDispatcherImpl::StreamVolumeSet(AudioOutputProxy* stream_proxy, | 117 void AudioOutputDispatcherImpl::StreamVolumeSet(AudioOutputProxy* stream_proxy, |
| 106 double volume) { | 118 double volume) { |
| 107 DCHECK(message_loop_->BelongsToCurrentThread()); | 119 DCHECK(message_loop_->BelongsToCurrentThread()); |
| 108 AudioStreamMap::iterator it = proxy_to_physical_map_.find(stream_proxy); | 120 AudioStreamMap::iterator it = proxy_to_physical_map_.find(stream_proxy); |
| 109 if (it != proxy_to_physical_map_.end()) { | 121 if (it != proxy_to_physical_map_.end()) { |
| 110 AudioOutputStream* physical_stream = it->second; | 122 AudioOutputStream* physical_stream = it->second; |
| 111 physical_stream->SetVolume(volume); | 123 physical_stream->SetVolume(volume); |
| 124 audio_manager_->GetMediaInternals()->OnSetAudioStreamVolume( |
| 125 this, g_stream_id_map[physical_stream], volume); |
| 112 } | 126 } |
| 113 } | 127 } |
| 114 | 128 |
| 115 void AudioOutputDispatcherImpl::StopStreamTask() { | 129 void AudioOutputDispatcherImpl::StopStreamTask() { |
| 116 DCHECK(message_loop_->BelongsToCurrentThread()); | 130 DCHECK(message_loop_->BelongsToCurrentThread()); |
| 117 | 131 |
| 118 if (pausing_streams_.empty()) | 132 if (pausing_streams_.empty()) |
| 119 return; | 133 return; |
| 120 | 134 |
| 121 AudioOutputStream* stream = pausing_streams_.back(); | 135 AudioOutputStream* stream = pausing_streams_.back(); |
| 122 pausing_streams_.pop_back(); | 136 pausing_streams_.pop_back(); |
| 123 idle_streams_.push_back(stream); | 137 idle_streams_.push_back(stream); |
| 124 close_timer_.Reset(); | 138 close_timer_.Reset(); |
| 125 } | 139 } |
| 126 | 140 |
| 141 void AudioOutputDispatcherImpl::LogCloseStream(AudioOutputStream* stream) { |
| 142 audio_manager_->GetMediaInternals()->OnSetAudioStreamStatus( |
| 143 this, g_stream_id_map[stream], "closed"); |
| 144 audio_manager_->GetMediaInternals()->OnDeleteAudioStream( |
| 145 this, g_stream_id_map[stream]); |
| 146 } |
| 147 |
| 127 void AudioOutputDispatcherImpl::CloseStream(AudioOutputProxy* stream_proxy) { | 148 void AudioOutputDispatcherImpl::CloseStream(AudioOutputProxy* stream_proxy) { |
| 128 DCHECK(message_loop_->BelongsToCurrentThread()); | 149 DCHECK(message_loop_->BelongsToCurrentThread()); |
| 129 | 150 |
| 130 while (!pausing_streams_.empty()) { | 151 while (!pausing_streams_.empty()) { |
| 131 idle_streams_.push_back(pausing_streams_.back()); | 152 idle_streams_.push_back(pausing_streams_.back()); |
| 132 pausing_streams_.pop_back(); | 153 pausing_streams_.pop_back(); |
| 133 } | 154 } |
| 134 | 155 |
| 135 DCHECK_GT(paused_proxies_, 0u); | 156 DCHECK_GT(paused_proxies_, 0u); |
| 136 paused_proxies_--; | 157 paused_proxies_--; |
| 137 | 158 |
| 138 while (idle_streams_.size() > paused_proxies_) { | 159 while (idle_streams_.size() > paused_proxies_) { |
| 139 idle_streams_.back()->Close(); | 160 idle_streams_.back()->Close(); |
| 161 LogCloseStream(idle_streams_.back()); |
| 140 idle_streams_.pop_back(); | 162 idle_streams_.pop_back(); |
| 141 } | 163 } |
| 142 } | 164 } |
| 143 | 165 |
| 144 void AudioOutputDispatcherImpl::Shutdown() { | 166 void AudioOutputDispatcherImpl::Shutdown() { |
| 145 DCHECK(message_loop_->BelongsToCurrentThread()); | 167 DCHECK(message_loop_->BelongsToCurrentThread()); |
| 146 | 168 |
| 147 // Cancel any pending tasks to close paused streams or create new ones. | 169 // Cancel any pending tasks to close paused streams or create new ones. |
| 148 weak_this_.InvalidateWeakPtrs(); | 170 weak_this_.InvalidateWeakPtrs(); |
| 149 | 171 |
| 150 // No AudioOutputProxy objects should hold a reference to us when we get | 172 // No AudioOutputProxy objects should hold a reference to us when we get |
| 151 // to this stage. | 173 // to this stage. |
| 152 DCHECK(HasOneRef()) << "Only the AudioManager should hold a reference"; | 174 DCHECK(HasOneRef()) << "Only the AudioManager should hold a reference"; |
| 153 | 175 |
| 154 AudioOutputStreamList::iterator it = idle_streams_.begin(); | 176 AudioOutputStreamList::iterator it = idle_streams_.begin(); |
| 155 for (; it != idle_streams_.end(); ++it) | 177 for (; it != idle_streams_.end(); ++it) { |
| 156 (*it)->Close(); | 178 (*it)->Close(); |
| 179 LogCloseStream(*it); |
| 180 } |
| 157 idle_streams_.clear(); | 181 idle_streams_.clear(); |
| 158 | 182 |
| 159 it = pausing_streams_.begin(); | 183 it = pausing_streams_.begin(); |
| 160 for (; it != pausing_streams_.end(); ++it) | 184 for (; it != pausing_streams_.end(); ++it) { |
| 161 (*it)->Close(); | 185 (*it)->Close(); |
| 186 LogCloseStream(*it); |
| 187 } |
| 162 pausing_streams_.clear(); | 188 pausing_streams_.clear(); |
| 163 } | 189 } |
| 164 | 190 |
| 165 bool AudioOutputDispatcherImpl::CreateAndOpenStream() { | 191 bool AudioOutputDispatcherImpl::CreateAndOpenStream() { |
| 166 DCHECK(message_loop_->BelongsToCurrentThread()); | 192 DCHECK(message_loop_->BelongsToCurrentThread()); |
| 167 AudioOutputStream* stream = audio_manager_->MakeAudioOutputStream( | 193 AudioOutputStream* stream = audio_manager_->MakeAudioOutputStream( |
| 168 params_, output_device_id_, input_device_id_); | 194 params_, output_device_id_, input_device_id_); |
| 169 if (!stream) | 195 if (!stream) |
| 170 return false; | 196 return false; |
| 171 | 197 |
| 172 if (!stream->Open()) { | 198 if (!stream->Open()) { |
| 173 stream->Close(); | 199 stream->Close(); |
| 174 return false; | 200 return false; |
| 175 } | 201 } |
| 202 |
| 203 g_stream_id_map[stream] = g_stream_id; |
| 204 audio_manager_->GetMediaInternals()->OnAudioStreamCreated( |
| 205 this, g_stream_id++, params_, input_device_id_); |
| 206 |
| 176 idle_streams_.push_back(stream); | 207 idle_streams_.push_back(stream); |
| 177 return true; | 208 return true; |
| 178 } | 209 } |
| 179 | 210 |
| 180 // This method is called by |close_timer_|. | 211 // This method is called by |close_timer_|. |
| 181 void AudioOutputDispatcherImpl::ClosePendingStreams() { | 212 void AudioOutputDispatcherImpl::ClosePendingStreams() { |
| 182 DCHECK(message_loop_->BelongsToCurrentThread()); | 213 DCHECK(message_loop_->BelongsToCurrentThread()); |
| 183 while (!idle_streams_.empty()) { | 214 while (!idle_streams_.empty()) { |
| 184 idle_streams_.back()->Close(); | 215 idle_streams_.back()->Close(); |
| 216 LogCloseStream(idle_streams_.back()); |
| 185 idle_streams_.pop_back(); | 217 idle_streams_.pop_back(); |
| 186 } | 218 } |
| 187 } | 219 } |
| 188 | 220 |
| 189 } // namespace media | 221 } // namespace media |
| OLD | NEW |