You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
dvmhost/src/dfsi/frames/FullRateVoice.cpp

192 lines
5.7 KiB

// SPDX-License-Identifier: GPL-2.0-only
/**
* Digital Voice Modem - DFSI Peer Application
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / DFSI Peer Application
* @derivedfrom MMDVMHost (https://github.com/g4klx/MMDVMHost)
* @license GPLv2 License (https://opensource.org/licenses/GPL-2.0)
*
* Copyright (C) 2024 Bryan Biedenkapp, N2PLL
*
*/
#include "frames/FullRateVoice.h"
#include "common/p25/dfsi/DFSIDefines.h"
#include "common/Utils.h"
#include "common/Log.h"
#include <cassert>
#include <cstring>
using namespace p25;
using namespace dfsi;
// ---------------------------------------------------------------------------
// Public Class Members
// ---------------------------------------------------------------------------
/// <summary>
/// Initializes a instance of the FullRateVoice class.
/// </summary>
FullRateVoice::FullRateVoice() :
imbeData(nullptr),
additionalData(nullptr),
m_frameType(P25_DFSI_LDU1_VOICE1),
m_totalErrors(0U),
m_muteFrame(false),
m_lostFrame(false),
m_superframeCnt(0U),
m_busy(0U)
{
imbeData = new uint8_t[IMBE_BUF_LEN];
::memset(imbeData, 0x00U, IMBE_BUF_LEN);
}
/// <summary>
/// Initializes a instance of the FullRateVoice class.
/// </summary>
/// <param name="data"></param>
FullRateVoice::FullRateVoice(uint8_t* data) :
imbeData(nullptr),
additionalData(nullptr),
m_frameType(P25_DFSI_LDU1_VOICE1),
m_totalErrors(0U),
m_muteFrame(false),
m_lostFrame(false),
m_superframeCnt(0U),
m_busy(0U)
{
decode(data);
}
/// <summary>
/// Finalizes a instance of the FullRateVoice class.
/// </summary>
FullRateVoice::~FullRateVoice()
{
if (imbeData != nullptr)
delete[] imbeData;
if (additionalData != nullptr)
delete[] additionalData;
}
/// <summary>
/// Decode a full rate voice frame.
/// </summary>
/// <param name="data"></param>
/// <returns></returns>
bool FullRateVoice::decode(const uint8_t* data)
{
assert(data != nullptr);
if (imbeData != nullptr)
delete imbeData;
imbeData = new uint8_t[IMBE_BUF_LEN];
::memset(imbeData, 0x00U, IMBE_BUF_LEN);
m_frameType = data[0U]; // Frame Type
::memcpy(imbeData, data + 1U, IMBE_BUF_LEN); // IMBE
m_totalErrors = (uint8_t)((data[12U] >> 5) & 0x07U); // Total Errors
m_muteFrame = (data[12U] & 0x02U) == 0x02U; // Mute Frame Flag
m_lostFrame = (data[12U] & 0x01U) == 0x01U; // Lost Frame Flag
m_superframeCnt = (uint8_t)((data[13U] >> 2) & 0x03U); // Superframe Counter
m_busy = (uint8_t)(data[13U] & 0x03U);
if (isVoice3thru8() || isVoice12thru17() || isVoice9or10()) {
if (additionalData != nullptr)
delete additionalData;
additionalData = new uint8_t[ADDITIONAL_LENGTH];
::memset(additionalData, 0x00U, ADDITIONAL_LENGTH);
if (isVoice9or10()) {
// CAI 9 and 10 are 3 bytes of additional data not 4
::memcpy(additionalData, data + 14U, ADDITIONAL_LENGTH - 1U);
} else {
::memcpy(additionalData, data + 14U, ADDITIONAL_LENGTH);
}
} else {
if (additionalData != nullptr)
delete additionalData;
additionalData = nullptr;
}
return true;
}
/// <summary>
/// Encode a full rate voice frame.
/// </summary>
/// <param name="data"></param>
void FullRateVoice::encode(uint8_t* data)
{
assert(data != nullptr);
assert(imbeData != nullptr);
data[0U] = m_frameType; // Frame Type
::memcpy(data + 1U, imbeData, IMBE_BUF_LEN); // IMBE
data[12U] = (uint8_t)(((m_totalErrors & 0x07U) << 5) + // Total Errors
(m_muteFrame ? 0x02U : 0x00U) + // Mute Frame Flag
(m_lostFrame ? 0x01U : 0x00U)); // Lost Frame Flag
data[13U] = (uint8_t)(((m_superframeCnt & 0x03U) << 2) + // Superframe Count
(m_busy & 0x03U)); // Busy Status
if ((isVoice3thru8() || isVoice12thru17() || isVoice9or10()) &&
additionalData != nullptr) {
if (isVoice9or10()) {
// CAI 9 and 10 are 3 bytes of additional data not 4
::memcpy(data + 14U, additionalData, ADDITIONAL_LENGTH - 1U);
} else {
::memcpy(data + 14U, additionalData, ADDITIONAL_LENGTH);
}
}
}
// ---------------------------------------------------------------------------
// Private Class Members
// ---------------------------------------------------------------------------
/// <summary>
///
/// </summary>
/// <returns></returns>
bool FullRateVoice::isVoice3thru8()
{
if ( (m_frameType == P25_DFSI_LDU1_VOICE3) || (m_frameType == P25_DFSI_LDU1_VOICE4) || (m_frameType == P25_DFSI_LDU1_VOICE5) ||
(m_frameType == P25_DFSI_LDU1_VOICE6) || (m_frameType == P25_DFSI_LDU1_VOICE7) || (m_frameType == P25_DFSI_LDU1_VOICE8) ) {
return true;
} else {
return false;
}
}
/// <summary>
///
/// </summary>
/// <returns></returns>
bool FullRateVoice::isVoice12thru17()
{
if ( (m_frameType == P25_DFSI_LDU2_VOICE12) || (m_frameType == P25_DFSI_LDU2_VOICE13) || (m_frameType == P25_DFSI_LDU2_VOICE14) ||
(m_frameType == P25_DFSI_LDU2_VOICE15) || (m_frameType == P25_DFSI_LDU2_VOICE16) || (m_frameType == P25_DFSI_LDU2_VOICE17) ) {
return true;
} else {
return false;
}
}
/// <summary>
///
/// </summary>
/// <returns></returns>
bool FullRateVoice::isVoice9or10()
{
if ( (m_frameType == P25_DFSI_LDU1_VOICE9) || (m_frameType == P25_DFSI_LDU2_VOICE10) ) {
return true;
} else {
return false;
}
}

Powered by TurnKey Linux.