// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "remoting/client/audio_player.h"
#include <algorithm>
#include "base/logging.h"
#include "base/stl_util.h"
// The number of channels in the audio stream (only supporting stereo audio
// for now).
const int kChannels = 2;
const int kSampleSizeBytes = 2;
// If queue grows bigger than 150ms we start dropping packets.
const int kMaxQueueLatencyMs = 150;
namespace remoting {
AudioPlayer::AudioPlayer()
: sampling_rate_(AudioPacket::SAMPLING_RATE_INVALID),
start_failed_(false),
queued_bytes_(0),
bytes_consumed_(0) {
}
AudioPlayer::~AudioPlayer() {
base::AutoLock auto_lock(lock_);
ResetQueue();
}
void AudioPlayer::ProcessAudioPacket(scoped_ptr<AudioPacket> packet) {
CHECK_EQ(1, packet->data_size());
DCHECK_EQ(AudioPacket::ENCODING_RAW, packet->encoding());
DCHECK_NE(AudioPacket::SAMPLING_RATE_INVALID, packet->sampling_rate());
DCHECK_EQ(kSampleSizeBytes, packet->bytes_per_sample());
DCHECK_EQ(static_cast<int>(kChannels), packet->channels());
DCHECK_EQ(packet->data(0).size() % (kChannels * kSampleSizeBytes), 0u);
// No-op if the Pepper player won't start.
if (start_failed_) {
return;
}
// Start the Pepper audio player if this is the first packet.
if (sampling_rate_ != packet->sampling_rate()) {
// Drop all packets currently in the queue, since they are sampled at the
// wrong rate.
{
base::AutoLock auto_lock(lock_);
ResetQueue();
}
sampling_rate_ = packet->sampling_rate();
bool success = ResetAudioPlayer(sampling_rate_);
if (!success) {
start_failed_ = true;
return;
}
}
base::AutoLock auto_lock(lock_);
queued_bytes_ += packet->data(0).size();
queued_packets_.push_back(packet.release());
int max_buffer_size_ =
kMaxQueueLatencyMs * sampling_rate_ * kSampleSizeBytes * kChannels /
base::Time::kMillisecondsPerSecond;
while (queued_bytes_ > max_buffer_size_) {
queued_bytes_ -= queued_packets_.front()->data(0).size() - bytes_consumed_;
DCHECK_GE(queued_bytes_, 0);
delete queued_packets_.front();
queued_packets_.pop_front();
bytes_consumed_ = 0;
}
}
// static
void AudioPlayer::AudioPlayerCallback(void* samples,
uint32 buffer_size,
void* data) {
AudioPlayer* audio_player = static_cast<AudioPlayer*>(data);
audio_player->FillWithSamples(samples, buffer_size);
}
void AudioPlayer::ResetQueue() {
lock_.AssertAcquired();
STLDeleteElements(&queued_packets_);
queued_bytes_ = 0;
bytes_consumed_ = 0;
}
void AudioPlayer::FillWithSamples(void* samples, uint32 buffer_size) {
base::AutoLock auto_lock(lock_);
const size_t bytes_needed = kChannels * kSampleSizeBytes *
GetSamplesPerFrame();
// Make sure we don't overrun the buffer.
CHECK_EQ(buffer_size, bytes_needed);
char* next_sample = static_cast<char*>(samples);
size_t bytes_extracted = 0;
while (bytes_extracted < bytes_needed) {
// Check if we've run out of samples for this packet.
if (queued_packets_.empty()) {
memset(next_sample, 0, bytes_needed - bytes_extracted);
return;
}
// Pop off the packet if we've already consumed all its bytes.
if (queued_packets_.front()->data(0).size() == bytes_consumed_) {
delete queued_packets_.front();
queued_packets_.pop_front();
bytes_consumed_ = 0;
continue;
}
const std::string& packet_data = queued_packets_.front()->data(0);
size_t bytes_to_copy = std::min(
packet_data.size() - bytes_consumed_,
bytes_needed - bytes_extracted);
memcpy(next_sample, packet_data.data() + bytes_consumed_, bytes_to_copy);
next_sample += bytes_to_copy;
bytes_consumed_ += bytes_to_copy;
bytes_extracted += bytes_to_copy;
queued_bytes_ -= bytes_to_copy;
DCHECK_GE(queued_bytes_, 0);
}
}
} // namespace remoting