Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2006-2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2006-2009 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 "base/histogram.h" | 5 #include "base/histogram.h" |
| 6 #include "base/lock.h" | 6 #include "base/lock.h" |
| 7 #include "base/message_loop.h" | 7 #include "base/message_loop.h" |
| 8 #include "base/process.h" | 8 #include "base/process.h" |
| 9 #include "base/shared_memory.h" | 9 #include "base/shared_memory.h" |
| 10 #include "base/waitable_event.h" | 10 #include "base/waitable_event.h" |
| 11 #include "chrome/browser/renderer_host/audio_renderer_host.h" | 11 #include "chrome/browser/renderer_host/audio_renderer_host.h" |
| 12 #include "chrome/common/ipc_logging.h" | |
| 12 #include "chrome/common/render_messages.h" | 13 #include "chrome/common/render_messages.h" |
| 13 | 14 |
| 14 namespace { | 15 namespace { |
| 15 | 16 |
| 16 void RecordIPCAudioLatency(base::TimeDelta latency) { | 17 void RecordRoundTripLatency(base::TimeDelta latency) { |
| 17 // Create a histogram of minimum 1ms and maximum 1000ms with 100 buckets. | 18 static ThreadSafeHistogram histogram("Audio.IPC_RoundTripLatency", |
| 18 static ThreadSafeHistogram histogram("Audio.IPCTransportLatency", | |
| 19 1, 1000, 100); | 19 1, 1000, 100); |
| 20 histogram.AddTime(latency); | 20 histogram.AddTime(latency); |
| 21 } | 21 } |
| 22 | 22 |
| 23 void RecordReceiveLatency(base::TimeDelta latency) { | |
| 24 static ThreadSafeHistogram histogram("Audio.IPC_Browser_ReceiveLatency", | |
| 25 1, 500, 100); | |
| 26 histogram.AddTime(latency); | |
| 27 } | |
| 28 | |
| 29 void RecordProcessTime(base::TimeDelta latency) { | |
| 30 static ThreadSafeHistogram histogram("Audio.IPC_Browser_ProcessTime", | |
| 31 1, 100, 100); | |
| 32 histogram.AddTime(latency); | |
| 33 } | |
| 34 | |
| 23 } // namespace | 35 } // namespace |
| 24 | 36 |
| 25 //----------------------------------------------------------------------------- | 37 //----------------------------------------------------------------------------- |
| 26 // AudioRendererHost::IPCAudioSource implementations. | 38 // AudioRendererHost::IPCAudioSource implementations. |
| 27 | 39 |
| 28 AudioRendererHost::IPCAudioSource::IPCAudioSource( | 40 AudioRendererHost::IPCAudioSource::IPCAudioSource( |
| 29 AudioRendererHost* host, | 41 AudioRendererHost* host, |
| 30 int process_id, | 42 int process_id, |
| 31 int route_id, | 43 int route_id, |
| 32 int stream_id, | 44 int stream_id, |
| (...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 145 return; | 157 return; |
| 146 double left_channel, right_channel; | 158 double left_channel, right_channel; |
| 147 stream_->GetVolume(&left_channel, &right_channel); | 159 stream_->GetVolume(&left_channel, &right_channel); |
| 148 host_->Send(new ViewMsg_NotifyAudioStreamVolume(route_id_, stream_id_, | 160 host_->Send(new ViewMsg_NotifyAudioStreamVolume(route_id_, stream_id_, |
| 149 left_channel, right_channel)); | 161 left_channel, right_channel)); |
| 150 } | 162 } |
| 151 | 163 |
| 152 size_t AudioRendererHost::IPCAudioSource::OnMoreData(AudioOutputStream* stream, | 164 size_t AudioRendererHost::IPCAudioSource::OnMoreData(AudioOutputStream* stream, |
| 153 void* dest, | 165 void* dest, |
| 154 size_t max_size) { | 166 size_t max_size) { |
| 155 base::TimeTicks tick_start = base::TimeTicks::HighResNow(); | 167 #ifdef IPC_MESSAGE_LOG_ENABLED |
|
scherkus (not reviewing)
2009/04/30 02:15:10
do you know how we get this defined?
| |
| 168 base::Time tick_start = base::Time::Now(); | |
|
scherkus (not reviewing)
2009/04/30 02:15:10
curious... why not HighResNow?
| |
| 169 #endif | |
| 156 { | 170 { |
| 157 AutoLock auto_lock(lock_); | 171 AutoLock auto_lock(lock_); |
| 158 // If we are ever stopped, don't ask for more audio packet from the | 172 // If we are ever stopped, don't ask for more audio packet from the |
| 159 // renderer. | 173 // renderer. |
| 160 if (stop_providing_packets_) | 174 if (stop_providing_packets_) |
| 161 return 0; | 175 return 0; |
| 162 } | 176 } |
| 163 | 177 |
| 164 // If we have an initial packet, use it immediately only in IO thread. | 178 // If we have an initial packet, use it immediately only in IO thread. |
| 165 // There's a case when IO thread is blocked and audio hardware thread can | 179 // There's a case when IO thread is blocked and audio hardware thread can |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 188 packet_read_event_.Wait(); | 202 packet_read_event_.Wait(); |
| 189 | 203 |
| 190 size_t last_packet_size = 0; | 204 size_t last_packet_size = 0; |
| 191 { | 205 { |
| 192 AutoLock auto_lock(lock_); | 206 AutoLock auto_lock(lock_); |
| 193 last_packet_size = last_packet_size_; | 207 last_packet_size = last_packet_size_; |
| 194 } | 208 } |
| 195 | 209 |
| 196 size_t copied = SafeCopyBuffer(dest, max_size, | 210 size_t copied = SafeCopyBuffer(dest, max_size, |
| 197 shared_memory_.memory(), last_packet_size); | 211 shared_memory_.memory(), last_packet_size); |
| 198 RecordIPCAudioLatency(base::TimeTicks::HighResNow() - tick_start); | 212 #ifdef IPC_MESSAGE_LOG_ENABLED |
| 213 // The logging to round trip latency doesn't have dependency on IPC logging. | |
| 214 // But it's good we use IPC logging to trigger logging of total latency. | |
| 215 if (IPC::Logging::current()->Enabled()) | |
| 216 RecordRoundTripLatency(base::Time::Now() - tick_start); | |
| 217 #endif | |
| 199 return copied; | 218 return copied; |
| 200 } | 219 } |
| 201 | 220 |
| 202 void AudioRendererHost::IPCAudioSource::OnClose(AudioOutputStream* stream) { | 221 void AudioRendererHost::IPCAudioSource::OnClose(AudioOutputStream* stream) { |
| 203 StopWaitingForPacket(); | 222 StopWaitingForPacket(); |
| 204 } | 223 } |
| 205 | 224 |
| 206 void AudioRendererHost::IPCAudioSource::OnError(AudioOutputStream* stream, | 225 void AudioRendererHost::IPCAudioSource::OnError(AudioOutputStream* stream, |
| 207 int code) { | 226 int code) { |
| 208 host_->SendErrorMessage(route_id_, stream_id_, code); | 227 host_->SendErrorMessage(route_id_, stream_id_, code); |
| (...skipping 197 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 406 | 425 |
| 407 void AudioRendererHost::OnNotifyPacketReady(const IPC::Message& msg, | 426 void AudioRendererHost::OnNotifyPacketReady(const IPC::Message& msg, |
| 408 int stream_id, size_t packet_size) { | 427 int stream_id, size_t packet_size) { |
| 409 DCHECK(MessageLoop::current() == io_loop_); | 428 DCHECK(MessageLoop::current() == io_loop_); |
| 410 IPCAudioSource* source = Lookup(msg.routing_id(), stream_id); | 429 IPCAudioSource* source = Lookup(msg.routing_id(), stream_id); |
| 411 if (source) { | 430 if (source) { |
| 412 source->NotifyPacketReady(packet_size); | 431 source->NotifyPacketReady(packet_size); |
| 413 } else { | 432 } else { |
| 414 SendErrorMessage(msg.routing_id(), stream_id, 0); | 433 SendErrorMessage(msg.routing_id(), stream_id, 0); |
| 415 } | 434 } |
| 435 #ifdef IPC_MESSAGE_LOG_ENABLED | |
| 436 if (IPC::Logging::current()->Enabled()) { | |
| 437 RecordReceiveLatency(base::Time::FromInternalValue(msg.received_time()) - | |
| 438 base::Time::FromInternalValue(msg.sent_time())); | |
| 439 RecordProcessTime(base::Time::Now() - | |
| 440 base::Time::FromInternalValue(msg.received_time())); | |
| 441 } | |
| 442 #endif | |
| 416 } | 443 } |
| 417 | 444 |
| 418 void AudioRendererHost::OnInitialized() { | 445 void AudioRendererHost::OnInitialized() { |
| 419 DCHECK(MessageLoop::current() == io_loop_); | 446 DCHECK(MessageLoop::current() == io_loop_); |
| 420 // Increase the ref count of this object so it is active until we do | 447 // Increase the ref count of this object so it is active until we do |
| 421 // Release(). | 448 // Release(). |
| 422 AddRef(); | 449 AddRef(); |
| 423 } | 450 } |
| 424 | 451 |
| 425 void AudioRendererHost::OnDestroyed() { | 452 void AudioRendererHost::OnDestroyed() { |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 491 if (MessageLoop::current() == io_loop_) { | 518 if (MessageLoop::current() == io_loop_) { |
| 492 OnDestroySource(source); | 519 OnDestroySource(source); |
| 493 } else { | 520 } else { |
| 494 // TODO(hclam): make sure it's always safe to post a task to IO loop. | 521 // TODO(hclam): make sure it's always safe to post a task to IO loop. |
| 495 // It is possible that IO message loop is destroyed but there's still some | 522 // It is possible that IO message loop is destroyed but there's still some |
| 496 // dangling audio hardware threads that try to call this method. | 523 // dangling audio hardware threads that try to call this method. |
| 497 io_loop_->PostTask(FROM_HERE, | 524 io_loop_->PostTask(FROM_HERE, |
| 498 NewRunnableMethod(this, &AudioRendererHost::OnDestroySource, source)); | 525 NewRunnableMethod(this, &AudioRendererHost::OnDestroySource, source)); |
| 499 } | 526 } |
| 500 } | 527 } |
| OLD | NEW |