| // Copyright 2016 Google Inc. 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 "cobalt/speech/audio_encoder_flac.h" |
| |
| #include "base/logging.h" |
| #include "base/memory/scoped_ptr.h" |
| #include "base/string_number_conversions.h" |
| |
| namespace cobalt { |
| namespace speech { |
| |
| namespace { |
| const char kContentTypeFLAC[] = "audio/x-flac; rate="; |
| const int kFLACCompressionLevel = 0; // 0 for speed |
| const int kBitsPerSample = 16; |
| const float kMaxInt16AsFloat32 = 32767.0f; |
| } // namespace |
| |
| AudioEncoderFlac::AudioEncoderFlac(int sample_rate) |
| : encoder_(FLAC__stream_encoder_new()) { |
| DCHECK(encoder_); |
| |
| // Set the number of channels to be encoded. |
| FLAC__stream_encoder_set_channels(encoder_, 1); |
| // Set the sample resolution of the input to be encoded. |
| FLAC__stream_encoder_set_bits_per_sample(encoder_, kBitsPerSample); |
| // Set the sample rate (in Hz) of the input to be encoded. |
| FLAC__stream_encoder_set_sample_rate(encoder_, |
| static_cast<uint32>(sample_rate)); |
| // Set the compression level. A higher level usually means more computation |
| // but higher compression. |
| FLAC__stream_encoder_set_compression_level(encoder_, kFLACCompressionLevel); |
| |
| // Initialize the encoder instance to encode native FLAC stream. |
| FLAC__StreamEncoderInitStatus encoder_status = |
| FLAC__stream_encoder_init_stream(encoder_, WriteCallback, NULL, NULL, |
| NULL, this); |
| DCHECK_EQ(encoder_status, FLAC__STREAM_ENCODER_INIT_STATUS_OK); |
| } |
| |
| AudioEncoderFlac::~AudioEncoderFlac() { |
| DCHECK(thread_checker_.CalledOnValidThread()); |
| FLAC__stream_encoder_delete(encoder_); |
| } |
| |
| void AudioEncoderFlac::Encode(const ShellAudioBus* audio_bus) { |
| DCHECK(thread_checker_.CalledOnValidThread()); |
| |
| DCHECK_EQ(audio_bus->channels(), 1); |
| uint32 frames = static_cast<uint32>(audio_bus->frames()); |
| scoped_array<FLAC__int32> flac_samples(new FLAC__int32[frames]); |
| for (uint32 i = 0; i < frames; ++i) { |
| if (audio_bus->sample_type() == ShellAudioBus::kFloat32) { |
| flac_samples[i] = static_cast<FLAC__int32>( |
| audio_bus->GetFloat32Sample(0, i) * kMaxInt16AsFloat32); |
| } else { |
| DCHECK_EQ(audio_bus->sample_type(), ShellAudioBus::kInt16); |
| flac_samples[i] = |
| static_cast<FLAC__int32>(audio_bus->GetInt16Sample(0, i)); |
| } |
| } |
| |
| FLAC__int32* flac_samples_ptr = flac_samples.get(); |
| // Submit data for encoding. |
| FLAC__bool success = |
| FLAC__stream_encoder_process(encoder_, &flac_samples_ptr, frames); |
| DCHECK(success); |
| } |
| |
| void AudioEncoderFlac::Finish() { |
| DCHECK(thread_checker_.CalledOnValidThread()); |
| |
| // Finish the encoding. It causes the encoder to encode any data still in |
| // its input pipe, and finally reset the encoder to the unintialized state. |
| FLAC__stream_encoder_finish(encoder_); |
| } |
| |
| std::string AudioEncoderFlac::GetMimeType() const { |
| DCHECK(thread_checker_.CalledOnValidThread()); |
| |
| return std::string(kContentTypeFLAC) + |
| base::UintToString(FLAC__stream_encoder_get_sample_rate(encoder_)); |
| } |
| |
| std::string AudioEncoderFlac::GetAndClearAvailableEncodedData() { |
| DCHECK(thread_checker_.CalledOnValidThread()); |
| |
| std::string result = encoded_data_; |
| encoded_data_.clear(); |
| return result; |
| } |
| |
| // A write callback which will be called anytime there is a raw encoded data to |
| // write. The call to FLAC__stream_encoder_init_stream() currently will also |
| // immediately call the write callback several times, once with the FLAC |
| // signature, and once for each encoded metadata block. |
| FLAC__StreamEncoderWriteStatus AudioEncoderFlac::WriteCallback( |
| const FLAC__StreamEncoder* encoder, const FLAC__byte buffer[], size_t bytes, |
| unsigned int samples, unsigned int current_frame, void* client_data) { |
| UNREFERENCED_PARAMETER(encoder); |
| UNREFERENCED_PARAMETER(samples); |
| UNREFERENCED_PARAMETER(current_frame); |
| |
| AudioEncoderFlac* audio_encoder = |
| reinterpret_cast<AudioEncoderFlac*>(client_data); |
| DCHECK(audio_encoder); |
| DCHECK(audio_encoder->thread_checker_.CalledOnValidThread()); |
| |
| audio_encoder->encoded_data_.append(reinterpret_cast<const char*>(buffer), |
| bytes); |
| |
| return FLAC__STREAM_ENCODER_WRITE_STATUS_OK; |
| } |
| |
| } // namespace speech |
| } // namespace cobalt |