650 lines
25 KiB
C#
650 lines
25 KiB
C#
|
using System;
|
|||
|
using System.Collections.Generic;
|
|||
|
using System.Linq;
|
|||
|
using System.Text;
|
|||
|
using System.Threading.Tasks;
|
|||
|
|
|||
|
namespace SipComponent
|
|||
|
{
|
|||
|
class DMR
|
|||
|
{
|
|||
|
private object _lockObject = new object();
|
|||
|
|
|||
|
//
|
|||
|
// DMR properties
|
|||
|
//
|
|||
|
/// <summary>
|
|||
|
/// The period in ms between sending PTT requests
|
|||
|
/// </summary>
|
|||
|
const int _T_request = 240;
|
|||
|
//const int _T_request = 120;
|
|||
|
|
|||
|
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// The total number of PTT Requests that can be sent.
|
|||
|
/// </summary>
|
|||
|
const int _T_numreq = 3;
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// The period in ms between sending PTT End
|
|||
|
/// </summary>
|
|||
|
const int _T_end = 20;
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// The total number of PTT End that are to be sent
|
|||
|
/// </summary>
|
|||
|
const int _T_numend = 3;
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// The time in seconds between sending of PTT Heartbeats
|
|||
|
/// </summary>
|
|||
|
const byte _T_hearbeat = 10;
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Returns the time in seconds between sending of PTT Heartbeats
|
|||
|
/// </summary>
|
|||
|
public static int T_heartbeat
|
|||
|
{
|
|||
|
get { return _T_hearbeat; }
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Gets the period in ms between sending PTT End
|
|||
|
/// </summary>
|
|||
|
public static int T_end
|
|||
|
{
|
|||
|
get { return _T_end; }
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Gets the total number of PTT End that are to be sent
|
|||
|
/// </summary>
|
|||
|
public static int T_numend
|
|||
|
{
|
|||
|
get { return _T_numend; }
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Returns the period in ms between sending PTT requests
|
|||
|
/// </summary>
|
|||
|
public static int T_request
|
|||
|
{
|
|||
|
get { return _T_request; }
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Gets the total number of PTT Requests that can be sent.
|
|||
|
/// </summary>
|
|||
|
public static int T_numreq
|
|||
|
{
|
|||
|
get { return _T_numreq; }
|
|||
|
}
|
|||
|
|
|||
|
public byte[] GeneratePTTRequest(int destionationID, int sourceID, byte transactionNumber, ref ushort sequenceNumber,
|
|||
|
uint timestamp, byte[] ssrc)
|
|||
|
{
|
|||
|
// Headerul RTP fix 12 octeti
|
|||
|
// Headerul Extins DMR = 4 octeti (Code Type + extension length) +
|
|||
|
// 32 octeti (8 * 4)
|
|||
|
// = 36 octeti
|
|||
|
// 12 + 36 = 48 octeti
|
|||
|
// Se pare ca pachetele RTP care contin voce contin 160 octeti de voce
|
|||
|
byte[] PTTrequest = new byte[12 + 36];
|
|||
|
// Adaug headerele standard RTP
|
|||
|
AddStandardRTPHeaders(PTTrequest, ref sequenceNumber, timestamp, ssrc); // PTTRequest
|
|||
|
// Adaug headerul extins DMR
|
|||
|
AddStandardDMRExtension(PTTrequest, destionationID, sourceID, RtpCallType.Private, StartReason.NormalStartOfCall, EndReason.OverContinues, Priority.Zero);
|
|||
|
// Adaug headerul extins specific Simoco
|
|||
|
AddManufacturerSpecificExtension(PTTrequest, PTT_Type.Request, transactionNumber, 0);
|
|||
|
|
|||
|
//
|
|||
|
return PTTrequest;
|
|||
|
}
|
|||
|
|
|||
|
public byte[] GeneratePTTStart(int destionationID, int sourceID, byte transactionNumber, ref ushort sequenceNumber,
|
|||
|
uint timestamp, byte[] ssrc)
|
|||
|
{
|
|||
|
// Scrie undeva ca ar trebui trimis fara voce
|
|||
|
byte[] PTTStart = new byte[12 + 36];
|
|||
|
// Adaug header RTP
|
|||
|
AddStandardRTPHeaders(PTTStart, ref sequenceNumber, timestamp, ssrc);
|
|||
|
// Adaug extensia DMR
|
|||
|
AddStandardDMRExtension(PTTStart, destionationID, sourceID, RtpCallType.Private, StartReason.NormalStartOfCall, EndReason.OverContinues, Priority.Zero);
|
|||
|
// Adaug extensia SIMOCO
|
|||
|
AddManufacturerSpecificExtension(PTTStart, PTT_Type.Start, transactionNumber, 0);
|
|||
|
|
|||
|
return PTTStart;
|
|||
|
}
|
|||
|
|
|||
|
public byte[] GeneratePTTEnd(int destionationID, int sourceID, byte transactionNumber, ref ushort sequenceNumber,
|
|||
|
uint timestamp, byte[] ssrc)
|
|||
|
{
|
|||
|
// Primul pachet PTT End poate contine si voce
|
|||
|
// O sa le trimit pe toate fara
|
|||
|
byte[] PTTEnd = new byte[12 + 36];
|
|||
|
// Adaug header RTP
|
|||
|
AddStandardRTPHeaders(PTTEnd, ref sequenceNumber, timestamp, ssrc);
|
|||
|
// Adaug extensia DMR
|
|||
|
AddStandardDMRExtension(PTTEnd, destionationID, sourceID, RtpCallType.Private, StartReason.OverContinues, EndReason.NormalEndOfCall, Priority.Zero);
|
|||
|
// Adaug extensia Simoco
|
|||
|
AddManufacturerSpecificExtension(PTTEnd, PTT_Type.End, transactionNumber, 0);
|
|||
|
|
|||
|
return PTTEnd;
|
|||
|
}
|
|||
|
|
|||
|
public byte[] GeneratePTTGrant(int destionationID, int sourceID, byte transactionNumber, ref ushort sequenceNumber,
|
|||
|
uint timestamp, byte[] ssrc)
|
|||
|
{
|
|||
|
byte[] PTTGrant = new byte[12 + 36];
|
|||
|
// Adaug header RTP
|
|||
|
AddStandardRTPHeaders(PTTGrant, ref sequenceNumber, timestamp, ssrc);
|
|||
|
// Adaug extesia DMR
|
|||
|
AddStandardDMRExtension(PTTGrant, destionationID, sourceID, RtpCallType.Private, StartReason.NotTheStartOfACall, EndReason.OverContinues, Priority.Zero);
|
|||
|
// Adaug extensia Simoco
|
|||
|
AddManufacturerSpecificExtension(PTTGrant, PTT_Type.Grant, transactionNumber, 0);
|
|||
|
|
|||
|
return PTTGrant;
|
|||
|
}
|
|||
|
|
|||
|
public byte[] GeneratePTTDeny(int destionationID, int sourceID, byte transactionNumber, ref ushort sequenceNumber,
|
|||
|
uint timestamp, byte[] ssrc)
|
|||
|
{
|
|||
|
byte[] PTTDeny = new byte[12 + 36];
|
|||
|
// Adaug header RTP
|
|||
|
AddStandardRTPHeaders(PTTDeny, ref sequenceNumber, timestamp, ssrc);
|
|||
|
// Adaug extensia DMR
|
|||
|
AddStandardDMRExtension(PTTDeny, destionationID, sourceID, RtpCallType.Private, StartReason.NotTheStartOfACall, EndReason.OverContinues, Priority.Zero);
|
|||
|
// Adaug extensia Simoco
|
|||
|
AddManufacturerSpecificExtension(PTTDeny, PTT_Type.Deny, transactionNumber, 0);
|
|||
|
|
|||
|
return PTTDeny;
|
|||
|
}
|
|||
|
|
|||
|
public byte[] GeneratePTTHeartbeatQuery(int destionationID, int sourceID, ref ushort sequenceNumber,
|
|||
|
uint timestamp, byte[] ssrc)
|
|||
|
{
|
|||
|
byte[] PTTHeartbeatQuery = new byte[48];
|
|||
|
// Adaug header RTP
|
|||
|
AddStandardRTPHeaders(PTTHeartbeatQuery, ref sequenceNumber, timestamp, ssrc);
|
|||
|
// Adaug extensia DMR
|
|||
|
AddStandardDMRExtension(PTTHeartbeatQuery, destionationID, sourceID, RtpCallType.Private, StartReason.NotTheStartOfACall,
|
|||
|
EndReason.OverContinues, Priority.Zero);
|
|||
|
// Adaug extensia Simoco
|
|||
|
AddManufacturerSpecificExtension(PTTHeartbeatQuery, PTT_Type.HeartbeatQuery, 0, _T_hearbeat);
|
|||
|
|
|||
|
return PTTHeartbeatQuery;
|
|||
|
}
|
|||
|
|
|||
|
public byte[] GeneratePTTHeartbeat(int destionationID, int sourceID, ref ushort sequenceNumber,
|
|||
|
uint timestamp, byte[] ssrc)
|
|||
|
{
|
|||
|
// PTT Heartbeat/PTT Heartbeat Query shall always be sent in a packet with Start Reason = 3 (Not the start
|
|||
|
// of an over) and End Reason = 0 (Not the end of a call).
|
|||
|
|
|||
|
// For Heartbeat/Heartbeat Query the TSN shall be set to 0
|
|||
|
|
|||
|
// Presupun ca se trimite fara voce
|
|||
|
|
|||
|
byte[] PTTHeartbeat = new byte[48]; // 12 + 36 = 12 + (8 x 4 + 4)
|
|||
|
// Adaug header RTP
|
|||
|
AddStandardRTPHeaders(PTTHeartbeat, ref sequenceNumber, timestamp, ssrc);
|
|||
|
// Adaug extensia DMR
|
|||
|
AddStandardDMRExtension(PTTHeartbeat, destionationID, sourceID, RtpCallType.Private, StartReason.NotTheStartOfACall, EndReason.OverContinues, Priority.Zero);
|
|||
|
// Adaug extensia SIMOCO
|
|||
|
AddManufacturerSpecificExtension(PTTHeartbeat, PTT_Type.Heartbeat, 0, _T_hearbeat);
|
|||
|
|
|||
|
return PTTHeartbeat;
|
|||
|
}
|
|||
|
|
|||
|
public void AddStandardVoiceRTPHeaders(byte[] packet, ref ushort sequenceNumber, uint timestamp, byte[] ssrc)
|
|||
|
{
|
|||
|
// Put PCMA in RTP packet
|
|||
|
// RTP header is in big endian
|
|||
|
/*
|
|||
|
* Header:
|
|||
|
* Version (2 bits) - 2 adica 10
|
|||
|
* Pading (1 bit) - 0
|
|||
|
* X (Extension) (1 bit) - 1 => OCTETUL 0 = 1001 0000 = 0x90
|
|||
|
* CC(CSRC Count) (4 bits) - 0 0 0 0
|
|||
|
*
|
|||
|
*
|
|||
|
*
|
|||
|
* M (marker) (1 bit) - 0
|
|||
|
* PT(payload type) (7 bits) - 8 adica 1000 => OCTETUL 1 = 0000 1000 = 0x08
|
|||
|
*
|
|||
|
* Sequence NB (16 bits) - incremented by 1 for each packet. Initial value should be random => OCTETUL 2 si 3
|
|||
|
*
|
|||
|
* Timestamp (32 bits) - initial value random
|
|||
|
* - incremented by "RTP packet duration" = audioDataSize <bit> / (samplingRate <1/s> * bitRate <bit>)
|
|||
|
* - OCTETUL 4, 5, 6, 7
|
|||
|
*
|
|||
|
*
|
|||
|
*
|
|||
|
*
|
|||
|
* SSRC (Synchronization source identifier - 32 bits) - unique identifier of the source stream = > OCTETUL 8, 9, 10, 11
|
|||
|
*
|
|||
|
* CSRC (Contributing source identifier - 32 bits) - ignorat..??? (se pare ca e optional - folosit in cazul stream-ului generat din mai
|
|||
|
* multe surce)
|
|||
|
*/
|
|||
|
// OCTET 0 - 10
|
|||
|
packet[0] = 0x90;
|
|||
|
// OCTET 1
|
|||
|
packet[1] = 0x08;
|
|||
|
// OCTET 2, 3 MSB (Big Endian)
|
|||
|
|
|||
|
packet[2] = (byte)(((sequenceNumber) >> 8) % 256);
|
|||
|
packet[3] = (byte)(sequenceNumber % 256);
|
|||
|
// OCTET 4, 5, 6, 7
|
|||
|
packet[4] = (byte)((timestamp >> 24) % 256);
|
|||
|
packet[5] = (byte)((timestamp >> 16) % 256);
|
|||
|
packet[6] = (byte)((timestamp >> 8) % 256);
|
|||
|
packet[7] = (byte)(timestamp % 256);
|
|||
|
lock (_lockObject)
|
|||
|
{
|
|||
|
sequenceNumber++;
|
|||
|
//timestamp += (uint)(2 * nrOfAudioBytes * 8 / bitRate);
|
|||
|
}
|
|||
|
// OCTET 8, 9, 10, 11
|
|||
|
Array.Copy(ssrc, 0, packet, 8, 4);
|
|||
|
}
|
|||
|
|
|||
|
public void AddStandardVoiceRTPHeadersZoipper(byte[] packet, ref ushort sequenceNumber, uint timestamp, byte[] ssrc)
|
|||
|
{
|
|||
|
// Put PCMA in RTP packet
|
|||
|
// RTP header is in big endian
|
|||
|
/*
|
|||
|
* Header:
|
|||
|
* Version (2 bits) - 2 adica 10
|
|||
|
* Pading (1 bit) - 0
|
|||
|
* X (Extension) (1 bit) - 0 => OCTETUL 0 = 1000 0000 = 0x80
|
|||
|
* CC(CSRC Count) (4 bits) - 0 0 0 0
|
|||
|
*
|
|||
|
*
|
|||
|
*
|
|||
|
* M (marker) (1 bit) - 0
|
|||
|
* PT(payload type) (7 bits) - 8 adica 1000 => OCTETUL 1 = 0000 1000 = 0x08
|
|||
|
*
|
|||
|
* Sequence NB (16 bits) - incremented by 1 for each packet. Initial value should be random => OCTETUL 2 si 3
|
|||
|
*
|
|||
|
* Timestamp (32 bits) - initial value random
|
|||
|
* - incremented by "RTP packet duration" = audioDataSize <bit> / (samplingRate <1/s> * bitRate <bit>)
|
|||
|
* - OCTETUL 4, 5, 6, 7
|
|||
|
*
|
|||
|
*
|
|||
|
*
|
|||
|
*
|
|||
|
* SSRC (Synchronization source identifier - 32 bits) - unique identifier of the source stream = > OCTETUL 8, 9, 10, 11
|
|||
|
*
|
|||
|
* CSRC (Contributing source identifier - 32 bits) - ignorat..??? (se pare ca e optional - folosit in cazul stream-ului generat din mai
|
|||
|
* multe surce)
|
|||
|
*/
|
|||
|
// OCTET 0 - 10
|
|||
|
packet[0] = 0x80;
|
|||
|
// OCTET 1
|
|||
|
packet[1] = 0x08;
|
|||
|
// OCTET 2, 3 MSB (Big Endian)
|
|||
|
|
|||
|
packet[2] = (byte)(((sequenceNumber) >> 8) % 256);
|
|||
|
packet[3] = (byte)(sequenceNumber % 256);
|
|||
|
// OCTET 4, 5, 6, 7
|
|||
|
packet[4] = (byte)((timestamp >> 24) % 256);
|
|||
|
packet[5] = (byte)((timestamp >> 16) % 256);
|
|||
|
packet[6] = (byte)((timestamp >> 8) % 256);
|
|||
|
packet[7] = (byte)(timestamp % 256);
|
|||
|
lock (_lockObject)
|
|||
|
{
|
|||
|
sequenceNumber++;
|
|||
|
//timestamp += (uint)(2 * nrOfAudioBytes * 8 / bitRate);
|
|||
|
}
|
|||
|
// OCTET 8, 9, 10, 11
|
|||
|
Array.Copy(ssrc, 0, packet, 8, 4);
|
|||
|
}
|
|||
|
|
|||
|
public void AddStandardRTPHeaders(byte[] packet, ref ushort sequenceNumber, uint timestamp, byte[] ssrc)
|
|||
|
{
|
|||
|
// Put PCMA in RTP packet
|
|||
|
// RTP header is in big endian
|
|||
|
/*
|
|||
|
* Header:
|
|||
|
* Version (2 bits) - 2 adica 10
|
|||
|
* Pading (1 bit) - 0
|
|||
|
* X (Extension) (1 bit) - 1 => OCTETUL 0 = 1001 0000 = 0x90
|
|||
|
* CC(CSRC Count) (4 bits) - 0 0 0 0
|
|||
|
*
|
|||
|
*
|
|||
|
*
|
|||
|
* M (marker) (1 bit) - 0
|
|||
|
* PT(payload type) (7 bits) - 8 adica 1000 => OCTETUL 1 = 0000 1000 = 0x08
|
|||
|
*
|
|||
|
* Sequence NB (16 bits) - incremented by 1 for each packet. Initial value should be random => OCTETUL 2 si 3
|
|||
|
*
|
|||
|
* Timestamp (32 bits) - initial value random
|
|||
|
* - incremented by "RTP packet duration" = audioDataSize <bit> / (samplingRate <1/s> * bitRate <bit>)
|
|||
|
* - OCTETUL 4, 5, 6, 7
|
|||
|
*
|
|||
|
*
|
|||
|
*
|
|||
|
*
|
|||
|
* SSRC (Synchronization source identifier - 32 bits) - unique identifier of the source stream = > OCTETUL 8, 9, 10, 11
|
|||
|
*
|
|||
|
* CSRC (Contributing source identifier - 32 bits) - ignorat..??? (se pare ca e optional - folosit in cazul stream-ului generat din mai
|
|||
|
* multe surce)
|
|||
|
*/
|
|||
|
// OCTET 0 - 10
|
|||
|
packet[0] = 0x90;
|
|||
|
// OCTET 1
|
|||
|
packet[1] = 0x08;
|
|||
|
// OCTET 2, 3 MSB (Big Endian)
|
|||
|
|
|||
|
packet[2] = (byte)(((sequenceNumber) >> 8) % 256);
|
|||
|
packet[3] = (byte)(sequenceNumber % 256);
|
|||
|
// OCTET 4, 5, 6, 7
|
|||
|
packet[4] = (byte)((timestamp >> 24) % 256);
|
|||
|
packet[5] = (byte)((timestamp >> 16) % 256);
|
|||
|
packet[6] = (byte)((timestamp >> 8) % 256);
|
|||
|
packet[7] = (byte)(timestamp % 256);
|
|||
|
lock (_lockObject)
|
|||
|
{
|
|||
|
sequenceNumber++;
|
|||
|
}
|
|||
|
// OCTET 8, 9, 10, 11
|
|||
|
Array.Copy(ssrc, 0, packet, 8, 4);
|
|||
|
}
|
|||
|
|
|||
|
public void AddStandardDMRExtension(byte[] packet, int DST_DMR_ID, int SRC_DMR_ID, RtpCallType typeOfCall, StartReason startReason,
|
|||
|
EndReason endReason, Priority callPriority)
|
|||
|
{
|
|||
|
// CODE_TYPE (16 bit) - 0xe0 0x00 (pentru Simoco) => OCTET 12 = 0xe0; OCTET 13 = 0x00;
|
|||
|
// LENGTH (16 bit) - 0x00 0x08 => OCTET 14 = 0x00; OCTET 15 = 0x08;
|
|||
|
|
|||
|
// Reserved (4 bit) - 0000
|
|||
|
// Frame No (4 bit) - 0000 => OCTET 16 = 0x00;
|
|||
|
// DST_DMR_ID (24 bit) - => OCTET 17, 18, 19 = DST_DMR_ID (bigendian)
|
|||
|
|
|||
|
// Reserved (8 bit) - 0x00 => OCTET 20 = 0x00;
|
|||
|
// DST_DMR_ID (24 bit) - => OCTET 21, 22, 23 = .........
|
|||
|
|
|||
|
// BS_ID (32 bit) - pare sa fie 0 pt simoco => OCTET 24, 25, 26, 27
|
|||
|
|
|||
|
// Proto Major (4 bit) - 0
|
|||
|
// Proto Minor (4 bit) - 0 => OCTET 28 = 0x00;
|
|||
|
// Colour Code (4 bit) - 0
|
|||
|
// Fading Control (4 bit) - 0 => OCTET 29 = 0x00;
|
|||
|
// Data Type (4 bit) - pare sa fie 0 pt simoco
|
|||
|
// Call Type (4 bit) - => OCTET 30 = ......
|
|||
|
// Src (2 bit) - 0
|
|||
|
// Start Reason (2 bit) - 0 - Over continues
|
|||
|
// - 1 - Normal start of call
|
|||
|
// - 2 - Late entry into over
|
|||
|
// - 3 - Not the start of a call
|
|||
|
// End Reason (4 bit) - 0 - Not the end of a call (over continues)
|
|||
|
// - 1 - Normal end of a call
|
|||
|
// - 2 - Fade (timer expired)
|
|||
|
// - 3 - Other (eg. receiver state change) => OCTET 31 = .........
|
|||
|
|
|||
|
// Service Options (8 bit) - 0000 | 00 | 2 bit priority ( 0 - 3 ) => Octet 32 = ........
|
|||
|
// Signal Quality (8 bit) = 0 => Octet 33 = 0x00
|
|||
|
// Reserved (4 bit) = 0
|
|||
|
// Encryption (4 bit) = F (no ecryption) => Octet 34 = 0x0F;
|
|||
|
// Key ID (8 bit) = 0 => Octet 35 = 0x00;
|
|||
|
|
|||
|
// Initialization Vector (32 bit) => OCTET 36, 37, 38, 39 = 0x00;
|
|||
|
|
|||
|
// OCTET 12 = 0xe0;
|
|||
|
packet[12] = 0xe0;
|
|||
|
// OCTET 15 = 0x08;
|
|||
|
packet[15] = 0x08;
|
|||
|
// OCTET 17, 18, 19 = DST_DMR_ID (bigendian)
|
|||
|
packet[17] = (byte)((DST_DMR_ID >> 16) % 256);
|
|||
|
packet[18] = (byte)((DST_DMR_ID >> 8) % 256);
|
|||
|
packet[19] = (byte)(DST_DMR_ID % 256);
|
|||
|
// OCTET 21, 22, 23 = SRC_DMR_ID (bigendian)
|
|||
|
packet[21] = (byte)((SRC_DMR_ID >> 16) % 256);
|
|||
|
packet[22] = (byte)((SRC_DMR_ID >> 8) % 256);
|
|||
|
packet[23] = (byte)(SRC_DMR_ID % 256);
|
|||
|
// OCTET 30 = 0000 xxxx (xxxx - Call Type)
|
|||
|
packet[30] = (byte)typeOfCall;
|
|||
|
// OCTET 31 = 00ss eeee (ss - Start Reason, eeee - End Reason)
|
|||
|
packet[31] = (byte)((byte)(startReason) | (byte)(endReason));
|
|||
|
// Octet 32 = 0000 00xx (xx - priority)
|
|||
|
packet[32] = (byte)callPriority;
|
|||
|
// Octet 34 = 0x0F (No encryption)
|
|||
|
packet[34] = 0x0F;
|
|||
|
|
|||
|
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
public void AddManufacturerSpecificExtension(byte[] packet, PTT_Type PTType, byte TSN, byte interval)
|
|||
|
{
|
|||
|
// ID = 1
|
|||
|
// Len = 3 => OCTET 40 = 0x13
|
|||
|
// PTT Type =
|
|||
|
/*
|
|||
|
* ptt Type Len Direction Description
|
|||
|
*
|
|||
|
0 1 SMF -> MMF Request
|
|||
|
1 1 MMF -> SMF Grant
|
|||
|
2 1 MMF <-> SMF Progress
|
|||
|
3 1 MMF <-> SMF End
|
|||
|
4 1 MMF -> SMF Start
|
|||
|
8 1 MMF -> SMF Deny
|
|||
|
9 1 MMF <-> SMF Heartbeat
|
|||
|
10 1 MMF <-> SMF Heartbeat Query
|
|||
|
*/
|
|||
|
// => OCTET 41 = PTT type
|
|||
|
// Service Options (8 bit) same as in RTP Header => OCTET 42 = OCTET 32
|
|||
|
// TSN (7 bit) transaction nb
|
|||
|
// L (1 bit) - Se pare ca e mereu 0 pt Simoco => OCTET 43 = TSN << 1;
|
|||
|
// INTERVAL - (8 bits) => OCTET 44 = Interval
|
|||
|
// => OCTET 45, 46, 47 = 0x00
|
|||
|
packet[40] = 0x13;
|
|||
|
packet[41] = (byte)PTType;
|
|||
|
packet[42] = packet[32];
|
|||
|
packet[43] = (byte)(TSN << 1);
|
|||
|
packet[44] = interval;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// Call Type (4 bit)
|
|||
|
// Bit 3 (MSB) 0 DMR call, 1 Analog call
|
|||
|
// Bit 2 0 Private call, 1 Group call
|
|||
|
// Bit 1 1 DMR CAll Alert/Analog Selective call
|
|||
|
// Bit 0 Reserved
|
|||
|
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Contains the types of call used in Half duplex mode
|
|||
|
/// </summary>
|
|||
|
internal enum RtpCallType : byte
|
|||
|
{
|
|||
|
/// <summary>
|
|||
|
/// DMR call, private
|
|||
|
/// 0000 0000
|
|||
|
///
|
|||
|
/// </summary>
|
|||
|
Private = 0x00,
|
|||
|
/// <summary>
|
|||
|
/// DMR call, group
|
|||
|
/// 0000 0100
|
|||
|
/// </summary>
|
|||
|
Group = 0x04
|
|||
|
}
|
|||
|
|
|||
|
internal enum StartReason : byte
|
|||
|
{
|
|||
|
// Start Reason (2 bit) - 0 - Over continues => 0x00
|
|||
|
// - 1 - Normal start of call => 00 01 0000 = 0x10
|
|||
|
// - 2 - Late entry into over => 00 10 0000 = 0x20
|
|||
|
// - 3 - Not the start of a call => 00 11 0000 = 0x30
|
|||
|
OverContinues = 0x00,
|
|||
|
NormalStartOfCall = 0x10,
|
|||
|
LateEntryIntoOver = 0x20,
|
|||
|
NotTheStartOfACall = 0x30
|
|||
|
}
|
|||
|
|
|||
|
internal enum EndReason : byte
|
|||
|
{
|
|||
|
// End Reason (4 bit) - 0 - Not the end of a call (over continues)
|
|||
|
// - 1 - Normal end of a call
|
|||
|
// - 2 - Fade (timer expired)
|
|||
|
// - 3 - Other (eg. receiver state change)
|
|||
|
OverContinues = 0x00,
|
|||
|
NormalEndOfCall = 0x01,
|
|||
|
TimerExpired = 0x02,
|
|||
|
Other = 0x03
|
|||
|
}
|
|||
|
|
|||
|
internal enum Priority : byte
|
|||
|
{
|
|||
|
Zero = 0,
|
|||
|
One,
|
|||
|
Two,
|
|||
|
Three
|
|||
|
}
|
|||
|
|
|||
|
internal enum PTT_Type : byte
|
|||
|
{
|
|||
|
// PTT Type =
|
|||
|
/*
|
|||
|
* ptt Type Len Direction Description
|
|||
|
*
|
|||
|
0 1 SMF -> MMF Request
|
|||
|
1 1 MMF -> SMF Grant
|
|||
|
2 1 MMF <-> SMF Progress
|
|||
|
3 1 MMF <-> SMF End
|
|||
|
4 1 MMF -> SMF Start
|
|||
|
8 1 MMF -> SMF Deny
|
|||
|
9 1 MMF <-> SMF Heartbeat
|
|||
|
10 1 MMF <-> SMF Heartbeat Query
|
|||
|
*/
|
|||
|
|
|||
|
Request = 0,
|
|||
|
Grant = 1,
|
|||
|
Progress = 2,
|
|||
|
End = 3,
|
|||
|
Start = 4,
|
|||
|
Deny = 8,
|
|||
|
Heartbeat = 9,
|
|||
|
HeartbeatQuery = 10
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
internal enum AlarmType : uint
|
|||
|
{
|
|||
|
USER_GENERATED = 0x01000000,
|
|||
|
MAN_DOWN = 0x02000000,
|
|||
|
LONE_WORKER = 0x04000000,
|
|||
|
NO_ALARM = 0x00000000
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Contains a list of sip types of calls
|
|||
|
/// </summary>
|
|||
|
public enum TypeOfCall
|
|||
|
{
|
|||
|
/// <summary>
|
|||
|
/// Full duplex call, like a normal phone (or Zoipper)
|
|||
|
/// </summary>
|
|||
|
FULL_DUPLEX,
|
|||
|
/// <summary>
|
|||
|
/// Half duplex call, like a radio PTT
|
|||
|
/// </summary>
|
|||
|
HALF_DUPLEX
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Provides data for the VoiceReceived event
|
|||
|
/// </summary>
|
|||
|
public class AudioEventArgs : EventArgs
|
|||
|
{
|
|||
|
byte[] _buffer;
|
|||
|
int _callSourceID;
|
|||
|
/// <summary>
|
|||
|
/// Voice buffer
|
|||
|
/// </summary>
|
|||
|
public byte[] Buffer
|
|||
|
{
|
|||
|
get { return _buffer; }
|
|||
|
}
|
|||
|
/// <summary>
|
|||
|
/// The sip ID of the user who sent the voice buffer
|
|||
|
/// </summary>
|
|||
|
public int CallSourceID
|
|||
|
{
|
|||
|
get { return _callSourceID; }
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Gets the sip id that we are in dialog with
|
|||
|
/// </summary>
|
|||
|
public int SipIdInDialogWith
|
|||
|
{
|
|||
|
get; private set;
|
|||
|
}
|
|||
|
|
|||
|
internal AudioEventArgs(byte[] data, int callSourceID, int sipIdInDialogWith)
|
|||
|
{
|
|||
|
_buffer = data;
|
|||
|
_callSourceID = callSourceID;
|
|||
|
SipIdInDialogWith = sipIdInDialogWith;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
internal class PTTEventArgs : EventArgs
|
|||
|
{
|
|||
|
PTT_Type _pttType;
|
|||
|
int _interval;
|
|||
|
long _radioID;
|
|||
|
byte _TSN;
|
|||
|
|
|||
|
public PTT_Type PTTTypeEnum
|
|||
|
{
|
|||
|
get { return _pttType; }
|
|||
|
}
|
|||
|
|
|||
|
public byte TSN
|
|||
|
{
|
|||
|
get { return _TSN; }
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Interval, in seconds
|
|||
|
/// </summary>
|
|||
|
public int Interval
|
|||
|
{
|
|||
|
get { return _interval; }
|
|||
|
}
|
|||
|
/// <summary>
|
|||
|
/// <para>Reprezinta SURSA streamului RTP in cazul Grant, Deny</para>
|
|||
|
/// <para>si DESTINATIA in cazul HeartbeatQuery si Heartbeat</para>
|
|||
|
/// </summary>
|
|||
|
public long RadioID
|
|||
|
{
|
|||
|
get { return _radioID; }
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Returns the id in dialog with
|
|||
|
/// </summary>
|
|||
|
public int SipIDinDialogWith
|
|||
|
{
|
|||
|
get;
|
|||
|
private set;
|
|||
|
}
|
|||
|
|
|||
|
public PTTEventArgs(int idInDialogWith, long radioID, PTT_Type pttType, byte TSN,
|
|||
|
int interval)
|
|||
|
{
|
|||
|
SipIDinDialogWith = idInDialogWith;
|
|||
|
_radioID = radioID;
|
|||
|
_pttType = pttType;
|
|||
|
_interval = interval;
|
|||
|
_TSN = TSN;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|