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

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 }
108
109 void AudioDirectiveHandler::RecordAudio(base::TimeDelta duration) {
110 recorder_->Record();
111 stop_recording_timer_.Start(
112 FROM_HERE, duration, this, &AudioDirectiveHandler::StopRecording);
113 } 114 }
114 115
115 // Private methods. 116 // Private methods.
116 117
117 void AudioDirectiveHandler::StopPlayback() { 118 void AudioDirectiveHandler::ProcessNextTransmit() {
118 player_->Stop(); 119 // If we have an active directive for audible or inaudible audio, ensure that
119 DVLOG(2) << "Done playing audio."; 120 // we are playing our respective token; if we do not have a directive, then
120 ExecuteNextTransmit(); 121 // make sure we aren't playing. This is duplicate code, but for just two
121 } 122 // elements, it has hard to make a case for processing a loop instead.
122 123
123 void AudioDirectiveHandler::StopRecording() { 124 scoped_ptr<AudioDirective> audible_transmit(
124 recorder_->Stop(); 125 transmits_list_audible_.GetActiveDirective());
125 DVLOG(2) << "Done recording audio."; 126 if (audible_transmit && !player_audible_->IsPlaying()) {
126 ExecuteNextReceive(); 127 DVLOG(3) << "Playing audible for op_id: " << audible_transmit->op_id;
127 } 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 }
128 141
129 void AudioDirectiveHandler::ExecuteNextTransmit() {
130 scoped_ptr<AudioDirective> audible_transmit(
131 directive_list_audible_.GetNextTransmit());
132 scoped_ptr<AudioDirective> inaudible_transmit( 142 scoped_ptr<AudioDirective> inaudible_transmit(
133 directive_list_inaudible_.GetNextTransmit()); 143 transmits_list_inaudible_.GetActiveDirective());
134 144 if (inaudible_transmit && !player_inaudible_->IsPlaying()) {
135 if (inaudible_transmit) { 145 DVLOG(3) << "Playing inaudible for op_id: " << inaudible_transmit->op_id;
136 PlayAudio(inaudible_transmit->samples, 146 player_inaudible_->Play(
137 inaudible_transmit->end_time - base::Time::Now()); 147 samples_cache_inaudible_.GetValue(current_token_inaudible_));
138 } 148 stop_inaudible_playback_timer_.Start(
139 if (audible_transmit) { 149 FROM_HERE,
140 PlayAudio(audible_transmit->samples, 150 inaudible_transmit->end_time - base::Time::Now(),
141 audible_transmit->end_time - base::Time::Now()); 151 this,
152 &AudioDirectiveHandler::ProcessNextTransmit);
153 } else if (!inaudible_transmit && player_inaudible_->IsPlaying()) {
154 DVLOG(3) << "Stopping inaudible playback.";
155 current_token_inaudible_.clear();
156 stop_inaudible_playback_timer_.Stop();
157 player_inaudible_->Stop();
142 } 158 }
143 } 159 }
144 160
145 void AudioDirectiveHandler::ExecuteNextReceive() { 161 void AudioDirectiveHandler::ProcessNextReceive() {
146 scoped_ptr<AudioDirective> audible_receive( 162 scoped_ptr<AudioDirective> receive(receives_list_.GetActiveDirective());
147 directive_list_audible_.GetNextReceive());
148 scoped_ptr<AudioDirective> inaudible_receive(
149 directive_list_inaudible_.GetNextReceive());
150 163
151 base::TimeDelta record_duration; 164 if (receive && !recorder_->IsRecording()) {
152 if (inaudible_receive) 165 DVLOG(3) << "Recording for op_id: " << receive->op_id;
153 record_duration = inaudible_receive->end_time - base::Time::Now(); 166 recorder_->Record();
154 if (audible_receive) { 167 stop_recording_timer_.Start(FROM_HERE,
155 record_duration = std::max(record_duration, 168 receive->end_time - base::Time::Now(),
156 audible_receive->end_time - base::Time::Now()); 169 this,
170 &AudioDirectiveHandler::ProcessNextReceive);
171 } else if (!receive && recorder_->IsRecording()) {
172 DVLOG(3) << "Stopping Recording";
173 stop_recording_timer_.Stop();
174 recorder_->Stop();
175 }
176 }
177
178 void AudioDirectiveHandler::HandleToken(const std::string token, bool audible) {
179 std::string valid_token = FromUrlSafe(token);
180
181 if (audible && samples_cache_audible_.HasKey(valid_token)) {
182 current_token_audible_ = token;
183 ProcessNextTransmit();
184 return;
157 } 185 }
158 186
159 if (record_duration > base::TimeDelta::FromSeconds(0)) 187 if (!audible && samples_cache_inaudible_.HasKey(valid_token)) {
160 RecordAudio(record_duration); 188 current_token_inaudible_ = token;
189 ProcessNextTransmit();
190 return;
191 }
192
193 encode_cb_.Run(valid_token,
194 audible,
195 base::Bind(&AudioDirectiveHandler::OnTokenEncoded,
196 base::Unretained(this)));
197 }
198
199 void AudioDirectiveHandler::OnTokenEncoded(
200 const std::string& token,
201 bool audible,
202 const scoped_refptr<media::AudioBusRefCounted>& samples) {
203 DVLOG(3) << "Token: " << token << "[audible:" << audible << "] encoded.";
204 if (audible) {
205 samples_cache_audible_.Add(token, samples);
206 current_token_audible_ = token;
207 // Force process transmits to pick up the new token.
208 if (player_audible_->IsPlaying())
209 player_audible_->Stop();
210 } else {
211 samples_cache_inaudible_.Add(token, samples);
212 current_token_inaudible_ = token;
213 // Force process transmits to pick up the new token.
214 if (player_inaudible_->IsPlaying())
215 player_inaudible_->Stop();
216 }
217
218 ProcessNextTransmit();
161 } 219 }
162 220
163 } // namespace copresence 221 } // namespace copresence
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698