| // 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(kSbTimeMillisecond); |
| } |
| } |
| } |
| |
| 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 |