blob: a795a823afae987a1a7fdc45e95eeac10e7a67cc [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef SRC_MEDIA_CODEC_CODECS_SW_SBC_CODEC_ADAPTER_SBC_DECODER_H_
#define SRC_MEDIA_CODEC_CODECS_SW_SBC_CODEC_ADAPTER_SBC_DECODER_H_
#include <lib/fit/defer.h>
#include <lib/fit/function.h>
#include <lib/syslog/cpp/macros.h>
#include <oi_codec_sbc.h>
#include <oi_status.h>
#include "chunk_input_stream.h"
#include "codec_adapter_sw.h"
#include "fuchsia/media/cpp/fidl.h"
#include "timestamp_extrapolator.h"
constexpr uint8_t kSbcSamplingFrequency16000Hz = 0b1000;
constexpr uint8_t kSbcSamplingFrequency32000Hz = 0b0100;
constexpr uint8_t kSbcSamplingFrequency44100Hz = 0b0010;
constexpr uint8_t kSbcSamplingFrequency48000Hz = 0b0001;
constexpr uint8_t kSbcChannelModeMono = 0b1000;
constexpr uint8_t kSbcChannelModeDualChannel = 0b0100;
constexpr uint8_t kSbcChannelModeStereo = 0b0010;
constexpr uint8_t kSbcChannelModeJointStereo = 0b0001;
typedef struct {
uint8_t sampling_frequency : 4;
uint8_t channel_mode : 4;
uint8_t block_length : 4;
uint8_t subbands : 2;
uint8_t allocation_method : 2;
uint8_t min_bitpool_value;
uint8_t max_bitpool_value;
} __attribute__((packed)) SbcCodecInfo;
class CodecAdapterSbcDecoder : public CodecAdapterSW<fit::deferred_action<fit::closure>> {
public:
CodecAdapterSbcDecoder(std::mutex& lock, CodecAdapterEvents* codec_adapter_events);
~CodecAdapterSbcDecoder();
fuchsia_sysmem2::BufferCollectionConstraints CoreCodecGetBufferCollectionConstraints2(
CodecPort port, const fuchsia::media::StreamBufferConstraints& stream_buffer_constraints,
const fuchsia::media::StreamBufferPartialSettings& partial_settings) override;
void CoreCodecSetBufferCollectionInfo(
CodecPort port, const fuchsia_sysmem2::BufferCollectionInfo& buffer_collection_info) override;
void CoreCodecStopStream() override;
protected:
// Processes input in a loop. Should only execute on input_processing_thread_.
// Loops for the lifetime of a stream.
void ProcessInputLoop() override;
void CleanUpAfterStream() override;
std::pair<fuchsia::media::FormatDetails, size_t> OutputFormatDetails() override;
private:
struct Context {
OI_CODEC_SBC_DECODER_CONTEXT context;
uint32_t context_data[CODEC_DATA_WORDS(SBC_MAX_CHANNELS, SBC_CODEC_FAST_FILTER_BUFFERS)];
fuchsia::media::PcmFormat output_format;
uint32_t max_pcm_chunk_size() {
return (output_format.bits_per_sample / 8) * SBC_MAX_SAMPLES_PER_FRAME * SBC_MAX_CHANNELS;
}
};
enum InputLoopStatus {
kOk = 0,
kShouldTerminate = 1,
};
/// Attempts to create a context from format details. Reports failures through
/// `events_`.
///
/// To configure the decoder output format, oob_bytes must be set in the format specified in the
/// Bluetooth A2DP spec, as follows:
///
/// SBC Codec Specific Information Elements (A2DP Sec. 4.3.2).
/// Packet structure:
/// Octet0: Sampling Frequency (b4-7), Channel Mode (b0-3)
/// Octet1: Block Length (b4-7), Subbands (b2-3), Allocation Method (b0-1)
/// Octet2: Minimum Bitpool Value [2,250]
/// Octet3: Maximum Bitpool Value [2,250]
InputLoopStatus CreateContext(const fuchsia::media::FormatDetails& format_details);
// Attempts to decode input packet. Reports failures through `events_`.
InputLoopStatus DecodeInput(CodecPacket* input_packet);
// Extract PCM format from SBC codec info bytes
static fuchsia::media::PcmFormat DecodeCodecInfo(const std::vector<uint8_t>& oob_bytes);
// Attempts to setup an output packet and return a pointer into `output_buffer_` at
// `output_offset_`. Caller should ensure output_offset_ does not exceed output buffer size
uint8_t* CurrentOutputBlock();
// Increment `output_offset_` and send output packet if full, clearing output state
void QueueAndSend(size_t bytes_written);
// If any data is queued, send it and clear output packet/buffer/offset.
void SendQueuedOutput();
std::optional<Context> context_;
// The output packet we are currently decoding into.
CodecPacket* output_packet_ = nullptr;
// The output buffer we are currently decoding into.
const CodecBuffer* output_buffer_ = nullptr;
// Offset into the output buffer we're decoding into.
size_t output_offset_ = 0;
};
#endif // SRC_MEDIA_CODEC_CODECS_SW_SBC_CODEC_ADAPTER_SBC_DECODER_H_