1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "content/browser/speech/audio_encoder.h"
6 
7 #include <stddef.h>
8 
9 #include <memory>
10 
11 #include "base/check_op.h"
12 #include "base/strings/string_number_conversions.h"
13 #include "content/browser/speech/audio_buffer.h"
14 
15 namespace content {
16 
17 namespace {
18 
19 const char kContentTypeFLAC[] = "audio/x-flac; rate=";
20 const int kFLACCompressionLevel = 0;  // 0 for speed
21 
WriteCallback(const FLAC__StreamEncoder * encoder,const FLAC__byte buffer[],size_t bytes,unsigned samples,unsigned current_frame,void * client_data)22 FLAC__StreamEncoderWriteStatus WriteCallback(
23     const FLAC__StreamEncoder* encoder,
24     const FLAC__byte buffer[],
25     size_t bytes,
26     unsigned samples,
27     unsigned current_frame,
28     void* client_data) {
29   AudioBuffer* encoded_audio_buffer = static_cast<AudioBuffer*>(client_data);
30   encoded_audio_buffer->Enqueue(buffer, bytes);
31   return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
32 }
33 
34 }  // namespace
35 
AudioEncoder(int sampling_rate,int bits_per_sample)36 AudioEncoder::AudioEncoder(int sampling_rate, int bits_per_sample)
37     : encoded_audio_buffer_(1), /* Byte granularity of encoded samples. */
38       encoder_(FLAC__stream_encoder_new()),
39       is_encoder_initialized_(false) {
40   FLAC__stream_encoder_set_channels(encoder_, 1);
41   FLAC__stream_encoder_set_bits_per_sample(encoder_, bits_per_sample);
42   FLAC__stream_encoder_set_sample_rate(encoder_, sampling_rate);
43   FLAC__stream_encoder_set_compression_level(encoder_, kFLACCompressionLevel);
44 
45   // Initializing the encoder will cause sync bytes to be written to
46   // its output stream, so we wait until the first call to Encode()
47   // before doing so.
48 }
49 
~AudioEncoder()50 AudioEncoder::~AudioEncoder() {
51   FLAC__stream_encoder_delete(encoder_);
52 }
53 
Encode(const AudioChunk & raw_audio)54 void AudioEncoder::Encode(const AudioChunk& raw_audio) {
55   DCHECK_EQ(raw_audio.bytes_per_sample(), 2);
56   if (!is_encoder_initialized_) {
57     const FLAC__StreamEncoderInitStatus encoder_status =
58         FLAC__stream_encoder_init_stream(encoder_, WriteCallback, nullptr,
59                                          nullptr, nullptr,
60                                          &encoded_audio_buffer_);
61     DCHECK_EQ(encoder_status, FLAC__STREAM_ENCODER_INIT_STATUS_OK);
62     is_encoder_initialized_ = true;
63   }
64 
65   // FLAC encoder wants samples as int32s.
66   const int num_samples = raw_audio.NumSamples();
67   std::unique_ptr<FLAC__int32[]> flac_samples(new FLAC__int32[num_samples]);
68   FLAC__int32* flac_samples_ptr = flac_samples.get();
69   for (int i = 0; i < num_samples; ++i)
70     flac_samples_ptr[i] = static_cast<FLAC__int32>(raw_audio.GetSample16(i));
71 
72   FLAC__stream_encoder_process(encoder_, &flac_samples_ptr, num_samples);
73 }
74 
Flush()75 void AudioEncoder::Flush() {
76   FLAC__stream_encoder_finish(encoder_);
77 }
78 
GetEncodedDataAndClear()79 scoped_refptr<AudioChunk> AudioEncoder::GetEncodedDataAndClear() {
80   return encoded_audio_buffer_.DequeueAll();
81 }
82 
GetMimeType()83 std::string AudioEncoder::GetMimeType() {
84   return std::string(kContentTypeFLAC) +
85          base::NumberToString(FLAC__stream_encoder_get_sample_rate(encoder_));
86 }
87 
GetBitsPerSample()88 int AudioEncoder::GetBitsPerSample() {
89   return FLAC__stream_encoder_get_bits_per_sample(encoder_);
90 }
91 
92 }  // namespace content
93