| OLD | NEW | 
|---|
| 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 | 
| OLD | NEW | 
|---|