Sound modem experiments

legacy
sh123 2022-07-29 17:54:24 +03:00
rodzic 381f10b70e
commit fae6937533
6 zmienionych plików z 155 dodań i 39 usunięć

Wyświetl plik

@ -28,7 +28,6 @@ import com.radio.codec2talkie.protocol.Protocol;
import com.radio.codec2talkie.protocol.ProtocolFactory;
import com.radio.codec2talkie.protocol.position.Position;
import com.radio.codec2talkie.settings.PreferenceKeys;
import com.radio.codec2talkie.storage.message.MessageItem;
import com.radio.codec2talkie.storage.message.MessageItemRepository;
import com.radio.codec2talkie.storage.position.PositionItemRepository;
import com.radio.codec2talkie.tools.AudioTools;
@ -87,16 +86,16 @@ public class AppWorker extends Thread {
String codec2ModeName = _sharedPreferences.getString(PreferenceKeys.CODEC2_MODE, _context.getResources().getStringArray(R.array.codec2_modes)[0]);
_codec2Mode = AudioTools.extractCodec2ModeId(codec2ModeName);
_logItemRepository = new LogItemRepository((Application)context);
_messageItemRepository = new MessageItemRepository((Application)context);
_positionItemRepository = new PositionItemRepository((Application)context);
_transport = TransportFactory.create(transportType, context);
_protocol = ProtocolFactory.create(_codec2Mode, context);
_processPeriodicTimer = new Timer();
_recordAudioBuffer = new short[_protocol.getPcmAudioBufferSize()];
_logItemRepository = new LogItemRepository((Application)context);
_messageItemRepository = new MessageItemRepository((Application)context);
_positionItemRepository = new PositionItemRepository((Application)context);
constructSystemAudioDevices();
}
@ -493,7 +492,7 @@ public class AppWorker extends Thread {
public void run() {
Log.i(TAG, "Starting message loop");
try {
sleep(1000);
sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}

Wyświetl plik

@ -76,22 +76,20 @@ public class ProtocolFactory {
break;
}
if (protocolType != ProtocolType.RAW) {
if (scramblingEnabled) {
proto = new Scrambler(proto, scramblingKey);
}
if (aprsEnabled) {
proto = new Ax25(proto);
}
if (recordingEnabled) {
proto = new Recorder(proto, codec2ModeId);
}
if (scramblingEnabled) {
proto = new Scrambler(proto, scramblingKey);
}
if (aprsEnabled) {
proto = new Ax25(proto);
}
if (recordingEnabled) {
proto = new Recorder(proto, codec2ModeId);
}
proto = new AudioFrameAggregator(proto, codec2ModeId);
proto = new AudioCodec2(proto, codec2ModeId);
if (aprsEnabled && protocolType != ProtocolType.RAW) {
if (aprsEnabled) { // && protocolType != ProtocolType.RAW) {
proto = new Aprs(proto);
}
return proto;

Wyświetl plik

@ -118,6 +118,7 @@ public class AX25Packet {
}
// data
buffer.put(rawData);
// return
buffer.flip();
byte[] b = new byte[buffer.remaining()];

Wyświetl plik

@ -0,0 +1,52 @@
package com.radio.codec2talkie.tools;
public class ChecksumTools {
private static final int[] _ccitTable = new int[] {
0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
};
public static int calculateFcs(byte[] data)
{
int crc = 0xffff;
for (int j = 0; j < data.length; j++) {
crc = (crc >> 8) ^ _ccitTable[(crc ^ (int)data[j]) & 0xff];
crc &= 0xffff;
}
return (crc ^ 0xffff);
}
}

Wyświetl plik

@ -11,17 +11,18 @@ import android.util.Log;
import androidx.preference.PreferenceManager;
import com.radio.codec2talkie.tools.ChecksumTools;
import com.ustadmobile.codec2.Codec2;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.BitSet;
public class SoundModem implements Transport {
private static final String TAG = SoundModem.class.getSimpleName();
private static final int AUDIO_SAMPLE_SIZE = 12000;
private static final int AUDIO_SAMPLE_SIZE = 48000;
private final String _name;
@ -44,7 +45,8 @@ public class SoundModem implements Transport {
_context = context;
_sharedPreferences = PreferenceManager.getDefaultSharedPreferences(_context);
_fskModem = Codec2.fskCreate(AUDIO_SAMPLE_SIZE, 300, 1600, 200);
//_fskModem = Codec2.fskCreate(AUDIO_SAMPLE_SIZE, 300, 1600, 200);
_fskModem = Codec2.fskCreate(AUDIO_SAMPLE_SIZE, 1200, 1200, 1000);
_recordAudioBuffer = new short[Codec2.fskDemodSamplesBufSize(_fskModem)];
_recordBitBuffer = new byte[Codec2.fskDemodBitsBufSize(_fskModem)];
@ -55,19 +57,20 @@ public class SoundModem implements Transport {
}
private void constructSystemAudioDevices() {
int _audioRecorderMinBufferSize = AudioRecord.getMinBufferSize(
int audioRecorderMinBufferSize = AudioRecord.getMinBufferSize(
AUDIO_SAMPLE_SIZE,
AudioFormat.CHANNEL_IN_MONO,
AudioFormat.ENCODING_PCM_16BIT);
int audioSource = MediaRecorder.AudioSource.MIC;
_systemAudioRecorder = new AudioRecord(
audioSource,
AUDIO_SAMPLE_SIZE,
AudioFormat.CHANNEL_IN_MONO,
AudioFormat.ENCODING_PCM_16BIT,
_audioRecorderMinBufferSize);
audioRecorderMinBufferSize);
int _audioPlayerMinBufferSize = AudioTrack.getMinBufferSize(
int audioPlayerMinBufferSize = AudioTrack.getMinBufferSize(
AUDIO_SAMPLE_SIZE,
AudioFormat.CHANNEL_OUT_MONO,
AudioFormat.ENCODING_PCM_16BIT);
@ -76,7 +79,7 @@ public class SoundModem implements Transport {
_systemAudioPlayer = new AudioTrack.Builder()
.setAudioAttributes(new AudioAttributes.Builder()
.setUsage(usage)
.setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
.setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
.build())
.setAudioFormat(new AudioFormat.Builder()
.setEncoding(AudioFormat.ENCODING_PCM_16BIT)
@ -84,7 +87,7 @@ public class SoundModem implements Transport {
.setChannelMask(AudioFormat.CHANNEL_OUT_MONO)
.build())
.setTransferMode(AudioTrack.MODE_STREAM)
.setBufferSizeInBytes(_audioPlayerMinBufferSize)
.setBufferSizeInBytes(audioPlayerMinBufferSize)
.build();
}
@ -98,32 +101,93 @@ public class SoundModem implements Transport {
return 0;
}
public static byte[] toByteBitArray(BitSet bits) {
byte[] bytes = new byte[bits.length()];
for (int i=0; i<bits.length(); i++) {
bytes[i] = (byte) (bits.get(i) ? 1 : 0);
public static byte[] toHdlcByteBitArray(byte[] data, boolean shouldBitStuff) {
StringBuilder s = new StringBuilder();
ByteBuffer bitBuffer = ByteBuffer.allocate(512*8);
int cntOnes = 0;
for (int i = 0; i < 8 * data.length; i++) {
int b = data[i / 8];
if ((b & (1 << (i % 8))) > 0) {
bitBuffer.put((byte)1);
s.append(1);
if (shouldBitStuff)
cntOnes += 1;
} else {
bitBuffer.put((byte)0);
s.append(0);
}
if (shouldBitStuff && cntOnes == 5) {
bitBuffer.put((byte)0);
s.append(0);
cntOnes = 0;
}
}
return bytes;
Log.i(TAG, s.toString());
bitBuffer.flip();
byte[] r = new byte[bitBuffer.remaining()];
bitBuffer.get(r);
return r;
}
public byte[] genPreamble(int count) {
byte[] preamble = new byte[count];
for (int i = 0; i < count; i++)
preamble[i] = (byte)0x7e;
return toHdlcByteBitArray(preamble, false);
}
public byte[] hdlcEncode(byte[] dataSrc) {
ByteBuffer buffer = ByteBuffer.allocate(512);
buffer.put(dataSrc);
int fcs = ChecksumTools.calculateFcs(dataSrc);
buffer.put((byte)((fcs >> 8) & 0xff));
buffer.put((byte)(fcs & 0xff));
buffer.flip();
byte[] data = new byte[buffer.remaining()];
buffer.get(data);
Log.i(TAG, String.format("checksum: %x", fcs));
Log.i(TAG, "" + Arrays.toString(data));
byte[] dataBytesAsBits = toHdlcByteBitArray(data, true);
Log.i(TAG, "write() " + data.length + " " + 8 * data.length + " " + dataBytesAsBits.length + " " + _playbackBitBuffer.length);
ByteBuffer hdlcBitBuffer = ByteBuffer.allocate(512*8);
hdlcBitBuffer.put(genPreamble(30));
hdlcBitBuffer.put(dataBytesAsBits);
hdlcBitBuffer.put(genPreamble(5));
hdlcBitBuffer.flip();
byte[] r = new byte[hdlcBitBuffer.remaining()];
hdlcBitBuffer.get(r);
return r;
}
@Override
public int write(byte[] data) throws IOException {
_systemAudioPlayer.play();
byte[] dataBits = toByteBitArray(BitSet.valueOf(data));
Log.i(TAG, "write() " + data.length + " " + dataBits.length + " " + _playbackBitBuffer.length);
public int write(byte[] dataSrc) throws IOException {
byte[] dataBytesAsBits = hdlcEncode(dataSrc);
int j = 0;
for (int i = 0; i < dataBits.length; i++, j++) {
for (int i = 0; i < dataBytesAsBits.length; i++, j++) {
if (j >= _playbackBitBuffer.length) {
Log.i(TAG, "-- " + i + " " + j);
Codec2.fskModulate(_fskModem, _playbackAudioBuffer, _playbackBitBuffer);
_systemAudioPlayer.write(_playbackAudioBuffer, 0, _playbackAudioBuffer.length);
_systemAudioPlayer.play();
j = 0;
}
_playbackBitBuffer[j] = dataBits[i];
_playbackBitBuffer[j] = dataBytesAsBits[i];
}
Log.i(TAG, "-- " + j);
Codec2.fskModulate(_fskModem, _playbackAudioBuffer, _playbackBitBuffer);
Codec2.fskModulate(_fskModem, _playbackAudioBuffer, Arrays.copyOf(_playbackBitBuffer, j));
_systemAudioPlayer.write(_playbackAudioBuffer, 0, _playbackAudioBuffer.length);
_systemAudioPlayer.play();
return 0;
}

Wyświetl plik

@ -153,14 +153,16 @@ namespace Java_com_ustadmobile_codec2_Codec2 {
static jlong fskModulate(JNIEnv *env, jclass clazz, jlong n, jshortArray outputSamples, jbyteArray inputBits) {
ContextFsk *conFsk = getContextFsk(n);
jbyte *jbuf = env->GetByteArrayElements(inputBits, nullptr);
for (int i = 0; i < conFsk->Nbits; i++) {
//for (int i = 0; i < conFsk->Nbits; i++) {
int inputBitsSize = env->GetArrayLength(inputBits);
for (int i = 0; i < inputBitsSize; i++) {
auto v = (unsigned char) jbuf[i];
conFsk->modBits[i] = v;
}
env->ReleaseByteArrayElements(inputBits, jbuf, 0);
//env->DeleteLocalRef(inputBits);
fsk_mod(conFsk->fsk, conFsk->modBuf, conFsk->modBits, conFsk->Nbits);
fsk_mod(conFsk->fsk, conFsk->modBuf, conFsk->modBits, inputBitsSize);
jshort *jOutBuf = env->GetShortArrayElements(outputSamples, nullptr);
for (int i = 0; i < conFsk->N; i++) {