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

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
15 namespace copresence {
16
17 namespace { 17 namespace {
18 18
19 // UrlSafe is defined as: 19 base::Time GetClosestEventTime(AudioDirectiveList* list,
Daniel Erat 2014/10/18 21:21:18 nit: GetEarliestEventTime?
rkc 2014/10/20 16:45:37 Done.
20 // '/' represented by a '_' and '+' represented by a '-' 20 base::Time event_time) {
21 // TODO(rkc): Move this processing to the whispernet wrapper. 21 if (list->GetActiveDirective())
22 std::string FromUrlSafe(std::string token) { 22 return std::min(list->GetActiveDirective()->end_time, event_time);
23 base::ReplaceChars(token, "-", "+", &token); 23 return event_time;
24 base::ReplaceChars(token, "_", "/", &token);
25 return token;
26 } 24 }
27 25
28 const int kSampleExpiryTimeMs = 60 * 60 * 1000; // 60 minutes.
29 const int kMaxSamples = 10000;
30
31 } // namespace 26 } // namespace
32 27
33 namespace copresence {
34
35 // Public methods. 28 // Public methods.
36 29
37 AudioDirectiveHandler::AudioDirectiveHandler( 30 AudioDirectiveHandler::AudioDirectiveHandler() {
38 const AudioRecorder::DecodeSamplesCallback& decode_cb,
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 } 31 }
52 32
53 AudioDirectiveHandler::~AudioDirectiveHandler() { 33 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 } 34 }
61 35
62 void AudioDirectiveHandler::Initialize() { 36 void AudioDirectiveHandler::Initialize(
63 player_audible_ = new AudioPlayer(); 37 const AudioManager::DecodeSamplesCallback& decode_cb,
64 player_audible_->Initialize(); 38 const AudioManager::EncodeTokenCallback& encode_cb) {
65 39 audio_manager_ = make_scoped_ptr(new AudioManager());
Daniel Erat 2014/10/18 21:21:17 just do audio_manager_.reset(new AudioManager);
rkc 2014/10/20 16:45:37 Done.
66 player_inaudible_ = new AudioPlayer(); 40 audio_manager_->Initialize(decode_cb, encode_cb);
67 player_inaudible_->Initialize();
68
69 recorder_ = new AudioRecorder(decode_cb_);
70 recorder_->Initialize();
71 } 41 }
72 42
73 void AudioDirectiveHandler::AddInstruction(const TokenInstruction& instruction, 43 void AudioDirectiveHandler::AddInstruction(const TokenInstruction& instruction,
74 const std::string& op_id, 44 const std::string& op_id,
75 base::TimeDelta ttl) { 45 base::TimeDelta ttl) {
76 switch (instruction.token_instruction_type()) { 46 switch (instruction.token_instruction_type()) {
77 case TRANSMIT: 47 case TRANSMIT:
78 DVLOG(2) << "Audio Transmit Directive received. Token: " 48 DVLOG(2) << "Audio Transmit Directive received. Token: "
79 << instruction.token_id() 49 << instruction.token_id()
50 << " with medium= " << instruction.medium()
80 << " with TTL=" << ttl.InMilliseconds(); 51 << " with TTL=" << ttl.InMilliseconds();
81 switch (instruction.medium()) { 52 switch (instruction.medium()) {
82 case AUDIO_ULTRASOUND_PASSBAND: 53 case AUDIO_ULTRASOUND_PASSBAND:
83 transmits_list_inaudible_.AddDirective(op_id, ttl); 54 transmits_list_[INAUDIBLE].AddDirective(op_id, ttl);
84 PlayToken(instruction.token_id(), false); 55 audio_manager_->SetToken(INAUDIBLE, instruction.token_id());
85 break; 56 break;
86 case AUDIO_AUDIBLE_DTMF: 57 case AUDIO_AUDIBLE_DTMF:
87 transmits_list_audible_.AddDirective(op_id, ttl); 58 transmits_list_[AUDIBLE].AddDirective(op_id, ttl);
88 PlayToken(instruction.token_id(), true); 59 audio_manager_->SetToken(AUDIBLE, instruction.token_id());
89 break; 60 break;
90 default: 61 default:
91 NOTREACHED(); 62 NOTREACHED();
92 } 63 }
93 break; 64 break;
94 case RECEIVE: 65 case RECEIVE:
95 DVLOG(2) << "Audio Receive Directive received. TTL=" 66 DVLOG(2) << "Audio Receive Directive received."
96 << ttl.InMilliseconds(); 67 << " with medium= " << instruction.medium()
97 receives_list_.AddDirective(op_id, ttl); 68 << " with TTL=" << ttl.InMilliseconds();
98 ProcessNextReceive(); 69 switch (instruction.medium()) {
70 case AUDIO_ULTRASOUND_PASSBAND:
71 receives_list_[INAUDIBLE].AddDirective(op_id, ttl);
72 break;
73 case AUDIO_AUDIBLE_DTMF:
74 receives_list_[AUDIBLE].AddDirective(op_id, ttl);
75 break;
76 default:
77 NOTREACHED();
78 }
99 break; 79 break;
100 case UNKNOWN_TOKEN_INSTRUCTION_TYPE: 80 case UNKNOWN_TOKEN_INSTRUCTION_TYPE:
101 default: 81 default:
102 LOG(WARNING) << "Unknown Audio Transmit Directive received."; 82 LOG(WARNING) << "Unknown Audio Transmit Directive received. type = "
83 << instruction.token_instruction_type();
103 } 84 }
85 ProcessNextInstruction();
104 } 86 }
105 87
106 void AudioDirectiveHandler::RemoveInstructions(const std::string& op_id) { 88 void AudioDirectiveHandler::RemoveInstructions(const std::string& op_id) {
107 transmits_list_audible_.RemoveDirective(op_id); 89 transmits_list_[AUDIBLE].RemoveDirective(op_id);
108 transmits_list_inaudible_.RemoveDirective(op_id); 90 transmits_list_[INAUDIBLE].RemoveDirective(op_id);
109 receives_list_.RemoveDirective(op_id); 91 receives_list_[AUDIBLE].RemoveDirective(op_id);
92 receives_list_[INAUDIBLE].RemoveDirective(op_id);
110 93
111 ProcessNextTransmit(); 94 ProcessNextInstruction();
112 ProcessNextReceive();
113 } 95 }
114 96
115 // Private methods. 97 // Private methods.
116 98
117 void AudioDirectiveHandler::ProcessNextTransmit() { 99 void AudioDirectiveHandler::ProcessNextInstruction() {
118 // If we have an active directive for audible or inaudible audio, ensure that 100 if (audio_event_timer_.IsRunning())
Daniel Erat 2014/10/18 21:21:17 you can just call Stop() unconditionally without c
rkc 2014/10/20 16:45:37 Done.
119 // we are playing our respective token; if we do not have a directive, then 101 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 102
123 scoped_ptr<AudioDirective> audible_transmit( 103 // Change audio_manager_ state for audible transmits.
124 transmits_list_audible_.GetActiveDirective()); 104 if (transmits_list_[AUDIBLE].GetActiveDirective())
125 if (audible_transmit && !player_audible_->IsPlaying() && 105 audio_manager_->StartPlaying(AUDIBLE);
126 samples_cache_audible_.HasKey(current_token_audible_)) { 106 else
127 DVLOG(3) << "Playing audible for op_id: " << audible_transmit->op_id; 107 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 }
141 108
142 scoped_ptr<AudioDirective> inaudible_transmit( 109 // Change audio_manager_ state for inaudible transmits.
143 transmits_list_inaudible_.GetActiveDirective()); 110 if (transmits_list_[INAUDIBLE].GetActiveDirective())
144 if (inaudible_transmit && !player_inaudible_->IsPlaying() && 111 audio_manager_->StartPlaying(INAUDIBLE);
145 samples_cache_inaudible_.HasKey(current_token_inaudible_)) { 112 else
146 DVLOG(3) << "Playing inaudible for op_id: " << inaudible_transmit->op_id; 113 audio_manager_->StopPlaying(INAUDIBLE);
147 player_inaudible_->Play( 114
148 samples_cache_inaudible_.GetValue(current_token_inaudible_)); 115 // Change audio_manager_ state for audible receives.
149 stop_inaudible_playback_timer_.Start( 116 if (receives_list_[AUDIBLE].GetActiveDirective())
150 FROM_HERE, 117 audio_manager_->StartRecording(AUDIBLE);
151 inaudible_transmit->end_time - base::Time::Now(), 118 else
152 this, 119 audio_manager_->StopRecording(AUDIBLE);
153 &AudioDirectiveHandler::ProcessNextTransmit); 120
154 } else if (!inaudible_transmit && player_inaudible_->IsPlaying()) { 121 // Change audio_manager_ state for inaudible receives.
155 DVLOG(3) << "Stopping inaudible playback."; 122 if (receives_list_[INAUDIBLE].GetActiveDirective())
156 current_token_inaudible_.clear(); 123 audio_manager_->StartRecording(INAUDIBLE);
157 stop_inaudible_playback_timer_.Stop(); 124 else
158 player_inaudible_->Stop(); 125 audio_manager_->StopRecording(INAUDIBLE);
126
127 base::TimeDelta next_event_time = NextInstructionExpiry();
128 if (next_event_time > base::TimeDelta::FromMilliseconds(0)) {
129 audio_event_timer_.Start(FROM_HERE,
130 next_event_time,
131 this,
132 &AudioDirectiveHandler::ProcessNextInstruction);
159 } 133 }
160 } 134 }
161 135
162 void AudioDirectiveHandler::ProcessNextReceive() { 136 base::TimeDelta AudioDirectiveHandler::NextInstructionExpiry() {
Daniel Erat 2014/10/18 21:21:17 nit: rename to GetNextInstructionExpiry()
rkc 2014/10/20 16:45:37 Done.
163 scoped_ptr<AudioDirective> receive(receives_list_.GetActiveDirective()); 137 // We cache now, since, calling Now() twice doesn't guarantee that the time
138 // will increase (it may even decrease). This ensures that if we have no
139 // instructions, we return back a 0 time.
140 base::Time now = base::Time::Now();
164 141
165 if (receive && !recorder_->IsRecording()) { 142 base::Time next_event = GetClosestEventTime(&transmits_list_[AUDIBLE], now);
166 DVLOG(3) << "Recording for op_id: " << receive->op_id; 143 next_event = GetClosestEventTime(&transmits_list_[INAUDIBLE], next_event);
167 recorder_->Record(); 144 next_event = GetClosestEventTime(&receives_list_[AUDIBLE], next_event);
168 stop_recording_timer_.Start(FROM_HERE, 145 next_event = GetClosestEventTime(&receives_list_[INAUDIBLE], next_event);
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 }
177 }
178 146
179 void AudioDirectiveHandler::PlayToken(const std::string token, bool audible) { 147 return next_event - now;
180 std::string valid_token = FromUrlSafe(token);
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 }
196 }
197
198 void AudioDirectiveHandler::PlayEncodedToken(
199 const std::string& token,
200 bool audible,
201 const scoped_refptr<media::AudioBusRefCounted>& samples) {
202 DVLOG(3) << "Token " << token << "[audible:" << audible << "] encoded.";
203 if (audible) {
204 samples_cache_audible_.Add(token, samples);
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 }
216
217 ProcessNextTransmit();
218 } 148 }
219 149
220 } // namespace copresence 150 } // namespace copresence
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698