//
// The contents of this file are subject to the Mozilla Public License
// Version 1.0 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://www.mozilla.org/MPL/
//
// Software distributed under the License is distributed on an "AS IS"
// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
// the License for the specific language governing rights and limitations
// under the License.
//
// The Original Code is CPhone, a cross platform voip gui.
//
// The Initial Developer of the Original Code is Derek Smithies.
//
// Copyright (C) 2002 Indranet Technologies Ltd,
// http://www.indranet-technologies.com
// All Rights Reserved.
//
// Contributor(s): _______________
/*
*
* $Log: mainwindowSub.cxx,v $
* Revision 1.21 2005/02/02 23:14:46 dereksmithies
* Fix compilation for when IXJ is absent.
*
* Revision 1.20 2004/06/02 04:56:43 dereksmithies
* Bring up to date with CVS as of today, Uses codec plugins now.
* You may need to set the PWLIBPLUGINPATH environment variable.
*
* Revision 1.19 2004/04/23 05:09:59 dereksmithies
* Fixes so it works with latest openh323 lib, and not lock X display.
*
* Revision 1.18 2004/04/21 22:08:43 dereksmithies
* Fixes to bring up to date with current openh323 CVS. Thanks to Peter Nixon.
*
* Revision 1.17 2004/04/14 07:25:19 dereksmithies
* Updates, so it compiles on windows XP. Big Thanks to Francisco Huerta
*
* Revision 1.16 2004/02/19 21:25:43 dereksmithies
* Make nat traversal update address on incoming call. Thanks dag@bakke.com
*
* Revision 1.15 2004/02/18 21:21:49 dereksmithies
* Implement suggestion from dag@bakke.com - nat traversal name resolved on call startup also.
*
* Revision 1.14 2004/02/18 03:16:55 dereksmithies
* Fix Nat translation feature. Thanks to dag@bakke.com for finding the problem.
*
* Revision 1.13 2004/01/02 04:06:24 dereksmithies
* Bring up to date with openh323 libraries. Get Plugins to work corectly.
*
* Revision 1.12 2003/09/02 03:37:32 dereksmithies
* Add statistics, new icons, toolbuttons (icon + name)
*
* Revision 1.11 2003/08/26 04:48:02 dereksmithies
* Fixes to get statistics working right, add icons, add ok,cancel,apply buttons
*
* Revision 1.10 2003/08/07 23:56:38 dereksmithies
* Main Program Icon always comes up at the end of a call.
*
* Revision 1.9 2003/08/06 23:36:39 peternixon
* Change image to an embedded XPM
*
* Revision 1.8 2003/08/06 21:41:19 peternixon
* stop segfault if graphic does not exist
*
* Revision 1.7 2003/08/06 05:04:25 dereksmithies
* Add feature to display bmp
*
* Revision 1.6 2003/05/20 03:32:28 dereksmithies
* Better handling of ixj handset states, and call progress states.
*
* Revision 1.5 2003/05/09 04:34:46 dereksmithies
* Tidy up gatekeeper finding. Works reliably.
*
* Revision 1.4 2003/05/09 03:08:24 dereksmithies
* Fix Microtelco handling, and message display
*
* Revision 1.3 2003/05/06 22:40:36 dereksmithies
* Fixes to get it working correctly on microtelco.
*
* Revision 1.2 2003/04/04 04:37:49 dereksmithies
* Major upgrade.
* Ixj & microtelco support added. Fix threading issues.
*
* Revision 1.1.1.1 2002/05/12 22:55:05 dereksmithies
* Initial release.
*
*
*
*
*/
#include <ptlib.h>
#include <qapplication.h>
#include <qlabel.h>
#include <qtoolbutton.h>
#include <qapp.h>
#include "addressbookSub.h"
#include "audiopropertiesSub.h"
#include "callanswer.h"
#include "callanswerSub.h"
#include "cpendpoint.h"
#include "main.h"
#include "mainwindowSub.h"
#include "message.h"
#include "qtvid.h"
#include "settingsSub.h"
#include "videopropertiesSub.h"
#include "statisticsSub.h"
#include "h323pdu.h"
#include "h261codec.h"
#include "h263codec.h"
#include "ffh263codec.h"
#include <h323.h>
#include "images/cphone.xpm"
#include "images/connect_on.xpm"
#include "images/connect_off.xpm"
MainUi::MainUi()
:FormMainWindow(0, "main ui", FALSE,
WDestructiveClose | WType_TopLevel)
{
// move(20,20);
cPhoneIcon = NULL;
epState = epNoTone;
QCustomEvent *ce =new QCustomEvent(MAIN_UI_UP);
QApplication::postEvent(this, ce);
}
MainUi::~MainUi()
{
if (transmitVideoChannel != NULL)
delete transmitVideoChannel;
if (receiveVideoChannel != NULL)
delete receiveVideoChannel;
#ifdef HAS_IXJ
lidThread.TerminateThread();
lidThread.WaitForTermination();
#endif
}
void MainUi::InitialiseConfiguration()
{
remoteComputer = "";
toolButtonConnect->setPixmap((const char **)connect_on);
localVideoThread = NULL;
transmitVideoChannel = NULL;
receiveVideoChannel = NULL;
firstErrorOpenAudioChannel = TRUE;
applicationIsExiting = FALSE;
#ifdef HAS_IXJ
ixjCardNames = OpalIxJDevice::GetDeviceNames();
lidThread.StartRunning();
#endif
connectOpts.Initialise();
videoOpts.Initialise();
audioOpts.Initialise();
soundCardNames = PSoundChannel::GetDeviceNames(PSoundChannel::Player);
InitialiseVideoDisplay();
CPhone::Current().SetWindowId(eMainUi, winId());
QPixmap p = QPixmap(cphone_xpm);
cPhoneIcon = new QImage(p.width(), p.height(), 32);
*cPhoneIcon = p;
cPhoneIcon->convertDepth(32);
CreateLocalVideoDisplayThread();
audioOpts.AudioDeviceChange();
// return;
if (InitialiseVoipSettings() == FALSE) {
cerr << "Program cannot run due to an initialisation failure." << endl;
exit(00);
}
}
void MainUi::AudioClicked_slot()
{
if (CPhone::Current().GetWindow(eAudioProperties) != NULL) {
CPhone::Current().GetWindow(eAudioProperties)->raise();
return;
}
AudioProperties *audioProperties = new AudioProperties(audioOpts);
audioProperties->show();
}
void MainUi::ConnectClicked_slot()
{
if (!currentCallToken.IsEmpty()) {
ExitCurrentCall();
return;
}
if (CPhone::Current().GetWindow(eAddressBook) != NULL) {
CPhone::Current().GetWindow(eAddressBook)->raise();
return;
}
AddressBook *addressBook = new AddressBook();
addressBook->show();
}
void MainUi::VideoClicked_slot()
{
if (CPhone::Current().GetWindow(eVideoProperties) != NULL) {
CPhone::Current().GetWindow(eVideoProperties)->raise();
return;
}
VideoProperties *videoProperties = new VideoProperties(videoOpts);
videoProperties->show();
}
void MainUi::SettingsClicked_slot()
{
if (CPhone::Current().GetWindow(eSettings) != NULL) {
CPhone::Current().GetWindow(eSettings)->raise();
return;
}
Settings *settingsCall = new Settings(connectOpts);
settingsCall->show();
}
void MainUi::ExitClicked_slot()
{
close(TRUE);
}
PVideoOutputDevice *MainUi::GetDisplayModule (BOOL isEncoding, BOOL isFlipped)
{
VideoDisplay *displayWidget =
((isEncoding) ? FormMainWindow::VideoDisplayLocal :
FormMainWindow::VideoDisplayReceived);
return new QtVideoDevice(isEncoding, displayWidget, isFlipped);
}
BOOL MainUi::CreateLocalVideoDisplayThread()
{
QImage *q = new QImage(*cPhoneIcon);
q->detach();
FormMainWindow::VideoDisplayReceived->DisplayQImage(q);
if (!videoOpts.GetDisplayLocal())
return TRUE;
if (localVideoThread != NULL)
return TRUE;
transmitVideoChannel->AttachVideoPlayer(GetDisplayModule(TRUE, videoOpts.GetFlipLocal()), FALSE);
localVideoThread = new LocalVideoDisplayThread(transmitVideoChannel);
return TRUE;
}
BOOL MainUi::DeleteLocalVideoDisplayThread()
{
if (localVideoThread != NULL) {
localVideoThread->InitiateTermination();
localVideoThread->WaitForTermination();
delete localVideoThread;
localVideoThread = NULL;
}
return TRUE;
}
void MainUi::SetDisplayString(QString qMessage)
{
LabelDisplayUserInformation->prepareDisplayText(qMessage);
QCustomEvent *ce =new QCustomEvent(QEvent::User);
QApplication::postEvent(LabelDisplayUserInformation, ce);
killTimers();
startTimer(20 * 1000); //display text for 20 seconds;
}
void MainUi::DisplayInfoMessage(char *message)
{
QString qMessage(message);
DisplayInfoMessage(qMessage);
}
void MainUi::DisplayInfoMessage(PString message)
{
QString qMessage(message.GetPointer());
DisplayInfoMessage(qMessage);
}
void MainUi::DisplayInfoMessage(QString message)
{
MessageCustomEvent * error = new MessageCustomEvent(CUSTOM_EVENT_MESSAGE, "Information", message);
QApplication::postEvent(this, error);
}
void MainUi::DisplayCriticalError(QString message)
{
MessageCustomEvent * error = new MessageCustomEvent(CUSTOM_EVENT_MESSAGE, "Critical", message);
QApplication::postEvent(this, error);
}
void MainUi::DisplayCriticalError(PString message)
{
QString qMessage(message.GetPointer());
DisplayCriticalError(qMessage);
}
void MainUi::DisplayCriticalError(char * message)
{
QString qMessage(message);
DisplayCriticalError(qMessage);
}
void MainUi::QueryCallAnswer(PString remoteNode)
{
if (CPhone::Current().GetWindow(eCallAnswer) != NULL)
return;
remoteComputer = remoteNode.GetPointer();
QString incomingCall("Incoming call from " + remoteComputer);
DisplayMessage(incomingCall);
#if defined(HAS_IXJ)
lidThread.RingPhone();
#endif
QApplication::postEvent(this, new QCustomEvent(CALL_ANSWER_INITIATE));
}
void MainUi::closeEvent(QCloseEvent *e)
{
StartTerminationProcess();
e->accept();
}
void MainUi::customEvent(QCustomEvent *e)
{
//THESE three options are generated by the callanswer window.
//The CallAnswer window guarantees one response per instantiation.
if (e->type() == CALL_ANSWER_RESPONSE_YES) {
AnswerCall(H323Connection::AnswerCallNow); //yes from callanswer.
DisplayMessage("In call with " + remoteComputer);
}
if (e->type() == CALL_ANSWER_RESPONSE_NO)
AnswerCall(H323Connection::AnswerCallDenied); //no from callanswer.
if (e->type() == CALL_ANSWER_RESPONSE_TMO)
AnswerCall(H323Connection::AnswerCallDenied); //timeout from callanswer.
//THIS option is generated when this class is created.
//ensures that things are only built when the gui is ready for action.
if (e->type() == MAIN_UI_UP)
InitialiseConfiguration();
if (e->type() == CALL_ANSWER_INITIATE) {
CallAnswer * dialogCallAnswer = new CallAnswer(remoteComputer);
dialogCallAnswer->show();
}
if (e->type() == CUSTOM_EVENT_MESSAGE) {
MessageCustomEvent *ce = (MessageCustomEvent *) e;
ThreadSafeMessage *m = new ThreadSafeMessage(ce->GetTitle(), ce->GetMessage());
m->show();
}
return;
}
void MainUi::timerEvent(QTimerEvent *)
{
LabelDisplayUserInformation->clear(); //setText("");
}
void MainUi::OnConnectionEstablished(PString message)
{
//Before the current call starts to use video, delete the local display.
DeleteLocalVideoDisplayThread();
DisplayMessage(message);
OnConnectionEstablished(TRUE);
}
void MainUi::OnConnectionCleared(PString message)
{
DisplayMessage(message);
videoOpts.AttachVideoCodec(NULL);
CreateLocalVideoDisplayThread();
OnConnectionEstablished(FALSE);
}
void MainUi::OnConnectionEstablished(BOOL isEstablished)
{
Settings *settingsCall = (Settings *)CPhone::Current().GetWindow(eSettings);
if (settingsCall != NULL)
settingsCall->OnConnectionEstablished(isEstablished);
AudioProperties *audioProperties = (AudioProperties *)CPhone::Current().GetWindow(eAudioProperties);
if (audioProperties != NULL)
audioProperties->OnConnectionEstablished(isEstablished);
AddressBook *addressBook = (AddressBook *)CPhone::Current().GetWindow(eAddressBook);
if (addressBook != NULL)
addressBook->OnConnectionEstablished(isEstablished);
UpdateToolButtonConnect(isEstablished);
}
void MainUi::UpdateToolButtonConnect(BOOL isEstablished)
{
toolButtonConnect->setPixmap((const char **)(isEstablished ? connect_off : connect_on));
toolButtonConnect->setTextLabel(isEstablished ? tr("Disconnect") : tr("Connect"));
}
void MainUi::DisplayMessage(PString message)
{
DisplayMessage(QString((const char *)message));
}
void MainUi::DisplayMessage(char * message)
{
DisplayMessage(QString(message));
}
void MainUi::DisplayMessage(QString message)
{
// PTRACE(1, "GuiThread\t MainWindow " << (const char *)message);
SetDisplayString(message);
}
BOOL MainUi::DisplayLocalIsNow(BOOL doDisplayLocal)
{
if (doDisplayLocal)
transmitVideoChannel->AttachVideoPlayer(GetDisplayModule(TRUE, videoOpts.GetFlipLocal()), FALSE);
else
transmitVideoChannel->AttachVideoPlayer(PVideoOutputDevice::CreateDevice("NULL"), FALSE);
if (IsInCall())
return TRUE;
if (doDisplayLocal)
CreateLocalVideoDisplayThread();
else
DeleteLocalVideoDisplayThread();
return TRUE;
}
void MainUi:: TranslateTCPAddress(PIPSocket::Address &localAddr, const PIPSocket::Address &remoteAddr)
{
if (connectOpts.doNatTraversal) // && (remoteAddr.Byte1() != 192))
localAddr = masqAddress;
return;
}
BOOL MainUi::AttachPlayerReaderToVideoChannel(BOOL isEncoding)
{
CpVideoChannel *vChannel= isEncoding ? transmitVideoChannel : receiveVideoChannel;
BOOL doFlip = isEncoding ? videoOpts.GetFlipLocal() : videoOpts.GetFlipReceived();
if (isEncoding) {
if (videoOpts.GetDisplayLocal())
vChannel->AttachVideoPlayer(GetDisplayModule(isEncoding, doFlip), FALSE);
vChannel->AttachVideoReader(NULL, FALSE);
vChannel->AttachVideoReader(videoOpts.GetNewVideoGrabber(), FALSE);
} else
vChannel->AttachVideoPlayer(GetDisplayModule(isEncoding, doFlip), FALSE);
return TRUE;
}
BOOL MainUi::InitialiseVideoDisplay()
{
if (transmitVideoChannel == NULL)
transmitVideoChannel = new CpVideoChannel();
if (receiveVideoChannel == NULL)
receiveVideoChannel = new CpVideoChannel();
videoOpts.AttachVideoChannels(receiveVideoChannel, transmitVideoChannel);
AttachPlayerReaderToVideoChannel(TRUE); //Encoding
AttachPlayerReaderToVideoChannel(FALSE); //Decoding
return TRUE;
}
void MainUi::DeleteVideoDisplay()
{
if (receiveVideoChannel != NULL)
receiveVideoChannel->AttachVideoPlayer(NULL, FALSE);
if (transmitVideoChannel != NULL) {
transmitVideoChannel->AttachVideoPlayer(NULL, FALSE);
transmitVideoChannel->AttachVideoReader(NULL, FALSE);
}
}
void MainUi::UpdateUdpPorts()
{
SetRtpIpPorts(connectOpts.lowUdpPort, connectOpts.highUdpPort); /* PortBase, PortMax*/
}
PStringToString MainUi::GetInterfaceAddressList()
{
PIPSocket::InterfaceTable if_table;
if (!PIPSocket::GetInterfaceTable(if_table)) {
cerr << "GetInterfaceTable() failed. No interface table" << endl;
exit(0);
}
PStringToString interfaceList;
for (PINDEX i = 0; i < if_table.GetSize(); i++)
interfaceList.SetAt(if_table[i].GetName(), if_table[i].GetAddress());
return interfaceList;
}
BOOL MainUi::InitialiseVoipSettings()
{
if (!connectOpts.userName.IsEmpty())
SetLocalUserName(connectOpts.userName);
initialBandwidth = 100000; // Standard 10base LAN in 100's of bits/sec
soundChannelBuffers = audioOpts.GetBuffers();
PINDEX i;
PStringToString nameIpAddress = GetInterfaceAddressList();
for (i = 0; i < nameIpAddress.GetSize(); i++) {
PString interfaceStr = nameIpAddress.GetDataAt(i);
PIPSocket::Address interfaceAddress(interfaceStr);
H323ListenerTCP * listener = new H323ListenerTCP(*this, interfaceAddress, H323EndPoint::DefaultTcpPort);
if (!StartListener(listener)) {
cerr << "Warning:: could not open H.323 listener port on "
<< interfaceAddress << PString(":") << PString(H323EndPoint::DefaultTcpPort) << endl;
delete listener;
}
}
if (GetListeners().GetSize() == 0) {
cerr << "\n\nError: could not get any H323 listeners on ::" << endl
<< nameIpAddress << endl
<< "\n\nIs there another copy of CPhone already running?" << endl;
return FALSE;
}
UpdateUdpPorts();
AddAllCapabilities();
connectOpts.LoadCapabilitiesFromDisk();
RebuildCapabilityTable();
if (connectOpts.doMicroTelco) {
connectOpts.doMicroTelco = MicroTelcoActivate(TRUE);
if (!connectOpts.doMicroTelco)
DisplayCriticalError("Failed to connect to MicroTelco \n" + GetGatekeeperRegistrationMessage());
}
if (!InitialiseGatekeeper())
DisplayCriticalError("Gatekeeper discovery process \n" + GetGatekeeperRegistrationMessage());
UpdateNatTraversalAddress();
return TRUE;
}
void MainUi::SetCodecFrames(const PString & fmt, unsigned frames)
{
H323Capability * cap = capabilities.FindCapability(fmt);
if (cap == NULL)
DisplayMessage("Cannot find codec " + fmt);
else
cap->SetTxFramesInPacket(frames);
}
void MainUi::AddAllCapabilities()
{
int packetUtilisation = connectOpts.packetUtilization;
int g711Opts[11] = {10, 12, 14, 18, 24, 30, 47, 80, 130, 190, 240};
int g711Frames = g711Opts[packetUtilisation];
int gsmFrames = (int) (((double)packetUtilisation * 6)/10) + 1;
capabilities.RemoveAll();
#if defined(HAS_IXJ)
lidThread.AddIxjCapabilities(capabilities);
#endif
H323EndPoint::AddAllCapabilities(0, 0, "*");
SetCodecFrames(OpalGSM0610, gsmFrames);
SetCodecFrames(OpalG711uLaw64k, g711Frames);
SetCodecFrames(OpalG711ALaw64k, g711Frames);
//AddCapability puts the codec into the list of codecs we can send
//SetCapability puts the codec into the list of codecs we can send and receive
SetCapability(0, 1, new H323_H261Capability(2, 0, FALSE, FALSE, 6217));
SetCapability(0, 1, new H323_H261Capability(0, 4, FALSE, FALSE, 6217));
#define ADD_H263_VIDEO_CAPAB(a) \
SetCapability(0, 1, new a(0, 0, 1, 0, 0, 0, 0)); \
SetCapability(0, 1, new a(0, 1, 0, 0, 0, 0, 0));
#if H323_AVCODEC
ADD_H263_VIDEO_CAPAB (H323_FFH263Capability);
#endif
#if H323_VICH263
ADD_H263_VIDEO_CAPAB (H323_H263Capability);
#endif
H323_UserInputCapability::AddAllCapabilities(capabilities, 0, P_MAX_INDEX);
PStringList availableCapabilities;
for(PINDEX i = 0; i < capabilities.GetSize(); i++)
availableCapabilities += capabilities[i].GetFormatName();
connectOpts.SetAvailableCapabilities(availableCapabilities);
}
void MainUi::ReorderCapabilities()
{
PStringArray toRemove = connectOpts.GetDisabledCapabilities();
capabilities.Remove(toRemove);
PStringArray toReorder = connectOpts.GetEnabledCapabilities();
capabilities.Reorder(toReorder);
for(PINDEX i = 0; i < toReorder.GetSize(); i++)
if (toReorder[i].Find("CIF") != P_MAX_INDEX) {
autoStartTransmitVideo = TRUE;
autoStartReceiveVideo = TRUE;
break;
}
}
void MainUi::RebuildCapabilityTable()
{
AddAllCapabilities();
ReorderCapabilities();
}
BOOL MainUi::SetSoundDevice(const char * optionName,
PSoundChannel::Directions dir)
{
PString dev = audioOpts.GetAudioDevice();
if (dir == PSoundChannel::Player) {
if (SetSoundChannelPlayDevice(dev))
return TRUE;
}
else {
if (SetSoundChannelRecordDevice(dev))
return TRUE;
}
cerr << "SET SOUND DEVICE to be "<< dev << " failed."<< endl;
return FALSE;
}
H323Connection * MainUi::CreateConnection(unsigned callReference)
{
unsigned opt = 0;
UpdateNatTraversalAddress();
if (connectOpts.noFastStart)
opt += H323Connection::FastStartOptionDisable;
if (connectOpts.noH245Tunnelling)
opt += H323Connection::H245TunnelingOptionDisable;
return new CpConnection(callReference, opt);
}
BOOL MainUi::OnIncomingCall(H323Connection & connection,
const H323SignalPDU & setupPDU,
H323SignalPDU &)
{
if (applicationIsExiting)
return FALSE;
if (setupPDU.m_h323_uu_pdu.HasOptionalField(H225_H323_UU_PDU::e_nonStandardData)) {
PString param = setupPDU.m_h323_uu_pdu.m_nonStandardData.m_data.AsString();
if (!param)
cout << "Incoming setup PDU contains non-standard parameter: \"" << param << "\"." << endl;
}
if (!currentCallToken.IsEmpty())
cout << "WARNING: current call token not empty" << endl;
if (currentCallToken.IsEmpty() ) {
currentCallToken = connection.GetCallToken();
return TRUE;
}
PTime now;
PString msg = "Call from \"" + connection.GetRemotePartyName() + "\" ignored";
DisplayMessage(msg);
connection.ClearCall(H323Connection::EndedByLocalBusy);
return FALSE;
}
BOOL MainUi::WaitingForACall()
{
return currentCallToken.IsEmpty();
}
void MainUi::OnNoAnswerTimeout()
{
H323Connection * connection = FindConnectionWithLock(currentCallToken);
if (connection == NULL)
return;
connection->ClearCall(H323Connection::EndedByNoAnswer);
connection->Unlock();
}
void MainUi::OnConnectionEstablished(H323Connection & connection,
const PString & /*token*/)
{
OnConnectionEstablished( "Call with \"" +connection.GetRemotePartyName() + "\" started");
epState = epCallInProgress;
}
void MainUi::OnConnectionCleared(H323Connection & connection, const PString & clearedCallToken)
{
firstErrorOpenAudioChannel = TRUE;
// stop any request for "Call Answer Y/N"
StopCallAnswer();
audioOpts.AttachAudioChannel(TRUE, NULL); //IsEncoding channel is set to NULL
audioOpts.AttachAudioChannel(FALSE, NULL);//receiving channel is set to NULL
// ignore connections that are not the current connection
if (clearedCallToken != currentCallToken) {
return;
}
currentCallToken = PString(); // indicate that our connection is now cleared
// indicate call has hungup
epState = epCallHungup;
PString remoteName = "\"" + connection.GetRemotePartyName() + "\"";
PString message;
switch (connection.GetCallEndReason()) {
case H323Connection::EndedByCallForwarded :
message = "";
break;
case H323Connection::EndedByRemoteUser :
message = remoteName + " has cleared the call";
break;
case H323Connection::EndedByCallerAbort :
message = remoteName + " has stopped calling";
break;
case H323Connection::EndedByRefusal :
message = remoteName + " did not accept your call";
break;
case H323Connection::EndedByRemoteBusy :
message = remoteName + " was busy";
break;
case H323Connection::EndedByRemoteCongestion :
message = PString("Congested link to ") + remoteName;
break;
case H323Connection::EndedByNoAnswer :
message = remoteName + " did not answer your call";
break;
case H323Connection::EndedByTransportFail :
message = "Call with " + remoteName + " ended abnormally";
break;
case H323Connection::EndedByCapabilityExchange :
message = "Could not find common codec with " + remoteName;
break;
case H323Connection::EndedByNoAccept :
message = "Did not accept incoming call from " + remoteName;
break;
case H323Connection::EndedByAnswerDenied :
message = "Refused incoming call from " + remoteName;
break;
case H323Connection::EndedByNoUser :
message = "Gatekeeper could find user " + remoteName;
break;
case H323Connection::EndedByNoBandwidth :
message = "Call to " + remoteName + " aborted, insufficient bandwidth";
break;
case H323Connection::EndedByUnreachable :
message = remoteName + " could not be reached";
break;
case H323Connection::EndedByHostOffline :
message = remoteName + " is not online";
break;
case H323Connection::EndedByNoEndPoint :
message = "No phone running for " + remoteName;
break;
case H323Connection::EndedByConnectFail :
message = "Transport error calling " + remoteName;
break;
default :
PTimeInterval timeInt = PTime() - connection.GetConnectionStartTime() ;
message = "Goodbye " + remoteName;
if (IsInCall())
message += ". Duration: " + timeInt.AsString(0);
}
#if defined(HAS_IXJ)
lidThread.RingPhone(FALSE);
#endif
OnConnectionCleared(message);
}
//When a connection to a remote computer is created, this routine is called lots
//of times (4). We want to avoid displaying 4 Critical error messages.
//The variable firstErrorOpenAudioChannel is used to do this.
BOOL MainUi::OpenAudioChannel(H323Connection & connection,
BOOL isEncoding,
unsigned bufferSize,
H323AudioCodec & codec)
{
#if defined(HAS_IXJ)
if (lidThread.lid.IsOpen()) {
// PTRACE(2, "ep\tAttaching " << lidThread.GetDeviceName() << " to codec");
if (!codec.AttachChannel(new OpalLineChannel(lidThread.lid, OpalIxJDevice::POTSLine, codec)))
return FALSE;
}
else
#endif
if (!H323EndPoint::OpenAudioChannel(connection, isEncoding, bufferSize, codec)) {
PStringStream str;
if (isEncoding)
str << GetSoundChannelRecordDevice();
else
str << GetSoundChannelPlayDevice();
PString thisMessage = "Sound device \"" + str + "\" could not be opened.\n\n" +
"Check:\n" +
" 1)Full duplex device, \n" +
" 2)permissions" ;
if (firstErrorOpenAudioChannel) {
firstErrorOpenAudioChannel = FALSE;
DisplayCriticalError(thisMessage) ;
}
return FALSE;
}
codec.SetSilenceDetectionMode(audioOpts.GetDisableSilence() ?
H323AudioCodec::NoSilenceDetection :
H323AudioCodec::AdaptiveSilenceDetection );
PChannel *channel = codec.GetRawDataChannel();
audioOpts.AttachAudioChannel(isEncoding, channel);
if (isEncoding)
audioOpts.VolumeMicrophoneChange();
else
audioOpts.VolumeSpeakerChange();
return TRUE;
}
BOOL MainUi::OpenVideoChannel(H323Connection & connection,
BOOL isEncoding,
H323VideoCodec & codec)
{
CpVideoChannel * channel;
channel = isEncoding ? transmitVideoChannel : receiveVideoChannel;
if (isEncoding) {
codec.SetTxQualityLevel(videoOpts.GetTransmitQuality());
codec.SetBackgroundFill(4); //The videoFill parameter in ohphone);
codec.SetMaxBitRate(0); // this disables bitrate control
videoOpts.AttachVideoCodec(&codec);
}
//Select false, do NOT delete video channel on closing codec.
return codec.AttachChannel(channel, FALSE);
}
//
// if gateway is empty, dest is assumed to be IP address[:port]
// if gateway is non-empty,
// - gateway is assumed to be an IP address[:port]port,
// - dest is an e164 address which is passed to the gateway.
//
void MainUi::MakeOutgoingCall(const PString & dest,
const PString & gateway)
{
UpdateNatTraversalAddress();
DisplayMessage("Call " + dest);
PString fullAddress;
if (!gateway.IsEmpty()) {
fullAddress = gateway;
fullAddress = dest.Trim() + '@' + fullAddress;
} else
fullAddress = dest;
UpdateToolButtonConnect(true);
if (!MakeCall(fullAddress, currentCallToken)) {
DisplayMessage("Cannot make call to \"" + fullAddress + "\"");
return;
}
epState = epConnectingCall;
}
void MainUi::StartCall(const PString & ostr)
{
MakeOutgoingCall(ostr, PString());
return;
}
void MainUi::StartTerminationProcess()
{
applicationIsExiting = TRUE;
videoOpts.SaveSettings();
audioOpts.SaveSettings();
connectOpts.SaveSettings();
ClearAllCalls();
#ifdef HAS_IXJ
lidThread.TerminateThread();
lidThread.WaitForTermination();
#endif
epState = epDialTone;
SendDieMessageToWindow(eAddressBook);
SendDieMessageToWindow(eAudioProperties);
SendDieMessageToWindow(eSettings);
SendDieMessageToWindow(eStatistics);
SendDieMessageToWindow(eVideoProperties);
DeleteLocalVideoDisplayThread();
DeleteVideoDisplay();
connectOpts.CloseCurrentTraceFile();
}
void MainUi::ExitCurrentCall()
{
StopCallAnswer();
if ((epState == epDialTone) || (epState == epNoTone))
return;
if (!currentCallToken.IsEmpty())
DisplayMessage("Closing call with " + currentCallToken);
ClearAllCalls();
}
void MainUi::OpenStatistics_slot()
{
if (CPhone::Current().GetWindow(eStatistics) != NULL)
return;
Statistics * dialogStatistics = new Statistics();
dialogStatistics->show();
}
BOOL MainUi::SearchForAGatekeeper(PString gkName)
{
BOOL foundGk = FALSE;
if(gkName.IsEmpty()) {
//Search for a gatekeeper of unknown name.
DisplayMessage("Searching for gatekeeper");
foundGk = DiscoverGatekeeper(new H323TransportUDP(*this));
} else {
//Search for gatekeeper of known name.
DisplayMessage("Search for \"" + gkName + "\"");
foundGk = LocateGatekeeper(gkName);
}
if (foundGk) {
PStringStream str;
str << *gatekeeper;
DisplayMessage("Gatekeeper \"" + str + "\" found");
connectOpts.gatekeeperName = str;
} else {
if(gkName.IsEmpty())
DisplayMessage("Sorry: Gatekeeper discovery failed");
else
DisplayMessage("Gatekeeper \"" + gkName + "\" not found");
}
return foundGk;
}
void MainUi::AnswerCall(H323Connection::AnswerCallResponse response)
{
if (epState != epAnsweringCall)
return;
//Make absolutely certain, "Call Answer Y/N" has died.
StopCallAnswer();
H323Connection * connection = FindConnectionWithLock(currentCallToken);
if (connection == NULL)
return;
connection->AnsweringCall(response);
connection->Unlock();
if (response == H323Connection::AnswerCallNow)
epState = epCallInProgress;
else
epState = epCallHungup;
}
void MainUi::SendDieMessageToWindow(enum WindowName name)
{
QWidget *dialog = CPhone::Current().GetWindow(name);
if (dialog != NULL)
QApplication::sendEvent(dialog, new QCustomEvent(CUSTOM_EVENT_DIE));
}
void MainUi::StopCallAnswer()
{
SendDieMessageToWindow(eCallAnswer);
}
BOOL MainUi::SetDisableSilenceDetection(BOOL disableSilence)
{
SetSilenceDetectionMode(disableSilence ?
H323AudioCodec::NoSilenceDetection :
H323AudioCodec::AdaptiveSilenceDetection );
return TRUE;
}
BOOL MainUi::SetEchoCancellation(PString newEchoCancellation)
{
#if defined(HAS_IXJ)
PStringArray names = GetAvailableEchoCancNames();
for (PINDEX i = 0; i < names.GetSize(); i++)
if (strcmp(newEchoCancellation, names[i]) == 0) {
return lidThread.SetEchoCancellation(i);
}
#endif
return FALSE;
};
PStringArray MainUi::GetAvailableDeviceNames()
{
return soundCardNames + ixjCardNames;
}
PStringArray MainUi::GetAvailableEchoCancNames()
{
const char *cNames[] = {"Off", "Low", "Medium", "High", "Auto AEC", "Auto AEC/AGC"};
PStringArray names(6, cNames, FALSE);
return names;
}
void MainUi::SetSoundChannelBufferDepth(unsigned int newDepth)
{
H323EndPoint::SetSoundChannelBufferDepth(newDepth);
}
void MainUi::SetAudioJitterDelay(unsigned int low, unsigned int high)
{
H323EndPoint::SetAudioJitterDelay(low, high);
}
BOOL MainUi::SetSoundChannelRecordDevice(const PString &newDevice)
{
return H323EndPoint::SetSoundChannelRecordDevice(newDevice);
}
BOOL MainUi::SetSoundChannelPlayDevice(const PString &newDevice)
{
return H323EndPoint::SetSoundChannelPlayDevice(newDevice);
}
void MainUi::UpdateNatTraversalAddress()
{
PIPSocket::Address ip;
if (connectOpts.doNatTraversal) {
if (!PIPSocket::GetHostAddress(connectOpts.externalNatAddress, ip)) {
DisplayCriticalError("Sorry:: Failed to store address for " + connectOpts.externalNatAddress);
masqAddress = 0;
} else
masqAddress = ip;
} else
masqAddress = 0;
}
BOOL MainUi::MicroTelcoActivate(BOOL doActivate)
{
if (doActivate) {
SetLocalUserName(connectOpts.userName); /*Which removes old alisases */
AddAliasName(connectOpts.microTelcoAccount);
SetGatekeeperPassword(connectOpts.microTelcoPassword);
return SetGatekeeper("gk.microtelco.com", new H323TransportUDP(*this));
}
RemoveGatekeeper();
return TRUE;
}
PString MainUi::GetGatekeeperName()
{
H323Gatekeeper *gk = CPhone::GetUi().GetGatekeeper();
if (gk == NULL)
return PString();
return gk->GetName();
}
BOOL MainUi::InitialiseGatekeeper()
{
BOOL success = TRUE;
if (connectOpts.searchForGatekeeper)
return DiscoverGatekeeper(new H323TransportUDP(*this));
if (connectOpts.gatekeeperName.IsEmpty())
RemoveGatekeeper();
else
success = SetGatekeeper(connectOpts.gatekeeperName);
return success;
}
PString MainUi::GetGatekeeperRegistrationMessage()
{
H323Gatekeeper *gk = GetGatekeeper();
if (gk == NULL)
return "No gatekeeper in system";
switch (gk->GetRegistrationFailReason()) {
case H323Gatekeeper::RegistrationSuccessful:
return "Successful";
case H323Gatekeeper::UnregisteredLocally:
return "Unregistered locally";
case H323Gatekeeper::UnregisteredByGatekeeper:
return "Unregistered by gatekeeper";
case H323Gatekeeper::GatekeeperLostRegistration:
return "Lost registration";
case H323Gatekeeper::InvalidListener:
return "Invalid listener";
case H323Gatekeeper::DuplicateAlias:
return "Duplicate alias";
case H323Gatekeeper::SecurityDenied:
return "Security denied";
case H323Gatekeeper::TransportError:
return "Transport error";
default:
return "Unknown registration reason";
}
return "Unkonwn registration reason";
}
void MainUi::UpdateUserName()
{
PString newUserName = (const char *)connectOpts.userName;
SetLocalUserName(newUserName);
}
H323Connection *MainUi::GetCurrentConnectionWithLock()
{
return FindConnectionWithLock(currentCallToken);
}
H323Connection::AnswerCallResponse MainUi::AnswerCallConditional(const PString & caller, PString newCallToken)
{
currentCallToken = newCallToken;
if (connectOpts.autoAnswer) {
DisplayMessage("Commence call: " + PTime().AsString());
return H323Connection::AnswerCallNow;
}
epState = epAnsweringCall;
QueryCallAnswer(caller);
return H323Connection::AnswerCallPending;
}
void MainUi::HandleHandsetDown(BOOL isDown)
{
#ifdef HAS_IXJ
DisplayMessage(lidThread.GetDeviceName() + " has gone " + (isDown ? "on" : "off") + " hook");
if (isDown) {
ExitCurrentCall();
epState = epNoTone;
} else {
if (CPhone::Current().GetWindow(eCallAnswer) != NULL)
QApplication::postEvent(this, new QCustomEvent(CALL_ANSWER_RESPONSE_YES));
else
epState = epDialTone;
}
#endif
}
syntax highlighted by Code2HTML, v. 0.9.1