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