Upstreaming browser/ui/uikit_ui_util from iOS.
[chromium-blink-merge.git] / remoting / client / audio_player.cc
bloba26f1bc18bb83fb62204306aaad0ab776691d6ad
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.
5 #include "remoting/client/audio_player.h"
7 #include <algorithm>
9 #include "base/logging.h"
10 #include "base/stl_util.h"
12 // The number of channels in the audio stream (only supporting stereo audio
13 // for now).
14 const int kChannels = 2;
15 const int kSampleSizeBytes = 2;
17 // If queue grows bigger than 150ms we start dropping packets.
18 const int kMaxQueueLatencyMs = 150;
20 namespace remoting {
22 AudioPlayer::AudioPlayer()
23 : sampling_rate_(AudioPacket::SAMPLING_RATE_INVALID),
24 start_failed_(false),
25 queued_bytes_(0),
26 bytes_consumed_(0) {
29 AudioPlayer::~AudioPlayer() {
30 base::AutoLock auto_lock(lock_);
31 ResetQueue();
34 void 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);
42 // No-op if the Pepper player won't start.
43 if (start_failed_) {
44 return;
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.
52 base::AutoLock auto_lock(lock_);
53 ResetQueue();
56 sampling_rate_ = packet->sampling_rate();
57 bool success = ResetAudioPlayer(sampling_rate_);
58 if (!success) {
59 start_failed_ = true;
60 return;
64 base::AutoLock auto_lock(lock_);
66 queued_bytes_ += packet->data(0).size();
67 queued_packets_.push_back(packet.release());
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;
81 // static
82 void 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);
89 void AudioPlayer::ResetQueue() {
90 lock_.AssertAcquired();
91 STLDeleteElements(&queued_packets_);
92 queued_bytes_ = 0;
93 bytes_consumed_ = 0;
96 void AudioPlayer::FillWithSamples(void* samples, uint32 buffer_size) {
97 base::AutoLock auto_lock(lock_);
99 const size_t bytes_needed = kChannels * kSampleSizeBytes *
100 GetSamplesPerFrame();
102 // Make sure we don't overrun the buffer.
103 CHECK_EQ(buffer_size, bytes_needed);
105 char* next_sample = static_cast<char*>(samples);
106 size_t bytes_extracted = 0;
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;
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;
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);
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);
137 } // namespace remoting