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 "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 Loading... | |
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(¤t_segment_id_, sizeof(current_segment_id_)); | 166 socket_->Send(¤t_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 |
OLD | NEW |