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

Side by Side Diff: components/copresence/handlers/audio/audio_directive_handler.cc

Issue 637223011: Redesign the copresence audio handlers. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git/+/master
Patch Set: 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
1 // Copyright 2014 The Chromium Authors. All rights reserved. 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 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 "components/copresence/handlers/audio/audio_directive_handler.h" 5 #include "components/copresence/handlers/audio/audio_directive_handler.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/logging.h" 8 #include "base/logging.h"
9 #include "base/memory/scoped_ptr.h" 9 #include "base/memory/scoped_ptr.h"
10 #include "base/strings/string_util.h"
11 #include "base/time/time.h" 10 #include "base/time/time.h"
12 #include "components/copresence/mediums/audio/audio_player.h"
13 #include "components/copresence/mediums/audio/audio_recorder.h"
14 #include "components/copresence/proto/data.pb.h" 11 #include "components/copresence/proto/data.pb.h"
12 #include "components/copresence/public/copresence_constants.h"
15 #include "media/base/audio_bus.h" 13 #include "media/base/audio_bus.h"
16 14
17 namespace {
18
19 // UrlSafe is defined as:
20 // '/' represented by a '_' and '+' represented by a '-'
21 // TODO(rkc): Move this processing to the whispernet wrapper.
22 std::string FromUrlSafe(std::string token) {
23 base::ReplaceChars(token, "-", "+", &token);
24 base::ReplaceChars(token, "_", "/", &token);
25 return token;
26 }
27
28 const int kSampleExpiryTimeMs = 60 * 60 * 1000; // 60 minutes.
29 const int kMaxSamples = 10000;
30
31 } // namespace
32
33 namespace copresence { 15 namespace copresence {
34 16
35 // Public methods. 17 // Public methods.
36 18
37 AudioDirectiveHandler::AudioDirectiveHandler( 19 AudioDirectiveHandler::AudioDirectiveHandler()
38 const AudioRecorder::DecodeSamplesCallback& decode_cb, 20 : audio_manager_(make_scoped_ptr<AudioManager>(NULL)) {
Daniel Erat 2014/10/17 22:25:59 don't think you need this; scoped_ptr's default c'
rkc 2014/10/18 00:21:54 Done.
39 const AudioDirectiveHandler::EncodeTokenCallback& encode_cb)
40 : player_audible_(NULL),
41 player_inaudible_(NULL),
42 recorder_(NULL),
43 decode_cb_(decode_cb),
44 encode_cb_(encode_cb),
45 samples_cache_audible_(
46 base::TimeDelta::FromMilliseconds(kSampleExpiryTimeMs),
47 kMaxSamples),
48 samples_cache_inaudible_(
49 base::TimeDelta::FromMilliseconds(kSampleExpiryTimeMs),
50 kMaxSamples) {
51 } 21 }
52 22
53 AudioDirectiveHandler::~AudioDirectiveHandler() { 23 AudioDirectiveHandler::~AudioDirectiveHandler() {
54 if (player_audible_)
55 player_audible_->Finalize();
56 if (player_inaudible_)
57 player_inaudible_->Finalize();
58 if (recorder_)
59 recorder_->Finalize();
60 } 24 }
61 25
62 void AudioDirectiveHandler::Initialize() { 26 void AudioDirectiveHandler::Initialize(
63 player_audible_ = new AudioPlayer(); 27 const AudioManager::DecodeSamplesCallback& decode_cb,
64 player_audible_->Initialize(); 28 const AudioManager::EncodeTokenCallback& encode_cb) {
65 29 audio_manager_ = make_scoped_ptr(new AudioManager());
66 player_inaudible_ = new AudioPlayer(); 30 audio_manager_->Initialize(decode_cb, encode_cb);
67 player_inaudible_->Initialize();
68
69 recorder_ = new AudioRecorder(decode_cb_);
70 recorder_->Initialize();
71 } 31 }
72 32
73 void AudioDirectiveHandler::AddInstruction(const TokenInstruction& instruction, 33 void AudioDirectiveHandler::AddInstruction(const TokenInstruction& instruction,
74 const std::string& op_id, 34 const std::string& op_id,
75 base::TimeDelta ttl) { 35 base::TimeDelta ttl) {
76 switch (instruction.token_instruction_type()) { 36 switch (instruction.token_instruction_type()) {
77 case TRANSMIT: 37 case TRANSMIT:
78 DVLOG(2) << "Audio Transmit Directive received. Token: " 38 DVLOG(2) << "Audio Transmit Directive received. Token: "
79 << instruction.token_id() 39 << instruction.token_id()
40 << " with medium= " << instruction.medium()
80 << " with TTL=" << ttl.InMilliseconds(); 41 << " with TTL=" << ttl.InMilliseconds();
81 switch (instruction.medium()) { 42 switch (instruction.medium()) {
82 case AUDIO_ULTRASOUND_PASSBAND: 43 case AUDIO_ULTRASOUND_PASSBAND:
83 transmits_list_inaudible_.AddDirective(op_id, ttl); 44 transmits_list_[INAUDIBLE].AddDirective(op_id, ttl);
84 PlayToken(instruction.token_id(), false); 45 audio_manager_->SetToken(INAUDIBLE, instruction.token_id());
85 break; 46 break;
86 case AUDIO_AUDIBLE_DTMF: 47 case AUDIO_AUDIBLE_DTMF:
87 transmits_list_audible_.AddDirective(op_id, ttl); 48 transmits_list_[AUDIBLE].AddDirective(op_id, ttl);
88 PlayToken(instruction.token_id(), true); 49 audio_manager_->SetToken(AUDIBLE, instruction.token_id());
89 break; 50 break;
90 default: 51 default:
91 NOTREACHED(); 52 NOTREACHED();
92 } 53 }
93 break; 54 break;
94 case RECEIVE: 55 case RECEIVE:
95 DVLOG(2) << "Audio Receive Directive received. TTL=" 56 DVLOG(2) << "Audio Receive Directive received."
96 << ttl.InMilliseconds(); 57 << " with medium= " << instruction.medium()
97 receives_list_.AddDirective(op_id, ttl); 58 << " with TTL=" << ttl.InMilliseconds();
98 ProcessNextReceive(); 59 switch (instruction.medium()) {
60 case AUDIO_ULTRASOUND_PASSBAND:
61 receives_list_[INAUDIBLE].AddDirective(op_id, ttl);
62 break;
63 case AUDIO_AUDIBLE_DTMF:
64 receives_list_[AUDIBLE].AddDirective(op_id, ttl);
65 break;
66 default:
67 NOTREACHED();
68 }
99 break; 69 break;
100 case UNKNOWN_TOKEN_INSTRUCTION_TYPE: 70 case UNKNOWN_TOKEN_INSTRUCTION_TYPE:
101 default: 71 default:
102 LOG(WARNING) << "Unknown Audio Transmit Directive received."; 72 LOG(WARNING) << "Unknown Audio Transmit Directive received. type = "
73 << instruction.token_instruction_type();
103 } 74 }
75 ProcessNextInstruction();
104 } 76 }
105 77
106 void AudioDirectiveHandler::RemoveInstructions(const std::string& op_id) { 78 void AudioDirectiveHandler::RemoveInstructions(const std::string& op_id) {
107 transmits_list_audible_.RemoveDirective(op_id); 79 transmits_list_[AUDIBLE].RemoveDirective(op_id);
108 transmits_list_inaudible_.RemoveDirective(op_id); 80 transmits_list_[INAUDIBLE].RemoveDirective(op_id);
109 receives_list_.RemoveDirective(op_id); 81 receives_list_[AUDIBLE].RemoveDirective(op_id);
82 receives_list_[INAUDIBLE].RemoveDirective(op_id);
110 83
111 ProcessNextTransmit(); 84 ProcessNextInstruction();
112 ProcessNextReceive();
113 } 85 }
114 86
115 // Private methods. 87 // Private methods.
116 88
117 void AudioDirectiveHandler::ProcessNextTransmit() { 89 void AudioDirectiveHandler::ProcessNextInstruction() {
118 // If we have an active directive for audible or inaudible audio, ensure that 90 if (audio_event_timer_.IsRunning())
119 // we are playing our respective token; if we do not have a directive, then 91 audio_event_timer_.Stop();
120 // make sure we aren't playing. This is duplicate code, but for just two
121 // elements, it has hard to make a case for processing a loop instead.
122 92
123 scoped_ptr<AudioDirective> audible_transmit( 93 // Change audio_manager_ state for audible transmits.
124 transmits_list_audible_.GetActiveDirective()); 94 if (transmits_list_[AUDIBLE].GetActiveDirective()) {
Daniel Erat 2014/10/17 22:25:59 nit: omit curly brackets here and below
rkc 2014/10/18 00:21:54 Done.
125 if (audible_transmit && !player_audible_->IsPlaying() && 95 audio_manager_->StartPlaying(AUDIBLE);
126 samples_cache_audible_.HasKey(current_token_audible_)) { 96 } else {
127 DVLOG(3) << "Playing audible for op_id: " << audible_transmit->op_id; 97 audio_manager_->StopPlaying(AUDIBLE);
128 player_audible_->Play(
129 samples_cache_audible_.GetValue(current_token_audible_));
130 stop_audible_playback_timer_.Start(
131 FROM_HERE,
132 audible_transmit->end_time - base::Time::Now(),
133 this,
134 &AudioDirectiveHandler::ProcessNextTransmit);
135 } else if (!audible_transmit && player_audible_->IsPlaying()) {
136 DVLOG(3) << "Stopping audible playback.";
137 current_token_audible_.clear();
138 stop_audible_playback_timer_.Stop();
139 player_audible_->Stop();
140 } 98 }
141 99
142 scoped_ptr<AudioDirective> inaudible_transmit( 100 // Change audio_manager_ state for inaudible transmits.
143 transmits_list_inaudible_.GetActiveDirective()); 101 if (transmits_list_[INAUDIBLE].GetActiveDirective()) {
144 if (inaudible_transmit && !player_inaudible_->IsPlaying() && 102 audio_manager_->StartPlaying(INAUDIBLE);
145 samples_cache_inaudible_.HasKey(current_token_inaudible_)) { 103 } else {
146 DVLOG(3) << "Playing inaudible for op_id: " << inaudible_transmit->op_id; 104 audio_manager_->StopPlaying(INAUDIBLE);
147 player_inaudible_->Play( 105 }
148 samples_cache_inaudible_.GetValue(current_token_inaudible_)); 106
149 stop_inaudible_playback_timer_.Start( 107 // Change audio_manager_ state for audible receives.
150 FROM_HERE, 108 if (receives_list_[AUDIBLE].GetActiveDirective()) {
151 inaudible_transmit->end_time - base::Time::Now(), 109 audio_manager_->StartRecording(AUDIBLE);
152 this, 110 } else {
153 &AudioDirectiveHandler::ProcessNextTransmit); 111 audio_manager_->StopRecording(AUDIBLE);
154 } else if (!inaudible_transmit && player_inaudible_->IsPlaying()) { 112 }
155 DVLOG(3) << "Stopping inaudible playback."; 113
156 current_token_inaudible_.clear(); 114 // Change audio_manager_ state for inaudible receives.
157 stop_inaudible_playback_timer_.Stop(); 115 if (receives_list_[INAUDIBLE].GetActiveDirective()) {
158 player_inaudible_->Stop(); 116 audio_manager_->StartRecording(INAUDIBLE);
117 } else {
118 audio_manager_->StopRecording(INAUDIBLE);
119 }
120
121 base::TimeDelta next_event_time = NextInstructionExpiry();
122 if (next_event_time > base::TimeDelta::FromMilliseconds(0)) {
123 audio_event_timer_.Start(FROM_HERE,
124 next_event_time,
125 this,
126 &AudioDirectiveHandler::ProcessNextInstruction);
159 } 127 }
160 } 128 }
161 129
162 void AudioDirectiveHandler::ProcessNextReceive() { 130 base::TimeDelta AudioDirectiveHandler::NextInstructionExpiry() {
163 scoped_ptr<AudioDirective> receive(receives_list_.GetActiveDirective()); 131 // We cache now, since, calling Now() twice doesn't gaurantee that the time
Daniel Erat 2014/10/17 22:25:59 nit: guarantee
rkc 2014/10/18 00:21:54 Done.
132 // will increase (it may even decrease). This ensures that if we have no
133 // instructions, we return back a 0 time.
134 base::Time now = base::Time::Now();
164 135
165 if (receive && !recorder_->IsRecording()) { 136 base::Time closest_event_time = now;
166 DVLOG(3) << "Recording for op_id: " << receive->op_id; 137 if (transmits_list_[AUDIBLE].GetActiveDirective()) {
167 recorder_->Record(); 138 closest_event_time =
168 stop_recording_timer_.Start(FROM_HERE, 139 transmits_list_[AUDIBLE].GetActiveDirective()->end_time;
169 receive->end_time - base::Time::Now(),
170 this,
171 &AudioDirectiveHandler::ProcessNextReceive);
172 } else if (!receive && recorder_->IsRecording()) {
173 DVLOG(3) << "Stopping Recording";
174 stop_recording_timer_.Stop();
175 recorder_->Stop();
176 } 140 }
177 } 141 if (transmits_list_[INAUDIBLE].GetActiveDirective()) {
Daniel Erat 2014/10/17 22:25:59 how about moving this into a helper function so it
rkc 2014/10/18 00:21:54 Done.
178 142 closest_event_time =
179 void AudioDirectiveHandler::PlayToken(const std::string token, bool audible) { 143 std::min(transmits_list_[INAUDIBLE].GetActiveDirective()->end_time,
180 std::string valid_token = FromUrlSafe(token); 144 closest_event_time);
181
182 // If the token has been encoded already, use the cached samples.
183 if (audible && samples_cache_audible_.HasKey(valid_token)) {
184 current_token_audible_ = token;
185 ProcessNextTransmit();
186 } else if (!audible && samples_cache_inaudible_.HasKey(valid_token)) {
187 current_token_inaudible_ = token;
188 ProcessNextTransmit();
189 } else {
190 // Otherwise, encode the token and then play it.
191 encode_cb_.Run(valid_token,
192 audible,
193 base::Bind(&AudioDirectiveHandler::PlayEncodedToken,
194 base::Unretained(this)));
195 } 145 }
196 } 146 if (receives_list_[AUDIBLE].GetActiveDirective()) {
197 147 closest_event_time =
198 void AudioDirectiveHandler::PlayEncodedToken( 148 std::min(receives_list_[AUDIBLE].GetActiveDirective()->end_time,
199 const std::string& token, 149 closest_event_time);
200 bool audible, 150 }
201 const scoped_refptr<media::AudioBusRefCounted>& samples) { 151 if (receives_list_[INAUDIBLE].GetActiveDirective()) {
202 DVLOG(3) << "Token " << token << "[audible:" << audible << "] encoded."; 152 closest_event_time =
203 if (audible) { 153 std::min(receives_list_[INAUDIBLE].GetActiveDirective()->end_time,
204 samples_cache_audible_.Add(token, samples); 154 closest_event_time);
205 current_token_audible_ = token;
206 // Force process transmits to pick up the new token.
207 if (player_audible_->IsPlaying())
208 player_audible_->Stop();
209 } else {
210 samples_cache_inaudible_.Add(token, samples);
211 current_token_inaudible_ = token;
212 // Force process transmits to pick up the new token.
213 if (player_inaudible_->IsPlaying())
214 player_inaudible_->Stop();
215 } 155 }
216 156
217 ProcessNextTransmit(); 157 return closest_event_time - now;
218 } 158 }
219 159
220 } // namespace copresence 160 } // namespace copresence
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698