From d2711d807b602680d847e43741b5611212afa248 Mon Sep 17 00:00:00 2001 From: sh123 Date: Sat, 9 Dec 2023 19:54:54 +0200 Subject: [PATCH] Added missing file --- .../codec2talkie/protocol/AudioOpus.java | 212 ++++++++++++++++++ 1 file changed, 212 insertions(+) create mode 100644 codec2talkie/src/main/java/com/radio/codec2talkie/protocol/AudioOpus.java diff --git a/codec2talkie/src/main/java/com/radio/codec2talkie/protocol/AudioOpus.java b/codec2talkie/src/main/java/com/radio/codec2talkie/protocol/AudioOpus.java new file mode 100644 index 0000000..a20c322 --- /dev/null +++ b/codec2talkie/src/main/java/com/radio/codec2talkie/protocol/AudioOpus.java @@ -0,0 +1,212 @@ +package com.radio.codec2talkie.protocol; + +import android.content.Context; +import android.content.SharedPreferences; +import android.util.Log; + +import androidx.preference.PreferenceManager; + +import com.radio.codec2talkie.protocol.message.TextMessage; +import com.radio.codec2talkie.protocol.position.Position; +import com.radio.codec2talkie.settings.PreferenceKeys; +import com.radio.codec2talkie.transport.Transport; +import com.radio.opus.Opus; + +import java.io.IOException; + +public class AudioOpus implements Protocol { + + private static final String TAG = AudioOpus.class.getSimpleName(); + + private final Protocol _childProtocol; + + private static final int SAMPLE_RATE = 8000; + + private int _pcmFrameSize; + + private char[] _recordAudioEncodedBuffer; + private short[] _playbackAudioBuffer; + + private ProtocolCallback _parentProtocolCallback; + + private long _opusCon; + private int _audioBufferSize; + + public AudioOpus(Protocol childProtocol) { + _childProtocol = childProtocol; + } + + @Override + public void initialize(Transport transport, Context context, ProtocolCallback protocolCallback) throws IOException { + _parentProtocolCallback = protocolCallback; + _childProtocol.initialize(transport, context, _protocolCallback); + + SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context); + int bitRate = Integer.parseInt(sharedPreferences.getString(PreferenceKeys.OPUS_BIT_RATE, "3200")); + int complexity = Integer.parseInt(sharedPreferences.getString(PreferenceKeys.OPUS_COMPLEXITY, "5")); + float pcmFrameDuration = Float.parseFloat(sharedPreferences.getString(PreferenceKeys.OPUS_FRAME_SIZE, "40")); + + int superFrameSize = Integer.parseInt(sharedPreferences.getString(PreferenceKeys.CODEC2_TX_FRAME_MAX_SIZE, "48")); + _pcmFrameSize = (int)(SAMPLE_RATE * pcmFrameDuration); + + _playbackAudioBuffer = new short[10*_pcmFrameSize]; + _recordAudioEncodedBuffer = new char[superFrameSize]; + + _opusCon = Opus.create(SAMPLE_RATE, 1, Opus.OPUS_APPLICATION_VOIP, bitRate, complexity); + } + + @Override + public int getPcmAudioRecordBufferSize() { + return _pcmFrameSize; + } + + @Override + public void sendCompressedAudio(String src, String dst, byte[] frame) throws IOException { + _childProtocol.sendCompressedAudio(src, dst, frame); + } + + @Override + public void sendTextMessage(TextMessage textMessage) throws IOException { + _childProtocol.sendTextMessage(textMessage); + } + + @Override + public void sendPcmAudio(String src, String dst, short[] pcmFrame) throws IOException { + _parentProtocolCallback.onTransmitPcmAudio(src, dst, pcmFrame); + int encodedBytesCnt = Opus.encode(_opusCon, pcmFrame, _pcmFrameSize, _recordAudioEncodedBuffer); + if (encodedBytesCnt == 0) { + Log.w(TAG, "Nothing was encoded"); + return; + } + if (encodedBytesCnt > 0) { + byte[] frame = new byte[encodedBytesCnt]; + for (int i = 0; i < encodedBytesCnt; i++) { + frame[i] = (byte) _recordAudioEncodedBuffer[i]; + } + _childProtocol.sendCompressedAudio(src, dst, frame); + } else { + Log.e(TAG, "Encode error: " + encodedBytesCnt); + _parentProtocolCallback.onProtocolTxError(); + } + } + + @Override + public void sendData(String src, String dst, String path, byte[] dataPacket) throws IOException { + _childProtocol.sendData(src, dst, path, dataPacket); + } + + @Override + public boolean receive() throws IOException { + return _childProtocol.receive(); + } + + ProtocolCallback _protocolCallback = new ProtocolCallback() { + @Override + protected void onReceivePosition(Position position) { + _parentProtocolCallback.onReceivePosition(position); + } + + @Override + protected void onReceivePcmAudio(String src, String dst, short[] pcmFrame) { + _parentProtocolCallback.onReceivePcmAudio(src, dst, pcmFrame); + } + + @Override + protected void onReceiveCompressedAudio(String src, String dst, byte[] audioEncodedFrame) { + int decodedSamplesCnt = Opus.decode(_opusCon, audioEncodedFrame, _playbackAudioBuffer, _pcmFrameSize); + if (decodedSamplesCnt == 0) { + Log.w(TAG, "Nothing was decoded"); + return; + } + short [] decodedSamples = new short[decodedSamplesCnt]; + if (decodedSamplesCnt > 0) { + System.arraycopy(_playbackAudioBuffer, 0, decodedSamples, 0, decodedSamplesCnt); + } else { + Log.e(TAG, "Decode error: " + decodedSamplesCnt); + _parentProtocolCallback.onProtocolRxError(); + } + _parentProtocolCallback.onReceivePcmAudio(src, dst, decodedSamples); + } + + @Override + protected void onReceiveTextMessage(TextMessage textMessage) { + _parentProtocolCallback.onReceiveTextMessage(textMessage); + } + + @Override + protected void onReceiveData(String src, String dst, String path, byte[] data) { + _parentProtocolCallback.onReceiveData(src, dst, path, data); + } + + @Override + protected void onReceiveSignalLevel(short rssi, short snr) { + _parentProtocolCallback.onReceiveSignalLevel(rssi, snr); + } + + @Override + protected void onReceiveTelemetry(int batVoltage) { + _parentProtocolCallback.onReceiveTelemetry(batVoltage); + } + + @Override + protected void onReceiveLog(String logData) { + _parentProtocolCallback.onReceiveLog(logData); + } + + @Override + protected void onTransmitPcmAudio(String src, String dst, short[] frame) { + _parentProtocolCallback.onTransmitPcmAudio(src, dst, frame); + } + + @Override + protected void onTransmitCompressedAudio(String src, String dst, byte[] frame) { + _parentProtocolCallback.onTransmitCompressedAudio(src, dst, frame); + } + + @Override + protected void onTransmitTextMessage(TextMessage textMessage) { + _parentProtocolCallback.onTransmitTextMessage(textMessage); + } + + @Override + protected void onTransmitPosition(Position position) { + _parentProtocolCallback.onTransmitPosition(position); + } + + @Override + protected void onTransmitData(String src, String dst, String path, byte[] data) { + _parentProtocolCallback.onTransmitData(src, dst, path, data); + } + + @Override + protected void onTransmitLog(String logData) { + _parentProtocolCallback.onTransmitLog(logData); + } + + @Override + protected void onProtocolRxError() { + _parentProtocolCallback.onProtocolRxError(); + } + + @Override + protected void onProtocolTxError() { + _parentProtocolCallback.onProtocolTxError(); + } + }; + + @Override + public void sendPosition(Position position) throws IOException { + _childProtocol.sendPosition(position); + } + + @Override + public void flush() throws IOException { + _childProtocol.flush(); + } + + @Override + public void close() { + Opus.destroy(_opusCon); + _childProtocol.close(); + } +}