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_player.h"
6
7#include <algorithm>
8
9#include "base/logging.h"
10#include "base/stl_util.h"
11
12// The number of channels in the audio stream (only supporting stereo audio
13// for now).
14const int kChannels = 2;
15const int kSampleSizeBytes = 2;
16
17// If queue grows bigger than 150ms we start dropping packets.
18const int kMaxQueueLatencyMs = 150;
19
20namespace remoting {
21
22AudioPlayer::AudioPlayer()
23    : sampling_rate_(AudioPacket::SAMPLING_RATE_INVALID),
24      start_failed_(false),
25      queued_bytes_(0),
26      bytes_consumed_(0) {
27}
28
29AudioPlayer::~AudioPlayer() {
30  base::AutoLock auto_lock(lock_);
31  ResetQueue();
32}
33
34void AudioPlayer::ProcessAudioPacket(scoped_ptr<AudioPacket> packet) {
35  CHECK_EQ(1, packet->data_size());
36  DCHECK_EQ(AudioPacket::ENCODING_RAW, packet->encoding());
37  DCHECK_NE(AudioPacket::SAMPLING_RATE_INVALID, packet->sampling_rate());
38  DCHECK_EQ(kSampleSizeBytes, packet->bytes_per_sample());
39  DCHECK_EQ(static_cast<int>(kChannels), packet->channels());
40  DCHECK_EQ(packet->data(0).size() % (kChannels * kSampleSizeBytes), 0u);
41
42  // No-op if the Pepper player won't start.
43  if (start_failed_) {
44    return;
45  }
46
47  // Start the Pepper audio player if this is the first packet.
48  if (sampling_rate_ != packet->sampling_rate()) {
49    // Drop all packets currently in the queue, since they are sampled at the
50    // wrong rate.
51    {
52      base::AutoLock auto_lock(lock_);
53      ResetQueue();
54    }
55
56    sampling_rate_ = packet->sampling_rate();
57    bool success = ResetAudioPlayer(sampling_rate_);
58    if (!success) {
59      start_failed_ = true;
60      return;
61    }
62  }
63
64  base::AutoLock auto_lock(lock_);
65
66  queued_bytes_ += packet->data(0).size();
67  queued_packets_.push_back(packet.release());
68
69  int max_buffer_size_ =
70      kMaxQueueLatencyMs * sampling_rate_ * kSampleSizeBytes * kChannels /
71      base::Time::kMillisecondsPerSecond;
72  while (queued_bytes_ > max_buffer_size_) {
73    queued_bytes_ -= queued_packets_.front()->data(0).size() - bytes_consumed_;
74    DCHECK_GE(queued_bytes_, 0);
75    delete queued_packets_.front();
76    queued_packets_.pop_front();
77    bytes_consumed_ = 0;
78  }
79}
80
81// static
82void AudioPlayer::AudioPlayerCallback(void* samples,
83                                      uint32 buffer_size,
84                                      void* data) {
85  AudioPlayer* audio_player = static_cast<AudioPlayer*>(data);
86  audio_player->FillWithSamples(samples, buffer_size);
87}
88
89void AudioPlayer::ResetQueue() {
90  lock_.AssertAcquired();
91  STLDeleteElements(&queued_packets_);
92  queued_bytes_ = 0;
93  bytes_consumed_ = 0;
94}
95
96void AudioPlayer::FillWithSamples(void* samples, uint32 buffer_size) {
97  base::AutoLock auto_lock(lock_);
98
99  const size_t bytes_needed = kChannels * kSampleSizeBytes *
100      GetSamplesPerFrame();
101
102  // Make sure we don't overrun the buffer.
103  CHECK_EQ(buffer_size, bytes_needed);
104
105  char* next_sample = static_cast<char*>(samples);
106  size_t bytes_extracted = 0;
107
108  while (bytes_extracted < bytes_needed) {
109    // Check if we've run out of samples for this packet.
110    if (queued_packets_.empty()) {
111      memset(next_sample, 0, bytes_needed - bytes_extracted);
112      return;
113    }
114
115    // Pop off the packet if we've already consumed all its bytes.
116    if (queued_packets_.front()->data(0).size() == bytes_consumed_) {
117      delete queued_packets_.front();
118      queued_packets_.pop_front();
119      bytes_consumed_ = 0;
120      continue;
121    }
122
123    const std::string& packet_data = queued_packets_.front()->data(0);
124    size_t bytes_to_copy = std::min(
125        packet_data.size() - bytes_consumed_,
126        bytes_needed - bytes_extracted);
127    memcpy(next_sample, packet_data.data() + bytes_consumed_, bytes_to_copy);
128
129    next_sample += bytes_to_copy;
130    bytes_consumed_ += bytes_to_copy;
131    bytes_extracted += bytes_to_copy;
132    queued_bytes_ -= bytes_to_copy;
133    DCHECK_GE(queued_bytes_, 0);
134  }
135}
136
137}  // namespace remoting
138