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

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

Issue 461803003: Stop playing/recording when not needed. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 6 years, 4 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 | Annotate | Revision Log
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 <algorithm>
8
9 #include "base/bind.h" 7 #include "base/bind.h"
10 #include "base/logging.h" 8 #include "base/logging.h"
11 #include "base/memory/scoped_ptr.h" 9 #include "base/memory/scoped_ptr.h"
10 #include "base/strings/string_util.h"
12 #include "base/time/time.h" 11 #include "base/time/time.h"
13 #include "components/copresence/mediums/audio/audio_player.h" 12 #include "components/copresence/mediums/audio/audio_player.h"
14 #include "components/copresence/mediums/audio/audio_recorder.h" 13 #include "components/copresence/mediums/audio/audio_recorder.h"
15 #include "components/copresence/proto/data.pb.h" 14 #include "components/copresence/proto/data.pb.h"
16 #include "media/base/audio_bus.h" 15 #include "media/base/audio_bus.h"
17 16
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
18 namespace copresence { 33 namespace copresence {
19 34
20 // Public methods. 35 // Public methods.
21 36
22 AudioDirectiveHandler::AudioDirectiveHandler( 37 AudioDirectiveHandler::AudioDirectiveHandler(
23 const AudioRecorder::DecodeSamplesCallback& decode_cb, 38 const AudioRecorder::DecodeSamplesCallback& decode_cb,
24 const AudioDirectiveList::EncodeTokenCallback& encode_cb) 39 const AudioDirectiveHandler::EncodeTokenCallback& encode_cb)
25 : directive_list_inaudible_( 40 : player_audible_(NULL),
26 encode_cb, 41 player_inaudible_(NULL),
27 base::Bind(&AudioDirectiveHandler::ExecuteNextTransmit,
28 base::Unretained(this)),
29 false),
30 directive_list_audible_(
31 encode_cb,
32 base::Bind(&AudioDirectiveHandler::ExecuteNextTransmit,
33 base::Unretained(this)),
34 true),
35 player_(NULL),
36 recorder_(NULL), 42 recorder_(NULL),
37 decode_cb_(decode_cb) { 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) {
38 } 51 }
39 52
40 AudioDirectiveHandler::~AudioDirectiveHandler() { 53 AudioDirectiveHandler::~AudioDirectiveHandler() {
41 if (player_) 54 if (player_audible_)
42 player_->Finalize(); 55 player_audible_->Finalize();
56 if (player_inaudible_)
57 player_inaudible_->Finalize();
43 if (recorder_) 58 if (recorder_)
44 recorder_->Finalize(); 59 recorder_->Finalize();
45 } 60 }
46 61
47 void AudioDirectiveHandler::Initialize() { 62 void AudioDirectiveHandler::Initialize() {
48 player_ = new AudioPlayer(); 63 player_audible_ = new AudioPlayer();
49 player_->Initialize(); 64 player_audible_->Initialize();
65
66 player_inaudible_ = new AudioPlayer();
67 player_inaudible_->Initialize();
50 68
51 recorder_ = new AudioRecorder(decode_cb_); 69 recorder_ = new AudioRecorder(decode_cb_);
52 recorder_->Initialize(); 70 recorder_->Initialize();
53 } 71 }
54 72
55 void AudioDirectiveHandler::AddInstruction(const TokenInstruction& instruction, 73 void AudioDirectiveHandler::AddInstruction(const TokenInstruction& instruction,
74 const std::string& op_id,
56 base::TimeDelta ttl) { 75 base::TimeDelta ttl) {
57 switch (instruction.token_instruction_type()) { 76 switch (instruction.token_instruction_type()) {
58 case TRANSMIT: 77 case TRANSMIT:
59 DVLOG(2) << "Audio Transmit Directive received. Token: " 78 DVLOG(2) << "Audio Transmit Directive received. Token: "
60 << instruction.token_id() 79 << instruction.token_id()
61 << " with TTL=" << ttl.InMilliseconds(); 80 << " with TTL=" << ttl.InMilliseconds();
62 // TODO(rkc): Fill in the op_id once we get it from the directive.
63 switch (instruction.medium()) { 81 switch (instruction.medium()) {
64 case AUDIO_ULTRASOUND_PASSBAND: 82 case AUDIO_ULTRASOUND_PASSBAND:
65 directive_list_inaudible_.AddTransmitDirective( 83 transmits_list_inaudible_.AddDirective(op_id, ttl);
66 instruction.token_id(), std::string(), ttl); 84 HandleToken(instruction.token_id(), false);
67 break; 85 break;
68 case AUDIO_AUDIBLE_DTMF: 86 case AUDIO_AUDIBLE_DTMF:
69 directive_list_audible_.AddTransmitDirective( 87 transmits_list_audible_.AddDirective(op_id, ttl);
70 instruction.token_id(), std::string(), ttl); 88 HandleToken(instruction.token_id(), true);
71 break; 89 break;
72 default: 90 default:
73 NOTREACHED(); 91 NOTREACHED();
74 } 92 }
75 break; 93 break;
76 case RECEIVE: 94 case RECEIVE:
77 DVLOG(2) << "Audio Receive Directive received. TTL=" 95 DVLOG(2) << "Audio Receive Directive received. TTL="
78 << ttl.InMilliseconds(); 96 << ttl.InMilliseconds();
79 // TODO(rkc): Fill in the op_id once we get it from the directive. 97 receives_list_.AddDirective(op_id, ttl);
80 switch (instruction.medium()) {
81 case AUDIO_ULTRASOUND_PASSBAND:
82 directive_list_inaudible_.AddReceiveDirective(std::string(), ttl);
83 break;
84 case AUDIO_AUDIBLE_DTMF:
85 directive_list_audible_.AddReceiveDirective(std::string(), ttl);
86 break;
87 default:
88 NOTREACHED();
89 }
90 break; 98 break;
91 case UNKNOWN_TOKEN_INSTRUCTION_TYPE: 99 case UNKNOWN_TOKEN_INSTRUCTION_TYPE:
92 default: 100 default:
93 LOG(WARNING) << "Unknown Audio Transmit Directive received."; 101 LOG(WARNING) << "Unknown Audio Transmit Directive received.";
94 } 102 }
95 // ExecuteNextTransmit will be called by directive_list_ when Add is done. 103 // ExecuteNextTransmit will be called by directive_list_ when Add is done.
96 ExecuteNextReceive(); 104 ProcessNextReceive();
97 } 105 }
98 106
99 // Protected methods. 107 void AudioDirectiveHandler::RemoveInstructions(const std::string& op_id) {
108 transmits_list_audible_.RemoveDirective(op_id);
109 transmits_list_inaudible_.RemoveDirective(op_id);
110 receives_list_.RemoveDirective(op_id);
100 111
101 void AudioDirectiveHandler::PlayAudio( 112 ProcessNextTransmit();
102 const scoped_refptr<media::AudioBusRefCounted>& samples, 113 ProcessNextReceive();
103 base::TimeDelta duration) {
104 player_->Play(samples);
105 stop_playback_timer_.Start(
106 FROM_HERE, duration, this, &AudioDirectiveHandler::StopPlayback);
107 } 114 }
108 115
109 void AudioDirectiveHandler::RecordAudio(base::TimeDelta duration) { 116 const std::string& AudioDirectiveHandler::PlayingAudibleToken() {
110 recorder_->Record(); 117 return current_token_audible_;
111 stop_recording_timer_.Start( 118 }
112 FROM_HERE, duration, this, &AudioDirectiveHandler::StopRecording); 119
120 const std::string& AudioDirectiveHandler::PlayingInaudibleToken() {
121 return current_token_inaudible_;
113 } 122 }
114 123
115 // Private methods. 124 // Private methods.
116 125
117 void AudioDirectiveHandler::StopPlayback() { 126 void AudioDirectiveHandler::ProcessNextTransmit() {
118 player_->Stop(); 127 // If we have an active directive for audible or inaudible audio, ensure that
119 DVLOG(2) << "Done playing audio."; 128 // we are playing our respective token; if we do not have a directive, then
120 ExecuteNextTransmit(); 129 // make sure we aren't playing. This is duplicate code, but for just two
121 } 130 // elements, it has hard to make a case for processing a loop instead.
122 131
123 void AudioDirectiveHandler::StopRecording() { 132 scoped_ptr<AudioDirective> audible_transmit(
124 recorder_->Stop(); 133 transmits_list_audible_.GetActiveDirective());
125 DVLOG(2) << "Done recording audio."; 134 if (audible_transmit && !player_audible_->IsPlaying()) {
126 ExecuteNextReceive(); 135 DVLOG(3) << "Playing audible for op_id: " << audible_transmit->op_id;
127 } 136 player_audible_->Play(
137 samples_cache_audible_.GetValue(current_token_audible_));
138 stop_audible_playback_timer_.Start(
139 FROM_HERE,
140 audible_transmit->end_time - base::Time::Now(),
141 this,
142 &AudioDirectiveHandler::ProcessNextTransmit);
143 } else if (!audible_transmit && player_audible_->IsPlaying()) {
144 DVLOG(3) << "Stopping audible playback.";
145 current_token_audible_.clear();
146 stop_audible_playback_timer_.Stop();
147 player_audible_->Stop();
148 }
128 149
129 void AudioDirectiveHandler::ExecuteNextTransmit() {
130 scoped_ptr<AudioDirective> audible_transmit(
131 directive_list_audible_.GetNextTransmit());
132 scoped_ptr<AudioDirective> inaudible_transmit( 150 scoped_ptr<AudioDirective> inaudible_transmit(
133 directive_list_inaudible_.GetNextTransmit()); 151 transmits_list_inaudible_.GetActiveDirective());
134 152 if (inaudible_transmit && !player_inaudible_->IsPlaying()) {
135 if (inaudible_transmit) { 153 DVLOG(3) << "Playing inaudible for op_id: " << inaudible_transmit->op_id;
136 PlayAudio(inaudible_transmit->samples, 154 player_inaudible_->Play(
137 inaudible_transmit->end_time - base::Time::Now()); 155 samples_cache_inaudible_.GetValue(current_token_inaudible_));
138 } 156 stop_inaudible_playback_timer_.Start(
139 if (audible_transmit) { 157 FROM_HERE,
140 PlayAudio(audible_transmit->samples, 158 inaudible_transmit->end_time - base::Time::Now(),
141 audible_transmit->end_time - base::Time::Now()); 159 this,
160 &AudioDirectiveHandler::ProcessNextTransmit);
161 } else if (!inaudible_transmit && player_inaudible_->IsPlaying()) {
162 DVLOG(3) << "Stopping inaudible playback.";
163 current_token_inaudible_.clear();
164 stop_inaudible_playback_timer_.Stop();
165 player_inaudible_->Stop();
142 } 166 }
143 } 167 }
144 168
145 void AudioDirectiveHandler::ExecuteNextReceive() { 169 void AudioDirectiveHandler::ProcessNextReceive() {
146 scoped_ptr<AudioDirective> audible_receive( 170 scoped_ptr<AudioDirective> receive(receives_list_.GetActiveDirective());
xiyuan 2014/08/12 18:57:50 So we no longer need to differentiate audible rece
rkc 2014/08/13 00:28:59 Nope. I didn't realize this earlier but we actuall
147 directive_list_audible_.GetNextReceive());
148 scoped_ptr<AudioDirective> inaudible_receive(
149 directive_list_inaudible_.GetNextReceive());
150 171
151 base::TimeDelta record_duration; 172 if (receive && !recorder_->IsRecording()) {
152 if (inaudible_receive) 173 DVLOG(3) << "Recording for op_id: " << receive->op_id;
153 record_duration = inaudible_receive->end_time - base::Time::Now(); 174 recorder_->Record();
154 if (audible_receive) { 175 stop_recording_timer_.Start(FROM_HERE,
155 record_duration = std::max(record_duration, 176 receive->end_time - base::Time::Now(),
156 audible_receive->end_time - base::Time::Now()); 177 this,
178 &AudioDirectiveHandler::ProcessNextReceive);
179 } else if (!receive && recorder_->IsRecording()) {
180 DVLOG(3) << "Stopping Recording";
181 stop_recording_timer_.Stop();
182 recorder_->Stop();
183 }
184 }
185
186 void AudioDirectiveHandler::HandleToken(const std::string token, bool audible) {
187 std::string valid_token = FromUrlSafe(token);
188
189 if (audible && samples_cache_audible_.HasKey(valid_token)) {
190 current_token_audible_ = token;
191 ProcessNextTransmit();
192 return;
157 } 193 }
158 194
159 if (record_duration > base::TimeDelta::FromSeconds(0)) 195 if (!audible && samples_cache_inaudible_.HasKey(valid_token)) {
160 RecordAudio(record_duration); 196 current_token_inaudible_ = token;
197 ProcessNextTransmit();
198 return;
199 }
200
201 encode_cb_.Run(valid_token,
202 audible,
203 base::Bind(&AudioDirectiveHandler::OnTokenEncoded,
204 base::Unretained(this)));
205 }
206
207 void AudioDirectiveHandler::OnTokenEncoded(
208 const std::string& token,
209 bool audible,
210 const scoped_refptr<media::AudioBusRefCounted>& samples) {
211 DVLOG(3) << "Token: " << token << "[audible:" << audible << "] encoded.";
212 if (audible) {
213 samples_cache_audible_.Add(token, samples);
214 current_token_audible_ = token;
215 // Force process transmits to pick up the new token.
216 if (player_audible_->IsPlaying())
217 player_audible_->Stop();
218 } else {
219 samples_cache_inaudible_.Add(token, samples);
220 current_token_inaudible_ = token;
221 // Force process transmits to pick up the new token.
222 if (player_inaudible_->IsPlaying())
223 player_inaudible_->Stop();
224 }
225
226 ProcessNextTransmit();
161 } 227 }
162 228
163 } // namespace copresence 229 } // namespace copresence
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698