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