📄 lidep.cxx
字号:
// enabling audio on the PSTN line the POTS line will no longer be enable-able
// so this will fail and the ringing will be ignored
if (!line.EnableAudio())
return;
// Have incoming ring, create a new LID connection and let it handle it
connection = CreateConnection(*manager.CreateCall(), line, NULL, PString::Empty());
connectionsActive.SetAt(line.GetToken(), connection);
connection->StartIncoming();
}
/////////////////////////////////////////////////////////////////////////////
OpalLineConnection::OpalLineConnection(OpalCall & call,
OpalLIDEndPoint & ep,
OpalLine & ln,
const PString & number)
: OpalConnection(call, ep, ln.GetToken()),
endpoint(ep),
line(ln)
{
remotePartyNumber = number;
silenceDetector = new OpalLineSilenceDetector(line);
answerRingCount = 3;
requireTonesForDial = TRUE;
wasOffHook = FALSE;
handlerThread = NULL;
PTRACE(3, "LID Con\tConnection " << callToken << " created");
}
void OpalLineConnection::OnReleased()
{
PTRACE(2, "LID Con\tOnReleased " << *this);
if (handlerThread != NULL) {
PTRACE(3, "LID Con\tAwaiting handler thread termination " << *this);
// Stop the signalling handler thread
SetUserInput(PString()); // Break out of ReadUserInput
handlerThread->WaitForTermination();
delete handlerThread;
handlerThread = NULL;
}
PTRACE(3, "LID Con\tPlaying clear tone until handset onhook");
line.PlayTone(OpalLineInterfaceDevice::ClearTone);
line.Ring(FALSE);
line.SetOnHook();
phase = ReleasedPhase;
OpalConnection::OnReleased();
}
PString OpalLineConnection::GetDestinationAddress()
{
return ReadUserInput();
}
BOOL OpalLineConnection::SetAlerting(const PString & calleeName, BOOL)
{
if (IsOriginating()) {
PTRACE(3, "LID Con\tSetAlerting ignored on call we originated.");
return TRUE;
}
PTRACE(3, "LID Con\tSetAlerting " << *this);
if (GetPhase() != SetUpPhase)
return FALSE;
// switch phase
phase = AlertingPhase;
alertingTime = PTime();
line.SetCallerID(calleeName);
return line.PlayTone(OpalLineInterfaceDevice::RingTone);
}
BOOL OpalLineConnection::SetConnected()
{
if (IsOriginating()) {
PTRACE(3, "LID Con\tSetConnected ignored on call we originated.");
return TRUE;
}
PTRACE(3, "LID Con\tSetConnected " << *this);
if (GetPhase() < ConnectedPhase) {
// switch phase
phase = ConnectedPhase;
connectedTime = PTime();
return line.StopTone();
}
return FALSE;
}
OpalMediaFormatList OpalLineConnection::GetMediaFormats() const
{
OpalMediaFormatList formats = line.GetDevice().GetMediaFormats();
AddVideoMediaFormats(formats);
return formats;
}
OpalMediaStream * OpalLineConnection::CreateMediaStream(const OpalMediaFormat & mediaFormat,
unsigned sessionID,
BOOL isSource)
{
if (sessionID != OpalMediaFormat::DefaultAudioSessionID)
return OpalConnection::CreateMediaStream(mediaFormat, sessionID, isSource);
return new OpalLineMediaStream(mediaFormat, sessionID, isSource, line);
}
BOOL OpalLineConnection::OnOpenMediaStream(OpalMediaStream & mediaStream)
{
if (!OpalConnection::OnOpenMediaStream(mediaStream))
return FALSE;
if (mediaStream.IsSource()) {
OpalMediaPatch * patch = mediaStream.GetPatch();
if (patch != NULL) {
silenceDetector->SetParameters(endpoint.GetManager().GetSilenceDetectParams());
patch->AddFilter(silenceDetector->GetReceiveHandler(), line.GetReadFormat());
}
}
return TRUE;
}
BOOL OpalLineConnection::SendUserInputString(const PString & value)
{
return line.PlayDTMF(value);
}
BOOL OpalLineConnection::SendUserInputTone(char tone, int duration)
{
if (duration <= 0)
return line.PlayDTMF(&tone);
else
return line.PlayDTMF(&tone, duration);
}
BOOL OpalLineConnection::PromptUserInput(BOOL play)
{
PTRACE(3, "LID Con\tConnection " << callToken << " dial tone " << (play ? "on" : "off"));
if (play)
return line.PlayTone(OpalLineInterfaceDevice::DialTone);
else
return line.StopTone();
}
void OpalLineConnection::StartIncoming()
{
if (handlerThread == NULL)
handlerThread = PThread::Create(PCREATE_NOTIFIER(HandleIncoming), 0,
PThread::NoAutoDeleteThread,
PThread::LowPriority,
"Line Connection:%x");
}
void OpalLineConnection::Monitor(BOOL offHook)
{
if (offHook) {
PTRACE_IF(3, !wasOffHook, "LID Con\tConnection " << callToken << " off hook: phase=" << phase);
if(IsOriginating()){
if (phase == AlertingPhase) {
phase = ConnectedPhase;
OnConnected();
}
}
char tone;
while ((tone = line.ReadDTMF()) != '\0')
OnUserInputTone(tone, 180);
wasOffHook = TRUE;
}
else if (wasOffHook) {
PTRACE(3, "LID Con\tConnection " << callToken << " on hook: phase=" << phase);
Release(EndedByRemoteUser);
wasOffHook = FALSE;
}
}
void OpalLineConnection::HandleIncoming(PThread &, INT)
{
PTRACE(3, "LID Con\tHandling incoming call on " << *this);
phase = SetUpPhase;
if (line.IsTerminal())
remotePartyName = line.GetDescription();
else {
// Count incoming rings
unsigned count;
do {
count = line.GetRingCount();
if (count == 0) {
PTRACE(2, "LID Con\tIncoming PSTN call stopped.");
Release(EndedByCallerAbort);
return;
}
PThread::Sleep(100);
if (phase >= ReleasingPhase)
return;
} while (count < answerRingCount);
// Get caller ID
PString callerId;
if (line.GetCallerID(callerId, TRUE)) {
PStringArray words = callerId.Tokenise('\t', TRUE);
if (words.GetSize() < 3) {
PTRACE(2, "LID Con\tMalformed caller ID \"" << callerId << '"');
}
else {
remotePartyNumber = words[0].Trim();
remotePartyName = words[1].Trim();
if (remotePartyName.IsEmpty())
remotePartyName = remotePartyNumber;
}
}
line.SetOffHook();
}
wasOffHook = TRUE;
if (!OnIncomingConnection()) {
Release(EndedByCallerAbort);
return;
}
PTRACE(2, "LID\tIncoming call routed for " << *this);
if (!ownerCall.OnSetUp(*this))
Release(EndedByNoAccept);
}
BOOL OpalLineConnection::SetUpConnection()
{
PTRACE(3, "LID Con\tHandling outgoing call on " << *this);
phase = SetUpPhase;
originating = TRUE;
if (line.IsTerminal()) {
line.SetCallerID(remotePartyNumber);
line.Ring(TRUE);
phase = AlertingPhase;
OnAlerting();
}
else {
switch (line.DialOut(remotePartyNumber, requireTonesForDial)) {
case OpalLineInterfaceDevice::DialTone :
PTRACE(3, "LID Con\tNo dial tone on " << line);
return FALSE;
case OpalLineInterfaceDevice::RingTone :
PTRACE(3, "LID Con\tGot ringback on " << line);
phase = AlertingPhase;
OnAlerting();
break;
default :
PTRACE(3, "LID Con\tError dialling " << remotePartyNumber << " on " << line);
return FALSE;
}
}
return TRUE;
}
///////////////////////////////////////////////////////////////////////////////
OpalLineMediaStream::OpalLineMediaStream(const OpalMediaFormat & mediaFormat,
unsigned sessionID,
BOOL isSource,
OpalLine & ln)
: OpalMediaStream(mediaFormat, sessionID, isSource),
line(ln)
{
useDeblocking = FALSE;
missedCount = 0;
lastSID[0] = 2;
lastFrameWasSignal = TRUE;
}
BOOL OpalLineMediaStream::Open()
{
if (isOpen)
return TRUE;
if (IsSource()) {
if (!line.SetReadFormat(mediaFormat))
return FALSE;
useDeblocking = mediaFormat.GetFrameSize() != line.GetReadFrameSize();
}
else {
if (!line.SetWriteFormat(mediaFormat))
return FALSE;
useDeblocking = mediaFormat.GetFrameSize() != line.GetWriteFrameSize();
}
PTRACE(3, "Media\tStream set to " << mediaFormat << ", frame size: rd="
<< line.GetReadFrameSize() << " wr="
<< line.GetWriteFrameSize() << ", "
<< (useDeblocking ? "needs" : "no") << " reblocking.");
return OpalMediaStream::Open();
}
BOOL OpalLineMediaStream::Close()
{
if (IsSource())
line.StopReadCodec();
else
line.StopWriteCodec();
return OpalMediaStream::Close();
}
BOOL OpalLineMediaStream::ReadData(BYTE * buffer, PINDEX size, PINDEX & length)
{
length = 0;
if (IsSink()) {
PTRACE(1, "Media\tTried to read from sink media stream");
return FALSE;
}
if (useDeblocking) {
line.SetReadFrameSize(size);
if (line.ReadBlock(buffer, size)) {
length = size;
return TRUE;
}
}
else {
if (line.ReadFrame(buffer, length)) {
// In the case of G.723.1 remember the last SID frame we sent and send
// it again if the hardware sends us a CNG frame.
if (mediaFormat.GetPayloadType() == RTP_DataFrame::G7231) {
switch (length) {
case 1 : // CNG frame
memcpy(buffer, lastSID, 4);
length = 4;
lastFrameWasSignal = FALSE;
break;
case 4 :
if ((*(BYTE *)buffer&3) == 2)
memcpy(lastSID, buffer, 4);
lastFrameWasSignal = FALSE;
break;
default :
lastFrameWasSignal = TRUE;
}
}
return TRUE;
}
}
PTRACE_IF(1, line.GetDevice().GetErrorNumber() != 0,
"Media\tDevice read frame error: " << line.GetDevice().GetErrorText());
return FALSE;
}
BOOL OpalLineMediaStream::WriteData(const BYTE * buffer, PINDEX length, PINDEX & written)
{
written = 0;
if (IsSource()) {
PTRACE(1, "Media\tTried to write to source media stream");
return FALSE;
}
// Check for writing silence
PBYTEArray silenceBuffer;
if (length != 0)
missedCount = 0;
else {
switch (mediaFormat.GetPayloadType()) {
case RTP_DataFrame::G7231 :
if (missedCount++ < 4) {
static const BYTE g723_erasure_frame[24] = { 0xff, 0xff, 0xff, 0xff };
buffer = g723_erasure_frame;
length = 24;
}
else {
static const BYTE g723_cng_frame[4] = { 3 };
buffer = g723_cng_frame;
length = 1;
}
break;
case RTP_DataFrame::PCMU :
case RTP_DataFrame::PCMA :
buffer = silenceBuffer.GetPointer(line.GetWriteFrameSize());
length = silenceBuffer.GetSize();
memset((void *)buffer, 0xff, length);
break;
case RTP_DataFrame::G729 :
if (mediaFormat.Find('B') != P_MAX_INDEX) {
static const BYTE g729_sid_frame[2] = { 1 };
buffer = g729_sid_frame;
length = 2;
break;
}
// Else fall into default case
default :
buffer = silenceBuffer.GetPointer(line.GetWriteFrameSize()); // Fills with zeros
length = silenceBuffer.GetSize();
break;
}
}
if (useDeblocking) {
line.SetWriteFrameSize(length);
if (line.WriteBlock(buffer, length)) {
written = length;
return TRUE;
}
}
else {
if (line.WriteFrame(buffer, length, written))
return TRUE;
}
PTRACE_IF(1, line.GetDevice().GetErrorNumber() != 0,
"Media\tLID write frame error: " << line.GetDevice().GetErrorText());
return FALSE;
}
BOOL OpalLineMediaStream::IsSynchronous() const
{
return TRUE;
}
/////////////////////////////////////////////////////////////////////////////
OpalLineSilenceDetector::OpalLineSilenceDetector(OpalLine & l)
: line(l)
{
}
unsigned OpalLineSilenceDetector::GetAverageSignalLevel(const BYTE *, PINDEX)
{
return line.GetAverageSignalLevel(TRUE);
}
/////////////////////////////////////////////////////////////////////////////
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -