1// Copyright (c) 2012 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.
4
5#include "media/audio/audio_input_controller.h"
6
7#include "base/bind.h"
8#include "base/strings/string_number_conversions.h"
9#include "base/strings/stringprintf.h"
10#include "base/threading/thread_restrictions.h"
11#include "base/time/time.h"
12#include "media/audio/audio_parameters.h"
13#include "media/base/scoped_histogram_timer.h"
14#include "media/base/user_input_monitor.h"
15
16using base::TimeDelta;
17
18namespace {
19
20const int kMaxInputChannels = 3;
21
22// TODO(henrika): remove usage of timers and add support for proper
23// notification of when the input device is removed.  This was originally added
24// to resolve http://crbug.com/79936 for Windows platforms.  This then caused
25// breakage (very hard to repro bugs!) on other platforms: See
26// http://crbug.com/226327 and http://crbug.com/230972.
27// See also that the timer has been disabled on Mac now due to
28// crbug.com/357501.
29const int kTimerResetIntervalSeconds = 1;
30// We have received reports that the timer can be too trigger happy on some
31// Mac devices and the initial timer interval has therefore been increased
32// from 1 second to 5 seconds.
33const int kTimerInitialIntervalSeconds = 5;
34
35#if defined(AUDIO_POWER_MONITORING)
36// Time constant for AudioPowerMonitor.
37// The utilized smoothing factor (alpha) in the exponential filter is given
38// by 1-exp(-1/(fs*ts)), where fs is the sample rate in Hz and ts is the time
39// constant given by |kPowerMeasurementTimeConstantMilliseconds|.
40// Example: fs=44100, ts=10e-3 => alpha~0.022420
41//          fs=44100, ts=20e-3 => alpha~0.165903
42// A large smoothing factor corresponds to a faster filter response to input
43// changes since y(n)=alpha*x(n)+(1-alpha)*y(n-1), where x(n) is the input
44// and y(n) is the output.
45const int kPowerMeasurementTimeConstantMilliseconds = 10;
46
47// Time in seconds between two successive measurements of audio power levels.
48const int kPowerMonitorLogIntervalSeconds = 15;
49
50// A warning will be logged when the microphone audio volume is below this
51// threshold.
52const int kLowLevelMicrophoneLevelPercent = 10;
53
54// Logs if the user has enabled the microphone mute or not. This is normally
55// done by marking a checkbox in an audio-settings UI which is unique for each
56// platform. Elements in this enum should not be added, deleted or rearranged.
57enum MicrophoneMuteResult {
58  MICROPHONE_IS_MUTED = 0,
59  MICROPHONE_IS_NOT_MUTED = 1,
60  MICROPHONE_MUTE_MAX = MICROPHONE_IS_NOT_MUTED
61};
62
63void LogMicrophoneMuteResult(MicrophoneMuteResult result) {
64  UMA_HISTOGRAM_ENUMERATION("Media.MicrophoneMuted",
65                            result,
66                            MICROPHONE_MUTE_MAX + 1);
67}
68#endif
69}
70
71// Used to log the result of capture startup.
72// This was previously logged as a boolean with only the no callback and OK
73// options. The enum order is kept to ensure backwards compatibility.
74// Elements in this enum should not be deleted or rearranged; the only
75// permitted operation is to add new elements before CAPTURE_STARTUP_RESULT_MAX
76// and update CAPTURE_STARTUP_RESULT_MAX.
77enum CaptureStartupResult {
78  CAPTURE_STARTUP_NO_DATA_CALLBACK = 0,
79  CAPTURE_STARTUP_OK = 1,
80  CAPTURE_STARTUP_CREATE_STREAM_FAILED = 2,
81  CAPTURE_STARTUP_OPEN_STREAM_FAILED = 3,
82  CAPTURE_STARTUP_RESULT_MAX = CAPTURE_STARTUP_OPEN_STREAM_FAILED
83};
84
85void LogCaptureStartupResult(CaptureStartupResult result) {
86  UMA_HISTOGRAM_ENUMERATION("Media.AudioInputControllerCaptureStartupSuccess",
87                            result,
88                            CAPTURE_STARTUP_RESULT_MAX + 1);
89
90}
91
92namespace media {
93
94// static
95AudioInputController::Factory* AudioInputController::factory_ = NULL;
96
97AudioInputController::AudioInputController(EventHandler* handler,
98                                           SyncWriter* sync_writer,
99                                           UserInputMonitor* user_input_monitor)
100    : creator_task_runner_(base::MessageLoopProxy::current()),
101      handler_(handler),
102      stream_(NULL),
103      data_is_active_(false),
104      state_(CLOSED),
105      sync_writer_(sync_writer),
106      max_volume_(0.0),
107      user_input_monitor_(user_input_monitor),
108#if defined(AUDIO_POWER_MONITORING)
109      log_silence_state_(false),
110      silence_state_(SILENCE_STATE_NO_MEASUREMENT),
111#endif
112      prev_key_down_count_(0) {
113  DCHECK(creator_task_runner_.get());
114}
115
116AudioInputController::~AudioInputController() {
117  DCHECK_EQ(state_, CLOSED);
118}
119
120// static
121scoped_refptr<AudioInputController> AudioInputController::Create(
122    AudioManager* audio_manager,
123    EventHandler* event_handler,
124    const AudioParameters& params,
125    const std::string& device_id,
126    UserInputMonitor* user_input_monitor) {
127  DCHECK(audio_manager);
128
129  if (!params.IsValid() || (params.channels() > kMaxInputChannels))
130    return NULL;
131
132  if (factory_) {
133    return factory_->Create(
134        audio_manager, event_handler, params, user_input_monitor);
135  }
136  scoped_refptr<AudioInputController> controller(
137      new AudioInputController(event_handler, NULL, user_input_monitor));
138
139  controller->task_runner_ = audio_manager->GetTaskRunner();
140
141  // Create and open a new audio input stream from the existing
142  // audio-device thread.
143  if (!controller->task_runner_->PostTask(
144          FROM_HERE,
145          base::Bind(&AudioInputController::DoCreate,
146                     controller,
147                     base::Unretained(audio_manager),
148                     params,
149                     device_id))) {
150    controller = NULL;
151  }
152
153  return controller;
154}
155
156// static
157scoped_refptr<AudioInputController> AudioInputController::CreateLowLatency(
158    AudioManager* audio_manager,
159    EventHandler* event_handler,
160    const AudioParameters& params,
161    const std::string& device_id,
162    SyncWriter* sync_writer,
163    UserInputMonitor* user_input_monitor) {
164  DCHECK(audio_manager);
165  DCHECK(sync_writer);
166
167  if (!params.IsValid() || (params.channels() > kMaxInputChannels))
168    return NULL;
169
170  // Create the AudioInputController object and ensure that it runs on
171  // the audio-manager thread.
172  scoped_refptr<AudioInputController> controller(
173      new AudioInputController(event_handler, sync_writer, user_input_monitor));
174  controller->task_runner_ = audio_manager->GetTaskRunner();
175
176  // Create and open a new audio input stream from the existing
177  // audio-device thread. Use the provided audio-input device.
178  if (!controller->task_runner_->PostTask(
179          FROM_HERE,
180          base::Bind(&AudioInputController::DoCreateForLowLatency,
181                     controller,
182                     base::Unretained(audio_manager),
183                     params,
184                     device_id))) {
185    controller = NULL;
186  }
187
188  return controller;
189}
190
191// static
192scoped_refptr<AudioInputController> AudioInputController::CreateForStream(
193    const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
194    EventHandler* event_handler,
195    AudioInputStream* stream,
196    SyncWriter* sync_writer,
197    UserInputMonitor* user_input_monitor) {
198  DCHECK(sync_writer);
199  DCHECK(stream);
200
201  // Create the AudioInputController object and ensure that it runs on
202  // the audio-manager thread.
203  scoped_refptr<AudioInputController> controller(
204      new AudioInputController(event_handler, sync_writer, user_input_monitor));
205  controller->task_runner_ = task_runner;
206
207  // TODO(miu): See TODO at top of file.  Until that's resolved, we need to
208  // disable the error auto-detection here (since the audio mirroring
209  // implementation will reliably report error and close events).  Note, of
210  // course, that we're assuming CreateForStream() has been called for the audio
211  // mirroring use case only.
212  if (!controller->task_runner_->PostTask(
213          FROM_HERE,
214          base::Bind(&AudioInputController::DoCreateForStream,
215                     controller,
216                     stream))) {
217    controller = NULL;
218  }
219
220  return controller;
221}
222
223void AudioInputController::Record() {
224  task_runner_->PostTask(FROM_HERE, base::Bind(
225      &AudioInputController::DoRecord, this));
226}
227
228void AudioInputController::Close(const base::Closure& closed_task) {
229  DCHECK(!closed_task.is_null());
230  DCHECK(creator_task_runner_->BelongsToCurrentThread());
231
232  task_runner_->PostTaskAndReply(
233      FROM_HERE, base::Bind(&AudioInputController::DoClose, this), closed_task);
234}
235
236void AudioInputController::SetVolume(double volume) {
237  task_runner_->PostTask(FROM_HERE, base::Bind(
238      &AudioInputController::DoSetVolume, this, volume));
239}
240
241void AudioInputController::SetAutomaticGainControl(bool enabled) {
242  task_runner_->PostTask(FROM_HERE, base::Bind(
243      &AudioInputController::DoSetAutomaticGainControl, this, enabled));
244}
245
246void AudioInputController::DoCreate(AudioManager* audio_manager,
247                                    const AudioParameters& params,
248                                    const std::string& device_id) {
249  DCHECK(task_runner_->BelongsToCurrentThread());
250  SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioInputController.CreateTime");
251  if (handler_)
252    handler_->OnLog(this, "AIC::DoCreate");
253
254#if defined(AUDIO_POWER_MONITORING)
255  // Create the audio (power) level meter given the provided audio parameters.
256  // An AudioBus is also needed to wrap the raw data buffer from the native
257  // layer to match AudioPowerMonitor::Scan().
258  // TODO(henrika): Remove use of extra AudioBus. See http://crbug.com/375155.
259  last_audio_level_log_time_ = base::TimeTicks::Now();
260  audio_level_.reset(new media::AudioPowerMonitor(
261      params.sample_rate(),
262      TimeDelta::FromMilliseconds(kPowerMeasurementTimeConstantMilliseconds)));
263  audio_params_ = params;
264  silence_state_ = SILENCE_STATE_NO_MEASUREMENT;
265#endif
266
267  // TODO(miu): See TODO at top of file.  Until that's resolved, assume all
268  // platform audio input requires the |no_data_timer_| be used to auto-detect
269  // errors.  In reality, probably only Windows needs to be treated as
270  // unreliable here.
271  DoCreateForStream(audio_manager->MakeAudioInputStream(params, device_id));
272}
273
274void AudioInputController::DoCreateForLowLatency(AudioManager* audio_manager,
275                                                 const AudioParameters& params,
276                                                 const std::string& device_id) {
277  DCHECK(task_runner_->BelongsToCurrentThread());
278
279#if defined(AUDIO_POWER_MONITORING)
280  // We only log silence state UMA stats for low latency mode and if we use a
281  // real device.
282  if (params.format() != AudioParameters::AUDIO_FAKE)
283    log_silence_state_ = true;
284#endif
285
286  low_latency_create_time_ = base::TimeTicks::Now();
287  DoCreate(audio_manager, params, device_id);
288}
289
290void AudioInputController::DoCreateForStream(
291    AudioInputStream* stream_to_control) {
292  DCHECK(task_runner_->BelongsToCurrentThread());
293
294  DCHECK(!stream_);
295  stream_ = stream_to_control;
296
297  if (!stream_) {
298    if (handler_)
299      handler_->OnError(this, STREAM_CREATE_ERROR);
300    LogCaptureStartupResult(CAPTURE_STARTUP_CREATE_STREAM_FAILED);
301    return;
302  }
303
304  if (stream_ && !stream_->Open()) {
305    stream_->Close();
306    stream_ = NULL;
307    if (handler_)
308      handler_->OnError(this, STREAM_OPEN_ERROR);
309    LogCaptureStartupResult(CAPTURE_STARTUP_OPEN_STREAM_FAILED);
310    return;
311  }
312
313  DCHECK(!no_data_timer_.get());
314
315  // Create the data timer which will call FirstCheckForNoData(). The timer
316  // is started in DoRecord() and restarted in each DoCheckForNoData()
317  // callback.
318  // The timer is enabled for logging purposes. The NO_DATA_ERROR triggered
319  // from the timer must be ignored by the EventHandler.
320  // TODO(henrika): remove usage of timer when it has been verified on Canary
321  // that we are safe doing so. Goal is to get rid of |no_data_timer_| and
322  // everything that is tied to it. crbug.com/357569.
323  no_data_timer_.reset(new base::Timer(
324      FROM_HERE, base::TimeDelta::FromSeconds(kTimerInitialIntervalSeconds),
325      base::Bind(&AudioInputController::FirstCheckForNoData,
326                 base::Unretained(this)), false));
327
328  state_ = CREATED;
329  if (handler_)
330    handler_->OnCreated(this);
331
332  if (user_input_monitor_) {
333    user_input_monitor_->EnableKeyPressMonitoring();
334    prev_key_down_count_ = user_input_monitor_->GetKeyPressCount();
335  }
336}
337
338void AudioInputController::DoRecord() {
339  DCHECK(task_runner_->BelongsToCurrentThread());
340  SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioInputController.RecordTime");
341
342  if (state_ != CREATED)
343    return;
344
345  {
346    base::AutoLock auto_lock(lock_);
347    state_ = RECORDING;
348  }
349
350  if (handler_)
351    handler_->OnLog(this, "AIC::DoRecord");
352
353  if (no_data_timer_) {
354    // Start the data timer. Once |kTimerResetIntervalSeconds| have passed,
355    // a callback to FirstCheckForNoData() is made.
356    no_data_timer_->Reset();
357  }
358
359  stream_->Start(this);
360  if (handler_)
361    handler_->OnRecording(this);
362}
363
364void AudioInputController::DoClose() {
365  DCHECK(task_runner_->BelongsToCurrentThread());
366  SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioInputController.CloseTime");
367
368  if (state_ == CLOSED)
369    return;
370
371  // If this is a low-latency stream, log the total duration (since DoCreate)
372  // and add it to a UMA histogram.
373  if (!low_latency_create_time_.is_null()) {
374    base::TimeDelta duration =
375        base::TimeTicks::Now() - low_latency_create_time_;
376    UMA_HISTOGRAM_LONG_TIMES("Media.InputStreamDuration", duration);
377    if (handler_) {
378      std::string log_string =
379          base::StringPrintf("AIC::DoClose: stream duration=");
380      log_string += base::Int64ToString(duration.InSeconds());
381      log_string += " seconds";
382      handler_->OnLog(this, log_string);
383    }
384  }
385
386  // Delete the timer on the same thread that created it.
387  no_data_timer_.reset();
388
389  DoStopCloseAndClearStream();
390  SetDataIsActive(false);
391
392  if (SharedMemoryAndSyncSocketMode())
393    sync_writer_->Close();
394
395  if (user_input_monitor_)
396    user_input_monitor_->DisableKeyPressMonitoring();
397
398#if defined(AUDIO_POWER_MONITORING)
399  // Send UMA stats if enabled.
400  if (log_silence_state_)
401    LogSilenceState(silence_state_);
402  log_silence_state_ = false;
403#endif
404
405  state_ = CLOSED;
406}
407
408void AudioInputController::DoReportError() {
409  DCHECK(task_runner_->BelongsToCurrentThread());
410  if (handler_)
411    handler_->OnError(this, STREAM_ERROR);
412}
413
414void AudioInputController::DoSetVolume(double volume) {
415  DCHECK(task_runner_->BelongsToCurrentThread());
416  DCHECK_GE(volume, 0);
417  DCHECK_LE(volume, 1.0);
418
419  if (state_ != CREATED && state_ != RECORDING)
420    return;
421
422  // Only ask for the maximum volume at first call and use cached value
423  // for remaining function calls.
424  if (!max_volume_) {
425    max_volume_ = stream_->GetMaxVolume();
426  }
427
428  if (max_volume_ == 0.0) {
429    DLOG(WARNING) << "Failed to access input volume control";
430    return;
431  }
432
433  // Set the stream volume and scale to a range matched to the platform.
434  stream_->SetVolume(max_volume_ * volume);
435}
436
437void AudioInputController::DoSetAutomaticGainControl(bool enabled) {
438  DCHECK(task_runner_->BelongsToCurrentThread());
439  DCHECK_NE(state_, RECORDING);
440
441  // Ensure that the AGC state only can be modified before streaming starts.
442  if (state_ != CREATED)
443    return;
444
445  stream_->SetAutomaticGainControl(enabled);
446}
447
448void AudioInputController::FirstCheckForNoData() {
449  DCHECK(task_runner_->BelongsToCurrentThread());
450  LogCaptureStartupResult(GetDataIsActive() ?
451                          CAPTURE_STARTUP_OK :
452                          CAPTURE_STARTUP_NO_DATA_CALLBACK);
453  if (handler_) {
454    handler_->OnLog(this, GetDataIsActive() ?
455                    "AIC::FirstCheckForNoData => data is active" :
456                    "AIC::FirstCheckForNoData => data is NOT active");
457  }
458  DoCheckForNoData();
459}
460
461void AudioInputController::DoCheckForNoData() {
462  DCHECK(task_runner_->BelongsToCurrentThread());
463
464  if (!GetDataIsActive()) {
465    // The data-is-active marker will be false only if it has been more than
466    // one second since a data packet was recorded. This can happen if a
467    // capture device has been removed or disabled.
468    if (handler_)
469      handler_->OnError(this, NO_DATA_ERROR);
470  }
471
472  // Mark data as non-active. The flag will be re-enabled in OnData() each
473  // time a data packet is received. Hence, under normal conditions, the
474  // flag will only be disabled during a very short period.
475  SetDataIsActive(false);
476
477  // Restart the timer to ensure that we check the flag again in
478  // |kTimerResetIntervalSeconds|.
479  no_data_timer_->Start(
480      FROM_HERE, base::TimeDelta::FromSeconds(kTimerResetIntervalSeconds),
481      base::Bind(&AudioInputController::DoCheckForNoData,
482      base::Unretained(this)));
483}
484
485void AudioInputController::OnData(AudioInputStream* stream,
486                                  const AudioBus* source,
487                                  uint32 hardware_delay_bytes,
488                                  double volume) {
489  // Mark data as active to ensure that the periodic calls to
490  // DoCheckForNoData() does not report an error to the event handler.
491  SetDataIsActive(true);
492
493  {
494    base::AutoLock auto_lock(lock_);
495    if (state_ != RECORDING)
496      return;
497  }
498
499  bool key_pressed = false;
500  if (user_input_monitor_) {
501    size_t current_count = user_input_monitor_->GetKeyPressCount();
502    key_pressed = current_count != prev_key_down_count_;
503    prev_key_down_count_ = current_count;
504    DVLOG_IF(6, key_pressed) << "Detected keypress.";
505  }
506
507  // Use SharedMemory and SyncSocket if the client has created a SyncWriter.
508  // Used by all low-latency clients except WebSpeech.
509  if (SharedMemoryAndSyncSocketMode()) {
510    sync_writer_->Write(source, volume, key_pressed);
511    sync_writer_->UpdateRecordedBytes(hardware_delay_bytes);
512
513#if defined(AUDIO_POWER_MONITORING)
514    // Only do power-level measurements if an AudioPowerMonitor object has
515    // been created. Done in DoCreate() but not DoCreateForStream(), hence
516    // logging will mainly be done for WebRTC and WebSpeech clients.
517    if (!audio_level_)
518      return;
519
520    // Perform periodic audio (power) level measurements.
521    if ((base::TimeTicks::Now() - last_audio_level_log_time_).InSeconds() >
522        kPowerMonitorLogIntervalSeconds) {
523      // Wrap data into an AudioBus to match AudioPowerMonitor::Scan.
524      // TODO(henrika): remove this section when capture side uses AudioBus.
525      // See http://crbug.com/375155 for details.
526      audio_level_->Scan(*source, source->frames());
527
528      // Get current average power level and add it to the log.
529      // Possible range is given by [-inf, 0] dBFS.
530      std::pair<float, bool> result = audio_level_->ReadCurrentPowerAndClip();
531
532      // Add current microphone volume to log and UMA histogram.
533      const int mic_volume_percent = static_cast<int>(100.0 * volume);
534
535      // Use event handler on the audio thread to relay a message to the ARIH
536      // in content which does the actual logging on the IO thread.
537      task_runner_->PostTask(FROM_HERE,
538                             base::Bind(&AudioInputController::DoLogAudioLevels,
539                                        this,
540                                        result.first,
541                                        mic_volume_percent));
542
543      last_audio_level_log_time_ = base::TimeTicks::Now();
544
545      // Reset the average power level (since we don't log continuously).
546      audio_level_->Reset();
547    }
548#endif
549    return;
550  }
551
552  // TODO(henrika): Investigate if we can avoid the extra copy here.
553  // (see http://crbug.com/249316 for details). AFAIK, this scope is only
554  // active for WebSpeech clients.
555  scoped_ptr<AudioBus> audio_data =
556      AudioBus::Create(source->channels(), source->frames());
557  source->CopyTo(audio_data.get());
558
559  // Ownership of the audio buffer will be with the callback until it is run,
560  // when ownership is passed to the callback function.
561  task_runner_->PostTask(
562      FROM_HERE,
563      base::Bind(
564          &AudioInputController::DoOnData, this, base::Passed(&audio_data)));
565}
566
567void AudioInputController::DoOnData(scoped_ptr<AudioBus> data) {
568  DCHECK(task_runner_->BelongsToCurrentThread());
569  if (handler_)
570    handler_->OnData(this, data.get());
571}
572
573void AudioInputController::DoLogAudioLevels(float level_dbfs,
574                                            int microphone_volume_percent) {
575#if defined(AUDIO_POWER_MONITORING)
576  DCHECK(task_runner_->BelongsToCurrentThread());
577  if (!handler_)
578    return;
579
580  // Detect if the user has enabled hardware mute by pressing the mute
581  // button in audio settings for the selected microphone.
582  const bool microphone_is_muted = stream_->IsMuted();
583  if (microphone_is_muted) {
584    LogMicrophoneMuteResult(MICROPHONE_IS_MUTED);
585    handler_->OnLog(this, "AIC::OnData: microphone is muted!");
586    // Return early if microphone is muted. No need to adding logs and UMA stats
587    // of audio levels if we know that the micropone is muted.
588    return;
589  }
590
591  LogMicrophoneMuteResult(MICROPHONE_IS_NOT_MUTED);
592
593  std::string log_string = base::StringPrintf(
594      "AIC::OnData: average audio level=%.2f dBFS", level_dbfs);
595  static const float kSilenceThresholdDBFS = -72.24719896f;
596  if (level_dbfs < kSilenceThresholdDBFS)
597    log_string += " <=> low audio input level!";
598  handler_->OnLog(this, log_string);
599
600  UpdateSilenceState(level_dbfs < kSilenceThresholdDBFS);
601
602  UMA_HISTOGRAM_PERCENTAGE("Media.MicrophoneVolume", microphone_volume_percent);
603  log_string = base::StringPrintf(
604      "AIC::OnData: microphone volume=%d%%", microphone_volume_percent);
605  if (microphone_volume_percent < kLowLevelMicrophoneLevelPercent)
606    log_string += " <=> low microphone level!";
607  handler_->OnLog(this, log_string);
608#endif
609}
610
611void AudioInputController::OnError(AudioInputStream* stream) {
612  // Handle error on the audio-manager thread.
613  task_runner_->PostTask(FROM_HERE, base::Bind(
614      &AudioInputController::DoReportError, this));
615}
616
617void AudioInputController::DoStopCloseAndClearStream() {
618  DCHECK(task_runner_->BelongsToCurrentThread());
619
620  // Allow calling unconditionally and bail if we don't have a stream to close.
621  if (stream_ != NULL) {
622    stream_->Stop();
623    stream_->Close();
624    stream_ = NULL;
625  }
626
627  // The event handler should not be touched after the stream has been closed.
628  handler_ = NULL;
629}
630
631void AudioInputController::SetDataIsActive(bool enabled) {
632  base::subtle::Release_Store(&data_is_active_, enabled);
633}
634
635bool AudioInputController::GetDataIsActive() {
636  return (base::subtle::Acquire_Load(&data_is_active_) != false);
637}
638
639#if defined(AUDIO_POWER_MONITORING)
640void AudioInputController::UpdateSilenceState(bool silence) {
641  if (silence) {
642    if (silence_state_ == SILENCE_STATE_NO_MEASUREMENT) {
643      silence_state_ = SILENCE_STATE_ONLY_SILENCE;
644    } else if (silence_state_ == SILENCE_STATE_ONLY_AUDIO) {
645      silence_state_ = SILENCE_STATE_AUDIO_AND_SILENCE;
646    } else {
647      DCHECK(silence_state_ == SILENCE_STATE_ONLY_SILENCE ||
648             silence_state_ == SILENCE_STATE_AUDIO_AND_SILENCE);
649    }
650  } else {
651    if (silence_state_ == SILENCE_STATE_NO_MEASUREMENT) {
652      silence_state_ = SILENCE_STATE_ONLY_AUDIO;
653    } else if (silence_state_ == SILENCE_STATE_ONLY_SILENCE) {
654      silence_state_ = SILENCE_STATE_AUDIO_AND_SILENCE;
655    } else {
656      DCHECK(silence_state_ == SILENCE_STATE_ONLY_AUDIO ||
657             silence_state_ == SILENCE_STATE_AUDIO_AND_SILENCE);
658    }
659  }
660}
661
662void AudioInputController::LogSilenceState(SilenceState value) {
663  UMA_HISTOGRAM_ENUMERATION("Media.AudioInputControllerSessionSilenceReport",
664                            value,
665                            SILENCE_STATE_MAX + 1);
666}
667#endif
668
669}  // namespace media
670