#1670 Resolves missing audio segments for some DMR Cap+ call events.

This commit is contained in:
Dennis Sheirer
2023-10-15 08:47:42 -04:00
parent bad5a1f9f0
commit b391ebbb5f
2 changed files with 38 additions and 48 deletions

View File

@@ -1,6 +1,6 @@
/* /*
* ***************************************************************************** * *****************************************************************************
* Copyright (C) 2014-2022 Dennis Sheirer * Copyright (C) 2014-2023 Dennis Sheirer
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@@ -38,7 +38,6 @@ import io.github.dsheirer.module.decode.dmr.message.data.lc.LCMessage;
import io.github.dsheirer.module.decode.dmr.message.data.lc.full.AbstractVoiceChannelUser; import io.github.dsheirer.module.decode.dmr.message.data.lc.full.AbstractVoiceChannelUser;
import io.github.dsheirer.module.decode.dmr.message.data.lc.full.FullLCMessage; import io.github.dsheirer.module.decode.dmr.message.data.lc.full.FullLCMessage;
import io.github.dsheirer.module.decode.dmr.message.data.terminator.Terminator; import io.github.dsheirer.module.decode.dmr.message.data.terminator.Terminator;
import io.github.dsheirer.module.decode.dmr.message.type.ServiceOptions;
import io.github.dsheirer.module.decode.dmr.message.voice.VoiceEMBMessage; import io.github.dsheirer.module.decode.dmr.message.voice.VoiceEMBMessage;
import io.github.dsheirer.module.decode.dmr.message.voice.VoiceMessage; import io.github.dsheirer.module.decode.dmr.message.voice.VoiceMessage;
import io.github.dsheirer.preference.UserPreferences; import io.github.dsheirer.preference.UserPreferences;
@@ -104,44 +103,24 @@ public class DMRAudioModule extends AmbeAudioModule implements IdentifierUpdateP
public void receive(IMessage message) public void receive(IMessage message)
{ {
if(hasAudioCodec() && message.getTimeslot() == getTimeslot()) if(hasAudioCodec() && message.getTimeslot() == getTimeslot())
{
//Attempt to set the audio encryption state from certain types of messages
if(!mEncryptedCallStateEstablished)
{ {
//DCDM doesn't provide FLCs or EMBs ... assume that the call is unencrypted. //DCDM doesn't provide FLCs or EMBs ... assume that the call is unencrypted.
if(!mEncryptedCallStateEstablished && message instanceof VoiceMessage vm && if(message instanceof VoiceMessage vm && vm.getSyncPattern().isDirectMode())
vm.getSyncPattern().isDirectMode())
{ {
mEncryptedCallStateEstablished = true; mEncryptedCallStateEstablished = true;
mEncryptedCall = false; mEncryptedCall = false;
List<byte[]> frames = vm.getAMBEFrames();
for(byte[] frame: frames)
{
processAudio(frame, message.getTimestamp());
}
} }
//Both Motorola and Hytera signal their Basic Privacy (BP) scrambling in some of the Voice B-F frames //Both Motorola and Hytera signal their Basic Privacy (BP) scrambling in some of the Voice B-F frames
//in the EMB field. //in the EMB field.
else if(!mEncryptedCallStateEstablished && message instanceof VoiceEMBMessage voiceMessage) else if(message instanceof VoiceEMBMessage voiceMessage && voiceMessage.getEMB().isValid())
{
if(voiceMessage.getEMB().isValid())
{ {
mEncryptedCallStateEstablished = true; mEncryptedCallStateEstablished = true;
mEncryptedCall = voiceMessage.getEMB().isEncrypted(); mEncryptedCall = voiceMessage.getEMB().isEncrypted();
} }
else if(message instanceof VoiceHeader voiceHeader)
List<byte[]> frames = voiceMessage.getAMBEFrames();
for(byte[] frame: frames)
{
processAudio(frame, message.getTimestamp());
}
}
else if(message instanceof VoiceMessage voiceMessage)
{
List<byte[]> frames = voiceMessage.getAMBEFrames();
for(byte[] frame: frames)
{
processAudio(frame, message.getTimestamp());
}
}
else if(!mEncryptedCallStateEstablished && message instanceof VoiceHeader voiceHeader)
{ {
LCMessage lc = voiceHeader.getLCMessage(); LCMessage lc = voiceHeader.getLCMessage();
@@ -154,14 +133,25 @@ public class DMRAudioModule extends AmbeAudioModule implements IdentifierUpdateP
} }
} }
} }
//Note: the DMRMessageProcess extracts Full Link Control messages from Voice Frames B-C and sends them //Note: the DMRMessageProcessor extracts Full Link Control messages from Voice Frames B-C and sends them
// independent of any DMR Burst messaging. When encountered, it can be assumed that they are part of // independent of any DMR Burst messaging. When encountered, it can be assumed that they are part of
// an ongoing call and can be used to establish encryption state when the FLC is a voice channel user. // an ongoing call and can be used to establish encryption state when the FLC is a voice channel user.
else if(!mEncryptedCallStateEstablished && message instanceof AbstractVoiceChannelUser avcu) else if(message instanceof AbstractVoiceChannelUser avcu)
{ {
ServiceOptions serviceOptions = avcu.getServiceOptions();
mEncryptedCallStateEstablished = true; mEncryptedCallStateEstablished = true;
mEncryptedCall = serviceOptions.isEncrypted(); mEncryptedCall = avcu.getServiceOptions().isEncrypted();
}
}
//Queue or process audio frames. Note: audio frames are held/queued until encrypted state is established
//before any audio is generated for the audio segment.
if(message instanceof VoiceMessage voiceMessage)
{
List<byte[]> frames = voiceMessage.getAMBEFrames();
for(byte[] frame: frames)
{
processAudio(frame, message.getTimestamp());
}
} }
else if(message instanceof Terminator) else if(message instanceof Terminator)
{ {

View File

@@ -21,13 +21,13 @@ package io.github.dsheirer.module.decode.dmr.message.data.lc.full.motorola;
import io.github.dsheirer.bits.CorrectedBinaryMessage; import io.github.dsheirer.bits.CorrectedBinaryMessage;
import io.github.dsheirer.module.decode.dmr.message.IServiceOptionsProvider; import io.github.dsheirer.module.decode.dmr.message.IServiceOptionsProvider;
import io.github.dsheirer.module.decode.dmr.message.data.lc.full.FullLCMessage; import io.github.dsheirer.module.decode.dmr.message.data.lc.full.AbstractVoiceChannelUser;
import io.github.dsheirer.module.decode.dmr.message.type.CapacityPlusServiceOptions; import io.github.dsheirer.module.decode.dmr.message.type.CapacityPlusServiceOptions;
/** /**
* Any Capacity Plus Voice Channel User link control message that contains vendor-specific service options. * Any Capacity Plus Voice Channel User link control message that contains vendor-specific service options.
*/ */
public abstract class CapacityPlusVoiceChannelUser extends FullLCMessage implements IServiceOptionsProvider public abstract class CapacityPlusVoiceChannelUser extends AbstractVoiceChannelUser implements IServiceOptionsProvider
{ {
private static final int[] SERVICE_OPTIONS = new int[]{16, 17, 18, 19, 20, 21, 22, 23}; private static final int[] SERVICE_OPTIONS = new int[]{16, 17, 18, 19, 20, 21, 22, 23};
//Reed Solomon FEC: 72-95 //Reed Solomon FEC: 72-95