12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file.
42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "media/audio/virtual_audio_output_stream.h"
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/logging.h"
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "media/audio/virtual_audio_input_stream.h"
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace media {
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)VirtualAudioOutputStream::VirtualAudioOutputStream(
13eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    const AudioParameters& params, VirtualAudioInputStream* target,
14eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    const AfterCloseCallback& after_close_cb)
15eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    : params_(params), target_input_stream_(target),
16eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      after_close_cb_(after_close_cb), callback_(NULL), volume_(1.0f) {
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(params_.IsValid());
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(target);
19eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
20eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // VAOS can be constructed on any thread, but will DCHECK that all
21eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // AudioOutputStream methods are called from the same thread.
22eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  thread_checker_.DetachFromThread();
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)VirtualAudioOutputStream::~VirtualAudioOutputStream() {
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!callback_);
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool VirtualAudioOutputStream::Open() {
30eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  DCHECK(thread_checker_.CalledOnValidThread());
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void VirtualAudioOutputStream::Start(AudioSourceCallback* callback)  {
35eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  DCHECK(thread_checker_.CalledOnValidThread());
362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!callback_);
372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  callback_ = callback;
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  target_input_stream_->AddOutputStream(this, params_);
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void VirtualAudioOutputStream::Stop() {
42eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  DCHECK(thread_checker_.CalledOnValidThread());
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (callback_) {
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    target_input_stream_->RemoveOutputStream(this, params_);
45eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    callback_ = NULL;
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void VirtualAudioOutputStream::Close() {
50eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  DCHECK(thread_checker_.CalledOnValidThread());
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Stop();
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // If a non-null AfterCloseCallback was provided to the constructor, invoke it
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // here.  The callback is moved to a stack-local first since |this| could be
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // destroyed during Run().
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!after_close_cb_.is_null()) {
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const AfterCloseCallback cb = after_close_cb_;
592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    after_close_cb_.Reset();
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    cb.Run(this);
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void VirtualAudioOutputStream::SetVolume(double volume) {
65eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  DCHECK(thread_checker_.CalledOnValidThread());
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  volume_ = volume;
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void VirtualAudioOutputStream::GetVolume(double* volume) {
70eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  DCHECK(thread_checker_.CalledOnValidThread());
712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  *volume = volume_;
722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)double VirtualAudioOutputStream::ProvideInput(AudioBus* audio_bus,
752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                              base::TimeDelta buffer_delay) {
76eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Note: This method may be invoked on any one thread, depending on the
77eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // platform.
782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(callback_);
792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const int frames = callback_->OnMoreData(audio_bus, AudioBuffersState());
812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (frames < audio_bus->frames())
822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    audio_bus->ZeroFramesPartial(frames, audio_bus->frames() - frames);
832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return frames > 0 ? volume_ : 0;
852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace media
88