ozone: evdev: Sync caps lock LED state to evdev
[chromium-blink-merge.git] / components / copresence / handlers / audio / audio_directive_handler_impl.cc
blobd91b4d8fddbf49c2876c5021bb18d2fccc300f97
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
3 // found in the LICENSE file.
5 #include "components/copresence/handlers/audio/audio_directive_handler_impl.h"
7 #include <algorithm>
8 #include <vector>
10 #include "base/bind.h"
11 #include "base/logging.h"
12 #include "base/memory/scoped_ptr.h"
13 #include "base/time/default_tick_clock.h"
14 #include "base/time/time.h"
15 #include "base/timer/timer.h"
16 #include "components/audio_modem/public/modem.h"
17 #include "components/copresence/handlers/audio/audio_directive_list.h"
18 #include "components/copresence/handlers/audio/tick_clock_ref_counted.h"
19 #include "components/copresence/proto/data.pb.h"
20 #include "components/copresence/public/copresence_constants.h"
21 #include "media/base/audio_bus.h"
23 using audio_modem::AUDIBLE;
24 using audio_modem::INAUDIBLE;
25 using audio_modem::TokenParameters;
27 namespace copresence {
29 namespace {
31 base::TimeTicks GetEarliestEventTime(AudioDirectiveList* list,
32 base::TimeTicks event_time) {
33 if (!list->GetActiveDirective())
34 return event_time;
36 return event_time.is_null() ?
37 list->GetActiveDirective()->end_time :
38 std::min(list->GetActiveDirective()->end_time, event_time);
41 void ConvertDirectives(const std::vector<AudioDirective>& in_directives,
42 std::vector<Directive>* out_directives) {
43 for (const AudioDirective& in_directive : in_directives)
44 out_directives->push_back(in_directive.server_directive);
47 } // namespace
50 // Public functions.
52 AudioDirectiveHandlerImpl::AudioDirectiveHandlerImpl(
53 const DirectivesCallback& update_directives_callback)
54 : update_directives_callback_(update_directives_callback),
55 audio_modem_(audio_modem::Modem::Create()),
56 audio_event_timer_(new base::OneShotTimer<AudioDirectiveHandler>),
57 clock_(new TickClockRefCounted(new base::DefaultTickClock)) {}
59 AudioDirectiveHandlerImpl::AudioDirectiveHandlerImpl(
60 const DirectivesCallback& update_directives_callback,
61 scoped_ptr<audio_modem::Modem> audio_modem,
62 scoped_ptr<base::Timer> timer,
63 const scoped_refptr<TickClockRefCounted>& clock)
64 : update_directives_callback_(update_directives_callback),
65 audio_modem_(audio_modem.Pass()),
66 audio_event_timer_(timer.Pass()),
67 clock_(clock) {}
69 AudioDirectiveHandlerImpl::~AudioDirectiveHandlerImpl() {}
71 void AudioDirectiveHandlerImpl::Initialize(
72 audio_modem::WhispernetClient* whispernet_client,
73 const audio_modem::TokensCallback& tokens_cb) {
74 DCHECK(audio_modem_);
75 audio_modem_->Initialize(whispernet_client, tokens_cb);
77 DCHECK(transmits_lists_.empty());
78 transmits_lists_.push_back(new AudioDirectiveList(clock_));
79 transmits_lists_.push_back(new AudioDirectiveList(clock_));
81 DCHECK(receives_lists_.empty());
82 receives_lists_.push_back(new AudioDirectiveList(clock_));
83 receives_lists_.push_back(new AudioDirectiveList(clock_));
86 void AudioDirectiveHandlerImpl::AddInstruction(
87 const Directive& directive,
88 const std::string& op_id) {
89 DCHECK(transmits_lists_.size() == 2u && receives_lists_.size() == 2u)
90 << "Call Initialize() before other AudioDirectiveHandler methods";
92 const TokenInstruction& instruction = directive.token_instruction();
93 base::TimeDelta ttl =
94 base::TimeDelta::FromMilliseconds(directive.ttl_millis());
95 const size_t token_length = directive.configuration().token_params().length();
97 switch (instruction.token_instruction_type()) {
98 case TRANSMIT:
99 DVLOG(2) << "Audio Transmit Directive received. Token: "
100 << instruction.token_id()
101 << " with medium=" << instruction.medium()
102 << " with TTL=" << ttl.InMilliseconds();
103 DCHECK_GT(token_length, 0u);
104 switch (instruction.medium()) {
105 case AUDIO_ULTRASOUND_PASSBAND:
106 audio_modem_->SetTokenParams(INAUDIBLE,
107 TokenParameters(token_length));
108 transmits_lists_[INAUDIBLE]->AddDirective(op_id, directive);
109 audio_modem_->SetToken(INAUDIBLE, instruction.token_id());
110 break;
111 case AUDIO_AUDIBLE_DTMF:
112 audio_modem_->SetTokenParams(AUDIBLE, TokenParameters(token_length));
113 transmits_lists_[AUDIBLE]->AddDirective(op_id, directive);
114 audio_modem_->SetToken(AUDIBLE, instruction.token_id());
115 break;
116 default:
117 NOTREACHED();
119 break;
121 case RECEIVE:
122 DVLOG(2) << "Audio Receive Directive received."
123 << " with medium=" << instruction.medium()
124 << " with TTL=" << ttl.InMilliseconds();
125 DCHECK_GT(token_length, 0u);
126 switch (instruction.medium()) {
127 case AUDIO_ULTRASOUND_PASSBAND:
128 audio_modem_->SetTokenParams(INAUDIBLE,
129 TokenParameters(token_length));
130 receives_lists_[INAUDIBLE]->AddDirective(op_id, directive);
131 break;
132 case AUDIO_AUDIBLE_DTMF:
133 audio_modem_->SetTokenParams(AUDIBLE, TokenParameters(token_length));
134 receives_lists_[AUDIBLE]->AddDirective(op_id, directive);
135 break;
136 default:
137 NOTREACHED();
139 break;
141 case UNKNOWN_TOKEN_INSTRUCTION_TYPE:
142 default:
143 LOG(WARNING) << "Unknown Audio Transmit Directive received. type = "
144 << instruction.token_instruction_type();
147 ProcessNextInstruction();
150 void AudioDirectiveHandlerImpl::RemoveInstructions(const std::string& op_id) {
151 DCHECK(transmits_lists_.size() == 2u && receives_lists_.size() == 2u)
152 << "Call Initialize() before other AudioDirectiveHandler methods";
154 transmits_lists_[AUDIBLE]->RemoveDirective(op_id);
155 transmits_lists_[INAUDIBLE]->RemoveDirective(op_id);
156 receives_lists_[AUDIBLE]->RemoveDirective(op_id);
157 receives_lists_[INAUDIBLE]->RemoveDirective(op_id);
159 ProcessNextInstruction();
162 const std::string AudioDirectiveHandlerImpl::PlayingToken(
163 audio_modem::AudioType type) const {
164 return audio_modem_->GetToken(type);
167 bool AudioDirectiveHandlerImpl::IsPlayingTokenHeard(
168 audio_modem::AudioType type) const {
169 return audio_modem_->IsPlayingTokenHeard(type);
173 // Private functions.
175 void AudioDirectiveHandlerImpl::ProcessNextInstruction() {
176 DCHECK(audio_event_timer_);
177 audio_event_timer_->Stop();
179 // Change |audio_modem_| state for audible transmits.
180 if (transmits_lists_[AUDIBLE]->GetActiveDirective())
181 audio_modem_->StartPlaying(AUDIBLE);
182 else
183 audio_modem_->StopPlaying(AUDIBLE);
185 // Change audio_modem_ state for inaudible transmits.
186 if (transmits_lists_[INAUDIBLE]->GetActiveDirective())
187 audio_modem_->StartPlaying(INAUDIBLE);
188 else
189 audio_modem_->StopPlaying(INAUDIBLE);
191 // Change audio_modem_ state for audible receives.
192 if (receives_lists_[AUDIBLE]->GetActiveDirective())
193 audio_modem_->StartRecording(AUDIBLE);
194 else
195 audio_modem_->StopRecording(AUDIBLE);
197 // Change audio_modem_ state for inaudible receives.
198 if (receives_lists_[INAUDIBLE]->GetActiveDirective())
199 audio_modem_->StartRecording(INAUDIBLE);
200 else
201 audio_modem_->StopRecording(INAUDIBLE);
203 base::TimeTicks next_event_time;
204 if (GetNextInstructionExpiry(&next_event_time)) {
205 audio_event_timer_->Start(
206 FROM_HERE,
207 next_event_time - clock_->NowTicks(),
208 base::Bind(&AudioDirectiveHandlerImpl::ProcessNextInstruction,
209 base::Unretained(this)));
212 // TODO(crbug.com/436584): Instead of this, store the directives
213 // in a single list, and prune them when expired.
214 std::vector<Directive> directives;
215 ConvertDirectives(transmits_lists_[AUDIBLE]->directives(), &directives);
216 ConvertDirectives(transmits_lists_[INAUDIBLE]->directives(), &directives);
217 ConvertDirectives(receives_lists_[AUDIBLE]->directives(), &directives);
218 ConvertDirectives(receives_lists_[INAUDIBLE]->directives(), &directives);
219 update_directives_callback_.Run(directives);
222 bool AudioDirectiveHandlerImpl::GetNextInstructionExpiry(
223 base::TimeTicks* expiry) {
224 DCHECK(expiry);
226 *expiry = GetEarliestEventTime(transmits_lists_[AUDIBLE], base::TimeTicks());
227 *expiry = GetEarliestEventTime(transmits_lists_[INAUDIBLE], *expiry);
228 *expiry = GetEarliestEventTime(receives_lists_[AUDIBLE], *expiry);
229 *expiry = GetEarliestEventTime(receives_lists_[INAUDIBLE], *expiry);
231 return !expiry->is_null();
234 } // namespace copresence