summaryrefslogtreecommitdiff
path: root/chromium/media/audio/clockless_audio_sink.cc
blob: ff809d0541dd49fc87f6559bf901563cb5c92cdc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "media/audio/clockless_audio_sink.h"

#include "base/threading/simple_thread.h"
#include "base/time/time.h"
#include "media/base/audio_renderer_sink.h"

namespace media {

// Internal to ClocklessAudioSink. Class is used to call Render() on a seperate
// thread, running as fast as it can read the data.
class ClocklessAudioSinkThread : public base::DelegateSimpleThread::Delegate {
 public:
  explicit ClocklessAudioSinkThread(const AudioParameters& params,
                                    AudioRendererSink::RenderCallback* callback)
      : callback_(callback),
        audio_bus_(AudioBus::Create(params)),
        stop_event_(new base::WaitableEvent(false, false)) {}

  void Start() {
    stop_event_->Reset();
    thread_.reset(new base::DelegateSimpleThread(this, "ClocklessAudioSink"));
    thread_->Start();
  }

  // Generate a signal to stop calling Render().
  base::TimeDelta Stop() {
    stop_event_->Signal();
    thread_->Join();
    return playback_time_;
  }

 private:
   // Call Render() repeatedly, keeping track of the rendering time.
   virtual void Run() OVERRIDE {
     base::TimeTicks start;
     while (!stop_event_->IsSignaled()) {
       int frames_received = callback_->Render(audio_bus_.get(), 0);
       if (frames_received <= 0) {
         // No data received, so let other threads run to provide data.
         base::PlatformThread::YieldCurrentThread();
       } else if (start.is_null()) {
         // First time we processed some audio, so record the starting time.
         start = base::TimeTicks::HighResNow();
       } else {
         // Keep track of the last time data was rendered.
         playback_time_ = base::TimeTicks::HighResNow() - start;
       }
     }
   }

  AudioRendererSink::RenderCallback* callback_;
  scoped_ptr<AudioBus> audio_bus_;
  scoped_ptr<base::WaitableEvent> stop_event_;
  scoped_ptr<base::DelegateSimpleThread> thread_;
  base::TimeDelta playback_time_;
};

ClocklessAudioSink::ClocklessAudioSink()
    : initialized_(false),
      playing_(false) {}

ClocklessAudioSink::~ClocklessAudioSink() {}

void ClocklessAudioSink::Initialize(const AudioParameters& params,
                                    RenderCallback* callback) {
  DCHECK(!initialized_);
  thread_.reset(new ClocklessAudioSinkThread(params, callback));
  initialized_ = true;
}

void ClocklessAudioSink::Start() {
  DCHECK(!playing_);
}

void ClocklessAudioSink::Stop() {
  DCHECK(initialized_);

  if (!playing_)
    return;

  playback_time_ = thread_->Stop();
}

void ClocklessAudioSink::Play() {
  DCHECK(initialized_);

  if (playing_)
    return;

  playing_ = true;
  thread_->Start();
}

void ClocklessAudioSink::Pause() {
  Stop();
}

bool ClocklessAudioSink::SetVolume(double volume) {
  // Audio is always muted.
  return volume == 0.0;
}

}  // namespace media