mirror of
https://github.com/dz0ny/meshcore-sar.git
synced 2026-08-11 16:30:28 +00:00
fix: retain voice codec settings now
ref:
This commit is contained in:
69
test/providers/messages_provider_voice_test.dart
Normal file
69
test/providers/messages_provider_voice_test.dart
Normal file
@@ -0,0 +1,69 @@
|
||||
import 'dart:typed_data';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:meshcore_sar_app/models/message.dart';
|
||||
import 'package:meshcore_sar_app/providers/messages_provider.dart';
|
||||
import 'package:meshcore_sar_app/utils/voice_message_parser.dart';
|
||||
|
||||
void main() {
|
||||
TestWidgetsFlutterBinding.ensureInitialized();
|
||||
|
||||
group('MessagesProvider voice detection', () {
|
||||
test('marks VE1 envelope messages as voice', () {
|
||||
final provider = MessagesProvider();
|
||||
final envelope = VoiceEnvelope(
|
||||
sessionId: 'deafbead',
|
||||
mode: VoicePacketMode.mode1200,
|
||||
total: 3,
|
||||
durationMs: 2400,
|
||||
senderKey6: 'aabbccddeeff',
|
||||
timestampSec: 1700000000,
|
||||
);
|
||||
|
||||
final message = Message(
|
||||
id: 'm1',
|
||||
messageType: MessageType.channel,
|
||||
channelIdx: 0,
|
||||
pathLen: 0,
|
||||
textType: MessageTextType.plain,
|
||||
senderTimestamp: 1700000000,
|
||||
text: envelope.encodeText(),
|
||||
receivedAt: DateTime.now(),
|
||||
senderPublicKeyPrefix: Uint8List.fromList([0, 1, 2, 3, 4, 5]),
|
||||
deliveryStatus: MessageDeliveryStatus.sent,
|
||||
);
|
||||
|
||||
provider.addMessage(message);
|
||||
final stored = provider.messages.single;
|
||||
expect(stored.isVoice, isTrue);
|
||||
expect(stored.voiceId, equals('deafbead'));
|
||||
});
|
||||
|
||||
test('marks legacy V text packets as voice', () {
|
||||
final provider = MessagesProvider();
|
||||
final packet = VoicePacket(
|
||||
sessionId: '00112233',
|
||||
mode: VoicePacketMode.mode700c,
|
||||
index: 0,
|
||||
total: 1,
|
||||
codec2Data: Uint8List.fromList([1, 2, 3]),
|
||||
);
|
||||
final message = Message(
|
||||
id: 'm2',
|
||||
messageType: MessageType.channel,
|
||||
channelIdx: 0,
|
||||
pathLen: 0,
|
||||
textType: MessageTextType.plain,
|
||||
senderTimestamp: 1700000001,
|
||||
text: packet.encodeText(),
|
||||
receivedAt: DateTime.now(),
|
||||
senderPublicKeyPrefix: Uint8List.fromList([0, 1, 2, 3, 4, 5]),
|
||||
deliveryStatus: MessageDeliveryStatus.sent,
|
||||
);
|
||||
|
||||
provider.addMessage(message);
|
||||
final stored = provider.messages.single;
|
||||
expect(stored.isVoice, isTrue);
|
||||
expect(stored.voiceId, equals('00112233'));
|
||||
});
|
||||
});
|
||||
}
|
||||
152
test/utils/voice_message_parser_test.dart
Normal file
152
test/utils/voice_message_parser_test.dart
Normal file
@@ -0,0 +1,152 @@
|
||||
import 'dart:typed_data';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:meshcore_sar_app/utils/voice_message_parser.dart';
|
||||
|
||||
void main() {
|
||||
group('VoiceEnvelope', () {
|
||||
test('encodes and parses valid envelope', () {
|
||||
final env = VoiceEnvelope(
|
||||
sessionId: 'deadbeef',
|
||||
mode: VoicePacketMode.mode1200,
|
||||
total: 4,
|
||||
durationMs: 3200,
|
||||
senderKey6: 'aabbccddeeff',
|
||||
timestampSec: 1700000000,
|
||||
);
|
||||
|
||||
final text = env.encodeText();
|
||||
expect(VoiceEnvelope.isVoiceEnvelopeText(text), isTrue);
|
||||
|
||||
final parsed = VoiceEnvelope.tryParseText(text);
|
||||
expect(parsed, isNotNull);
|
||||
expect(parsed!.sessionId, equals('deadbeef'));
|
||||
expect(parsed.mode, equals(VoicePacketMode.mode1200));
|
||||
expect(parsed.total, equals(4));
|
||||
expect(parsed.durationMs, equals(3200));
|
||||
expect(parsed.senderKey6, equals('aabbccddeeff'));
|
||||
expect(parsed.version, equals(1));
|
||||
});
|
||||
|
||||
test('rejects invalid envelope payload', () {
|
||||
final text = 'VE1:nothex:1:2:1000:aabbccddeeff:1700000000:1';
|
||||
expect(VoiceEnvelope.tryParseText(text), isNull);
|
||||
});
|
||||
});
|
||||
|
||||
group('VoiceFetchRequest', () {
|
||||
test('encodes and parses valid request', () {
|
||||
final req = VoiceFetchRequest(
|
||||
sessionId: '00112233',
|
||||
requesterKey6: 'ffeeddccbbaa',
|
||||
timestampSec: 1700000001,
|
||||
);
|
||||
final text = req.encodeText();
|
||||
expect(VoiceFetchRequest.isVoiceFetchRequestText(text), isTrue);
|
||||
|
||||
final parsed = VoiceFetchRequest.tryParseText(text);
|
||||
expect(parsed, isNotNull);
|
||||
expect(parsed!.sessionId, equals('00112233'));
|
||||
expect(parsed.want, equals('all'));
|
||||
expect(parsed.requesterKey6, equals('ffeeddccbbaa'));
|
||||
expect(parsed.version, equals(1));
|
||||
});
|
||||
|
||||
test('rejects invalid request payload', () {
|
||||
expect(
|
||||
VoiceFetchRequest.tryParseText(
|
||||
'VR1:00112233:chunk:ffeeddccbbaa:1700000001:1',
|
||||
),
|
||||
isNull,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
group('VoicePacket backward compatibility', () {
|
||||
test('parses legacy V: text format', () {
|
||||
final pkt = VoicePacket(
|
||||
sessionId: 'a1b2c3d4',
|
||||
mode: VoicePacketMode.mode700c,
|
||||
index: 0,
|
||||
total: 1,
|
||||
codec2Data: Uint8List.fromList([1, 2, 3, 4]),
|
||||
);
|
||||
final encoded = pkt.encodeText();
|
||||
final parsed = VoicePacket.tryParseText(encoded);
|
||||
expect(parsed, isNotNull);
|
||||
expect(parsed!.sessionId, equals('a1b2c3d4'));
|
||||
expect(parsed.total, equals(1));
|
||||
expect(parsed.codec2Data, equals(Uint8List.fromList([1, 2, 3, 4])));
|
||||
});
|
||||
|
||||
test('constructs binary datagram from actual packet data', () {
|
||||
final actualCodec2 = Uint8List.fromList([
|
||||
0xD3,
|
||||
0x19,
|
||||
0x7A,
|
||||
0x00,
|
||||
0xFE,
|
||||
0x44,
|
||||
0xC1,
|
||||
0x2B,
|
||||
0x88,
|
||||
]);
|
||||
|
||||
final pkt = VoicePacket(
|
||||
sessionId: '01020304',
|
||||
mode: VoicePacketMode.mode1300,
|
||||
index: 2,
|
||||
total: 5,
|
||||
codec2Data: actualCodec2,
|
||||
);
|
||||
|
||||
final datagram = pkt.encodeBinary();
|
||||
expect(datagram[0], equals(0x56)); // magic 'V'
|
||||
expect(datagram.sublist(1, 5), equals(Uint8List.fromList([1, 2, 3, 4])));
|
||||
expect(datagram[5], equals(VoicePacketMode.mode1300.id));
|
||||
expect(datagram[6], equals(2));
|
||||
expect(datagram[7], equals(5));
|
||||
expect(datagram.sublist(8), equals(actualCodec2));
|
||||
|
||||
final parsed = VoicePacket.tryParseBinary(datagram);
|
||||
expect(parsed, isNotNull);
|
||||
expect(parsed!.sessionId, equals('01020304'));
|
||||
expect(parsed.mode, equals(VoicePacketMode.mode1300));
|
||||
expect(parsed.index, equals(2));
|
||||
expect(parsed.total, equals(5));
|
||||
expect(parsed.codec2Data, equals(actualCodec2));
|
||||
});
|
||||
});
|
||||
|
||||
group('VoiceWaveform', () {
|
||||
test('builds bars from packet bytes', () {
|
||||
final packet = VoicePacket(
|
||||
sessionId: '1234abcd',
|
||||
mode: VoicePacketMode.mode1200,
|
||||
index: 0,
|
||||
total: 1,
|
||||
codec2Data: Uint8List.fromList([
|
||||
0,
|
||||
255,
|
||||
10,
|
||||
245,
|
||||
120,
|
||||
130,
|
||||
64,
|
||||
192,
|
||||
32,
|
||||
224,
|
||||
]),
|
||||
);
|
||||
|
||||
final bars = VoiceWaveform.buildBarsFromPackets([packet], bars: 8);
|
||||
expect(bars.length, equals(8));
|
||||
expect(bars.every((v) => v >= 0.0 && v <= 1.0), isTrue);
|
||||
expect(bars.any((v) => v > 0.2), isTrue);
|
||||
});
|
||||
|
||||
test('returns zeros for missing packet data', () {
|
||||
final bars = VoiceWaveform.buildBarsFromPackets(const [], bars: 6);
|
||||
expect(bars, equals(List<double>.filled(6, 0.0)));
|
||||
});
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user