mirror of
https://github.com/torlando-tech/pyxis.git
synced 2026-03-29 13:19:55 +00:00
Replace custom ES7210 register-level driver with the verbatim LilyGO T-Deck Plus ES7210 library. The custom driver was writing MODE_CONFIG and clock doubler registers (master mode path) which broke the ES7210's clock chain, causing all-zero PCM output. The LilyGO library in slave mode leaves those registers at power-on defaults, which is correct since the ESP32 I2S master provides MCLK/BCLK/LRCK. Also includes LXST voice call protocol improvements: - LXST IN destination for receiving calls - Announce handler for tracking voice-capable peers - Path request before outgoing calls - Throttled SPIFFS saves in microReticulum (dirty flag) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
95 lines
3.0 KiB
C++
95 lines
3.0 KiB
C++
// Copyright (c) 2024 LXST contributors
|
|
// SPDX-License-Identifier: MPL-2.0
|
|
|
|
#pragma once
|
|
|
|
#include <cstdint>
|
|
#ifdef ARDUINO
|
|
#include <freertos/FreeRTOS.h>
|
|
#include <freertos/semphr.h>
|
|
#endif
|
|
|
|
struct CODEC2;
|
|
|
|
/**
|
|
* Codec2 wrapper for LXST voice streaming on ESP32.
|
|
*
|
|
* Ported from LXST-kt CodecWrapper (codec_wrapper.h/cpp), stripped to
|
|
* Codec2-only (no Opus) for the ESP32-S3 resource budget.
|
|
*
|
|
* Handles the LXST wire format:
|
|
* Encoded packet = [1-byte mode header] + [N codec2 sub-frames]
|
|
*
|
|
* Wire-compatible with LXST-kt (Android/Columba) and Python LXST.
|
|
*
|
|
* Mode header mapping (matches Codec2.kt and Python LXST):
|
|
* 0x00 = 700C (lib mode 8) - 700bps, 40ms frames, 7 bytes/frame
|
|
* 0x04 = 1600 (lib mode 2) - 1600bps, 20ms frames, 8 bytes/frame
|
|
* 0x06 = 3200 (lib mode 0) - 3200bps, 20ms frames, 8 bytes/frame
|
|
*/
|
|
class Codec2Wrapper {
|
|
public:
|
|
Codec2Wrapper();
|
|
~Codec2Wrapper();
|
|
|
|
Codec2Wrapper(const Codec2Wrapper&) = delete;
|
|
Codec2Wrapper& operator=(const Codec2Wrapper&) = delete;
|
|
|
|
/**
|
|
* Create a Codec2 encoder+decoder instance.
|
|
* @param libraryMode Codec2 library mode (0=3200, 2=1600, 8=700C)
|
|
* @return true on success
|
|
*/
|
|
bool create(int libraryMode);
|
|
|
|
/** Destroy the codec and release all resources. */
|
|
void destroy();
|
|
|
|
/**
|
|
* Decode encoded bytes to PCM int16.
|
|
* Strips mode header byte, loops over sub-frames.
|
|
* Handles dynamic mode switching if header changes.
|
|
*
|
|
* @param encoded Encoded data (with mode header byte)
|
|
* @param encodedBytes Length of encoded data
|
|
* @param output Output PCM int16 buffer
|
|
* @param maxOutputSamples Maximum samples that fit in output buffer
|
|
* @return Decoded sample count, or -1 on error
|
|
*/
|
|
int decode(const uint8_t* encoded, int encodedBytes,
|
|
int16_t* output, int maxOutputSamples);
|
|
|
|
/**
|
|
* Encode PCM int16 to encoded bytes.
|
|
* Prepends mode header byte, loops over sub-frames.
|
|
*
|
|
* @param pcm Input PCM int16 samples (8kHz mono)
|
|
* @param pcmSamples Number of input samples
|
|
* @param output Output buffer for encoded data
|
|
* @param maxOutputBytes Maximum bytes that fit in output buffer
|
|
* @return Encoded byte count, or -1 on error
|
|
*/
|
|
int encode(const int16_t* pcm, int pcmSamples,
|
|
uint8_t* output, int maxOutputBytes);
|
|
|
|
bool isCreated() const { return codec2_ != nullptr; }
|
|
int samplesPerFrame() const { return samplesPerFrame_; }
|
|
int bytesPerFrame() const { return bytesPerFrame_; }
|
|
uint8_t modeHeader() const { return modeHeader_; }
|
|
int libraryMode() const { return libraryMode_; }
|
|
|
|
private:
|
|
struct CODEC2* codec2_ = nullptr;
|
|
int samplesPerFrame_ = 0;
|
|
int bytesPerFrame_ = 0;
|
|
uint8_t modeHeader_ = 0;
|
|
int libraryMode_ = 0;
|
|
|
|
#ifdef ARDUINO
|
|
SemaphoreHandle_t mutex_ = nullptr;
|
|
#endif
|
|
|
|
static int headerToLibraryMode(uint8_t header);
|
|
static uint8_t libraryModeToHeader(int libraryMode);
|
|
};
|