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 "remoting/host/audio_scheduler.h"
6
7#include "base/bind.h"
8#include "base/location.h"
9#include "base/logging.h"
10#include "base/single_thread_task_runner.h"
11#include "remoting/codec/audio_encoder.h"
12#include "remoting/host/audio_capturer.h"
13#include "remoting/proto/audio.pb.h"
14#include "remoting/protocol/audio_stub.h"
15
16namespace remoting {
17
18AudioScheduler::AudioScheduler(
19    scoped_refptr<base::SingleThreadTaskRunner> audio_task_runner,
20    scoped_refptr<base::SingleThreadTaskRunner> network_task_runner,
21    scoped_ptr<AudioCapturer> audio_capturer,
22    scoped_ptr<AudioEncoder> audio_encoder,
23    protocol::AudioStub* audio_stub)
24    : audio_task_runner_(audio_task_runner),
25      network_task_runner_(network_task_runner),
26      audio_capturer_(audio_capturer.Pass()),
27      audio_encoder_(audio_encoder.Pass()),
28      audio_stub_(audio_stub),
29      network_stopped_(false),
30      enabled_(true) {
31  DCHECK(network_task_runner_->BelongsToCurrentThread());
32  DCHECK(audio_capturer_);
33  DCHECK(audio_encoder_);
34  DCHECK(audio_stub_);
35}
36
37void AudioScheduler::Start() {
38  DCHECK(network_task_runner_->BelongsToCurrentThread());
39
40  audio_task_runner_->PostTask(
41      FROM_HERE, base::Bind(&AudioScheduler::StartOnAudioThread, this));
42}
43
44void AudioScheduler::Stop() {
45  DCHECK(network_task_runner_->BelongsToCurrentThread());
46  DCHECK(audio_stub_);
47
48  // Clear |audio_stub_| to prevent audio packets being delivered to the client.
49  audio_stub_ = NULL;
50
51  audio_task_runner_->PostTask(
52      FROM_HERE,
53      base::Bind(&AudioScheduler::StopOnAudioThread, this));
54}
55
56AudioScheduler::~AudioScheduler() {
57}
58
59void AudioScheduler::StartOnAudioThread() {
60  DCHECK(audio_task_runner_->BelongsToCurrentThread());
61
62  // TODO(kxing): Do something with the return value.
63  audio_capturer_->Start(
64      base::Bind(&AudioScheduler::EncodeAudioPacket, this));
65}
66
67void AudioScheduler::StopOnAudioThread() {
68  DCHECK(audio_task_runner_->BelongsToCurrentThread());
69  audio_capturer_->Stop();
70}
71
72void AudioScheduler::Pause(bool pause) {
73  if (!audio_task_runner_->BelongsToCurrentThread()) {
74    audio_task_runner_->PostTask(
75        FROM_HERE, base::Bind(&AudioScheduler::Pause, this, pause));
76    return;
77  }
78
79  enabled_ = !pause;
80}
81
82void AudioScheduler::EncodeAudioPacket(scoped_ptr<AudioPacket> packet) {
83  DCHECK(audio_task_runner_->BelongsToCurrentThread());
84  DCHECK(packet.get());
85
86  if (!enabled_)
87    return;
88
89  scoped_ptr<AudioPacket> encoded_packet =
90      audio_encoder_->Encode(packet.Pass());
91
92  // The audio encoder returns a NULL audio packet if there's no audio to send.
93  if (encoded_packet.get()) {
94    network_task_runner_->PostTask(
95        FROM_HERE, base::Bind(&AudioScheduler::SendAudioPacket,
96                              this, base::Passed(&encoded_packet)));
97  }
98}
99
100void AudioScheduler::SendAudioPacket(scoped_ptr<AudioPacket> packet) {
101  DCHECK(network_task_runner_->BelongsToCurrentThread());
102  DCHECK(packet.get());
103
104  if (!audio_stub_)
105    return;
106
107  audio_stub_->ProcessAudioPacket(packet.Pass(), base::Closure());
108}
109
110}  // namespace remoting
111