Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / content / browser / renderer_host / media / audio_input_sync_writer.cc
blob722f63e5a470793c60724a7be309291b16b00e03
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
3 // found in the LICENSE file.
5 #include "content/browser/renderer_host/media/audio_input_sync_writer.h"
7 #include <algorithm>
9 #include "base/metrics/histogram.h"
10 #include "base/strings/stringprintf.h"
11 #include "content/browser/renderer_host/media/media_stream_manager.h"
13 using media::AudioBus;
15 namespace content {
17 namespace {
19 // Used to log if any audio glitches have been detected during an audio session.
20 // Elements in this enum should not be added, deleted or rearranged.
21 enum AudioGlitchResult {
22 AUDIO_CAPTURER_NO_AUDIO_GLITCHES = 0,
23 AUDIO_CAPTURER_AUDIO_GLITCHES = 1,
24 AUDIO_CAPTURER_AUDIO_GLITCHES_MAX = AUDIO_CAPTURER_AUDIO_GLITCHES
27 } // namespace
29 AudioInputSyncWriter::AudioInputSyncWriter(void* shared_memory,
30 size_t shared_memory_size,
31 int shared_memory_segment_count,
32 const media::AudioParameters& params)
33 : shared_memory_(static_cast<uint8*>(shared_memory)),
34 shared_memory_segment_count_(shared_memory_segment_count),
35 current_segment_id_(0),
36 creation_time_(base::Time::Now()),
37 audio_bus_memory_size_(AudioBus::CalculateMemorySize(params)),
38 next_buffer_id_(0),
39 next_read_buffer_index_(0),
40 number_of_filled_segments_(0),
41 write_count_(0),
42 write_error_count_(0),
43 trailing_error_count_(0) {
44 DCHECK_GT(shared_memory_segment_count, 0);
45 DCHECK_EQ(shared_memory_size % shared_memory_segment_count, 0u);
46 shared_memory_segment_size_ =
47 shared_memory_size / shared_memory_segment_count;
48 DVLOG(1) << "shared_memory_size: " << shared_memory_size;
49 DVLOG(1) << "shared_memory_segment_count: " << shared_memory_segment_count;
50 DVLOG(1) << "audio_bus_memory_size: " << audio_bus_memory_size_;
52 // Create vector of audio buses by wrapping existing blocks of memory.
53 uint8* ptr = shared_memory_;
54 for (int i = 0; i < shared_memory_segment_count; ++i) {
55 CHECK_EQ(0U, reinterpret_cast<uintptr_t>(ptr) &
56 (media::AudioBus::kChannelAlignment - 1));
57 media::AudioInputBuffer* buffer =
58 reinterpret_cast<media::AudioInputBuffer*>(ptr);
59 scoped_ptr<media::AudioBus> audio_bus =
60 media::AudioBus::WrapMemory(params, buffer->audio);
61 audio_buses_.push_back(audio_bus.release());
62 ptr += shared_memory_segment_size_;
66 AudioInputSyncWriter::~AudioInputSyncWriter() {
67 // Subtract 'trailing' errors that will happen if the renderer process was
68 // killed or e.g. the page refreshed while the input device was open etc.
69 // This trims off the end of both the error and write counts so that we
70 // preserve the proportion of errors before the teardown period.
71 DCHECK_LE(trailing_error_count_, write_error_count_);
72 DCHECK_LE(trailing_error_count_, write_count_);
73 write_error_count_ -= trailing_error_count_;
74 write_count_ -= trailing_error_count_;
76 if (write_count_ == 0)
77 return;
79 UMA_HISTOGRAM_PERCENTAGE(
80 "Media.AudioCapturerMissedReadDeadline",
81 100.0 * write_error_count_ / write_count_);
83 UMA_HISTOGRAM_ENUMERATION("Media.AudioCapturerAudioGlitches",
84 write_error_count_ == 0 ?
85 AUDIO_CAPTURER_NO_AUDIO_GLITCHES :
86 AUDIO_CAPTURER_AUDIO_GLITCHES,
87 AUDIO_CAPTURER_AUDIO_GLITCHES_MAX + 1);
89 std::string log_string = base::StringPrintf(
90 #if defined(COMPILER_MSVC)
91 "AISW: number of detected audio glitches: %Iu out of %Iu",
92 #else
93 "AISW: number of detected audio glitches: %zu out of %zu",
94 #endif
95 write_error_count_,
96 write_count_);
97 MediaStreamManager::SendMessageToNativeLog(log_string);
98 DVLOG(1) << log_string;
101 void AudioInputSyncWriter::Write(const media::AudioBus* data,
102 double volume,
103 bool key_pressed,
104 uint32 hardware_delay_bytes) {
105 ++write_count_;
107 #if !defined(OS_ANDROID)
108 static const base::TimeDelta kLogDelayThreadhold =
109 base::TimeDelta::FromMilliseconds(500);
111 std::ostringstream oss;
112 if (last_write_time_.is_null()) {
113 // This is the first time Write is called.
114 base::TimeDelta interval = base::Time::Now() - creation_time_;
115 oss << "AISW::Write: audio input data received for the first time: delay "
116 "= " << interval.InMilliseconds() << "ms";
118 } else {
119 base::TimeDelta interval = base::Time::Now() - last_write_time_;
120 if (interval > kLogDelayThreadhold) {
121 oss << "AISW::Write: audio input data delay unexpectedly long: delay = "
122 << interval.InMilliseconds() << "ms";
125 if (!oss.str().empty()) {
126 AddToNativeLog(oss.str());
127 DVLOG(1) << oss.str();
130 last_write_time_ = base::Time::Now();
131 #endif
133 // Check that the renderer side has read data so that we don't overwrite data
134 // that hasn't been read yet. The renderer side sends a signal over the socket
135 // each time it has read data. Here, we read those verifications before
136 // writing. We verify that each buffer index is in sequence.
137 size_t number_of_indices_available = socket_->Peek() / sizeof(uint32_t);
138 if (number_of_indices_available > 0) {
139 scoped_ptr<uint32_t[]> indices(new uint32_t[number_of_indices_available]);
140 size_t bytes_received = socket_->Receive(
141 &indices[0],
142 number_of_indices_available * sizeof(indices[0]));
143 DCHECK_EQ(number_of_indices_available * sizeof(indices[0]), bytes_received);
144 for (size_t i = 0; i < number_of_indices_available; ++i) {
145 ++next_read_buffer_index_;
146 CHECK_EQ(indices[i], next_read_buffer_index_);
147 --number_of_filled_segments_;
148 CHECK_GE(number_of_filled_segments_, 0);
152 // Check that the ring buffer isn't full, and if it is log error and drop the
153 // buffer.
154 if (number_of_filled_segments_ ==
155 static_cast<int>(shared_memory_segment_count_)) {
156 const std::string error_message =
157 "No room in ring buffer to write data to. Dropping the data.";
158 LOG(ERROR) << error_message;
159 AddToNativeLog(error_message);
160 ++write_error_count_;
161 ++trailing_error_count_;
162 return;
165 // Write audio parameters to shared memory.
166 uint8* ptr = shared_memory_;
167 ptr += current_segment_id_ * shared_memory_segment_size_;
168 media::AudioInputBuffer* buffer =
169 reinterpret_cast<media::AudioInputBuffer*>(ptr);
170 buffer->params.volume = volume;
171 buffer->params.size = audio_bus_memory_size_;
172 buffer->params.key_pressed = key_pressed;
173 buffer->params.hardware_delay_bytes = hardware_delay_bytes;
174 buffer->params.id = next_buffer_id_++;
176 // Copy data from the native audio layer into shared memory using pre-
177 // allocated audio buses.
178 media::AudioBus* audio_bus = audio_buses_[current_segment_id_];
179 data->CopyTo(audio_bus);
181 if (socket_->Send(&current_segment_id_, sizeof(current_segment_id_)) !=
182 sizeof(current_segment_id_)) {
183 const std::string error_message = "No room in socket buffer.";
184 LOG(ERROR) << error_message;
185 AddToNativeLog(error_message);
186 ++write_error_count_;
187 ++trailing_error_count_;
188 return;
191 // Successfully delivered the buffer. Clear the trailing failure count.
192 trailing_error_count_ = 0;
194 if (++current_segment_id_ >= shared_memory_segment_count_)
195 current_segment_id_ = 0;
197 ++number_of_filled_segments_;
198 CHECK_LE(number_of_filled_segments_,
199 static_cast<int>(shared_memory_segment_count_));
202 void AudioInputSyncWriter::Close() {
203 socket_->Close();
206 bool AudioInputSyncWriter::Init() {
207 socket_.reset(new base::CancelableSyncSocket());
208 foreign_socket_.reset(new base::CancelableSyncSocket());
209 return base::CancelableSyncSocket::CreatePair(socket_.get(),
210 foreign_socket_.get());
213 bool AudioInputSyncWriter::PrepareForeignSocket(
214 base::ProcessHandle process_handle,
215 base::SyncSocket::TransitDescriptor* descriptor) {
216 return foreign_socket_->PrepareTransitDescriptor(process_handle, descriptor);
219 void AudioInputSyncWriter::AddToNativeLog(const std::string& message) {
220 MediaStreamManager::SendMessageToNativeLog(message);
223 } // namespace content