blob: 18a0000dff9af88e51720772f818ff0e31e0d1ab [file]
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/speech/audio_buffer.h"
#include "base/check_op.h"
#include "base/compiler_specific.h"
AudioChunk::AudioChunk(int bytes_per_sample)
: bytes_per_sample_(bytes_per_sample) {}
AudioChunk::AudioChunk(size_t length, int bytes_per_sample)
: data_string_(length, '\0'), bytes_per_sample_(bytes_per_sample) {
DCHECK_EQ(length % bytes_per_sample, 0U);
}
AudioChunk::AudioChunk(const uint8_t* data, size_t length, int bytes_per_sample)
: data_string_(reinterpret_cast<const char*>(data), length),
bytes_per_sample_(bytes_per_sample) {
DCHECK_EQ(length % bytes_per_sample, 0U);
}
AudioChunk::AudioChunk(base::span<const uint8_t> data_span,
int bytes_per_sample)
: data_string_(data_span.begin(), data_span.end()),
bytes_per_sample_(bytes_per_sample) {
DCHECK_EQ(data_span.size() % bytes_per_sample, 0U);
}
AudioChunk::~AudioChunk() = default;
bool AudioChunk::IsEmpty() const {
return data_string_.empty();
}
size_t AudioChunk::NumSamples() const {
return data_string_.size() / bytes_per_sample_;
}
const std::string& AudioChunk::AsString() const {
return data_string_;
}
int16_t AudioChunk::GetSample16(size_t index) const {
DCHECK_EQ(static_cast<size_t>(bytes_per_sample_), sizeof(int16_t));
DCHECK(index < (data_string_.size() / sizeof(int16_t)));
return SamplesData16AsSpan()[index];
}
base::span<const int16_t> AudioChunk::SamplesData16AsSpan() const {
// SAFETY: SamplesData16 returns a pointer to data_ data.
// The only concern would be if the length is not multiple of sizeof(int16_t),
// which we CHECK below.
CHECK_EQ(data_string_.size() % sizeof(int16_t), 0u);
return UNSAFE_BUFFERS(base::span<const int16_t>(
reinterpret_cast<const int16_t*>(data_string_.data()),
data_string_.size() / sizeof(int16_t)));
}
AudioBuffer::AudioBuffer(int bytes_per_sample)
: bytes_per_sample_(bytes_per_sample) {
DCHECK(bytes_per_sample == 1 || bytes_per_sample == 2 ||
bytes_per_sample == 4);
}
AudioBuffer::~AudioBuffer() {
Clear();
}
void AudioBuffer::Enqueue(const uint8_t* data, size_t length) {
chunks_.push_back(new AudioChunk(data, length, bytes_per_sample_));
}
scoped_refptr<AudioChunk> AudioBuffer::DequeueSingleChunk() {
DCHECK(!chunks_.empty());
scoped_refptr<AudioChunk> chunk(chunks_.front());
chunks_.pop_front();
return chunk;
}
scoped_refptr<AudioChunk> AudioBuffer::DequeueAll() {
size_t resulting_length = 0;
ChunksContainer::const_iterator it;
// In order to improve performance, calulate in advance the total length
// and then copy the chunks.
for (it = chunks_.begin(); it != chunks_.end(); ++it) {
resulting_length += (*it)->AsString().length();
}
scoped_refptr<AudioChunk> chunk(
new AudioChunk(resulting_length, bytes_per_sample_));
uint8_t* dest = chunk->writable_data();
for (it = chunks_.begin(); it != chunks_.end(); ++it) {
UNSAFE_TODO(
memcpy(dest, (*it)->AsString().data(), (*it)->AsString().length()));
UNSAFE_TODO(dest += (*it)->AsString().length());
}
Clear();
return chunk;
}
void AudioBuffer::Clear() {
chunks_.clear();
}
bool AudioBuffer::IsEmpty() const {
return chunks_.empty();
}