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

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 DCHECK(whispernet_client);
63 encode_cb_ = encode_cb; 67 whispernet_client_ = whispernet_client;
68 tokens_cb_ = tokens_cb;
69
70 // These will be unregistered on destruction, so unretained is safe to use.
71 whispernet_client_->RegisterTokensCallback(
72 base::Bind(&AudioManagerImpl::OnTokensFound, base::Unretained(this)));
73 whispernet_client_->RegisterSamplesCallback(
74 base::Bind(&AudioManagerImpl::OnTokenEncoded, base::Unretained(this)));
64 75
65 if (!player_[AUDIBLE]) 76 if (!player_[AUDIBLE])
66 player_[AUDIBLE] = new AudioPlayerImpl(); 77 player_[AUDIBLE] = new AudioPlayerImpl();
67 player_[AUDIBLE]->Initialize(); 78 player_[AUDIBLE]->Initialize();
68 79
69 if (!player_[INAUDIBLE]) 80 if (!player_[INAUDIBLE])
70 player_[INAUDIBLE] = new AudioPlayerImpl(); 81 player_[INAUDIBLE] = new AudioPlayerImpl();
71 player_[INAUDIBLE]->Initialize(); 82 player_[INAUDIBLE]->Initialize();
72 83
73 decode_cancelable_cb_.Reset(base::Bind( 84 decode_cancelable_cb_.Reset(base::Bind(&WhispernetClient::DecodeSamples,
74 &AudioManagerImpl::DecodeSamplesConnector, base::Unretained(this))); 85 base::Unretained(whispernet_client_),
86 BOTH));
75 if (!recorder_) 87 if (!recorder_)
76 recorder_ = new AudioRecorderImpl(); 88 recorder_ = new AudioRecorderImpl();
77 recorder_->Initialize(decode_cancelable_cb_.callback()); 89 recorder_->Initialize(decode_cancelable_cb_.callback());
78 } 90 }
79 91
80 AudioManagerImpl::~AudioManagerImpl() { 92 AudioManagerImpl::~AudioManagerImpl() {
81 if (player_[AUDIBLE]) 93 if (player_[AUDIBLE])
82 player_[AUDIBLE]->Finalize(); 94 player_[AUDIBLE]->Finalize();
83 if (player_[INAUDIBLE]) 95 if (player_[INAUDIBLE])
84 player_[INAUDIBLE]->Finalize(); 96 player_[INAUDIBLE]->Finalize();
85 if (recorder_) 97 if (recorder_)
86 recorder_->Finalize(); 98 recorder_->Finalize();
99
100 DCHECK(whispernet_client_);
101 whispernet_client_->RegisterTokensCallback(TokensCallback());
102 whispernet_client_->RegisterSamplesCallback(SamplesCallback());
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 whispernet_client_->EncodeToken(token, type);
129 // RpcHandler->DirectiveHandler->AudioDirectiveHandler. The RpcHandler
130 // unsets any callbacks that were set on the Whispernet client before it
131 // destructs, unsetting this callback too - making unretained safe to use.
132 encode_cb_.Run(
133 token,
134 type,
135 base::Bind(&AudioManagerImpl::OnTokenEncoded, base::Unretained(this)));
136 } else { 153 } else {
137 UpdateToken(type, token); 154 UpdateToken(type, token);
138 } 155 }
139 } 156 }
140 157
141 const std::string AudioManagerImpl::GetToken(AudioType type) { 158 const std::string AudioManagerImpl::GetToken(AudioType type) {
142 return token_[type]; 159 return playing_token_[type];
143 } 160 }
144 161
145 bool AudioManagerImpl::IsRecording(AudioType type) { 162 bool AudioManagerImpl::IsRecording(AudioType type) {
146 return recording_[type]; 163 return recording_[type];
147 } 164 }
148 165
149 bool AudioManagerImpl::IsPlaying(AudioType type) { 166 bool AudioManagerImpl::IsPlaying(AudioType type) {
150 return playing_[type]; 167 return playing_[type];
151 } 168 }
152 169
170 bool AudioManagerImpl::IsPlayingTokenHeard(AudioType type) {
171 return heard_own_token_[type];
172 }
173
153 // Private methods. 174 // Private methods.
154 175
155 void AudioManagerImpl::OnTokenEncoded( 176 void AudioManagerImpl::OnTokenEncoded(
177 AudioType type,
156 const std::string& token, 178 const std::string& token,
157 AudioType type,
158 const scoped_refptr<media::AudioBusRefCounted>& samples) { 179 const scoped_refptr<media::AudioBusRefCounted>& samples) {
159 samples_cache_[type]->Add(token, samples); 180 samples_cache_[type]->Add(token, samples);
160 UpdateToken(type, token); 181 UpdateToken(type, token);
161 } 182 }
162 183
184 void AudioManagerImpl::OnTokensFound(const std::vector<AudioToken>& tokens) {
185 std::vector<AudioToken> tokens_to_report;
186 for (const auto& token : tokens) {
187 AudioType type = token.audible ? AUDIBLE : INAUDIBLE;
188 if (playing_token_[type] == token.token)
189 heard_own_token_[type] = true;
190
191 if (recording_[AUDIBLE] && token.audible) {
192 tokens_to_report.push_back(token);
193 } else if (recording_[INAUDIBLE] && !token.audible) {
194 tokens_to_report.push_back(token);
195 }
196 }
197
198 if (!tokens_to_report.empty())
199 tokens_cb_.Run(tokens_to_report);
200 }
201
163 void AudioManagerImpl::UpdateToken(AudioType type, const std::string& token) { 202 void AudioManagerImpl::UpdateToken(AudioType type, const std::string& token) {
164 DCHECK(type == AUDIBLE || type == INAUDIBLE); 203 DCHECK(type == AUDIBLE || type == INAUDIBLE);
165 if (token_[type] == token) 204 if (playing_token_[type] == token)
166 return; 205 return;
167 206
168 // Update token. 207 // Update token.
169 token_[type] = token; 208 playing_token_[type] = token;
170 209
210 // out playback with the new samples.
171 // If we are supposed to be playing this token type at this moment, switch 211 // If we are supposed to be playing this token type at this moment, switch
172 // out playback with the new samples.
173 if (playing_[type]) { 212 if (playing_[type]) {
174 if (player_[type]->IsPlaying()) 213 if (player_[type]->IsPlaying())
175 player_[type]->Stop(); 214 player_[type]->Stop();
176 StartPlaying(type); 215 StartPlaying(type);
177 } 216 }
178 } 217 }
179 218
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 219 } // namespace copresence
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698