mirror of
https://github.com/g4klx/MMDVMHost
synced 2025-12-22 08:05:49 +08:00
First code-complete version of the IAX protocol handler.
This commit is contained in:
329
FMIAXNetwork.cpp
329
FMIAXNetwork.cpp
@@ -49,6 +49,7 @@ const unsigned char AST_CONTROL_ANSWER = 4U;
|
|||||||
const unsigned char AST_CONTROL_OPTION = 11U;
|
const unsigned char AST_CONTROL_OPTION = 11U;
|
||||||
const unsigned char AST_CONTROL_KEY = 12U;
|
const unsigned char AST_CONTROL_KEY = 12U;
|
||||||
const unsigned char AST_CONTROL_UNKEY = 13U;
|
const unsigned char AST_CONTROL_UNKEY = 13U;
|
||||||
|
const unsigned char AST_CONTROL_STOP_SOUNDS = 255U;
|
||||||
|
|
||||||
const unsigned char AST_FORMAT_ULAW = 4U;
|
const unsigned char AST_FORMAT_ULAW = 4U;
|
||||||
|
|
||||||
@@ -113,6 +114,7 @@ m_buffer(2000U, "FM Network"),
|
|||||||
m_status(IAXS_DISCONNECTED),
|
m_status(IAXS_DISCONNECTED),
|
||||||
m_retryTimer(1000U, 0U, 500U),
|
m_retryTimer(1000U, 0U, 500U),
|
||||||
m_pingTimer(1000U, 20U),
|
m_pingTimer(1000U, 20U),
|
||||||
|
m_seed(),
|
||||||
m_timestamp(),
|
m_timestamp(),
|
||||||
m_sCallNo(0U),
|
m_sCallNo(0U),
|
||||||
m_dCallNo(0U),
|
m_dCallNo(0U),
|
||||||
@@ -166,7 +168,9 @@ bool CFMIAXNetwork::open()
|
|||||||
|
|
||||||
m_status = IAXS_CONNECTING;
|
m_status = IAXS_CONNECTING;
|
||||||
m_retryTimer.start();
|
m_retryTimer.start();
|
||||||
|
|
||||||
m_dCallNo = 0U;
|
m_dCallNo = 0U;
|
||||||
|
m_rxFrames = 0U;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -176,6 +180,9 @@ bool CFMIAXNetwork::writeStart()
|
|||||||
if (m_status != IAXS_CONNECTED)
|
if (m_status != IAXS_CONNECTED)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if (!m_enabled)
|
||||||
|
return false;
|
||||||
|
|
||||||
return writeKey(true);
|
return writeKey(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -187,7 +194,34 @@ bool CFMIAXNetwork::writeData(const float* data, unsigned int nSamples)
|
|||||||
if (m_status != IAXS_CONNECTED)
|
if (m_status != IAXS_CONNECTED)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return true;
|
if (!m_enabled)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
short audio[300U];
|
||||||
|
for (unsigned int i = 0U; i < nSamples; i++)
|
||||||
|
audio[i] = short(data[i] * 32767.0F + 0.5F); // Changing audio format from float to S16LE
|
||||||
|
|
||||||
|
#if defined(DEBUG_IAX)
|
||||||
|
LogDebug("IAX audio sent");
|
||||||
|
#endif
|
||||||
|
unsigned short ts = m_timestamp.elapsed();
|
||||||
|
|
||||||
|
unsigned char buffer[300U];
|
||||||
|
|
||||||
|
buffer[0U] = (m_sCallNo << 8) & 0xFFU;
|
||||||
|
buffer[1U] = (m_sCallNo << 0) & 0xFFU;
|
||||||
|
|
||||||
|
buffer[2U] = (ts << 8) & 0xFFU;
|
||||||
|
buffer[3U] = (ts << 0) & 0xFFU;
|
||||||
|
|
||||||
|
uLawEncode(audio, buffer + 4U, nSamples);
|
||||||
|
|
||||||
|
#if !defined(DEBUG_IAX)
|
||||||
|
if (m_debug)
|
||||||
|
#endif
|
||||||
|
CUtils::dump(1U, "FM IAX Network Data Sent", buffer, 4U + nSamples);
|
||||||
|
|
||||||
|
return m_socket.write(buffer, 4U + nSamples, m_addr, m_addrLen);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CFMIAXNetwork::writeEnd()
|
bool CFMIAXNetwork::writeEnd()
|
||||||
@@ -195,6 +229,9 @@ bool CFMIAXNetwork::writeEnd()
|
|||||||
if (m_status != IAXS_CONNECTED)
|
if (m_status != IAXS_CONNECTED)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if (!m_enabled)
|
||||||
|
return false;
|
||||||
|
|
||||||
return writeKey(false);
|
return writeKey(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -207,7 +244,10 @@ void CFMIAXNetwork::clock(unsigned int ms)
|
|||||||
writeNew();
|
writeNew();
|
||||||
break;
|
break;
|
||||||
case IAXS_AUTHORISING:
|
case IAXS_AUTHORISING:
|
||||||
writeAuth();
|
writeAuthRep();
|
||||||
|
break;
|
||||||
|
case IAXS_REGISTERING:
|
||||||
|
writeRegReq();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@@ -254,12 +294,14 @@ void CFMIAXNetwork::clock(unsigned int ms)
|
|||||||
#if defined(DEBUG_IAX)
|
#if defined(DEBUG_IAX)
|
||||||
LogDebug("IAX PING received");
|
LogDebug("IAX PING received");
|
||||||
#endif
|
#endif
|
||||||
|
m_rxFrames++;
|
||||||
writeAck(ts);
|
writeAck(ts);
|
||||||
writePong(ts);
|
writePong(ts);
|
||||||
} else if (compareFrame(buffer, AST_FRAME_IAX, IAX_COMMAND_PONG)) {
|
} else if (compareFrame(buffer, AST_FRAME_IAX, IAX_COMMAND_PONG)) {
|
||||||
#if defined(DEBUG_IAX)
|
#if defined(DEBUG_IAX)
|
||||||
LogDebug("IAX PONG received");
|
LogDebug("IAX PONG received");
|
||||||
#endif
|
#endif
|
||||||
|
m_rxFrames++;
|
||||||
writeAck(ts);
|
writeAck(ts);
|
||||||
} else if (compareFrame(buffer, AST_FRAME_IAX, IAX_COMMAND_ACCEPT)) {
|
} else if (compareFrame(buffer, AST_FRAME_IAX, IAX_COMMAND_ACCEPT)) {
|
||||||
#if defined(DEBUG_IAX)
|
#if defined(DEBUG_IAX)
|
||||||
@@ -269,7 +311,9 @@ void CFMIAXNetwork::clock(unsigned int ms)
|
|||||||
if (m_dCallNo == 0U)
|
if (m_dCallNo == 0U)
|
||||||
m_dCallNo = ((buffer[0U] << 8) | (buffer[1U] << 0)) & 0x7FFFU;
|
m_dCallNo = ((buffer[0U] << 8) | (buffer[1U] << 0)) & 0x7FFFU;
|
||||||
|
|
||||||
|
m_rxFrames++;
|
||||||
writeAck(ts);
|
writeAck(ts);
|
||||||
|
m_retryTimer.stop();
|
||||||
} else if (compareFrame(buffer, AST_FRAME_IAX, IAX_COMMAND_REGREJ)) {
|
} else if (compareFrame(buffer, AST_FRAME_IAX, IAX_COMMAND_REGREJ)) {
|
||||||
#if defined(DEBUG_IAX)
|
#if defined(DEBUG_IAX)
|
||||||
LogDebug("IAX REGREJ received");
|
LogDebug("IAX REGREJ received");
|
||||||
@@ -288,6 +332,59 @@ void CFMIAXNetwork::clock(unsigned int ms)
|
|||||||
m_status = IAXS_DISCONNECTED;
|
m_status = IAXS_DISCONNECTED;
|
||||||
m_retryTimer.stop();
|
m_retryTimer.stop();
|
||||||
m_pingTimer.stop();
|
m_pingTimer.stop();
|
||||||
|
} else if (compareFrame(buffer, AST_FRAME_CONTROL, AST_CONTROL_RINGING)) {
|
||||||
|
#if defined(DEBUG_IAX)
|
||||||
|
LogDebug("IAX RINGING received");
|
||||||
|
#endif
|
||||||
|
m_rxFrames++;
|
||||||
|
writeAck(ts);
|
||||||
|
} else if (compareFrame(buffer, AST_FRAME_IAX, IAX_COMMAND_REGAUTH)) {
|
||||||
|
#if defined(DEBUG_IAX)
|
||||||
|
LogDebug("IAX REGAUTH received");
|
||||||
|
#endif
|
||||||
|
m_rxFrames++;
|
||||||
|
|
||||||
|
if ((buffer[12U] == IAX_IE_AUTHMETHODS) &&
|
||||||
|
(buffer[15U] == IAX_AUTH_MD5) &&
|
||||||
|
(buffer[16U] == IAX_IE_CHALLENGE)) {
|
||||||
|
// Grab the destination call number if we don't have it already
|
||||||
|
if (m_dCallNo == 0U)
|
||||||
|
m_dCallNo = ((buffer[0U] << 8) | (buffer[1U] << 0)) & 0x7FFFU;
|
||||||
|
|
||||||
|
m_seed = std::string((char*)(buffer + 18U), buffer[17U]);
|
||||||
|
|
||||||
|
m_status = IAXS_REGISTERING;
|
||||||
|
m_retryTimer.start();
|
||||||
|
writeRegReq();
|
||||||
|
}
|
||||||
|
} else if (compareFrame(buffer, AST_FRAME_IAX, IAX_COMMAND_AUTHREQ)) {
|
||||||
|
#if defined(DEBUG_IAX)
|
||||||
|
LogDebug("IAX AUTHREQ received");
|
||||||
|
#endif
|
||||||
|
m_rxFrames++;
|
||||||
|
|
||||||
|
if ((buffer[12U] == IAX_IE_AUTHMETHODS) &&
|
||||||
|
(buffer[15U] == IAX_AUTH_MD5) &&
|
||||||
|
(buffer[16U] == IAX_IE_CHALLENGE)) {
|
||||||
|
// Grab the destination call number if we don't have it already
|
||||||
|
if (m_dCallNo == 0U)
|
||||||
|
m_dCallNo = ((buffer[0U] << 8) | (buffer[1U] << 0)) & 0x7FFFU;
|
||||||
|
|
||||||
|
m_seed = std::string((char*)(buffer + 18U), buffer[17U]);
|
||||||
|
|
||||||
|
m_status = IAXS_AUTHORISING;
|
||||||
|
m_retryTimer.start();
|
||||||
|
writeAuthRep();
|
||||||
|
}
|
||||||
|
} else if (compareFrame(buffer, AST_FRAME_IAX, IAX_COMMAND_REGACK)) {
|
||||||
|
#if defined(DEBUG_IAX)
|
||||||
|
LogDebug("IAX REGACK received");
|
||||||
|
#endif
|
||||||
|
m_rxFrames++;
|
||||||
|
writeAck(ts);
|
||||||
|
|
||||||
|
if (m_status == IAXS_CONNECTING)
|
||||||
|
writeNew();
|
||||||
} else if (compareFrame(buffer, AST_FRAME_IAX, IAX_COMMAND_HANGUP)) {
|
} else if (compareFrame(buffer, AST_FRAME_IAX, IAX_COMMAND_HANGUP)) {
|
||||||
#if defined(DEBUG_IAX)
|
#if defined(DEBUG_IAX)
|
||||||
LogDebug("IAX HANGUP received");
|
LogDebug("IAX HANGUP received");
|
||||||
@@ -308,15 +405,55 @@ void CFMIAXNetwork::clock(unsigned int ms)
|
|||||||
|
|
||||||
writeAck(ts);
|
writeAck(ts);
|
||||||
|
|
||||||
|
m_rxFrames++;
|
||||||
m_status = IAXS_CONNECTED;
|
m_status = IAXS_CONNECTED;
|
||||||
m_retryTimer.stop();
|
m_retryTimer.stop();
|
||||||
m_pingTimer.start();
|
m_pingTimer.start();
|
||||||
|
} else if (compareFrame(buffer, AST_FRAME_IAX, IAX_COMMAND_VNAK)) {
|
||||||
|
#if defined(DEBUG_IAX)
|
||||||
|
LogDebug("IAX VNAK received");
|
||||||
|
#endif
|
||||||
|
m_rxFrames++;
|
||||||
|
writeAck(ts);
|
||||||
|
} else if (compareFrame(buffer, AST_FRAME_CONTROL, AST_CONTROL_STOP_SOUNDS)) {
|
||||||
|
#if defined(DEBUG_IAX)
|
||||||
|
LogDebug("IAX STOP SOUNDS received");
|
||||||
|
#endif
|
||||||
|
m_rxFrames++;
|
||||||
|
writeAck(ts);
|
||||||
|
} else if (compareFrame(buffer, AST_FRAME_CONTROL, AST_CONTROL_OPTION)) {
|
||||||
|
#if defined(DEBUG_IAX)
|
||||||
|
LogDebug("IAX OPTION received");
|
||||||
|
#endif
|
||||||
|
m_rxFrames++;
|
||||||
|
writeAck(ts);
|
||||||
|
} else if (compareFrame(buffer, AST_FRAME_TEXT, 0U)) {
|
||||||
|
#if defined(DEBUG_IAX)
|
||||||
|
LogDebug("IAX TEXT received - %s", buffer + 12U);
|
||||||
|
#endif
|
||||||
|
writeAck(ts);
|
||||||
} else if (compareFrame(buffer, AST_FRAME_IAX, IAX_COMMAND_LAGRQ)) {
|
} else if (compareFrame(buffer, AST_FRAME_IAX, IAX_COMMAND_LAGRQ)) {
|
||||||
#if defined(DEBUG_IAX)
|
#if defined(DEBUG_IAX)
|
||||||
LogDebug("IAX LAGRQ received");
|
LogDebug("IAX LAGRQ received");
|
||||||
#endif
|
#endif
|
||||||
|
m_rxFrames++;
|
||||||
writeAck(ts);
|
writeAck(ts);
|
||||||
writeLagRp();
|
writeLagRp(ts);
|
||||||
|
} else if (compareFrame(buffer, AST_FRAME_VOICE, AST_FORMAT_ULAW)) {
|
||||||
|
#if defined(DEBUG_IAX)
|
||||||
|
LogDebug("IAX ULAW received");
|
||||||
|
#endif
|
||||||
|
m_rxFrames++;
|
||||||
|
writeAck(ts);
|
||||||
|
|
||||||
|
if (!m_enabled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_buffer.addData(buffer + 12U, length - 12U);
|
||||||
|
|
||||||
|
short audio[160U];
|
||||||
|
::memset(audio, 0x00U, 160U * sizeof(short));
|
||||||
|
writeAudio(audio, 160U);
|
||||||
} else if ((buffer[0U] & 0x80U) == 0x00U) {
|
} else if ((buffer[0U] & 0x80U) == 0x00U) {
|
||||||
#if defined(DEBUG_IAX)
|
#if defined(DEBUG_IAX)
|
||||||
LogDebug("IAX audio received");
|
LogDebug("IAX audio received");
|
||||||
@@ -325,6 +462,8 @@ void CFMIAXNetwork::clock(unsigned int ms)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
m_buffer.addData(buffer + 4U, length - 4U);
|
m_buffer.addData(buffer + 4U, length - 4U);
|
||||||
|
} else {
|
||||||
|
CUtils::dump(2U, "Unknown IAX message received", buffer, length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -333,7 +472,7 @@ unsigned int CFMIAXNetwork::readData(float* out, unsigned int nOut)
|
|||||||
assert(out != NULL);
|
assert(out != NULL);
|
||||||
assert(nOut > 0U);
|
assert(nOut > 0U);
|
||||||
|
|
||||||
unsigned int bytes = m_buffer.dataSize() / sizeof(unsigned short);
|
unsigned int bytes = m_buffer.dataSize() / sizeof(unsigned char);
|
||||||
if (bytes == 0U)
|
if (bytes == 0U)
|
||||||
return 0U;
|
return 0U;
|
||||||
|
|
||||||
@@ -341,12 +480,13 @@ unsigned int CFMIAXNetwork::readData(float* out, unsigned int nOut)
|
|||||||
nOut = bytes;
|
nOut = bytes;
|
||||||
|
|
||||||
unsigned char buffer[1500U];
|
unsigned char buffer[1500U];
|
||||||
m_buffer.getData(buffer, nOut * sizeof(unsigned short));
|
m_buffer.getData(buffer, nOut * sizeof(unsigned char));
|
||||||
|
|
||||||
for (unsigned int i = 0U; i < nOut; i++) {
|
short audio[1500U];
|
||||||
short val = ((buffer[i * 2U + 0U] & 0xFFU) << 0) + ((buffer[i * 2U + 1U] & 0xFFU) << 8);
|
uLawDecode(buffer, audio, nOut);
|
||||||
out[i] = float(val) / 65536.0F;
|
|
||||||
}
|
for (unsigned int i = 0U; i < nOut; i++)
|
||||||
|
out[i] = float(audio[i]) / 65536.0F;
|
||||||
|
|
||||||
return nOut;
|
return nOut;
|
||||||
}
|
}
|
||||||
@@ -459,8 +599,10 @@ bool CFMIAXNetwork::writeAuthRep()
|
|||||||
#if defined(DEBUG_IAX)
|
#if defined(DEBUG_IAX)
|
||||||
LogDebug("IAX AUTHREP sent");
|
LogDebug("IAX AUTHREP sent");
|
||||||
#endif
|
#endif
|
||||||
|
std::string password = m_seed + m_password;
|
||||||
|
|
||||||
char hash[MD5_DIGEST_STRING_LENGTH];
|
char hash[MD5_DIGEST_STRING_LENGTH];
|
||||||
::MD5Data((unsigned char*)m_password.c_str(), m_password.size(), hash);
|
::MD5Data((unsigned char*)password.c_str(), password.size(), hash);
|
||||||
|
|
||||||
unsigned short sCall = m_sCallNo | 0x8000U;
|
unsigned short sCall = m_sCallNo | 0x8000U;
|
||||||
unsigned int ts = m_timestamp.elapsed();
|
unsigned int ts = m_timestamp.elapsed();
|
||||||
@@ -694,13 +836,12 @@ bool CFMIAXNetwork::writeAck(unsigned int ts)
|
|||||||
return m_socket.write(buffer, 12U, m_addr, m_addrLen);
|
return m_socket.write(buffer, 12U, m_addr, m_addrLen);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CFMIAXNetwork::writeLagRp()
|
bool CFMIAXNetwork::writeLagRp(unsigned int ts)
|
||||||
{
|
{
|
||||||
#if defined(DEBUG_IAX)
|
#if defined(DEBUG_IAX)
|
||||||
LogDebug("IAX LAGRP sent");
|
LogDebug("IAX LAGRP sent");
|
||||||
#endif
|
#endif
|
||||||
unsigned short sCall = m_sCallNo | 0x8000U;
|
unsigned short sCall = m_sCallNo | 0x8000U;
|
||||||
unsigned int ts = m_timestamp.elapsed();
|
|
||||||
|
|
||||||
unsigned char buffer[15U];
|
unsigned char buffer[15U];
|
||||||
|
|
||||||
@@ -778,6 +919,170 @@ bool CFMIAXNetwork::writeHangup()
|
|||||||
return m_socket.write(buffer, 14U + ::strlen(REASON), m_addr, m_addrLen);
|
return m_socket.write(buffer, 14U + ::strlen(REASON), m_addr, m_addrLen);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CFMIAXNetwork::writeRegReq()
|
||||||
|
{
|
||||||
|
const unsigned short REFRESH_TIME = 60U;
|
||||||
|
|
||||||
|
#if defined(DEBUG_IAX)
|
||||||
|
LogDebug("IAX REGREQ sent");
|
||||||
|
#endif
|
||||||
|
unsigned short sCall = m_sCallNo | 0x8000U;
|
||||||
|
unsigned int ts = m_timestamp.elapsed();
|
||||||
|
|
||||||
|
unsigned char buffer[70U];
|
||||||
|
|
||||||
|
buffer[0U] = (sCall << 8) & 0xFFU;
|
||||||
|
buffer[1U] = (sCall << 0) & 0xFFU;
|
||||||
|
|
||||||
|
buffer[2U] = (m_dCallNo << 8) & 0xFFU;
|
||||||
|
buffer[3U] = (m_dCallNo << 0) & 0xFFU;
|
||||||
|
|
||||||
|
buffer[4U] = (ts << 24) & 0xFFU;
|
||||||
|
buffer[5U] = (ts << 16) & 0xFFU;
|
||||||
|
buffer[6U] = (ts << 8) & 0xFFU;
|
||||||
|
buffer[7U] = (ts << 0) & 0xFFU;
|
||||||
|
|
||||||
|
buffer[8U] = m_oSeqNo;
|
||||||
|
|
||||||
|
buffer[9U] = m_iSeqNo;
|
||||||
|
|
||||||
|
buffer[10U] = AST_FRAME_IAX;
|
||||||
|
|
||||||
|
buffer[11U] = IAX_COMMAND_REGREQ;
|
||||||
|
|
||||||
|
buffer[12U] = IAX_IE_USERNAME;
|
||||||
|
buffer[13U] = m_username.size();
|
||||||
|
::memcpy(buffer + 14U, m_username.c_str(), m_username.size());
|
||||||
|
|
||||||
|
unsigned int offset = 14U + m_username.size();
|
||||||
|
|
||||||
|
if (m_dCallNo > 0U) {
|
||||||
|
std::string password = m_seed + m_password;
|
||||||
|
|
||||||
|
char hash[MD5_DIGEST_STRING_LENGTH];
|
||||||
|
::MD5Data((unsigned char*)password.c_str(), password.size(), hash);
|
||||||
|
|
||||||
|
buffer[offset++] = IAX_IE_MD5_RESULT;
|
||||||
|
buffer[offset++] = MD5_DIGEST_STRING_LENGTH;
|
||||||
|
|
||||||
|
::memcpy(buffer + offset, hash, MD5_DIGEST_STRING_LENGTH);
|
||||||
|
offset += MD5_DIGEST_STRING_LENGTH;
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer[offset++] = IAX_IE_REFRESH;
|
||||||
|
buffer[offset++] = sizeof(unsigned short);
|
||||||
|
buffer[offset++] = (REFRESH_TIME >> 8) & 0xFFU;
|
||||||
|
buffer[offset++] = (REFRESH_TIME >> 0) & 0xFFU;
|
||||||
|
|
||||||
|
#if !defined(DEBUG_IAX)
|
||||||
|
if (m_debug)
|
||||||
|
#endif
|
||||||
|
CUtils::dump(1U, "FM IAX Network Data Sent", buffer, offset);
|
||||||
|
|
||||||
|
m_oSeqNo++;
|
||||||
|
|
||||||
|
return m_socket.write(buffer, offset, m_addr, m_addrLen);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CFMIAXNetwork::uLawEncode(const short* audio, unsigned char* buffer, unsigned int length) const
|
||||||
|
{
|
||||||
|
assert(audio != NULL);
|
||||||
|
assert(buffer != NULL);
|
||||||
|
|
||||||
|
const unsigned short MULAW_MAX = 0x1FFFU;
|
||||||
|
const unsigned short MULAW_BIAS = 33U;
|
||||||
|
|
||||||
|
for (unsigned int i = 0U; i < length; i++) {
|
||||||
|
unsigned short mask = 0x1000U;
|
||||||
|
unsigned char sign;
|
||||||
|
unsigned char position = 12U;
|
||||||
|
unsigned short number;
|
||||||
|
|
||||||
|
if (audio[i] < 0) {
|
||||||
|
number = -audio[i];
|
||||||
|
sign = 0x80U;
|
||||||
|
} else {
|
||||||
|
number = audio[i];
|
||||||
|
sign = 0x00U;
|
||||||
|
}
|
||||||
|
|
||||||
|
number += MULAW_BIAS;
|
||||||
|
if (number > MULAW_MAX)
|
||||||
|
number = MULAW_MAX;
|
||||||
|
|
||||||
|
for (; ((number & mask) != mask && position >= 5U); mask >>= 1, position--)
|
||||||
|
;
|
||||||
|
|
||||||
|
unsigned char lsb = (number >> (position - 4U)) & 0x0FU;
|
||||||
|
buffer[i] = ~(sign | ((position - 5U) << 4) | lsb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CFMIAXNetwork::uLawDecode(const unsigned char* buffer, short* audio, unsigned int length) const
|
||||||
|
{
|
||||||
|
assert(buffer != NULL);
|
||||||
|
assert(audio != NULL);
|
||||||
|
|
||||||
|
const unsigned short MULAW_BIAS = 33U;
|
||||||
|
|
||||||
|
for (unsigned int i = 0U; i < length; i++) {
|
||||||
|
bool sign = true;
|
||||||
|
|
||||||
|
unsigned char number = ~buffer[i];
|
||||||
|
if (number & 0x80U) {
|
||||||
|
number &= 0x7FU;
|
||||||
|
sign = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char position = ((number & 0xF0U) >> 4) + 5U;
|
||||||
|
short decoded = ((1 << position) | ((number & 0x0FU) << (position - 4U))
|
||||||
|
| (1 << (position - 5U))) - MULAW_BIAS;
|
||||||
|
|
||||||
|
audio[i] = sign ? decoded : -decoded;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CFMIAXNetwork::writeAudio(const short* audio, unsigned int length)
|
||||||
|
{
|
||||||
|
#if defined(DEBUG_IAX)
|
||||||
|
LogDebug("IAX ULAW sent");
|
||||||
|
#endif
|
||||||
|
unsigned short sCall = m_sCallNo | 0x8000U;
|
||||||
|
unsigned int ts = m_timestamp.elapsed();
|
||||||
|
|
||||||
|
unsigned char buffer[300U];
|
||||||
|
|
||||||
|
buffer[0U] = (sCall << 8) & 0xFFU;
|
||||||
|
buffer[1U] = (sCall << 0) & 0xFFU;
|
||||||
|
|
||||||
|
buffer[2U] = (m_dCallNo << 8) & 0xFFU;
|
||||||
|
buffer[3U] = (m_dCallNo << 0) & 0xFFU;
|
||||||
|
|
||||||
|
buffer[4U] = (ts << 24) & 0xFFU;
|
||||||
|
buffer[5U] = (ts << 16) & 0xFFU;
|
||||||
|
buffer[6U] = (ts << 8) & 0xFFU;
|
||||||
|
buffer[7U] = (ts << 0) & 0xFFU;
|
||||||
|
|
||||||
|
buffer[8U] = m_oSeqNo;
|
||||||
|
|
||||||
|
buffer[9U] = m_iSeqNo;
|
||||||
|
|
||||||
|
buffer[10U] = AST_FRAME_VOICE;
|
||||||
|
|
||||||
|
buffer[11U] = AST_FORMAT_ULAW;
|
||||||
|
|
||||||
|
uLawEncode(audio, buffer + 12U, length);
|
||||||
|
|
||||||
|
#if !defined(DEBUG_IAX)
|
||||||
|
if (m_debug)
|
||||||
|
#endif
|
||||||
|
CUtils::dump(1U, "FM IAX Network Data Sent", buffer, 12U + length);
|
||||||
|
|
||||||
|
m_oSeqNo++;
|
||||||
|
|
||||||
|
return m_socket.write(buffer, 12U + length, m_addr, m_addrLen);
|
||||||
|
}
|
||||||
|
|
||||||
bool CFMIAXNetwork::compareFrame(const unsigned char* buffer, unsigned char type1, unsigned char type2) const
|
bool CFMIAXNetwork::compareFrame(const unsigned char* buffer, unsigned char type1, unsigned char type2) const
|
||||||
{
|
{
|
||||||
assert(buffer != NULL);
|
assert(buffer != NULL);
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ enum IAX_STATUS {
|
|||||||
IAXS_DISCONNECTED,
|
IAXS_DISCONNECTED,
|
||||||
IAXS_CONNECTING,
|
IAXS_CONNECTING,
|
||||||
IAXS_AUTHORISING,
|
IAXS_AUTHORISING,
|
||||||
|
IAXS_REGISTERING,
|
||||||
IAXS_CONNECTED
|
IAXS_CONNECTED
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -72,6 +73,7 @@ private:
|
|||||||
IAX_STATUS m_status;
|
IAX_STATUS m_status;
|
||||||
CTimer m_retryTimer;
|
CTimer m_retryTimer;
|
||||||
CTimer m_pingTimer;
|
CTimer m_pingTimer;
|
||||||
|
std::string m_seed;
|
||||||
CStopWatch m_timestamp;
|
CStopWatch m_timestamp;
|
||||||
unsigned short m_sCallNo;
|
unsigned short m_sCallNo;
|
||||||
unsigned short m_dCallNo;
|
unsigned short m_dCallNo;
|
||||||
@@ -90,8 +92,13 @@ private:
|
|||||||
bool writePing();
|
bool writePing();
|
||||||
bool writePong(unsigned int ts);
|
bool writePong(unsigned int ts);
|
||||||
bool writeAck(unsigned int ts);
|
bool writeAck(unsigned int ts);
|
||||||
bool writeLagRp();
|
bool writeLagRp(unsigned int ts);
|
||||||
bool writeHangup();
|
bool writeHangup();
|
||||||
|
bool writeRegReq();
|
||||||
|
bool writeAudio(const short* audio, unsigned int length);
|
||||||
|
|
||||||
|
void uLawEncode(const short* audio, unsigned char* buffer, unsigned int length) const;
|
||||||
|
void uLawDecode(const unsigned char* buffer, short* audio, unsigned int length) const;
|
||||||
|
|
||||||
bool compareFrame(const unsigned char* buffer, unsigned char type1, unsigned char type2) const;
|
bool compareFrame(const unsigned char* buffer, unsigned char type1, unsigned char type2) const;
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user