Home | History | Annotate | Download | only in audio
      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_output_device.h"
      6 
      7 #include "base/basictypes.h"
      8 #include "base/debug/trace_event.h"
      9 #include "base/message_loop/message_loop.h"
     10 #include "base/threading/thread_restrictions.h"
     11 #include "base/time/time.h"
     12 #include "media/audio/audio_output_controller.h"
     13 #include "media/audio/audio_util.h"
     14 #include "media/audio/shared_memory_util.h"
     15 #include "media/base/limits.h"
     16 
     17 namespace media {
     18 
     19 // Takes care of invoking the render callback on the audio thread.
     20 // An instance of this class is created for each capture stream in
     21 // OnStreamCreated().
     22 class AudioOutputDevice::AudioThreadCallback
     23     : public AudioDeviceThread::Callback {
     24  public:
     25   AudioThreadCallback(const AudioParameters& audio_parameters,
     26                       base::SharedMemoryHandle memory,
     27                       int memory_length,
     28                       AudioRendererSink::RenderCallback* render_callback);
     29   virtual ~AudioThreadCallback();
     30 
     31   virtual void MapSharedMemory() OVERRIDE;
     32 
     33   // Called whenever we receive notifications about pending data.
     34   virtual void Process(int pending_data) OVERRIDE;
     35 
     36  private:
     37   AudioRendererSink::RenderCallback* render_callback_;
     38   scoped_ptr<AudioBus> input_bus_;
     39   scoped_ptr<AudioBus> output_bus_;
     40   DISALLOW_COPY_AND_ASSIGN(AudioThreadCallback);
     41 };
     42 
     43 AudioOutputDevice::AudioOutputDevice(
     44     scoped_ptr<AudioOutputIPC> ipc,
     45     const scoped_refptr<base::MessageLoopProxy>& io_loop)
     46     : ScopedLoopObserver(io_loop),
     47       callback_(NULL),
     48       ipc_(ipc.Pass()),
     49       state_(IDLE),
     50       play_on_start_(true),
     51       session_id_(-1),
     52       stopping_hack_(false) {
     53   CHECK(ipc_);
     54 
     55   // The correctness of the code depends on the relative values assigned in the
     56   // State enum.
     57   COMPILE_ASSERT(IPC_CLOSED < IDLE, invalid_enum_value_assignment_0);
     58   COMPILE_ASSERT(IDLE < CREATING_STREAM, invalid_enum_value_assignment_1);
     59   COMPILE_ASSERT(CREATING_STREAM < PAUSED, invalid_enum_value_assignment_2);
     60   COMPILE_ASSERT(PAUSED < PLAYING, invalid_enum_value_assignment_3);
     61 }
     62 
     63 void AudioOutputDevice::InitializeUnifiedStream(const AudioParameters& params,
     64                                                 RenderCallback* callback,
     65                                                 int session_id) {
     66   DCHECK(!callback_) << "Calling InitializeUnifiedStream() twice?";
     67   DCHECK(params.IsValid());
     68   audio_parameters_ = params;
     69   callback_ = callback;
     70   session_id_ = session_id;
     71 }
     72 
     73 void AudioOutputDevice::Initialize(const AudioParameters& params,
     74                                    RenderCallback* callback) {
     75   InitializeUnifiedStream(params, callback, 0);
     76 }
     77 
     78 AudioOutputDevice::~AudioOutputDevice() {
     79   // The current design requires that the user calls Stop() before deleting
     80   // this class.
     81   DCHECK(audio_thread_.IsStopped());
     82 }
     83 
     84 void AudioOutputDevice::Start() {
     85   DCHECK(callback_) << "Initialize hasn't been called";
     86   message_loop()->PostTask(FROM_HERE,
     87       base::Bind(&AudioOutputDevice::CreateStreamOnIOThread, this,
     88                  audio_parameters_));
     89 }
     90 
     91 void AudioOutputDevice::Stop() {
     92   {
     93     base::AutoLock auto_lock(audio_thread_lock_);
     94     audio_thread_.Stop(base::MessageLoop::current());
     95     stopping_hack_ = true;
     96   }
     97 
     98   message_loop()->PostTask(FROM_HERE,
     99       base::Bind(&AudioOutputDevice::ShutDownOnIOThread, this));
    100 }
    101 
    102 void AudioOutputDevice::Play() {
    103   message_loop()->PostTask(FROM_HERE,
    104       base::Bind(&AudioOutputDevice::PlayOnIOThread, this));
    105 }
    106 
    107 void AudioOutputDevice::Pause() {
    108   message_loop()->PostTask(FROM_HERE,
    109       base::Bind(&AudioOutputDevice::PauseOnIOThread, this));
    110 }
    111 
    112 bool AudioOutputDevice::SetVolume(double volume) {
    113   if (volume < 0 || volume > 1.0)
    114     return false;
    115 
    116   if (!message_loop()->PostTask(FROM_HERE,
    117           base::Bind(&AudioOutputDevice::SetVolumeOnIOThread, this, volume))) {
    118     return false;
    119   }
    120 
    121   return true;
    122 }
    123 
    124 void AudioOutputDevice::CreateStreamOnIOThread(const AudioParameters& params) {
    125   DCHECK(message_loop()->BelongsToCurrentThread());
    126   if (state_ == IDLE) {
    127     state_ = CREATING_STREAM;
    128     ipc_->CreateStream(this, params, session_id_);
    129   }
    130 }
    131 
    132 void AudioOutputDevice::PlayOnIOThread() {
    133   DCHECK(message_loop()->BelongsToCurrentThread());
    134   if (state_ == PAUSED) {
    135     ipc_->PlayStream();
    136     state_ = PLAYING;
    137     play_on_start_ = false;
    138   } else {
    139     play_on_start_ = true;
    140   }
    141 }
    142 
    143 void AudioOutputDevice::PauseOnIOThread() {
    144   DCHECK(message_loop()->BelongsToCurrentThread());
    145   if (state_ == PLAYING) {
    146     ipc_->PauseStream();
    147     state_ = PAUSED;
    148   }
    149   play_on_start_ = false;
    150 }
    151 
    152 void AudioOutputDevice::ShutDownOnIOThread() {
    153   DCHECK(message_loop()->BelongsToCurrentThread());
    154 
    155   // Close the stream, if we haven't already.
    156   if (state_ >= CREATING_STREAM) {
    157     ipc_->CloseStream();
    158     state_ = IDLE;
    159   }
    160 
    161   // We can run into an issue where ShutDownOnIOThread is called right after
    162   // OnStreamCreated is called in cases where Start/Stop are called before we
    163   // get the OnStreamCreated callback.  To handle that corner case, we call
    164   // Stop(). In most cases, the thread will already be stopped.
    165   //
    166   // Another situation is when the IO thread goes away before Stop() is called
    167   // in which case, we cannot use the message loop to close the thread handle
    168   // and can't rely on the main thread existing either.
    169   base::AutoLock auto_lock_(audio_thread_lock_);
    170   base::ThreadRestrictions::ScopedAllowIO allow_io;
    171   audio_thread_.Stop(NULL);
    172   audio_callback_.reset();
    173   stopping_hack_ = false;
    174 }
    175 
    176 void AudioOutputDevice::SetVolumeOnIOThread(double volume) {
    177   DCHECK(message_loop()->BelongsToCurrentThread());
    178   if (state_ >= CREATING_STREAM)
    179     ipc_->SetVolume(volume);
    180 }
    181 
    182 void AudioOutputDevice::OnStateChanged(AudioOutputIPCDelegate::State state) {
    183   DCHECK(message_loop()->BelongsToCurrentThread());
    184 
    185   // Do nothing if the stream has been closed.
    186   if (state_ < CREATING_STREAM)
    187     return;
    188 
    189   // TODO(miu): Clean-up inconsistent and incomplete handling here.
    190   // http://crbug.com/180640
    191   switch (state) {
    192     case AudioOutputIPCDelegate::kPlaying:
    193     case AudioOutputIPCDelegate::kPaused:
    194       break;
    195     case AudioOutputIPCDelegate::kError:
    196       DLOG(WARNING) << "AudioOutputDevice::OnStateChanged(kError)";
    197       // Don't dereference the callback object if the audio thread
    198       // is stopped or stopping.  That could mean that the callback
    199       // object has been deleted.
    200       // TODO(tommi): Add an explicit contract for clearing the callback
    201       // object.  Possibly require calling Initialize again or provide
    202       // a callback object via Start() and clear it in Stop().
    203       if (!audio_thread_.IsStopped())
    204         callback_->OnRenderError();
    205       break;
    206     default:
    207       NOTREACHED();
    208       break;
    209   }
    210 }
    211 
    212 void AudioOutputDevice::OnStreamCreated(
    213     base::SharedMemoryHandle handle,
    214     base::SyncSocket::Handle socket_handle,
    215     int length) {
    216   DCHECK(message_loop()->BelongsToCurrentThread());
    217 #if defined(OS_WIN)
    218   DCHECK(handle);
    219   DCHECK(socket_handle);
    220 #else
    221   DCHECK_GE(handle.fd, 0);
    222   DCHECK_GE(socket_handle, 0);
    223 #endif
    224   DCHECK_GT(length, 0);
    225 
    226   if (state_ != CREATING_STREAM)
    227     return;
    228 
    229   // We can receive OnStreamCreated() on the IO thread after the client has
    230   // called Stop() but before ShutDownOnIOThread() is processed. In such a
    231   // situation |callback_| might point to freed memory. Instead of starting
    232   // |audio_thread_| do nothing and wait for ShutDownOnIOThread() to get called.
    233   //
    234   // TODO(scherkus): The real fix is to have sane ownership semantics. The fact
    235   // that |callback_| (which should own and outlive this object!) can point to
    236   // freed memory is a mess. AudioRendererSink should be non-refcounted so that
    237   // owners (WebRtcAudioDeviceImpl, AudioRendererImpl, etc...) can Stop() and
    238   // delete as they see fit. AudioOutputDevice should internally use WeakPtr
    239   // to handle teardown and thread hopping. See http://crbug.com/151051 for
    240   // details.
    241   base::AutoLock auto_lock(audio_thread_lock_);
    242   if (stopping_hack_)
    243     return;
    244 
    245   DCHECK(audio_thread_.IsStopped());
    246   audio_callback_.reset(new AudioOutputDevice::AudioThreadCallback(
    247       audio_parameters_, handle, length, callback_));
    248   audio_thread_.Start(audio_callback_.get(), socket_handle,
    249       "AudioOutputDevice");
    250   state_ = PAUSED;
    251 
    252   // We handle the case where Play() and/or Pause() may have been called
    253   // multiple times before OnStreamCreated() gets called.
    254   if (play_on_start_)
    255     PlayOnIOThread();
    256 }
    257 
    258 void AudioOutputDevice::OnIPCClosed() {
    259   DCHECK(message_loop()->BelongsToCurrentThread());
    260   state_ = IPC_CLOSED;
    261   ipc_.reset();
    262 }
    263 
    264 void AudioOutputDevice::WillDestroyCurrentMessageLoop() {
    265   LOG(ERROR) << "IO loop going away before the audio device has been stopped";
    266   ShutDownOnIOThread();
    267 }
    268 
    269 // AudioOutputDevice::AudioThreadCallback
    270 
    271 AudioOutputDevice::AudioThreadCallback::AudioThreadCallback(
    272     const AudioParameters& audio_parameters,
    273     base::SharedMemoryHandle memory,
    274     int memory_length,
    275     AudioRendererSink::RenderCallback* render_callback)
    276     : AudioDeviceThread::Callback(audio_parameters,
    277                                   memory,
    278                                   memory_length,
    279                                   1),
    280       render_callback_(render_callback) {
    281 }
    282 
    283 AudioOutputDevice::AudioThreadCallback::~AudioThreadCallback() {
    284 }
    285 
    286 void AudioOutputDevice::AudioThreadCallback::MapSharedMemory() {
    287   CHECK_EQ(total_segments_, 1);
    288   CHECK(shared_memory_.Map(TotalSharedMemorySizeInBytes(memory_length_)));
    289 
    290   // Calculate output and input memory size.
    291   int output_memory_size = AudioBus::CalculateMemorySize(audio_parameters_);
    292   int input_channels = audio_parameters_.input_channels();
    293   int frames = audio_parameters_.frames_per_buffer();
    294   int input_memory_size =
    295       AudioBus::CalculateMemorySize(input_channels, frames);
    296 
    297   int io_size = output_memory_size + input_memory_size;
    298 
    299   DCHECK_EQ(memory_length_, io_size);
    300 
    301   output_bus_ =
    302       AudioBus::WrapMemory(audio_parameters_, shared_memory_.memory());
    303 
    304   if (input_channels > 0) {
    305     // The input data is after the output data.
    306     char* input_data =
    307         static_cast<char*>(shared_memory_.memory()) + output_memory_size;
    308     input_bus_ =
    309         AudioBus::WrapMemory(input_channels, frames, input_data);
    310   }
    311 }
    312 
    313 // Called whenever we receive notifications about pending data.
    314 void AudioOutputDevice::AudioThreadCallback::Process(int pending_data) {
    315   if (pending_data == kPauseMark) {
    316     memset(shared_memory_.memory(), 0, memory_length_);
    317     SetActualDataSizeInBytes(&shared_memory_, memory_length_, 0);
    318     return;
    319   }
    320 
    321   // Convert the number of pending bytes in the render buffer
    322   // into milliseconds.
    323   int audio_delay_milliseconds = pending_data / bytes_per_ms_;
    324 
    325   TRACE_EVENT0("audio", "AudioOutputDevice::FireRenderCallback");
    326 
    327   // Update the audio-delay measurement then ask client to render audio.  Since
    328   // |output_bus_| is wrapping the shared memory the Render() call is writing
    329   // directly into the shared memory.
    330   int input_channels = audio_parameters_.input_channels();
    331   size_t num_frames = audio_parameters_.frames_per_buffer();
    332 
    333   if (input_bus_.get() && input_channels > 0) {
    334     render_callback_->RenderIO(input_bus_.get(),
    335                                output_bus_.get(),
    336                                audio_delay_milliseconds);
    337   } else {
    338     num_frames = render_callback_->Render(output_bus_.get(),
    339                                           audio_delay_milliseconds);
    340   }
    341 
    342   // Let the host know we are done.
    343   // TODO(dalecurtis): Technically this is not always correct.  Due to channel
    344   // padding for alignment, there may be more data available than this.  We're
    345   // relying on AudioSyncReader::Read() to parse this with that in mind.  Rename
    346   // these methods to Set/GetActualFrameCount().
    347   SetActualDataSizeInBytes(
    348       &shared_memory_, memory_length_,
    349       num_frames * sizeof(*output_bus_->channel(0)) * output_bus_->channels());
    350 }
    351 
    352 }  // namespace media.
    353