Enable squelch and add loopback setting

aprs
sh123 2022-08-11 12:01:02 +03:00
rodzic 5d315c3dea
commit b0c331a8bb
11 zmienionych plików z 98 dodań i 32 usunięć

Wyświetl plik

@ -62,7 +62,7 @@ public class AppWorker extends Thread {
// output data., mic -> bt // output data., mic -> bt
private AudioRecord _systemAudioRecorder; private AudioRecord _systemAudioRecorder;
private final short[] _recordAudioBuffer; private short[] _recordAudioBuffer;
// callbacks // callbacks
private final Handler _onPlayerStateChanged; private final Handler _onPlayerStateChanged;
@ -98,7 +98,6 @@ public class AppWorker extends Thread {
_protocol = ProtocolFactory.create(_codec2Mode, context); _protocol = ProtocolFactory.create(_codec2Mode, context);
_processPeriodicTimer = new Timer(); _processPeriodicTimer = new Timer();
_recordAudioBuffer = new short[_protocol.getPcmAudioBufferSize()];
constructSystemAudioDevices(transportType); constructSystemAudioDevices(transportType);
} }
@ -541,6 +540,7 @@ public class AppWorker extends Thread {
try { try {
_protocol.initialize(_transport, _context, _protocolCallback); _protocol.initialize(_transport, _context, _protocolCallback);
_recordAudioBuffer = new short[_protocol.getPcmAudioBufferSize()];
startWorkerMessageHandler(); startWorkerMessageHandler();
Looper.loop(); Looper.loop();
} catch (IOException e) { } catch (IOException e) {

Wyświetl plik

@ -1,9 +1,15 @@
package com.radio.codec2talkie.protocol; package com.radio.codec2talkie.protocol;
import android.content.Context; import android.content.Context;
import android.content.SharedPreferences;
import android.util.Log;
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.transport.Transport; import com.radio.codec2talkie.transport.Transport;
import com.ustadmobile.codec2.Codec2; import com.ustadmobile.codec2.Codec2;
@ -11,8 +17,7 @@ import java.io.IOException;
import java.util.Arrays; import java.util.Arrays;
public class Freedv implements Protocol { public class Freedv implements Protocol {
private final int _freedvMode; private static final String TAG = Freedv.class.getSimpleName();
private final Protocol _childProtocol;
private ProtocolCallback _parentProtocolCallback; private ProtocolCallback _parentProtocolCallback;
private Transport _transport; private Transport _transport;
@ -22,18 +27,20 @@ public class Freedv implements Protocol {
private short[] _modemTxBuffer; private short[] _modemTxBuffer;
private short[] _speechRxBuffer; private short[] _speechRxBuffer;
public Freedv(Protocol childProtocol, int freedvMode) { public Freedv() {
_childProtocol = childProtocol;
_freedvMode = freedvMode;
} }
@Override @Override
public void initialize(Transport transport, Context context, ProtocolCallback parentProtocolCallback) throws IOException { public void initialize(Transport transport, Context context, ProtocolCallback parentProtocolCallback) throws IOException {
_transport = transport; _transport = transport;
_parentProtocolCallback = parentProtocolCallback; _parentProtocolCallback = parentProtocolCallback;
_childProtocol.initialize(transport, context, _parentProtocolCallback);
_freedv = Codec2.freedvCreate(_freedvMode); SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
String modemType = sharedPreferences.getString(PreferenceKeys.PORTS_SOUND_MODEM_TYPE, "1200");
int mode = Integer.parseInt(modemType.substring(1));
Log.i(TAG, "Using freedv mode " + mode);
_freedv = Codec2.freedvCreate(mode);
_modemTxBuffer = new short[Codec2.freedvGetNomModemSamples(_freedv)]; _modemTxBuffer = new short[Codec2.freedvGetNomModemSamples(_freedv)];
_speechRxBuffer = new short[Codec2.freedvGetMaxSpeechSamples(_freedv)]; _speechRxBuffer = new short[Codec2.freedvGetMaxSpeechSamples(_freedv)];
} }
@ -46,7 +53,9 @@ public class Freedv implements Protocol {
@Override @Override
public void sendPcmAudio(String src, String dst, int codec, short[] pcmFrame) throws IOException { public void sendPcmAudio(String src, String dst, int codec, short[] pcmFrame) throws IOException {
Codec2.freedvTx(_freedv, _modemTxBuffer, pcmFrame); Codec2.freedvTx(_freedv, _modemTxBuffer, pcmFrame);
Log.i(TAG, "send pcm " + _modemTxBuffer.length);
_transport.write(_modemTxBuffer); _transport.write(_modemTxBuffer);
_parentProtocolCallback.onTransmitPcmAudio(src, dst, codec, pcmFrame);
} }
@Override @Override
@ -69,6 +78,7 @@ public class Freedv implements Protocol {
if (bytesRead == nin) { if (bytesRead == nin) {
long cntRead = Codec2.freedvRx(_freedv, _speechRxBuffer, buf); long cntRead = Codec2.freedvRx(_freedv, _speechRxBuffer, buf);
if (cntRead > 0) { if (cntRead > 0) {
Log.i(TAG, "receive " + cntRead);
_parentProtocolCallback.onReceivePcmAudio(null, null, -1, Arrays.copyOf(_speechRxBuffer, (int) cntRead)); _parentProtocolCallback.onReceivePcmAudio(null, null, -1, Arrays.copyOf(_speechRxBuffer, (int) cntRead));
return true; return true;
} }

Wyświetl plik

@ -14,7 +14,8 @@ public class ProtocolFactory {
HDLC("HDLC"), HDLC("HDLC"),
KISS("KISS"), KISS("KISS"),
KISS_BUFFERED("KISS BUF"), KISS_BUFFERED("KISS BUF"),
KISS_PARROT("KISS RPT"); KISS_PARROT("KISS RPT"),
FREEDV("FREEDV");
private final String _name; private final String _name;
@ -35,7 +36,11 @@ public class ProtocolFactory {
// Use HDLC instead of KISS for the sound modem as we are the modem // Use HDLC instead of KISS for the sound modem as we are the modem
if (sharedPreferences.getString(PreferenceKeys.PORTS_TYPE, "loopback").equals("sound_modem")) { if (sharedPreferences.getString(PreferenceKeys.PORTS_TYPE, "loopback").equals("sound_modem")) {
protocolType = ProtocolFactory.ProtocolType.HDLC; if (sharedPreferences.getString(PreferenceKeys.PORTS_SOUND_MODEM_TYPE, "1200").startsWith("F")) {
protocolType = ProtocolType.FREEDV;
} else {
protocolType = ProtocolFactory.ProtocolType.HDLC;
}
} else if (sharedPreferences.getBoolean(PreferenceKeys.KISS_ENABLED, true)) { } else if (sharedPreferences.getBoolean(PreferenceKeys.KISS_ENABLED, true)) {
if (sharedPreferences.getBoolean(PreferenceKeys.KISS_PARROT, false)) { if (sharedPreferences.getBoolean(PreferenceKeys.KISS_PARROT, false)) {
protocolType = ProtocolFactory.ProtocolType.KISS_PARROT; protocolType = ProtocolFactory.ProtocolType.KISS_PARROT;
@ -77,6 +82,9 @@ public class ProtocolFactory {
case HDLC: case HDLC:
proto = new Hdlc(sharedPreferences); proto = new Hdlc(sharedPreferences);
break; break;
case FREEDV:
// standalone
return new Freedv();
case RAW: case RAW:
default: default:
proto = new Raw(); proto = new Raw();
@ -96,7 +104,7 @@ public class ProtocolFactory {
proto = new AudioFrameAggregator(proto, codec2ModeId); proto = new AudioFrameAggregator(proto, codec2ModeId);
proto = new AudioCodec2(proto, codec2ModeId); proto = new AudioCodec2(proto, codec2ModeId);
if (aprsEnabled) { // && protocolType != ProtocolType.RAW) { if (aprsEnabled) {
proto = new Aprs(proto); proto = new Aprs(proto);
} }
return proto; return proto;

Wyświetl plik

@ -23,6 +23,7 @@ public final class PreferenceKeys {
public static String PORTS_SOUND_MODEM_RIG = "ports_sound_modem_rig"; public static String PORTS_SOUND_MODEM_RIG = "ports_sound_modem_rig";
public static String PORTS_SOUND_MODEM_GAIN ="ports_sound_modem_gain"; public static String PORTS_SOUND_MODEM_GAIN ="ports_sound_modem_gain";
public static String PORTS_SOUND_MODEM_PTT_OFF_DELAY_MS = "ports_sound_modem_ptt_off_delay_ms"; public static String PORTS_SOUND_MODEM_PTT_OFF_DELAY_MS = "ports_sound_modem_ptt_off_delay_ms";
public static String PORTS_SOUND_MODEM_LOOPBACK="ports_sound_modem_loopback";
public static String CODEC2_MODE = "codec2_mode"; public static String CODEC2_MODE = "codec2_mode";
public static String CODEC2_RECORDING_ENABLED = "codec2_recording_enabled"; public static String CODEC2_RECORDING_ENABLED = "codec2_recording_enabled";

Wyświetl plik

@ -17,6 +17,7 @@ import com.radio.codec2talkie.rigctl.RigCtlFactory;
import com.radio.codec2talkie.settings.PreferenceKeys; import com.radio.codec2talkie.settings.PreferenceKeys;
import java.io.IOException; import java.io.IOException;
import java.nio.BufferOverflowException;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.ShortBuffer; import java.nio.ShortBuffer;
import java.util.Timer; import java.util.Timer;
@ -43,12 +44,17 @@ public class SoundModem implements Transport, Runnable {
private final ShortBuffer _recordAudioBuffer; private final ShortBuffer _recordAudioBuffer;
private boolean _isLoopback = false;
public SoundModem(Context context) { public SoundModem(Context context) {
_name = "SndModem";
_isPttOn = false;
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context); SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
boolean disableRx = sharedPreferences.getBoolean(PreferenceKeys.PORTS_SOUND_MODEM_DISABLE_RX, false); boolean disableRx = sharedPreferences.getBoolean(PreferenceKeys.PORTS_SOUND_MODEM_DISABLE_RX, false);
_pttOffDelayMs = Integer.parseInt(sharedPreferences.getString(PreferenceKeys.PORTS_SOUND_MODEM_PTT_OFF_DELAY_MS, "1000")); _pttOffDelayMs = Integer.parseInt(sharedPreferences.getString(PreferenceKeys.PORTS_SOUND_MODEM_PTT_OFF_DELAY_MS, "1000"));
_name = "SndModem"; _isLoopback = sharedPreferences.getBoolean(PreferenceKeys.PORTS_SOUND_MODEM_LOOPBACK, false);
constructSystemAudioDevices(disableRx); constructSystemAudioDevices(disableRx);
@ -59,11 +65,9 @@ public class SoundModem implements Transport, Runnable {
e.printStackTrace(); e.printStackTrace();
} }
_recordAudioBuffer = ShortBuffer.allocate(4096); _recordAudioBuffer = ShortBuffer.allocate(_isLoopback ? 1024*100 : 1024*10);
_isPttOn = false; if (!disableRx && !_isLoopback)
if (!disableRx)
new Thread(this).start(); new Thread(this).start();
} }
@ -124,6 +128,7 @@ public class SoundModem implements Transport, Runnable {
public int read(short[] audioSamples) throws IOException { public int read(short[] audioSamples) throws IOException {
synchronized (_recordAudioBuffer) { synchronized (_recordAudioBuffer) {
if (_recordAudioBuffer.position() >= audioSamples.length) { if (_recordAudioBuffer.position() >= audioSamples.length) {
//Log.i(TAG, "read " + _recordAudioBuffer.position());
_recordAudioBuffer.flip(); _recordAudioBuffer.flip();
_recordAudioBuffer.get(audioSamples); _recordAudioBuffer.get(audioSamples);
_recordAudioBuffer.compact(); _recordAudioBuffer.compact();
@ -138,7 +143,20 @@ public class SoundModem implements Transport, Runnable {
pttOn(); pttOn();
if (_systemAudioPlayer.getPlayState() != AudioTrack.PLAYSTATE_PLAYING) if (_systemAudioPlayer.getPlayState() != AudioTrack.PLAYSTATE_PLAYING)
_systemAudioPlayer.play(); _systemAudioPlayer.play();
_systemAudioPlayer.write(audioSamples, 0, audioSamples.length); if (_isLoopback) {
synchronized (_recordAudioBuffer) {
for (short sample : audioSamples) {
try {
_recordAudioBuffer.put(sample);
} catch (BufferOverflowException e) {
e.printStackTrace();
_recordAudioBuffer.clear();
}
}
}
} else {
_systemAudioPlayer.write(audioSamples, 0, audioSamples.length);
}
_systemAudioPlayer.stop(); _systemAudioPlayer.stop();
pttOff(); pttOff();
return audioSamples.length; return audioSamples.length;
@ -156,6 +174,7 @@ public class SoundModem implements Transport, Runnable {
@Override @Override
public void run() { public void run() {
Log.i(TAG, "Starting receive thread");
android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_AUDIO); android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_AUDIO);
int readSize = 16; int readSize = 16;
short [] sampleBuf = new short[readSize]; short [] sampleBuf = new short[readSize];
@ -172,7 +191,12 @@ public class SoundModem implements Transport, Runnable {
} }
synchronized (_recordAudioBuffer) { synchronized (_recordAudioBuffer) {
for (short sample : sampleBuf) { for (short sample : sampleBuf) {
_recordAudioBuffer.put(sample); try {
_recordAudioBuffer.put(sample);
} catch (BufferOverflowException e) {
e.printStackTrace();
_recordAudioBuffer.clear();
}
} }
} }
} }

Wyświetl plik

@ -53,7 +53,7 @@ public class SoundModemFsk implements Transport, Runnable {
private boolean _isRunning = true; private boolean _isRunning = true;
private final ByteBuffer _sampleBuffer; private final ByteBuffer _sampleBuffer;
private final boolean _isLoopback = false; private boolean _isLoopback = false;
private final long _fskModem; private final long _fskModem;
@ -70,6 +70,8 @@ public class SoundModemFsk implements Transport, Runnable {
int bitRate = Integer.parseInt(_sharedPreferences.getString(PreferenceKeys.PORTS_SOUND_MODEM_TYPE, "1200")); int bitRate = Integer.parseInt(_sharedPreferences.getString(PreferenceKeys.PORTS_SOUND_MODEM_TYPE, "1200"));
int gain = Integer.parseInt(_sharedPreferences.getString(PreferenceKeys.PORTS_SOUND_MODEM_GAIN, "10000")); int gain = Integer.parseInt(_sharedPreferences.getString(PreferenceKeys.PORTS_SOUND_MODEM_GAIN, "10000"));
_pttOffDelayMs = Integer.parseInt(_sharedPreferences.getString(PreferenceKeys.PORTS_SOUND_MODEM_PTT_OFF_DELAY_MS, "1000")); _pttOffDelayMs = Integer.parseInt(_sharedPreferences.getString(PreferenceKeys.PORTS_SOUND_MODEM_PTT_OFF_DELAY_MS, "1000"));
_isLoopback = _sharedPreferences.getBoolean(PreferenceKeys.PORTS_SOUND_MODEM_LOOPBACK, false);
_name = "SndModemFsk" + bitRate; _name = "SndModemFsk" + bitRate;
if (bitRate == 300) { if (bitRate == 300) {
// <230 spacing for 300 bps does not work with codec2 fsk for receive // <230 spacing for 300 bps does not work with codec2 fsk for receive

Wyświetl plik

@ -1,11 +1,15 @@
package com.radio.codec2talkie.transport; package com.radio.codec2talkie.transport;
import android.content.Context; import android.content.Context;
import android.content.SharedPreferences;
import androidx.preference.PreferenceManager;
import com.radio.codec2talkie.connect.BleHandler; import com.radio.codec2talkie.connect.BleHandler;
import com.radio.codec2talkie.connect.BluetoothSocketHandler; import com.radio.codec2talkie.connect.BluetoothSocketHandler;
import com.radio.codec2talkie.connect.TcpIpSocketHandler; import com.radio.codec2talkie.connect.TcpIpSocketHandler;
import com.radio.codec2talkie.connect.UsbPortHandler; import com.radio.codec2talkie.connect.UsbPortHandler;
import com.radio.codec2talkie.settings.PreferenceKeys;
import java.io.IOException; import java.io.IOException;
@ -32,6 +36,7 @@ public class TransportFactory {
} }
public static Transport create(TransportType transportType, Context context) throws IOException { public static Transport create(TransportType transportType, Context context) throws IOException {
switch (transportType) { switch (transportType) {
case USB: case USB:
return new UsbSerial(UsbPortHandler.getPort(), UsbPortHandler.getName()); return new UsbSerial(UsbPortHandler.getPort(), UsbPortHandler.getName());
@ -42,10 +47,16 @@ public class TransportFactory {
case BLE: case BLE:
return new Ble(BleHandler.getGatt(), BleHandler.getName()); return new Ble(BleHandler.getGatt(), BleHandler.getName());
case SOUND_MODEM: case SOUND_MODEM:
return new SoundModemFsk(context); return isFreeDv(context) ? new SoundModem(context) : new SoundModemFsk(context);
case LOOPBACK: case LOOPBACK:
default: default:
return new Loopback(); return new Loopback();
} }
} }
private static boolean isFreeDv(Context context) {
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
String modemType = sharedPreferences.getString(PreferenceKeys.PORTS_SOUND_MODEM_TYPE, "1200");
return modemType.startsWith("F");
}
} }

Wyświetl plik

@ -332,9 +332,9 @@
<item>FreeDV 800XA</item> <item>FreeDV 800XA</item>
<item>FreeDV 700C</item> <item>FreeDV 700C</item>
<item>FreeDV 700D</item> <item>FreeDV 700D</item>
<item>FreeDV 2020</item> <!--item>FreeDV 2020</item>
<item>FreeDV 2020B</item> <item>FreeDV 2020B</item>
<item>FreeDV 700E</item> <item>FreeDV 700E</item-->
</string-array> </string-array>
<string-array name="ports_sound_modem_type_values"> <string-array name="ports_sound_modem_type_values">
@ -346,9 +346,9 @@
<item>F5</item> <item>F5</item>
<item>F6</item> <item>F6</item>
<item>F7</item> <item>F7</item>
<item>F8</item> <!--item>F8</item>
<item>F16</item> <item>F16</item>
<item>F13</item> <item>F13</item-->
</string-array> </string-array>
<string-array name="ports_type_labels"> <string-array name="ports_type_labels">

Wyświetl plik

@ -307,4 +307,6 @@
<string name="ports_sound_modem_rig_label">&#127899;</string> <string name="ports_sound_modem_rig_label">&#127899;</string>
<string name="ports_sound_modem_ptt_off_delay_ms_title">CAT PTT transmit off delay</string> <string name="ports_sound_modem_ptt_off_delay_ms_title">CAT PTT transmit off delay</string>
<string name="ports_sound_modem_ptt_off_delay_ms_summary">How long to wait before switching off the transmission after last data is sent out (milliseconds)</string> <string name="ports_sound_modem_ptt_off_delay_ms_summary">How long to wait before switching off the transmission after last data is sent out (milliseconds)</string>
<string name="ports_sound_modem_loopback_title">Enable modulator loopback mode</string>
<string name="ports_sound_modem_loopback_summary">Audio modulated samples will be fed back to de-modulator</string>
</resources> </resources>

Wyświetl plik

@ -22,13 +22,6 @@
app:defaultValue="200"> app:defaultValue="200">
</EditTextPreference> </EditTextPreference>
<SwitchPreference
app:key="ports_sound_modem_disable_rx"
app:title="@string/ports_sound_modem_disable_rx_title"
app:summary="@string/ports_sound_modem_disable_rx_summary"
app:defaultValue="false">
</SwitchPreference>
<ListPreference <ListPreference
app:key="ports_sound_modem_rig" app:key="ports_sound_modem_rig"
app:title="@string/ports_sound_modem_rig_title" app:title="@string/ports_sound_modem_rig_title"
@ -54,5 +47,19 @@
app:defaultValue="1000"> app:defaultValue="1000">
</EditTextPreference> </EditTextPreference>
<SwitchPreference
app:key="ports_sound_modem_disable_rx"
app:title="@string/ports_sound_modem_disable_rx_title"
app:summary="@string/ports_sound_modem_disable_rx_summary"
app:defaultValue="false">
</SwitchPreference>
<SwitchPreference
app:key="ports_sound_modem_loopback"
app:title="@string/ports_sound_modem_loopback_title"
app:summary="@string/ports_sound_modem_loopback_summary"
app:defaultValue="false">
</SwitchPreference>
</PreferenceCategory> </PreferenceCategory>
</PreferenceScreen> </PreferenceScreen>

Wyświetl plik

@ -105,6 +105,7 @@ namespace Java_com_ustadmobile_codec2_Codec2 {
freedv_get_n_max_speech_samples(conFreedv->freeDv) * sizeof(short))); freedv_get_n_max_speech_samples(conFreedv->freeDv) * sizeof(short)));
conFreedv->modemSamples = static_cast<short *>(malloc( conFreedv->modemSamples = static_cast<short *>(malloc(
freedv_get_n_max_modem_samples(conFreedv->freeDv) * sizeof(short))); freedv_get_n_max_modem_samples(conFreedv->freeDv) * sizeof(short)));
freedv_set_squelch_en(conFreedv->freeDv, 1);
return reinterpret_cast<jlong>(conFreedv); return reinterpret_cast<jlong>(conFreedv);
} }