// 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 #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 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(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(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(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