📄 voipapp.cpp
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// Use of this sample source code is subject to the terms of the Microsoft
// license agreement under which you licensed this sample source code. If
// you did not accept the terms of the license agreement, you are not
// authorized to use this sample source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the LICENSE.RTF on your install media or the root of your tools installation.
// THE SAMPLE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES.
//
#include "VoIPApp.hpp"
#include "Common.hpp"
#include "rtcerr.h"
#include "UIManager.hpp"
#include "Debug.hpp"
#include "wininet.h"
#include "urlmon.h"
#include "CommonFunctions.hpp"
#include "VoIPCall.hpp"
#include "Settings.hpp"
#include "regext.h"
#include "NewResource.hpp"
#include "VoIPStore.h"
#include "SettingsApi.hpp"
#include "CommandAPI.hpp"
//Macro to make queryinterface nicer
#define QI(riid, interface, ppv) \
if ((riid) == __uuidof(interface)) \
{ \
(*ppv) = static_cast<interface *>(this); \
AddRef(); \
return S_OK; \
} \
/*------------------------------------------------------------------------------
HookswitchHotkeyState
Internal enum for identifying the hook event
------------------------------------------------------------------------------*/
enum HookswitchHotkeyState
{
e_hhsHookUp = 0,
e_hhsHookDown,
e_hhsSpeakerToggle
};
//key name for all the data
const WCHAR c_SIPRegKeyPath[] = L"System\\VoIP\\SIP";
//values:
//rtc will be initialized with the DWORD stored in this value
const WCHAR c_RTCInitializationFlags[] = L"RtcInitFlags";
//If this DWORD is non-zero, we will enable port 5060 for incoming SIP traffic
const WCHAR c_EnablePort5060[] = L"EnablePort5060";
//If this DWORD is non-zero, sessions will be created with the "fail on redirect" flag
const WCHAR c_FailOnRedirectEnabled[] = L"OutgoingFailOn302";
//indicate the maximum number of calls that are allowed simultanenously
const WCHAR c_MaxNumberOfCalls[] = L"MaxNumberOfCalls";
//default maximum number of calls taht are allowed simultaneously
const int c_DefaultMaxNumberOfCalls = 4;
/*------------------------------------------------------------------------------
GetSIPSetting
Read a SIP setting from the registry
Parameters:
pSettingName: The setting name
Returns (DWORD): Value from registry or 0 if the value doesn't exist
------------------------------------------------------------------------------*/
DWORD GetSIPSetting(
__in const WCHAR* pSettingName
)
{
ASSERT(pSettingName);
DWORD Value = 0;
RegistryGetDWORD(
HKEY_LOCAL_MACHINE,
c_SIPRegKeyPath,
pSettingName,
&Value
);
return Value;
}
/*------------------------------------------------------------------------------
GetRTCInitializationFlags
Get the flag value to initialize RTC with - please see the RTC initialization
flags in the documentation.
- Also does a quick check to make sure the values are valid...
------------------------------------------------------------------------------*/
LONG GetRTCInitializationFlags()
{
DWORD RegValue = GetSIPSetting(c_RTCInitializationFlags);
//if prefer_static_port is set, symmetric signalling has to be set as well
if (RegValue & RTCIF_PREFER_STATIC_PORT_FOR_SYMMETRIC_UDP)
{
RegValue |= RTCIF_ENABLE_SYMMETRIC_UDP_SIGNALING;
}
return static_cast<LONG>(RegValue);
}
/*------------------------------------------------------------------------------
GetRTCListenMode
Gets the RTC "listen mode" (based on registry settings),
which determine what ports to open for incoming SIP traffic
------------------------------------------------------------------------------*/
RTC_LISTEN_MODE GetRTCListenMode()
{
return (GetSIPSetting(c_EnablePort5060) ? RTCLM_BOTH : RTCLM_DYNAMIC);
}
/*------------------------------------------------------------------------------
GetRTCCreateSessionFlags
Get the flags passed into the CreateSession API taking
into account OEM settings from the registry
------------------------------------------------------------------------------*/
LONG GetRTCCreateSessionFlags()
{
return (GetSIPSetting(c_FailOnRedirectEnabled) ? RTCCS_FAIL_ON_REDIRECT : 0);
}
/*------------------------------------------------------------------------------
GetMaxNumberOfCalls
Get the max number of calls that are allowed simutanously
------------------------------------------------------------------------------*/
unsigned int GetMaxNumberOfCalls()
{
DWORD MaxNumber = 0;
HRESULT hr = RegistryGetDWORD(
HKEY_LOCAL_MACHINE,
c_SIPRegKeyPath,
c_MaxNumberOfCalls,
&MaxNumber
);
if (FAILED(hr))
{
return c_DefaultMaxNumberOfCalls;
}
if (MaxNumber < 2)
{
PHONEAPP_RETAILMSG(ZONE_PHONEAPP_ERROR, (L"The max number of calls specified in registry is less than 2!"));
return c_DefaultMaxNumberOfCalls;
}
return MaxNumber;
}
/*------------------------------------------------------------------------------
IsMuted
Helper function to determine the current mute status of RTC client
------------------------------------------------------------------------------*/
inline
bool IsMuted(
__in IRTCClient* pClient
)
{
if (pClient == NULL)
{
return false;
}
VARIANT_BOOL IsRTCMuted = VARIANT_FALSE;
pClient->get_AudioMuted(RTCAD_MICROPHONE, &IsRTCMuted);
return (IsRTCMuted == VARIANT_TRUE);
}
bool ShouldBeVisible(
const WCHAR* c_pCommandLine
)
{
static const WCHAR sc_Parameter[] = L"-n";
if (c_pCommandLine == NULL ||
c_pCommandLine[0] == NULL)
{
return true;
}
if (PhoneAppUtilities_t::InvStrCmpNI(
c_pCommandLine,
sc_Parameter,
ARRAYSIZE(sc_Parameter)
)== 0)
{
return false;
}
return true;
}
/*------------------------------------------------------------------------------
VoIPApp_t::VoIPApp_t
Constructor for the app class
------------------------------------------------------------------------------*/
VoIPApp_t::VoIPApp_t()
{
m_AudioMode = e_vamIdle;
m_HookSwitchIsUp = false;
m_fAlreadyRefreshed = TRUE;
m_vkLastKeyPressed = -1;
m_fWaitingForPressAndHold = FALSE;
m_PlayingProgressTone = false;
m_DoNotPlayDialTone = false;
m_OffHookByMakingCall = false;
DWORD dwTick = GetTickCount();
m_tickLastKeydown = dwTick;
m_tickLastUserAction = dwTick;
//intialize the newly added varaibles for Yamazaki
m_cpRTCClient = NULL;
m_cpConnectionPt = NULL;
m_NotificationWindow = NULL;
m_ConnectionPtCookie = 0;
m_MaxNumberOfCalls = c_DefaultMaxNumberOfCalls;
m_PendingAuthAction = ActionInvalid;
}
VoIPApp_t::~VoIPApp_t()
{
if (m_NotificationWindow)
{
DestroyWindow(m_NotificationWindow);
m_NotificationWindow = NULL;
}
UnregisterClass(
WNDCLASS_PHONEAPP,
GlobalData_t::s_ModuleInstance
);
ASSERT(m_CallList.size() == 0);
if (m_cpRTCClient != NULL)
{
ASSERT(0);
Uninitialize();
}
}
HRESULT
VoIPApp_t::ForegroundExistingApp(
void
)
{
if (IsOffHook())
{
// The phone is off-hook, simulate a hook mode change
// to force an update of the UI
m_UIManager.OnHookModeChange(false);
}
return S_OK;
}
// IUnknown implementation
ULONG VoIPApp_t::AddRef()
{
return ++m_cRefs;
}
ULONG VoIPApp_t::Release()
{
//not a real COM object - release does not delete the object
m_cRefs--;
ASSERT(m_cRefs >= 0);
return m_cRefs;
}
HRESULT VoIPApp_t::QueryInterface(
REFIID riid,
VOID** ppvObj
)
{
if (! ppvObj)
{
ASSERT(FALSE);
return E_POINTER;
}
if (riid == IID_IUnknown)
{
(*ppvObj) = static_cast<IUnknown*>(static_cast<IRTCEventNotification*>(this));
AddRef();
return S_OK;
}
QI(riid, IRTCEventNotification, ppvObj)
return E_NOINTERFACE;
}
/*------------------------------------------------------------------------------
VoIPApp_t::Shutdown
Begins the shutdown process for the application
Returns (HRESULT):
------------------------------------------------------------------------------*/
HRESULT VoIPApp_t::Shutdown()
{
//uninitialize the voip manager - if we can't pretend the uninitialization already happened
PostMessage(NULL, WM_CLOSE, 0, 0);
return S_OK;
}
/*------------------------------------------------------------------------------
VoIPApp_t::EnsureOffHook
Ensures that the phone is off hook right now
if the phone is not offhook - simulates a speaker-phone press
Returns (HRESULT): indicating success or failure
------------------------------------------------------------------------------*/
HRESULT VoIPApp_t::EnsureOffHook()
{
//if we are already offhook, do nothing
if (m_AudioMode != e_vamIdle)
{
return S_FALSE;
}
//otherwise simulate the speaker toggle being pressed
return OnHookModeChange(HotKeys_t::vkSpeaker, FALSE); //FALSE means KEYDOWN event
}
/*------------------------------------------------------------------------------
VoIPApp_t::PlayProgressToneForDisconnectedCall
If a call disconnects for a non-normal reason (e.g. busy, bad number etc),
play the appropriate progress tone for the call
Parameters:
pCall: The call that was disconnected
pfPlayingTone: indicate if it is playing any tone for disconnect or not
Returns (HRESULT): indicating success or failure
------------------------------------------------------------------------------*/
HRESULT
VoIPApp_t::PlayProgressToneForDisconnectedCall(
Call_t* pCall,
bool* pPlayingTone
)
{
if (pCall == NULL || pPlayingTone == NULL)
{
return E_INVALIDARG;
}
HRESULT hr = S_OK;
DWORD NetworkStatus = pCall->GetNetworkStatus();
AudioManager_t::ProgressToneType_e ProgressToneType = AudioManager_t::ProgressToneInvalid;
if (FAILED(NetworkStatus))
{
switch (NetworkStatus)
{
case RTC_E_STATUS_CLIENT_BUSY_HERE:
case RTC_E_STATUS_GLOBAL_BUSY_EVERYWHERE:
ProgressToneType = AudioManager_t::ProgressToneClientBusy;
break;
default:
ProgressToneType = AudioManager_t::ProgressToneReorder;
break;
}
hr = PlayProgressTone(ProgressToneType);
*pPlayingTone = true;
}
else
{
hr = StopActiveTone();
*pPlayingTone = false;
}
return hr;
}
/*------------------------------------------------------------------------------
VoIPApp_t::InitializeHookState
Initializes the internal state of the hookswitch on startup
Returns (HRESULT):
------------------------------------------------------------------------------*/
HRESULT VoIPApp_t::InitializeHookState()
{
ASSERT(m_AudioMode == e_vamIdle);
HRESULT hr = S_FALSE;
if (GetAsyncKeyState(HotKeys_t::GetHotKey(HotKeys_t::vkHookSwitch)) & 0x80)
{
m_HookSwitchIsUp = true;
//Simulate a press
hr = OnHookModeChange(HotKeys_t::vkHookSwitch, FALSE); //false means key down
}
else
{
m_HookSwitchIsUp = false;
}
return hr;
}
/*------------------------------------------------------------------------------
VoIPApp_t::RespondToHotKey
Handle a hotkey press
------------------------------------------------------------------------------*/
LRESULT VoIPApp_t::RespondToHotKey(
INT HotkeyId,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -