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

Side by Side Diff: components/copresence/mediums/audio/audio_manager_impl.cc

Issue 704923002: Add polling and audio check to copresence. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 6 years, 1 month 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/mediums/audio/audio_manager_impl.h" 5 #include "components/copresence/mediums/audio/audio_manager_impl.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <vector> 8 #include <vector>
9 9
10 #include "base/bind.h" 10 #include "base/bind.h"
11 #include "base/bind_helpers.h" 11 #include "base/bind_helpers.h"
12 #include "base/logging.h" 12 #include "base/logging.h"
13 #include "base/run_loop.h" 13 #include "base/run_loop.h"
14 #include "base/strings/string_util.h" 14 #include "base/strings/string_util.h"
15 #include "components/copresence/mediums/audio/audio_player_impl.h" 15 #include "components/copresence/mediums/audio/audio_player_impl.h"
16 #include "components/copresence/mediums/audio/audio_recorder_impl.h" 16 #include "components/copresence/mediums/audio/audio_recorder_impl.h"
17 #include "components/copresence/public/copresence_constants.h" 17 #include "components/copresence/public/copresence_constants.h"
18 #include "components/copresence/public/whispernet_client.h"
18 #include "content/public/browser/browser_thread.h" 19 #include "content/public/browser/browser_thread.h"
19 #include "media/audio/audio_manager.h" 20 #include "media/audio/audio_manager.h"
20 #include "media/audio/audio_manager_base.h" 21 #include "media/audio/audio_manager_base.h"
21 #include "media/base/audio_bus.h" 22 #include "media/base/audio_bus.h"
22 23
23 namespace copresence { 24 namespace copresence {
24 25
25 namespace { 26 namespace {
26 27
27 // UrlSafe is defined as: 28 // UrlSafe is defined as:
28 // '/' represented by a '_' and '+' represented by a '-' 29 // '/' represented by a '_' and '+' represented by a '-'
29 // TODO(rkc): Move this processing to the whispernet wrapper. 30 // TODO(rkc): Move this processing to the whispernet wrapper.
30 std::string FromUrlSafe(std::string token) { 31 std::string FromUrlSafe(std::string token) {
31 base::ReplaceChars(token, "-", "+", &token); 32 base::ReplaceChars(token, "-", "+", &token);
32 base::ReplaceChars(token, "_", "/", &token); 33 base::ReplaceChars(token, "_", "/", &token);
33 return token; 34 return token;
34 } 35 }
35 36
36 const int kSampleExpiryTimeMs = 60 * 60 * 1000; // 60 minutes. 37 const int kSampleExpiryTimeMs = 60 * 60 * 1000; // 60 minutes.
37 const int kMaxSamples = 10000; 38 const int kMaxSamples = 10000;
38 39
39 } // namespace 40 } // namespace
40 41
41 // Public methods. 42 // Public methods.
42 43
43 AudioManagerImpl::AudioManagerImpl() : recorder_(nullptr) { 44 AudioManagerImpl::AudioManagerImpl()
45 : whispernet_client_(nullptr), recorder_(nullptr) {
44 // TODO(rkc): Move all of these into initializer lists once it is allowed. 46 // TODO(rkc): Move all of these into initializer lists once it is allowed.
45 playing_[AUDIBLE] = false; 47 playing_[AUDIBLE] = false;
46 playing_[INAUDIBLE] = false; 48 playing_[INAUDIBLE] = false;
47 recording_[AUDIBLE] = false; 49 recording_[AUDIBLE] = false;
48 recording_[INAUDIBLE] = false; 50 recording_[INAUDIBLE] = false;
51 heard_own_token_[AUDIBLE] = false;
52 heard_own_token_[INAUDIBLE] = false;
49 53
50 player_[AUDIBLE] = nullptr; 54 player_[AUDIBLE] = nullptr;
51 player_[INAUDIBLE] = nullptr; 55 player_[INAUDIBLE] = nullptr;
52 } 56 }
53 57
54 void AudioManagerImpl::Initialize(const DecodeSamplesCallback& decode_cb, 58 void AudioManagerImpl::Initialize(WhispernetClient* whispernet_client,
55 const EncodeTokenCallback& encode_cb) { 59 const TokensCallback& tokens_cb) {
56 samples_cache_.resize(2); 60 samples_cache_.resize(2);
57 samples_cache_[AUDIBLE] = new SamplesMap( 61 samples_cache_[AUDIBLE] = new SamplesMap(
58 base::TimeDelta::FromMilliseconds(kSampleExpiryTimeMs), kMaxSamples); 62 base::TimeDelta::FromMilliseconds(kSampleExpiryTimeMs), kMaxSamples);
59 samples_cache_[INAUDIBLE] = new SamplesMap( 63 samples_cache_[INAUDIBLE] = new SamplesMap(
60 base::TimeDelta::FromMilliseconds(kSampleExpiryTimeMs), kMaxSamples); 64 base::TimeDelta::FromMilliseconds(kSampleExpiryTimeMs), kMaxSamples);
61 65
62 decode_cb_ = decode_cb; 66 whispernet_client_ = whispernet_client;
Charlie 2014/11/06 17:28:23 DCHECK this. You can pass in stubs in from the tes
rkc 2014/11/06 19:58:24 Done.
63 encode_cb_ = encode_cb; 67 tokens_cb_ = tokens_cb;
68
69 // These will be unregistered on destruction, so unretained is safe to use.
70 whispernet_client_->RegisterTokensCallback(
71 base::Bind(&AudioManagerImpl::OnTokensFound, base::Unretained(this)));
72 whispernet_client_->RegisterSamplesCallback(
73 base::Bind(&AudioManagerImpl::OnTokenEncoded, base::Unretained(this)));
64 74
65 if (!player_[AUDIBLE]) 75 if (!player_[AUDIBLE])
66 player_[AUDIBLE] = new AudioPlayerImpl(); 76 player_[AUDIBLE] = new AudioPlayerImpl();
67 player_[AUDIBLE]->Initialize(); 77 player_[AUDIBLE]->Initialize();
68 78
69 if (!player_[INAUDIBLE]) 79 if (!player_[INAUDIBLE])
70 player_[INAUDIBLE] = new AudioPlayerImpl(); 80 player_[INAUDIBLE] = new AudioPlayerImpl();
71 player_[INAUDIBLE]->Initialize(); 81 player_[INAUDIBLE]->Initialize();
72 82
73 decode_cancelable_cb_.Reset(base::Bind( 83 decode_cancelable_cb_.Reset(base::Bind(&WhispernetClient::DecodeSamples,
74 &AudioManagerImpl::DecodeSamplesConnector, base::Unretained(this))); 84 base::Unretained(whispernet_client_),
85 BOTH));
75 if (!recorder_) 86 if (!recorder_)
76 recorder_ = new AudioRecorderImpl(); 87 recorder_ = new AudioRecorderImpl();
77 recorder_->Initialize(decode_cancelable_cb_.callback()); 88 recorder_->Initialize(decode_cancelable_cb_.callback());
78 } 89 }
79 90
80 AudioManagerImpl::~AudioManagerImpl() { 91 AudioManagerImpl::~AudioManagerImpl() {
81 if (player_[AUDIBLE]) 92 if (player_[AUDIBLE])
82 player_[AUDIBLE]->Finalize(); 93 player_[AUDIBLE]->Finalize();
83 if (player_[INAUDIBLE]) 94 if (player_[INAUDIBLE])
84 player_[INAUDIBLE]->Finalize(); 95 player_[INAUDIBLE]->Finalize();
85 if (recorder_) 96 if (recorder_)
86 recorder_->Finalize(); 97 recorder_->Finalize();
98
99 if (whispernet_client_) {
Charlie 2014/11/06 17:28:23 No if since this will be DCHECK'ed
rkc 2014/11/06 19:58:24 Done but breaks the RPC handler test. Had to fix t
100 whispernet_client_->RegisterTokensCallback(TokensCallback());
101 whispernet_client_->RegisterSamplesCallback(SamplesCallback());
102 }
87 } 103 }
88 104
89 void AudioManagerImpl::StartPlaying(AudioType type) { 105 void AudioManagerImpl::StartPlaying(AudioType type) {
90 DCHECK(type == AUDIBLE || type == INAUDIBLE); 106 DCHECK(type == AUDIBLE || type == INAUDIBLE);
91 playing_[type] = true; 107 playing_[type] = true;
92 // If we don't have our token encoded yet, this check will be false, for now. 108 // If we don't have our token encoded yet, this check will be false, for now.
93 // Once our token is encoded, OnTokenEncoded will call UpdateToken, which 109 // Once our token is encoded, OnTokenEncoded will call UpdateToken, which
94 // will call this code again (if we're still supposed to be playing). 110 // will call this code again (if we're still supposed to be playing).
95 if (samples_cache_[type]->HasKey(token_[type]) && 111 if (samples_cache_[type]->HasKey(playing_token_[type]) &&
96 !player_[type]->IsPlaying()) { 112 !player_[type]->IsPlaying()) {
97 DCHECK(!token_[type].empty()); 113 DCHECK(!playing_token_[type].empty());
98 player_[type]->Play(samples_cache_[type]->GetValue(token_[type])); 114 player_[type]->Play(samples_cache_[type]->GetValue(playing_token_[type]));
115 // If we're playing, we always record to hear what we are playing.
116 if (!recorder_->IsRecording())
117 recorder_->Record();
99 } 118 }
100 } 119 }
101 120
102 void AudioManagerImpl::StopPlaying(AudioType type) { 121 void AudioManagerImpl::StopPlaying(AudioType type) {
103 DCHECK(type == AUDIBLE || type == INAUDIBLE); 122 DCHECK(type == AUDIBLE || type == INAUDIBLE);
104 playing_[type] = false; 123 playing_[type] = false;
105 if (player_[type]->IsPlaying()) 124 if (player_[type]->IsPlaying()) {
106 player_[type]->Stop(); 125 player_[type]->Stop();
126 // If we were only recording to hear our own played tokens, stop.
127 if (recorder_->IsRecording() && !recording_[AUDIBLE] &&
128 !recording_[INAUDIBLE])
129 recorder_->Stop();
130 }
107 } 131 }
108 132
109 void AudioManagerImpl::StartRecording(AudioType type) { 133 void AudioManagerImpl::StartRecording(AudioType type) {
110 DCHECK(type == AUDIBLE || type == INAUDIBLE); 134 DCHECK(type == AUDIBLE || type == INAUDIBLE);
111 recording_[type] = true; 135 recording_[type] = true;
112 if (!recorder_->IsRecording()) 136 if (!recorder_->IsRecording())
113 recorder_->Record(); 137 recorder_->Record();
114 } 138 }
115 139
116 void AudioManagerImpl::StopRecording(AudioType type) { 140 void AudioManagerImpl::StopRecording(AudioType type) {
117 DCHECK(type == AUDIBLE || type == INAUDIBLE); 141 DCHECK(type == AUDIBLE || type == INAUDIBLE);
118 recording_[type] = false; 142 recording_[type] = false;
119 if (recorder_->IsRecording()) 143 if (recorder_->IsRecording())
120 recorder_->Stop(); 144 recorder_->Stop();
121 } 145 }
122 146
123 void AudioManagerImpl::SetToken(AudioType type, 147 void AudioManagerImpl::SetToken(AudioType type,
124 const std::string& url_unsafe_token) { 148 const std::string& url_unsafe_token) {
125 DCHECK(type == AUDIBLE || type == INAUDIBLE); 149 DCHECK(type == AUDIBLE || type == INAUDIBLE);
126 std::string token = FromUrlSafe(url_unsafe_token); 150 std::string token = FromUrlSafe(url_unsafe_token);
127 if (!samples_cache_[type]->HasKey(token)) { 151 if (!samples_cache_[type]->HasKey(token)) {
128 // We're destructed by the destruction chain of 152 // We're destructed by the destruction chain of
Charlie 2014/11/06 17:28:23 This comment is out of date.
rkc 2014/11/06 19:58:24 Done.
129 // RpcHandler->DirectiveHandler->AudioDirectiveHandler. The RpcHandler 153 // RpcHandler->DirectiveHandler->AudioDirectiveHandler. The RpcHandler
130 // unsets any callbacks that were set on the Whispernet client before it 154 // unsets any callbacks that were set on the Whispernet client before it
131 // destructs, unsetting this callback too - making unretained safe to use. 155 // destructs, unsetting this callback too - making unretained safe to use.
132 encode_cb_.Run( 156 whispernet_client_->EncodeToken(token, type);
133 token,
134 type,
135 base::Bind(&AudioManagerImpl::OnTokenEncoded, base::Unretained(this)));
136 } else { 157 } else {
137 UpdateToken(type, token); 158 UpdateToken(type, token);
138 } 159 }
139 } 160 }
140 161
141 const std::string AudioManagerImpl::GetToken(AudioType type) { 162 const std::string AudioManagerImpl::GetToken(AudioType type) {
142 return token_[type]; 163 return playing_token_[type];
143 } 164 }
144 165
145 bool AudioManagerImpl::IsRecording(AudioType type) { 166 bool AudioManagerImpl::IsRecording(AudioType type) {
146 return recording_[type]; 167 return recording_[type];
147 } 168 }
148 169
149 bool AudioManagerImpl::IsPlaying(AudioType type) { 170 bool AudioManagerImpl::IsPlaying(AudioType type) {
150 return playing_[type]; 171 return playing_[type];
151 } 172 }
152 173
174 bool AudioManagerImpl::IsPlayingTokenHeard(AudioType type) {
175 return heard_own_token_[type];
176 }
177
153 // Private methods. 178 // Private methods.
154 179
155 void AudioManagerImpl::OnTokenEncoded( 180 void AudioManagerImpl::OnTokenEncoded(
181 AudioType type,
156 const std::string& token, 182 const std::string& token,
157 AudioType type,
158 const scoped_refptr<media::AudioBusRefCounted>& samples) { 183 const scoped_refptr<media::AudioBusRefCounted>& samples) {
159 samples_cache_[type]->Add(token, samples); 184 samples_cache_[type]->Add(token, samples);
160 UpdateToken(type, token); 185 UpdateToken(type, token);
161 } 186 }
162 187
188 void AudioManagerImpl::OnTokensFound(const std::vector<AudioToken>& tokens) {
189 std::vector<AudioToken> tokens_to_report;
190 for (const auto& token : tokens) {
191 AudioType type = token.audible ? AUDIBLE : INAUDIBLE;
192 if (playing_token_[type] == token.token)
193 heard_own_token_[type] = true;
194
195 if (recording_[AUDIBLE] && token.audible) {
196 tokens_to_report.push_back(token);
197 } else if (recording_[INAUDIBLE] && !token.audible) {
198 tokens_to_report.push_back(token);
199 }
200 }
201
202 if (!tokens_cb_.is_null() && !tokens_to_report.empty())
Charlie 2014/11/06 17:28:23 Why should tokens_cb_ be null?
rkc 2014/11/06 19:58:24 Done.
203 tokens_cb_.Run(tokens_to_report);
204 }
205
163 void AudioManagerImpl::UpdateToken(AudioType type, const std::string& token) { 206 void AudioManagerImpl::UpdateToken(AudioType type, const std::string& token) {
164 DCHECK(type == AUDIBLE || type == INAUDIBLE); 207 DCHECK(type == AUDIBLE || type == INAUDIBLE);
165 if (token_[type] == token) 208 if (playing_token_[type] == token)
166 return; 209 return;
167 210
168 // Update token. 211 // Update token.
169 token_[type] = token; 212 playing_token_[type] = token;
170 213
171 // If we are supposed to be playing this token type at this moment, switch 214 // If we are supposed to be playing this token type at this moment, switch
172 // out playback with the new samples. 215 // out playback with the new samples.
173 if (playing_[type]) { 216 if (playing_[type]) {
174 if (player_[type]->IsPlaying()) 217 if (player_[type]->IsPlaying())
175 player_[type]->Stop(); 218 player_[type]->Stop();
176 StartPlaying(type); 219 StartPlaying(type);
177 } 220 }
178 } 221 }
179 222
180 void AudioManagerImpl::DecodeSamplesConnector(const std::string& samples) {
181 AudioType decode_type = AUDIO_TYPE_UNKNOWN;
182
183 if (recording_[AUDIBLE] && recording_[INAUDIBLE])
184 decode_type = BOTH;
185 else if (recording_[AUDIBLE])
186 decode_type = AUDIBLE;
187 else if (recording_[INAUDIBLE])
188 decode_type = INAUDIBLE;
189
190 decode_cb_.Run(decode_type, samples);
191 }
192
193 } // namespace copresence 223 } // namespace copresence
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698