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"
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
;
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
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
)),
39 next_read_buffer_index_(0),
40 number_of_filled_segments_(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)
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",
93 "AISW: number of detected audio glitches: %zu out of %zu",
97 MediaStreamManager::SendMessageToNativeLog(log_string
);
98 DVLOG(1) << log_string
;
101 void AudioInputSyncWriter::Write(const media::AudioBus
* data
,
104 uint32 hardware_delay_bytes
) {
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";
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();
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(
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
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_
;
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(¤t_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_
;
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() {
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