TeaSpeak-Client/native/serverconnection/src/audio/codec/Converter.h

188 lines
5.6 KiB
C++

#pragma once
#include <string>
#include <memory>
#include <optional>
namespace tc::audio::codec {
enum struct AudioCodec {
Unknown,
/* supported */
OpusVoice,
OpusMusic,
/* Not yet supported */
//Flac,
/* Removed in summer 2020 */
SpeexNarrow,
SpeexWide,
SpeexUltraWide,
Celt,
};
class AudioEncoder;
class AudioDecoder;
[[nodiscard]] extern bool audio_encode_supported(const AudioCodec& /* codec */);
[[nodiscard]] extern std::unique_ptr<AudioEncoder> create_audio_encoder(const AudioCodec& /* codec */);
[[nodiscard]] extern bool audio_decode_supported(const AudioCodec& /* codec */);
[[nodiscard]] extern std::unique_ptr<AudioDecoder> create_audio_decoder(const AudioCodec& /* codec */);
[[nodiscard]] constexpr inline std::optional<uint8_t> audio_codec_to_protocol_id(const AudioCodec& codec) {
switch(codec) {
case AudioCodec::SpeexNarrow:
return std::make_optional(0);
case AudioCodec::SpeexWide:
return std::make_optional(1);
case AudioCodec::SpeexUltraWide:
return std::make_optional(2);
case AudioCodec::Celt:
return std::make_optional(3);
case AudioCodec::OpusVoice:
return std::make_optional(4);
case AudioCodec::OpusMusic:
return std::make_optional(5);
default:
return std::nullopt;
}
}
[[nodiscard]] constexpr inline std::optional<AudioCodec> audio_codec_from_protocol_id(uint8_t id) {
switch(id) {
case 0:
return std::make_optional(AudioCodec::SpeexNarrow);
case 1:
return std::make_optional(AudioCodec::SpeexWide);
case 2:
return std::make_optional(AudioCodec::SpeexUltraWide);
case 3:
return std::make_optional(AudioCodec::Celt);
case 4:
return std::make_optional(AudioCodec::OpusVoice);
case 5:
return std::make_optional(AudioCodec::OpusMusic);
default:
return std::nullopt;
}
}
[[nodiscard]] constexpr inline const char* audio_codec_name(const AudioCodec& codec) {
switch(codec) {
case AudioCodec::SpeexNarrow:
return "speex narrow";
case AudioCodec::SpeexWide:
return "speex wide";
case AudioCodec::SpeexUltraWide:
return "speex ultra wide";
case AudioCodec::Celt:
return "celt";
case AudioCodec::OpusVoice:
return "opus voice";
case AudioCodec::OpusMusic:
return "opus music";
case AudioCodec::Unknown:
return "unknown";
default:
return "invalid";
}
}
struct EncoderBufferInfo {
size_t sample_count{0};
bool head_sequence{false};
bool flush_encoder{false};
};
/**
* Encoders should only be accessed by one thread at once
*/
class AudioEncoder {
public:
explicit AudioEncoder() = default;
virtual ~AudioEncoder() = default;
[[nodiscard]] virtual bool valid() const = 0;
[[nodiscard]] virtual bool initialize(std::string& /* error */) = 0;
virtual void reset_sequence() = 0;
/**
* Get the codecs sample rate.
*/
[[nodiscard]] virtual size_t sample_rate() const = 0;
/**
* Get the codecs audio channel count.
*/
[[nodiscard]] virtual size_t channel_count() const = 0;
/**
* @returns the expected output length.
* If unknown a size near the MTU will be returned.
*/
[[nodiscard]] virtual size_t expected_encoded_length(const float* /* samples */, size_t /* sample count */) const = 0;
/**
* Encode a chunk of audio data.
* @return `true` on success else `false`
*/
[[nodiscard]] virtual bool encode(std::string& /* error */, void* /* target buffer */, size_t& /* target length */, const EncoderBufferInfo& /* buffer info */, const float* /* samples */) = 0;
};
struct DecodePayloadInfo {
/**
* Use a value of zero to indicate packet loss
*/
size_t byte_length{0};
bool fec_decode{false};
};
class AudioDecoder {
public:
explicit AudioDecoder() = default;
virtual ~AudioDecoder() = default;
[[nodiscard]] virtual bool valid() const = 0;
[[nodiscard]] virtual bool initialize(std::string& /* error */) = 0;
virtual void reset_sequence() = 0;
/**
* Get the codecs sample rate (will be the output rate)
*/
[[nodiscard]] virtual size_t sample_rate() const = 0;
/**
* Get the codecs audio channel count.
*/
[[nodiscard]] virtual size_t channel_count() const = 0;
/**
* @returns the expected sample count
*/
[[nodiscard]] virtual size_t expected_decoded_length(const void* /* payload */, size_t /* payload length */) const = 0;
[[nodiscard]] virtual bool decode(std::string& /* error */, float* /* target buffer */, size_t& /* target sample count */, const DecodePayloadInfo& /* payload info */, const void* /* payload */) = 0;
};
}