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/client/audio_decode_scheduler.h"
6
7#include "base/bind.h"
8#include "base/location.h"
9#include "base/single_thread_task_runner.h"
10#include "remoting/client/audio_player.h"
11#include "remoting/codec/audio_decoder.h"
12#include "remoting/proto/audio.pb.h"
13
14namespace remoting {
15
16class AudioDecodeScheduler::Core : public base::RefCountedThreadSafe<Core> {
17 public:
18  Core(scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
19       scoped_refptr<base::SingleThreadTaskRunner> audio_decode_task_runner,
20       scoped_ptr<AudioPlayer> audio_player);
21
22  void Initialize(const protocol::SessionConfig& config);
23  void ProcessAudioPacket(scoped_ptr<AudioPacket> packet,
24                          const base::Closure& done);
25
26  // Called by AudioDecodeScheduler when it is destroyed.
27  void Detach();
28
29 private:
30  friend class base::RefCountedThreadSafe<Core>;
31
32  virtual ~Core();
33
34  // Called on the audio decoder thread.
35  void DecodePacket(scoped_ptr<AudioPacket> packet, const base::Closure& done);
36
37  // Called on the main thread.
38  void ProcessDecodedPacket(scoped_ptr<AudioPacket> packet,
39                            const base::Closure& done);
40
41  scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_;
42  scoped_refptr<base::SingleThreadTaskRunner> audio_decode_task_runner_;
43  scoped_ptr<AudioDecoder> decoder_;
44  scoped_ptr<AudioPlayer> audio_player_;
45
46  DISALLOW_COPY_AND_ASSIGN(Core);
47};
48
49AudioDecodeScheduler::Core::Core(
50    scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
51    scoped_refptr<base::SingleThreadTaskRunner> audio_decode_task_runner,
52    scoped_ptr<AudioPlayer> audio_player)
53    : main_task_runner_(main_task_runner),
54      audio_decode_task_runner_(audio_decode_task_runner),
55      audio_player_(audio_player.Pass()) {
56}
57
58AudioDecodeScheduler::Core::~Core() {
59}
60
61void AudioDecodeScheduler::Core::Initialize(
62    const protocol::SessionConfig& config) {
63  DCHECK(main_task_runner_->BelongsToCurrentThread());
64  decoder_.reset(AudioDecoder::CreateAudioDecoder(config).release());
65}
66
67void AudioDecodeScheduler::Core::ProcessAudioPacket(
68    scoped_ptr<AudioPacket> packet,
69    const base::Closure& done) {
70  DCHECK(main_task_runner_->BelongsToCurrentThread());
71  audio_decode_task_runner_->PostTask(FROM_HERE, base::Bind(
72      &AudioDecodeScheduler::Core::DecodePacket, this,
73      base::Passed(&packet), done));
74}
75
76void AudioDecodeScheduler::Core::Detach() {
77  DCHECK(main_task_runner_->BelongsToCurrentThread());
78  audio_player_.reset();
79}
80
81void AudioDecodeScheduler::Core::DecodePacket(
82    scoped_ptr<AudioPacket> packet,
83    const base::Closure& done) {
84  DCHECK(audio_decode_task_runner_->BelongsToCurrentThread());
85  scoped_ptr<AudioPacket> decoded_packet = decoder_->Decode(packet.Pass());
86
87  main_task_runner_->PostTask(FROM_HERE, base::Bind(
88      &AudioDecodeScheduler::Core::ProcessDecodedPacket, this,
89      base::Passed(&decoded_packet), done));
90}
91
92void AudioDecodeScheduler::Core::ProcessDecodedPacket(
93    scoped_ptr<AudioPacket> packet,
94    const base::Closure& done) {
95  DCHECK(main_task_runner_->BelongsToCurrentThread());
96  // Only process |packet| if it is non-NULL.
97  if (packet.get() && audio_player_.get())
98    audio_player_->ProcessAudioPacket(packet.Pass());
99  done.Run();
100}
101
102AudioDecodeScheduler::AudioDecodeScheduler(
103    scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
104    scoped_refptr<base::SingleThreadTaskRunner> audio_decode_task_runner,
105    scoped_ptr<AudioPlayer> audio_player)
106    : core_(new Core(main_task_runner, audio_decode_task_runner,
107                     audio_player.Pass())) {
108}
109
110AudioDecodeScheduler::~AudioDecodeScheduler() {
111  core_->Detach();
112}
113
114void AudioDecodeScheduler::Initialize(const protocol::SessionConfig& config) {
115  core_->Initialize(config);
116}
117
118void AudioDecodeScheduler::ProcessAudioPacket(scoped_ptr<AudioPacket> packet,
119                                              const base::Closure& done) {
120  core_->ProcessAudioPacket(packet.Pass(), done);
121}
122
123}  // namespace remoting
124