Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(456)

Side by Side Diff: content/browser/renderer_host/media/audio_input_sync_writer.cc

Issue 1302423006: Ensure that data is not overwritten in the audio input shared memory ring buffer that sits on the b… (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Code review + rebase. Created 5 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 "content/browser/renderer_host/media/audio_input_sync_writer.h" 5 #include "content/browser/renderer_host/media/audio_input_sync_writer.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 8
9 #include "base/memory/shared_memory.h" 9 #include "base/memory/shared_memory.h"
10 #include "base/metrics/histogram.h"
11 #include "base/strings/stringprintf.h"
10 #include "content/browser/renderer_host/media/media_stream_manager.h" 12 #include "content/browser/renderer_host/media/media_stream_manager.h"
11 13
12 using media::AudioBus; 14 using media::AudioBus;
13 15
14 namespace content { 16 namespace content {
15 17
18 namespace {
19
20 // TODO BEFORE COMMIT: Which value makes sense? I.e. how long can we accept
21 // blocking the soundcard thread and wait before dropping data.
tommi (sloooow) - chröme 2015/08/28 13:43:06 Could this be dynamically chosen somehow based on
Henrik Grunell 2015/09/02 14:27:55 I assume you mean number of segments in the ring b
22 const base::TimeDelta kReadCheckTimeout =
23 base::TimeDelta::FromMilliseconds(10);
24
25 // Used to log if any audio glitches have been detected during an audio session.
26 // Elements in this enum should not be added, deleted or rearranged.
27 enum AudioGlitchResult {
28 AUDIO_CAPTURER_NO_AUDIO_GLITCHES = 0,
29 AUDIO_CAPTURER_AUDIO_GLITCHES = 1,
30 AUDIO_CAPTURER_AUDIO_GLITCHES_MAX = AUDIO_CAPTURER_AUDIO_GLITCHES
31 };
32
33 } // namespace
34
16 AudioInputSyncWriter::AudioInputSyncWriter(base::SharedMemory* shared_memory, 35 AudioInputSyncWriter::AudioInputSyncWriter(base::SharedMemory* shared_memory,
17 int shared_memory_segment_count, 36 int shared_memory_segment_count,
18 const media::AudioParameters& params) 37 const media::AudioParameters& params)
19 : shared_memory_(shared_memory), 38 : shared_memory_(shared_memory),
20 shared_memory_segment_count_(shared_memory_segment_count), 39 shared_memory_segment_count_(shared_memory_segment_count),
21 current_segment_id_(0), 40 current_segment_id_(0),
22 creation_time_(base::Time::Now()), 41 creation_time_(base::Time::Now()),
23 audio_bus_memory_size_(AudioBus::CalculateMemorySize(params)), 42 audio_bus_memory_size_(AudioBus::CalculateMemorySize(params)),
24 next_buffer_id_(0) { 43 next_buffer_id_(0),
44 expected_buffer_reads_(0),
45 read_verification_count_(0),
46 read_verification_timeout_count_(0) {
25 DCHECK_GT(shared_memory_segment_count, 0); 47 DCHECK_GT(shared_memory_segment_count, 0);
26 DCHECK_EQ(shared_memory->requested_size() % shared_memory_segment_count, 0u); 48 DCHECK_EQ(shared_memory->requested_size() % shared_memory_segment_count, 0u);
27 shared_memory_segment_size_ = 49 shared_memory_segment_size_ =
28 shared_memory->requested_size() / shared_memory_segment_count; 50 shared_memory->requested_size() / shared_memory_segment_count;
29 DVLOG(1) << "SharedMemory::requested_size: " 51 DVLOG(1) << "SharedMemory::requested_size: "
30 << shared_memory->requested_size(); 52 << shared_memory->requested_size();
31 DVLOG(1) << "shared_memory_segment_count: " << shared_memory_segment_count; 53 DVLOG(1) << "shared_memory_segment_count: " << shared_memory_segment_count;
32 DVLOG(1) << "audio_bus_memory_size: " << audio_bus_memory_size_; 54 DVLOG(1) << "audio_bus_memory_size: " << audio_bus_memory_size_;
33 55
34 // Create vector of audio buses by wrapping existing blocks of memory. 56 // Create vector of audio buses by wrapping existing blocks of memory.
35 uint8* ptr = static_cast<uint8*>(shared_memory_->memory()); 57 uint8* ptr = static_cast<uint8*>(shared_memory_->memory());
36 for (int i = 0; i < shared_memory_segment_count; ++i) { 58 for (int i = 0; i < shared_memory_segment_count; ++i) {
37 CHECK((reinterpret_cast<uintptr_t>(ptr) & 59 CHECK((reinterpret_cast<uintptr_t>(ptr) &
38 (media::AudioBus::kChannelAlignment - 1)) == 0U); 60 (media::AudioBus::kChannelAlignment - 1)) == 0U);
39 media::AudioInputBuffer* buffer = 61 media::AudioInputBuffer* buffer =
40 reinterpret_cast<media::AudioInputBuffer*>(ptr); 62 reinterpret_cast<media::AudioInputBuffer*>(ptr);
41 scoped_ptr<media::AudioBus> audio_bus = 63 scoped_ptr<media::AudioBus> audio_bus =
42 media::AudioBus::WrapMemory(params, buffer->audio); 64 media::AudioBus::WrapMemory(params, buffer->audio);
43 audio_buses_.push_back(audio_bus.release()); 65 audio_buses_.push_back(audio_bus.release());
44 ptr += shared_memory_segment_size_; 66 ptr += shared_memory_segment_size_;
45 } 67 }
46 } 68 }
47 69
48 AudioInputSyncWriter::~AudioInputSyncWriter() {} 70 AudioInputSyncWriter::~AudioInputSyncWriter() {
71 if (read_verification_count_ == 0)
72 return;
73
74 UMA_HISTOGRAM_PERCENTAGE(
75 "Media.AudioCapturerMissedReadDeadline",
76 100.0 * read_verification_timeout_count_ / read_verification_count_);
77
78 UMA_HISTOGRAM_ENUMERATION("Media.AudioCapturerAudioGlitches",
79 read_verification_timeout_count_ == 0 ?
80 AUDIO_CAPTURER_NO_AUDIO_GLITCHES :
81 AUDIO_CAPTURER_AUDIO_GLITCHES,
82 AUDIO_CAPTURER_AUDIO_GLITCHES_MAX + 1);
83
84 std::string log_string = base::StringPrintf(
85 "AISW: number of detected audio glitches: %lu out of %lu",
86 read_verification_timeout_count_,
87 read_verification_count_);
88 MediaStreamManager::SendMessageToNativeLog(log_string);
89 DVLOG(1) << log_string;
90 }
49 91
50 void AudioInputSyncWriter::Write(const media::AudioBus* data, 92 void AudioInputSyncWriter::Write(const media::AudioBus* data,
51 double volume, 93 double volume,
52 bool key_pressed, 94 bool key_pressed,
53 uint32 hardware_delay_bytes) { 95 uint32 hardware_delay_bytes) {
54 #if !defined(OS_ANDROID) 96 #if !defined(OS_ANDROID)
55 static const base::TimeDelta kLogDelayThreadhold = 97 static const base::TimeDelta kLogDelayThreadhold =
56 base::TimeDelta::FromMilliseconds(500); 98 base::TimeDelta::FromMilliseconds(500);
57 99
58 std::ostringstream oss; 100 std::ostringstream oss;
(...skipping 11 matching lines...) Expand all
70 } 112 }
71 } 113 }
72 if (!oss.str().empty()) { 114 if (!oss.str().empty()) {
73 MediaStreamManager::SendMessageToNativeLog(oss.str()); 115 MediaStreamManager::SendMessageToNativeLog(oss.str());
74 DVLOG(1) << oss.str(); 116 DVLOG(1) << oss.str();
75 } 117 }
76 118
77 last_write_time_ = base::Time::Now(); 119 last_write_time_ = base::Time::Now();
78 #endif 120 #endif
79 121
122 // Check that the renderer side has read data so that we don't overwrite.
123 // The renderer side sends a signal over the socket each time it has read
124 // data. Here, we count the number of reads we expect to have been done. When
125 // we reach |shared_memory_segment_count_|, we do
126 // (|shared_memory_segment_count_| / 2) socket receives, which normally is
127 // in queue. If we timeout, there's a problem with being able to read at the
128 // high enough pace, and we throw away the audio buffer.
129 if (expected_buffer_reads_ ==
130 static_cast<int>(shared_memory_segment_count_)) {
131 size_t bytes_received = 0;
132 uint32 dummy = 0;
133 for (uint32 i = 0; i < (shared_memory_segment_count_ + 1) / 2; ++i) {
tommi (sloooow) - chröme 2015/08/28 13:43:06 nit: calculate nr or repetitions outside the loop
Henrik Grunell 2015/09/02 14:27:55 I've removed the loop. I think Dale has a point, w
134 ++read_verification_count_;
135 bytes_received =
136 socket_->ReceiveWithTimeout(&dummy, sizeof(dummy), kReadCheckTimeout);
137 if (bytes_received != sizeof(dummy)) {
tommi (sloooow) - chröme 2015/08/28 13:43:06 if we timeout, should we break from the loop? Btw
Henrik Grunell 2015/09/02 14:27:55 Loop is gone.
138 const std::string error_message =
139 "Verifying shared memory read timed out. Dropping audio data.";
140 LOG(ERROR) << error_message;
141 MediaStreamManager::SendMessageToNativeLog(error_message);
142 ++read_verification_timeout_count_;
143 return;
144 }
145 --expected_buffer_reads_;
146 DCHECK_GE(expected_buffer_reads_, 0);
147 }
148 }
149
80 // Write audio parameters to shared memory. 150 // Write audio parameters to shared memory.
81 uint8* ptr = static_cast<uint8*>(shared_memory_->memory()); 151 uint8* ptr = static_cast<uint8*>(shared_memory_->memory());
82 ptr += current_segment_id_ * shared_memory_segment_size_; 152 ptr += current_segment_id_ * shared_memory_segment_size_;
83 media::AudioInputBuffer* buffer = 153 media::AudioInputBuffer* buffer =
84 reinterpret_cast<media::AudioInputBuffer*>(ptr); 154 reinterpret_cast<media::AudioInputBuffer*>(ptr);
85 buffer->params.volume = volume; 155 buffer->params.volume = volume;
86 buffer->params.size = audio_bus_memory_size_; 156 buffer->params.size = audio_bus_memory_size_;
87 buffer->params.key_pressed = key_pressed; 157 buffer->params.key_pressed = key_pressed;
88 buffer->params.hardware_delay_bytes = hardware_delay_bytes; 158 buffer->params.hardware_delay_bytes = hardware_delay_bytes;
89 buffer->params.id = next_buffer_id_++; 159 buffer->params.id = next_buffer_id_++;
90 160
91 // Copy data from the native audio layer into shared memory using pre- 161 // Copy data from the native audio layer into shared memory using pre-
92 // allocated audio buses. 162 // allocated audio buses.
93 media::AudioBus* audio_bus = audio_buses_[current_segment_id_]; 163 media::AudioBus* audio_bus = audio_buses_[current_segment_id_];
94 data->CopyTo(audio_bus); 164 data->CopyTo(audio_bus);
95 165
96 socket_->Send(&current_segment_id_, sizeof(current_segment_id_)); 166 socket_->Send(&current_segment_id_, sizeof(current_segment_id_));
97 167
98 if (++current_segment_id_ >= shared_memory_segment_count_) 168 if (++current_segment_id_ >= shared_memory_segment_count_)
99 current_segment_id_ = 0; 169 current_segment_id_ = 0;
170
171 ++expected_buffer_reads_;
172 DCHECK_LE(expected_buffer_reads_,
173 static_cast<int>(shared_memory_segment_count_));
100 } 174 }
101 175
102 void AudioInputSyncWriter::Close() { 176 void AudioInputSyncWriter::Close() {
103 socket_->Close(); 177 socket_->Close();
104 } 178 }
105 179
106 bool AudioInputSyncWriter::Init() { 180 bool AudioInputSyncWriter::Init() {
107 socket_.reset(new base::CancelableSyncSocket()); 181 socket_.reset(new base::CancelableSyncSocket());
108 foreign_socket_.reset(new base::CancelableSyncSocket()); 182 foreign_socket_.reset(new base::CancelableSyncSocket());
109 return base::CancelableSyncSocket::CreatePair(socket_.get(), 183 return base::CancelableSyncSocket::CreatePair(socket_.get(),
110 foreign_socket_.get()); 184 foreign_socket_.get());
111 } 185 }
112 186
113 bool AudioInputSyncWriter::PrepareForeignSocket( 187 bool AudioInputSyncWriter::PrepareForeignSocket(
114 base::ProcessHandle process_handle, 188 base::ProcessHandle process_handle,
115 base::SyncSocket::TransitDescriptor* descriptor) { 189 base::SyncSocket::TransitDescriptor* descriptor) {
116 return foreign_socket_->PrepareTransitDescriptor(process_handle, descriptor); 190 return foreign_socket_->PrepareTransitDescriptor(process_handle, descriptor);
117 } 191 }
118 192
119 193
120 } // namespace content 194 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698