blob: f1bd9497fd6bd20c0702554e67b47d1cc89b552b [file] [log] [blame]
// Copyright 2017 The Cobalt Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "starboard/shared/win32/audio_decoder_thread.h"
#include <deque>
#include <vector>
namespace starboard {
namespace shared {
namespace win32 {
namespace {
// Size of the queue for audio units.
const size_t kMaxProcessingElements = 64;
size_t WriteAsMuchAsPossible(
std::deque<scoped_refptr<InputBuffer> >* data_queue,
AbstractWin32AudioDecoder* audio_decoder) {
const size_t original_size = data_queue->size();
while (!data_queue->empty()) {
scoped_refptr<InputBuffer> buff = data_queue->front();
data_queue->pop_front();
if (buff) {
if (!audio_decoder->TryWrite(buff)) {
data_queue->push_front(buff);
break;
}
} else {
audio_decoder->WriteEndOfStream();
}
}
return original_size - data_queue->size();
}
std::vector<DecodedAudioPtr> ReadAllDecodedAudioSamples(
AbstractWin32AudioDecoder* audio_decoder) {
std::vector<DecodedAudioPtr> decoded_audio_out;
while (DecodedAudioPtr decoded_datum = audio_decoder->ProcessAndRead()) {
decoded_audio_out.push_back(decoded_datum);
}
return decoded_audio_out;
}
} // namespace.
AudioDecoderThread::AudioDecoderThread(AbstractWin32AudioDecoder* decoder_impl,
AudioDecodedCallback* callback)
: Thread("AudioDecoderThd"),
win32_audio_decoder_(decoder_impl),
callback_(callback) {
Start();
}
AudioDecoderThread::~AudioDecoderThread() {
Join();
}
bool AudioDecoderThread::QueueInput(const scoped_refptr<InputBuffer>& buffer) {
{
::starboard::ScopedLock lock(input_buffer_queue_mutex_);
input_buffer_queue_.push_back(buffer);
}
// increment() returns the previous value.
size_t element_count = processing_elements_.increment() + 1;
semaphore_.Put();
return element_count < kMaxProcessingElements;
}
void AudioDecoderThread::QueueEndOfStream() {
scoped_refptr<InputBuffer> empty;
QueueInput(empty);
}
void AudioDecoderThread::Run() {
std::deque<scoped_refptr<InputBuffer> > local_queue;
while (!join_called()) {
if (local_queue.empty()) {
TransferPendingInputTo(&local_queue);
}
bool work_done = false;
size_t number_written =
WriteAsMuchAsPossible(&local_queue, win32_audio_decoder_);
if (number_written > 0) {
processing_elements_.fetch_sub(static_cast<int32_t>(number_written));
work_done = true;
}
std::vector<DecodedAudioPtr> decoded_audio =
ReadAllDecodedAudioSamples(win32_audio_decoder_);
if (!decoded_audio.empty()) {
work_done = true;
for (auto it = decoded_audio.begin(); it != decoded_audio.end(); ++it) {
callback_->OnAudioDecoded(*it);
}
}
if (!work_done) {
semaphore_.TakeWait(1000);
}
}
}
void AudioDecoderThread::TransferPendingInputTo(
std::deque<scoped_refptr<InputBuffer> >* destination) {
::starboard::ScopedLock lock(input_buffer_queue_mutex_);
while (!input_buffer_queue_.empty()) {
destination->push_back(input_buffer_queue_.front());
input_buffer_queue_.pop_front();
}
}
} // namespace win32
} // namespace shared
} // namespace starboard