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

Side by Side Diff: content/browser/speech/speech_recognition_audio_receiver.cc

Issue 549373003: Binding media stream audio track to speech recognition [browser] Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Tommi's comments Created 6 years, 2 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
(Empty)
1 // Copyright 2014 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.
4
5 #include "content/browser/speech/speech_recognition_audio_receiver.h"
6
7 #include "base/bind.h"
8 #include "base/process/process_handle.h"
9 #include "content/public/browser/browser_thread.h"
10 #include "media/audio/audio_parameters.h"
11 #include "media/base/audio_bus.h"
12
13 namespace content {
14
15 // static
16 scoped_ptr<SpeechRecognitionAudioReceiver>
17 SpeechRecognitionAudioReceiver::Create(
18 const media::AudioParameters& audio_params,
no longer working on chromium 2014/10/17 12:28:10 fix the indentation.
burnik 2014/10/23 13:56:36 Done.
19 const base::ProcessHandle peer_process_handle,
20 media::AudioInputController::EventHandler* event_handler,
21 base::SingleThreadTaskRunner* task_runner,
22 base::SharedMemoryHandle* foreign_memory_handle,
23 base::SyncSocket::TransitDescriptor* foreign_socket_descriptor) {
24 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
25 DCHECK(event_handler);
26
27 scoped_ptr<SpeechRecognitionAudioReceiver> receiver(
28 new SpeechRecognitionAudioReceiver(audio_params,
29 event_handler,
30 task_runner));
31
32 if (!receiver->Initialize(peer_process_handle,
33 foreign_memory_handle,
34 foreign_socket_descriptor)) {
35 receiver.reset();
36 }
37
38 return receiver.Pass();
39 }
40
41 SpeechRecognitionAudioReceiver::SpeechRecognitionAudioReceiver(
42 const media::AudioParameters& audio_params,
43 media::AudioInputController::EventHandler* event_handler,
44 base::SingleThreadTaskRunner* task_runner)
45 : audio_params_(audio_params),
46 audio_chunk_duration_(base::TimeDelta::FromMilliseconds(
47 (audio_params_.frames_per_buffer() * 1000) /
48 audio_params_.sample_rate())),
49 task_runner_(task_runner),
50 event_handler_(event_handler),
51 dropped_packets_(0),
52 weak_ptr_factory_(this),
53 listening_(false) {
54 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
55 DCHECK(task_runner);
56 }
57
58 SpeechRecognitionAudioReceiver::~SpeechRecognitionAudioReceiver() {
59 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
60
61 // Make sure no new tasks are getting posted to the |task_runner_| and that we
62 // close the socket since the receiver is going away.
63 Stop();
64 }
65
66 bool SpeechRecognitionAudioReceiver::Initialize(
67 const base::ProcessHandle peer_process_handle,
68 base::SharedMemoryHandle* foreign_memory_handle,
69 base::SyncSocket::TransitDescriptor* foreign_socket_descriptor) {
70 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
71 DCHECK(foreign_memory_handle);
72 DCHECK(foreign_socket_descriptor);
73 DCHECK(!IsListening());
74
75 // All clean up on failure will be done by the destructor.
76 const size_t kSharedMemorySize = sizeof(media::AudioInputBufferParameters) +
77 media::AudioBus::CalculateMemorySize(audio_params_);
78 shared_memory_.reset(new base::SharedMemory());
79 if (!shared_memory_->CreateAndMapAnonymous(kSharedMemorySize)) {
80 DLOG(ERROR) << "Failed to create shared memory for the speech recognizer";
81 return false;
82 }
83 memset(shared_memory_->memory(), 0, kSharedMemorySize);
84
85 if (!shared_memory_->ShareToProcess(base::GetCurrentProcessHandle(),
86 foreign_memory_handle)) {
87 DLOG(ERROR) << "Failed to map and share the shared memory";
88 return false;
89 }
90
91 foreign_socket_.reset(new base::CancelableSyncSocket());
92 receiving_socket_.reset(new base::CancelableSyncSocket());
93 if (!base::SyncSocket::CreatePair(receiving_socket_.get(),
94 foreign_socket_.get())) {
95 DLOG(ERROR) << "Cannot create SyncSocket pair";
96 return false;
97 }
98
99 if (!foreign_socket_->PrepareTransitDescriptor(peer_process_handle,
100 foreign_socket_descriptor)) {
101 DLOG(ERROR) << "Cannot prepare syncsocket transit descriptor";
102 return false;
103 }
104
105 media::AudioInputBuffer* audio_buffer =
106 static_cast<media::AudioInputBuffer*>(shared_memory_->memory());
107 audio_bus_ = media::AudioBus::WrapMemory(audio_params_, audio_buffer->audio);
108 audio_bus_->Zero();
109
110 // Use |buffer->params.size| from shared memory to synchronize by counting
111 // audio buffers when receiving from the renderer.
112 audio_buffer->params.size = 0;
113
114 thread_checker_.DetachFromThread();
115
116 return true;
117 }
118
119 void SpeechRecognitionAudioReceiver::Listen() {
120 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
121 if (IsListening())
122 return;
123
124 // It will take at least 2 * |audio_chunk_duration_| ms for the producer to
125 // send the first packet, therefore we delay the task. We also allow a 100%
126 // time overhead on the socket receive timeout because the first packet
127 // usually arrives late (depending on the IPC and the renderer).
128 task_runner_->PostDelayedTask(
129 FROM_HERE,
130 base::Bind(&SpeechRecognitionAudioReceiver::Receive,
131 weak_ptr_factory_.GetWeakPtr(),
132 audio_chunk_duration_),
133 2 * audio_chunk_duration_);
134
135 SetListening(true);
136 }
137
138 void SpeechRecognitionAudioReceiver::Stop() {
no longer working on chromium 2014/10/17 12:28:10 you need to invalidate the weak pointer in this me
burnik 2014/10/23 13:56:36 Moved away from the weak ptr factory.
139 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
140 if (!IsListening())
141 return;
142
143 SetListening(false);
144
145 // We close the socket so the task runner thread doesn't block on it.
146 receiving_socket_->Shutdown();
147 }
148
149 void SpeechRecognitionAudioReceiver::Receive(
150 const base::TimeDelta& receive_timeout) {
151 DCHECK(thread_checker_.CalledOnValidThread());
152 DCHECK_LT(receive_timeout.InMilliseconds(), 1000);
153
154 // Maximum of consecutive dropped packets. When reached we trigger an error
155 // and stop reposting the task for |Receive()|.
156 static const uint32 kMaxDroppedPackets = 2;
157 static const size_t kSize = sizeof(media::AudioInputBufferParameters().size);
no longer working on chromium 2014/10/17 12:28:10 use sizeof(GetAudioBuffer()->params.size)
burnik 2014/10/23 13:56:36 Done.
158
159 // Receive with timeout not to block indefinitely. Ideally we block here for
160 // no time at all for all packets after the first one.
161 size_t bytes_received = receiving_socket_->ReceiveWithTimeout(
162 &(GetAudioBuffer()->params.size), kSize, receive_timeout);
163 DCHECK_EQ(0U, bytes_received % kSize);
164
165 // Register time to account for any delay before we repost the task.
166 const base::TimeTicks last_receive_time = base::TimeTicks::Now();
167
168 if (bytes_received == kSize) {
169 // Any previous issues with the socket are ignored.
170 dropped_packets_ = 0;
171
172 // Execute the client callback on this |task_runner_|'s thread.
173 event_handler_->OnData(NULL, audio_bus_.get());
174
175 // Notify host via shared memory that the buffer was consumed.
176 GetAudioBuffer()->params.size++;
177 } else {
178 // If Stop() was called we stop reposting the task.
179 if (!IsListening())
180 return;
181
182 // Socket issue: either a timeout occurred or socket is closed.
183 if (++dropped_packets_ >= kMaxDroppedPackets) {
184 DLOG(ERROR) << "Dropped max packets";
185 receiving_socket_->Shutdown();
186
187 // We have passed the limit of consecutive dropped packets so we trigger
188 // the error event.
189 event_handler_->OnError(
190 NULL, media::AudioInputController::UNKNOWN_ERROR);
191
192 return;
193 }
194 }
195
196 const base::TimeDelta time_delta = base::TimeTicks::Now() - last_receive_time;
no longer working on chromium 2014/10/17 12:28:10 I am a bit confused here, what does this time_delt
burnik 2014/10/23 13:56:36 Removed timing.
197 DCHECK_LE(time_delta.InMilliseconds(),
198 audio_chunk_duration_.InMilliseconds());
199
200 // Repost the task with allowing 50% delay on the socket receive.
201 base::MessageLoopProxy::current()->PostDelayedTask(
202 FROM_HERE,
203 base::Bind(&SpeechRecognitionAudioReceiver::Receive,
204 weak_ptr_factory_.GetWeakPtr(),
205 audio_chunk_duration_ / 2),
206 audio_chunk_duration_ - time_delta);
207 }
208
209 media::AudioInputBuffer* SpeechRecognitionAudioReceiver::GetAudioBuffer() {
210 DCHECK(thread_checker_.CalledOnValidThread());
211 DCHECK_GE(shared_memory_->mapped_size(), shared_memory_->requested_size());
212 return static_cast<media::AudioInputBuffer*>(shared_memory_->memory());
213 }
214
215 bool SpeechRecognitionAudioReceiver::IsListening() {
216 base::AutoLock lock(listening_lock_);
217 return listening_;
218 }
219
220 void SpeechRecognitionAudioReceiver::SetListening(const bool listening) {
221 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
222 base::AutoLock lock(listening_lock_);
223 listening_ = listening;
224 }
225
226 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698