kopia lustrzana https://github.com/sh123/codec2_talkie
APRS transmit over FreeDV data
rodzic
2e48935c67
commit
8aedde6f9c
|
@ -6,7 +6,6 @@ import android.util.Log;
|
||||||
|
|
||||||
import androidx.preference.PreferenceManager;
|
import androidx.preference.PreferenceManager;
|
||||||
|
|
||||||
import com.radio.codec2talkie.app.AppWorker;
|
|
||||||
import com.radio.codec2talkie.protocol.message.TextMessage;
|
import com.radio.codec2talkie.protocol.message.TextMessage;
|
||||||
import com.radio.codec2talkie.protocol.position.Position;
|
import com.radio.codec2talkie.protocol.position.Position;
|
||||||
import com.radio.codec2talkie.settings.PreferenceKeys;
|
import com.radio.codec2talkie.settings.PreferenceKeys;
|
||||||
|
@ -25,10 +24,14 @@ public class Freedv implements Protocol {
|
||||||
private Transport _transport;
|
private Transport _transport;
|
||||||
|
|
||||||
private long _freedv;
|
private long _freedv;
|
||||||
|
private long _freedvData;
|
||||||
|
|
||||||
private short[] _modemTxBuffer;
|
private short[] _modemTxBuffer;
|
||||||
private short[] _speechRxBuffer;
|
private short[] _speechRxBuffer;
|
||||||
|
|
||||||
|
private short[] _dataSamplesBuffer;
|
||||||
|
private byte[] _dataTxBuffer;
|
||||||
|
|
||||||
public Freedv() {
|
public Freedv() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,6 +51,10 @@ public class Freedv implements Protocol {
|
||||||
_freedv = Codec2.freedvCreate(mode, isSquelchEnabled, squelchSnr);
|
_freedv = Codec2.freedvCreate(mode, isSquelchEnabled, squelchSnr);
|
||||||
_modemTxBuffer = new short[Codec2.freedvGetNomModemSamples(_freedv)];
|
_modemTxBuffer = new short[Codec2.freedvGetNomModemSamples(_freedv)];
|
||||||
_speechRxBuffer = new short[Codec2.freedvGetMaxSpeechSamples(_freedv)];
|
_speechRxBuffer = new short[Codec2.freedvGetMaxSpeechSamples(_freedv)];
|
||||||
|
|
||||||
|
_freedvData = Codec2.freedvCreate(dataMode, isSquelchEnabled, squelchSnr);
|
||||||
|
_dataTxBuffer = new byte[Codec2.freedvGetBitsPerModemFrame(_freedvData) / 8];
|
||||||
|
_dataSamplesBuffer = new short[Codec2.freedvGetNTxSamples(_freedvData)];
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -75,7 +82,24 @@ public class Freedv implements Protocol {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void sendData(String src, String dst, byte[] dataPacket) throws IOException {
|
public void sendData(String src, String dst, byte[] dataPacket) throws IOException {
|
||||||
// TODO, send as data
|
Log.v(TAG, "sendData() " + dataPacket.length);
|
||||||
|
if (dataPacket.length > _dataTxBuffer.length - 2) {
|
||||||
|
Log.e(TAG, "Too large packet " + dataPacket.length + " > " + _dataTxBuffer.length);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
long cnt = Codec2.freedvRawDataPreambleTx(_freedvData, _dataSamplesBuffer);
|
||||||
|
Log.v(TAG, "sendData() write preamble " + cnt);
|
||||||
|
_transport.write(Arrays.copyOf(_dataSamplesBuffer, (int) cnt));
|
||||||
|
|
||||||
|
Arrays.fill(_dataTxBuffer, (byte) 0);
|
||||||
|
System.arraycopy(dataPacket, 0, _dataTxBuffer, 0, dataPacket.length);
|
||||||
|
Codec2.freedvRawDataTx(_freedvData, _dataSamplesBuffer, _dataTxBuffer);
|
||||||
|
Log.v(TAG, "sendData() write data " + _dataSamplesBuffer.length);
|
||||||
|
_transport.write(_dataSamplesBuffer);
|
||||||
|
|
||||||
|
cnt = Codec2.freedvRawDataPostambleTx(_freedvData, _dataSamplesBuffer);
|
||||||
|
Log.v(TAG, "sendData() write postamble " + cnt);
|
||||||
|
_transport.write(Arrays.copyOf(_dataSamplesBuffer, (int) cnt));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -109,6 +133,7 @@ public class Freedv implements Protocol {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void close() {
|
public void close() {
|
||||||
|
Codec2.freedvDestroy(_freedvData);
|
||||||
Codec2.freedvDestroy(_freedv);
|
Codec2.freedvDestroy(_freedv);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,7 +68,9 @@ public class ProtocolFactory {
|
||||||
boolean scramblingEnabled = SettingsWrapper.isKissScramblerEnabled(sharedPreferences);
|
boolean scramblingEnabled = SettingsWrapper.isKissScramblerEnabled(sharedPreferences);
|
||||||
String scramblingKey = SettingsWrapper.getKissScramblerKey(sharedPreferences);
|
String scramblingKey = SettingsWrapper.getKissScramblerKey(sharedPreferences);
|
||||||
boolean aprsEnabled = SettingsWrapper.isAprsEnabled(sharedPreferences);
|
boolean aprsEnabled = SettingsWrapper.isAprsEnabled(sharedPreferences);
|
||||||
|
boolean freedvEnabled = SettingsWrapper.isFreeDvSoundModemModulation(sharedPreferences);
|
||||||
|
|
||||||
|
// "root" protocol
|
||||||
Protocol proto;
|
Protocol proto;
|
||||||
switch (protocolType) {
|
switch (protocolType) {
|
||||||
case KISS:
|
case KISS:
|
||||||
|
@ -84,8 +86,8 @@ public class ProtocolFactory {
|
||||||
proto = new Hdlc(sharedPreferences);
|
proto = new Hdlc(sharedPreferences);
|
||||||
break;
|
break;
|
||||||
case FREEDV:
|
case FREEDV:
|
||||||
// standalone
|
proto = new Freedv();
|
||||||
return new Freedv();
|
break;
|
||||||
case RAW:
|
case RAW:
|
||||||
default:
|
default:
|
||||||
proto = new Raw();
|
proto = new Raw();
|
||||||
|
@ -98,12 +100,14 @@ public class ProtocolFactory {
|
||||||
if (aprsEnabled) {
|
if (aprsEnabled) {
|
||||||
proto = new Ax25(proto);
|
proto = new Ax25(proto);
|
||||||
}
|
}
|
||||||
if (recordingEnabled) {
|
if (!freedvEnabled) {
|
||||||
proto = new Recorder(proto, codec2ModeId);
|
if (recordingEnabled) {
|
||||||
}
|
proto = new Recorder(proto, codec2ModeId);
|
||||||
|
}
|
||||||
|
|
||||||
proto = new AudioFrameAggregator(proto, codec2ModeId);
|
proto = new AudioFrameAggregator(proto, codec2ModeId);
|
||||||
proto = new AudioCodec2(proto, codec2ModeId);
|
proto = new AudioCodec2(proto, codec2ModeId);
|
||||||
|
}
|
||||||
|
|
||||||
if (aprsEnabled) {
|
if (aprsEnabled) {
|
||||||
proto = new Aprs(proto);
|
proto = new Aprs(proto);
|
||||||
|
|
|
@ -85,7 +85,6 @@ public class SettingsWrapper {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isAprsEnabled(SharedPreferences sharedPreferences) {
|
public static boolean isAprsEnabled(SharedPreferences sharedPreferences) {
|
||||||
return sharedPreferences.getBoolean(PreferenceKeys.APRS_ENABLED, false) &&
|
return sharedPreferences.getBoolean(PreferenceKeys.APRS_ENABLED, false);
|
||||||
!isFreeDvSoundModemModulation(sharedPreferences); // no aprs when in freedv
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,7 +73,7 @@ public class SoundModemBase implements Runnable {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void constructSystemAudioDevices(boolean disableRx, int sampleRate) {
|
private void constructSystemAudioDevices(boolean disableRx, int sampleRate) {
|
||||||
int audioRecorderMinBufferSize = AudioRecord.getMinBufferSize(
|
int audioRecorderMinBufferSize = 10 * AudioRecord.getMinBufferSize(
|
||||||
sampleRate,
|
sampleRate,
|
||||||
AudioFormat.CHANNEL_IN_MONO,
|
AudioFormat.CHANNEL_IN_MONO,
|
||||||
AudioFormat.ENCODING_PCM_16BIT);
|
AudioFormat.ENCODING_PCM_16BIT);
|
||||||
|
@ -84,12 +84,13 @@ public class SoundModemBase implements Runnable {
|
||||||
sampleRate,
|
sampleRate,
|
||||||
AudioFormat.CHANNEL_IN_MONO,
|
AudioFormat.CHANNEL_IN_MONO,
|
||||||
AudioFormat.ENCODING_PCM_16BIT,
|
AudioFormat.ENCODING_PCM_16BIT,
|
||||||
10*audioRecorderMinBufferSize);
|
audioRecorderMinBufferSize);
|
||||||
|
|
||||||
int audioPlayerMinBufferSize = AudioTrack.getMinBufferSize(
|
int audioPlayerMinBufferSize = 10 * AudioTrack.getMinBufferSize(
|
||||||
sampleRate,
|
sampleRate,
|
||||||
AudioFormat.CHANNEL_OUT_MONO,
|
AudioFormat.CHANNEL_OUT_MONO,
|
||||||
AudioFormat.ENCODING_PCM_16BIT);
|
AudioFormat.ENCODING_PCM_16BIT);
|
||||||
|
|
||||||
if (!disableRx)
|
if (!disableRx)
|
||||||
_systemAudioRecorder.startRecording();
|
_systemAudioRecorder.startRecording();
|
||||||
|
|
||||||
|
@ -105,9 +106,11 @@ public class SoundModemBase implements Runnable {
|
||||||
.setChannelMask(AudioFormat.CHANNEL_OUT_MONO)
|
.setChannelMask(AudioFormat.CHANNEL_OUT_MONO)
|
||||||
.build())
|
.build())
|
||||||
.setTransferMode(AudioTrack.MODE_STREAM)
|
.setTransferMode(AudioTrack.MODE_STREAM)
|
||||||
.setBufferSizeInBytes(10*audioPlayerMinBufferSize)
|
.setBufferSizeInBytes(audioPlayerMinBufferSize)
|
||||||
.build();
|
.build();
|
||||||
_systemAudioPlayer.setVolume(AudioTrack.getMaxVolume());
|
_systemAudioPlayer.setVolume(AudioTrack.getMaxVolume());
|
||||||
|
|
||||||
|
Log.i(TAG, "Play buffer size " + audioPlayerMinBufferSize + ", recorder " + audioRecorderMinBufferSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected int read(short[] sampleBuffer, int samplesToRead) {
|
protected int read(short[] sampleBuffer, int samplesToRead) {
|
||||||
|
|
|
@ -112,7 +112,7 @@ namespace Java_com_ustadmobile_codec2_Codec2 {
|
||||||
conFreedv->rawData = static_cast<unsigned char *>(malloc(
|
conFreedv->rawData = static_cast<unsigned char *>(malloc(
|
||||||
freedv_get_bits_per_modem_frame(conFreedv->freeDv) / 8));
|
freedv_get_bits_per_modem_frame(conFreedv->freeDv) / 8));
|
||||||
conFreedv->rawDataSamples = static_cast<short *>(malloc(
|
conFreedv->rawDataSamples = static_cast<short *>(malloc(
|
||||||
freedv_get_n_tx_modem_samples(conFreedv->freeDv)));
|
freedv_get_n_tx_modem_samples(conFreedv->freeDv) * sizeof(short)));
|
||||||
// squelch
|
// squelch
|
||||||
freedv_set_squelch_en(conFreedv->freeDv, isSquelchEnabled);
|
freedv_set_squelch_en(conFreedv->freeDv, isSquelchEnabled);
|
||||||
freedv_set_snr_squelch_thresh(conFreedv->freeDv, squelchSnr);
|
freedv_set_snr_squelch_thresh(conFreedv->freeDv, squelchSnr);
|
||||||
|
@ -278,23 +278,21 @@ namespace Java_com_ustadmobile_codec2_Codec2 {
|
||||||
conFreedv->rawData[cntBytes-1] = crc16 & 0xff;
|
conFreedv->rawData[cntBytes-1] = crc16 & 0xff;
|
||||||
freedv_rawdatatx(conFreedv->freeDv, conFreedv->rawDataSamples, conFreedv->rawData);
|
freedv_rawdatatx(conFreedv->freeDv, conFreedv->rawDataSamples, conFreedv->rawData);
|
||||||
int cntSamples = freedv_get_n_tx_modem_samples(conFreedv->freeDv);
|
int cntSamples = freedv_get_n_tx_modem_samples(conFreedv->freeDv);
|
||||||
env->SetShortArrayRegion(outputModemSamples, 0, cntSamples, conFreedv->modemSamples);
|
env->SetShortArrayRegion(outputModemSamples, 0, cntSamples, conFreedv->rawDataSamples);
|
||||||
return cntSamples;
|
return cntSamples;
|
||||||
}
|
}
|
||||||
|
|
||||||
static jlong freedvRawDataPreambleTx(JNIEnv *env, jclass clazz, jlong n, jshortArray outputModemSamples) {
|
static jlong freedvRawDataPreambleTx(JNIEnv *env, jclass clazz, jlong n, jshortArray outputModemSamples) {
|
||||||
ContextFreedv *conFreedv = getContextFreedv(n);
|
ContextFreedv *conFreedv = getContextFreedv(n);
|
||||||
freedv_rawdatapreambletx(conFreedv->freeDv, conFreedv->rawDataSamples);
|
int cntSamples = freedv_rawdatapreambletx(conFreedv->freeDv, conFreedv->rawDataSamples);
|
||||||
int cntSamples = freedv_get_n_tx_modem_samples(conFreedv->freeDv);
|
env->SetShortArrayRegion(outputModemSamples, 0, cntSamples, conFreedv->rawDataSamples);
|
||||||
env->SetShortArrayRegion(outputModemSamples, 0, cntSamples, conFreedv->modemSamples);
|
|
||||||
return cntSamples;
|
return cntSamples;
|
||||||
}
|
}
|
||||||
|
|
||||||
static jlong freedvRawDataPostambleTx(JNIEnv *env, jclass clazz, jlong n, jshortArray outputModemSamples) {
|
static jlong freedvRawDataPostambleTx(JNIEnv *env, jclass clazz, jlong n, jshortArray outputModemSamples) {
|
||||||
ContextFreedv *conFreedv = getContextFreedv(n);
|
ContextFreedv *conFreedv = getContextFreedv(n);
|
||||||
freedv_rawdatapostambletx(conFreedv->freeDv, conFreedv->rawDataSamples);
|
int cntSamples = freedv_rawdatapostambletx(conFreedv->freeDv, conFreedv->rawDataSamples);
|
||||||
int cntSamples = freedv_get_n_tx_modem_samples(conFreedv->freeDv);
|
env->SetShortArrayRegion(outputModemSamples, 0, cntSamples, conFreedv->rawDataSamples);
|
||||||
env->SetShortArrayRegion(outputModemSamples, 0, cntSamples, conFreedv->modemSamples);
|
|
||||||
return cntSamples;
|
return cntSamples;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Ładowanie…
Reference in New Issue