diff --git a/pjsip-apps/build/activex-pjsua.dsp b/pjsip-apps/build/activex-pjsua.dsp new file mode 100644 index 000000000..6791a89c7 --- /dev/null +++ b/pjsip-apps/build/activex-pjsua.dsp @@ -0,0 +1,346 @@ +# Microsoft Developer Studio Project File - Name="activex_pjsua" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=activex_pjsua - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "activex-pjsua.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "activex-pjsua.mak" CFG="activex_pjsua - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "activex_pjsua - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "activex_pjsua - Win32 Unicode Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "activex_pjsua - Win32 Release MinSize" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "activex_pjsua - Win32 Release MinDependency" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "activex_pjsua - Win32 Unicode Release MinSize" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "activex_pjsua - Win32 Unicode Release MinDependency" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "activex_pjsua - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "./output/activex-pjsua-i386-debug" +# PROP BASE Intermediate_Dir "./output/activex-pjsua-i386-debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "./output/activex-pjsua-i386-debug" +# PROP Intermediate_Dir "./output/activex-pjsua-i386-debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /Gm /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /Yu"stdafx.h" /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /ZI /Od /D "_DEBUG" /D "_MBCS" /D "WIN32" /D "_WINDOWS" /D "_USRDLL" /D PJ_M_I386=1 /D PJ_WIN32=1 /FR /Yu"stdafx.h" /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386 /pdbtype:sept +# ADD LINK32 dsound.lib dxguid.lib netapi32.lib mswsock.lib ws2_32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386 /pdbtype:sept +# Begin Custom Build - Performing registration +OutDir=.\./output/activex-pjsua-i386-debug +TargetPath=.\output\activex-pjsua-i386-debug\activex-pjsua.dll +InputPath=.\output\activex-pjsua-i386-debug\activex-pjsua.dll +SOURCE="$(InputPath)" + +"$(OutDir)\regsvr32.trg" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + regsvr32 /s /c "$(TargetPath)" + echo regsvr32 exec. time > "$(OutDir)\regsvr32.trg" + +# End Custom Build + +!ELSEIF "$(CFG)" == "activex_pjsua - Win32 Unicode Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir ".\output\activex-pjsua-i386-unicode-debug" +# PROP BASE Intermediate_Dir ".\output\activex-pjsua-i386-unicode-debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir ".\output\activex-pjsua-i386-unicode-debug" +# PROP Intermediate_Dir ".\output\activex-pjsua-i386-unicode-debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /Gm /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_USRDLL" /D "_UNICODE" /Yu"stdafx.h" /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /ZI /Od /D "_DEBUG" /D "_UNICODE" /D "WIN32" /D "_WINDOWS" /D "_USRDLL" /D PJ_M_I386=1 /D PJ_WIN32=1 /Yu"stdafx.h" /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386 /pdbtype:sept +# ADD LINK32 dsound.lib dxguid.lib netapi32.lib mswsock.lib ws2_32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386 /pdbtype:sept +# Begin Custom Build - Performing registration +OutDir=.\output\activex-pjsua-i386-unicode-debug +TargetPath=.\output\activex-pjsua-i386-unicode-debug\activex-pjsua.dll +InputPath=.\output\activex-pjsua-i386-unicode-debug\activex-pjsua.dll +SOURCE="$(InputPath)" + +"$(OutDir)\regsvr32.trg" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + if "%OS%"=="" goto NOTNT + if not "%OS%"=="Windows_NT" goto NOTNT + regsvr32 /s /c "$(TargetPath)" + echo regsvr32 exec. time > "$(OutDir)\regsvr32.trg" + goto end + :NOTNT + echo Warning : Cannot register Unicode DLL on Windows 95 + :end + +# End Custom Build + +!ELSEIF "$(CFG)" == "activex_pjsua - Win32 Release MinSize" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir ".\output\activex-pjsua-i386-ReleaseMinSize" +# PROP BASE Intermediate_Dir ".\output\activex-pjsua-i386-ReleaseMinSize" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir ".\output\activex-pjsua-i386-ReleaseMinSize" +# PROP Intermediate_Dir ".\output\activex-pjsua-i386-ReleaseMinSize" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /O1 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "_ATL_DLL" /D "_ATL_MIN_CRT" /Yu"stdafx.h" /FD /c +# ADD CPP /nologo /MT /W3 /O1 /D "NDEBUG" /D "_MBCS" /D "_ATL_DLL" /D "_ATL_MIN_CRT" /D "WIN32" /D "_WINDOWS" /D "_USRDLL" /D PJ_M_I386=1 /D PJ_WIN32=1 /Yu"stdafx.h" /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386 +# ADD LINK32 dsound.lib dxguid.lib netapi32.lib mswsock.lib ws2_32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386 +# Begin Custom Build - Performing registration +OutDir=.\output\activex-pjsua-i386-ReleaseMinSize +TargetPath=.\output\activex-pjsua-i386-ReleaseMinSize\activex-pjsua.dll +InputPath=.\output\activex-pjsua-i386-ReleaseMinSize\activex-pjsua.dll +SOURCE="$(InputPath)" + +"$(OutDir)\regsvr32.trg" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + regsvr32 /s /c "$(TargetPath)" + echo regsvr32 exec. time > "$(OutDir)\regsvr32.trg" + +# End Custom Build + +!ELSEIF "$(CFG)" == "activex_pjsua - Win32 Release MinDependency" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir ".\output\activex-pjsua-i386-ReleaseMinDependency" +# PROP BASE Intermediate_Dir ".\output\activex-pjsua-i386-ReleaseMinDependency" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir ".\output\activex-pjsua-i386-ReleaseMinDependency" +# PROP Intermediate_Dir ".\output\activex-pjsua-i386-ReleaseMinDependency" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /O1 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "_ATL_STATIC_REGISTRY" /D "_ATL_MIN_CRT" /Yu"stdafx.h" /FD /c +# ADD CPP /nologo /MT /W3 /O1 /D "NDEBUG" /D "_MBCS" /D "_ATL_STATIC_REGISTRY" /D "_ATL_MIN_CRT" /D "WIN32" /D "_WINDOWS" /D "_USRDLL" /D PJ_M_I386=1 /D PJ_WIN32=1 /Yu"stdafx.h" /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386 +# ADD LINK32 dsound.lib dxguid.lib netapi32.lib mswsock.lib ws2_32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386 +# Begin Custom Build - Performing registration +OutDir=.\output\activex-pjsua-i386-ReleaseMinDependency +TargetPath=.\output\activex-pjsua-i386-ReleaseMinDependency\activex-pjsua.dll +InputPath=.\output\activex-pjsua-i386-ReleaseMinDependency\activex-pjsua.dll +SOURCE="$(InputPath)" + +"$(OutDir)\regsvr32.trg" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + regsvr32 /s /c "$(TargetPath)" + echo regsvr32 exec. time > "$(OutDir)\regsvr32.trg" + +# End Custom Build + +!ELSEIF "$(CFG)" == "activex_pjsua - Win32 Unicode Release MinSize" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir ".\output\activex-pjsua-i386-ReleaseUMinSize" +# PROP BASE Intermediate_Dir ".\output\activex-pjsua-i386-ReleaseUMinSize" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir ".\output\activex-pjsua-i386-ReleaseUMinSize" +# PROP Intermediate_Dir ".\output\activex-pjsua-i386-ReleaseUMinSize" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /O1 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_USRDLL" /D "_UNICODE" /D "_ATL_DLL" /D "_ATL_MIN_CRT" /Yu"stdafx.h" /FD /c +# ADD CPP /nologo /MT /W3 /O1 /D "NDEBUG" /D "_UNICODE" /D "_ATL_DLL" /D "_ATL_MIN_CRT" /D "WIN32" /D "_WINDOWS" /D "_USRDLL" /D PJ_M_I386=1 /D PJ_WIN32=1 /Yu"stdafx.h" /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386 +# ADD LINK32 dsound.lib dxguid.lib netapi32.lib mswsock.lib ws2_32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386 +# Begin Custom Build - Performing registration +OutDir=.\output\activex-pjsua-i386-ReleaseUMinSize +TargetPath=.\output\activex-pjsua-i386-ReleaseUMinSize\activex-pjsua.dll +InputPath=.\output\activex-pjsua-i386-ReleaseUMinSize\activex-pjsua.dll +SOURCE="$(InputPath)" + +"$(OutDir)\regsvr32.trg" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + if "%OS%"=="" goto NOTNT + if not "%OS%"=="Windows_NT" goto NOTNT + regsvr32 /s /c "$(TargetPath)" + echo regsvr32 exec. time > "$(OutDir)\regsvr32.trg" + goto end + :NOTNT + echo Warning : Cannot register Unicode DLL on Windows 95 + :end + +# End Custom Build + +!ELSEIF "$(CFG)" == "activex_pjsua - Win32 Unicode Release MinDependency" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir ".\output\activex-pjsua-i386-ReleaseUMinDependency" +# PROP BASE Intermediate_Dir ".\output\activex-pjsua-i386-ReleaseUMinDependency" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir ".\output\activex-pjsua-i386-ReleaseUMinDependency" +# PROP Intermediate_Dir ".\output\activex-pjsua-i386-ReleaseUMinDependency" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /O1 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_USRDLL" /D "_UNICODE" /D "_ATL_STATIC_REGISTRY" /D "_ATL_MIN_CRT" /Yu"stdafx.h" /FD /c +# ADD CPP /nologo /MT /W3 /O1 /D "NDEBUG" /D "_UNICODE" /D "_ATL_STATIC_REGISTRY" /D "_ATL_MIN_CRT" /D "WIN32" /D "_WINDOWS" /D "_USRDLL" /D PJ_M_I386=1 /D PJ_WIN32=1 /Yu"stdafx.h" /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386 +# ADD LINK32 dsound.lib dxguid.lib netapi32.lib mswsock.lib ws2_32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386 +# Begin Custom Build - Performing registration +OutDir=.\output\activex-pjsua-i386-ReleaseUMinDependency +TargetPath=.\output\activex-pjsua-i386-ReleaseUMinDependency\activex-pjsua.dll +InputPath=.\output\activex-pjsua-i386-ReleaseUMinDependency\activex-pjsua.dll +SOURCE="$(InputPath)" + +"$(OutDir)\regsvr32.trg" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + if "%OS%"=="" goto NOTNT + if not "%OS%"=="Windows_NT" goto NOTNT + regsvr32 /s /c "$(TargetPath)" + echo regsvr32 exec. time > "$(OutDir)\regsvr32.trg" + goto end + :NOTNT + echo Warning : Cannot register Unicode DLL on Windows 95 + :end + +# End Custom Build + +!ENDIF + +# Begin Target + +# Name "activex_pjsua - Win32 Debug" +# Name "activex_pjsua - Win32 Unicode Debug" +# Name "activex_pjsua - Win32 Release MinSize" +# Name "activex_pjsua - Win32 Release MinDependency" +# Name "activex_pjsua - Win32 Unicode Release MinSize" +# Name "activex_pjsua - Win32 Unicode Release MinDependency" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE="..\src\activex-pjsua\activex-pjsua.cpp" +# End Source File +# Begin Source File + +SOURCE="..\src\activex-pjsua\activex-pjsua.def" +# End Source File +# Begin Source File + +SOURCE="..\src\activex-pjsua\activex-pjsua.idl" +# ADD MTL /tlb "..\src\activex-pjsua\activex-pjsua.tlb" /h "../src/activex-pjsua/activex-pjsua.h" /iid "../src/activex-pjsua/activex-pjsua_i.c" /Oicf +# End Source File +# Begin Source File + +SOURCE="..\src\activex-pjsua\activex-pjsua.rc" +# End Source File +# Begin Source File + +SOURCE="..\src\activex-pjsua\app.cpp" +# End Source File +# Begin Source File + +SOURCE="..\src\activex-pjsua\pjsua-structs.idl" +# ADD MTL /h "../src/activex-pjsua/pjsua-structs.h" +# End Source File +# Begin Source File + +SOURCE="..\src\activex-pjsua\stdafx.cpp" +# ADD CPP /Yc"stdafx.h" +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE="..\src\activex-pjsua\activex-pjsua.h" +# End Source File +# Begin Source File + +SOURCE="..\src\activex-pjsua\activex-pjsuaCP.h" +# End Source File +# Begin Source File + +SOURCE="..\src\activex-pjsua\app.h" +# End Source File +# Begin Source File + +SOURCE="..\src\activex-pjsua\pjsua.h" +# End Source File +# Begin Source File + +SOURCE="..\src\activex-pjsua\resource.h" +# End Source File +# Begin Source File + +SOURCE="..\src\activex-pjsua\stdafx.h" +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# Begin Source File + +SOURCE="..\src\activex-pjsua\app.rgs" +# End Source File +# End Group +# End Target +# End Project diff --git a/pjsip-apps/build/pjsip_apps.dsw b/pjsip-apps/build/pjsip_apps.dsw index 240e30a5f..a21da5b4d 100644 --- a/pjsip-apps/build/pjsip_apps.dsw +++ b/pjsip-apps/build/pjsip_apps.dsw @@ -3,6 +3,42 @@ Microsoft Developer Studio Workspace File, Format Version 6.00 ############################################################################### +Project: "activex_pjsua"=".\activex-pjsua.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name pjlib + End Project Dependency + Begin Project Dependency + Project_Dep_Name pjlib_util + End Project Dependency + Begin Project Dependency + Project_Dep_Name pjmedia + End Project Dependency + Begin Project Dependency + Project_Dep_Name pjmedia_codec + End Project Dependency + Begin Project Dependency + Project_Dep_Name pjsip_core + End Project Dependency + Begin Project Dependency + Project_Dep_Name pjsip_simple + End Project Dependency + Begin Project Dependency + Project_Dep_Name pjsip_ua + End Project Dependency + Begin Project Dependency + Project_Dep_Name pjsua_lib + End Project Dependency +}}} + +############################################################################### + Project: "pjlib"="..\..\pjlib\build\pjlib.dsp" - Package Owner=<4> Package=<5> diff --git a/pjsip-apps/src/activex-pjsua/activex-pjsua.cpp b/pjsip-apps/src/activex-pjsua/activex-pjsua.cpp new file mode 100644 index 000000000..2736affda --- /dev/null +++ b/pjsip-apps/src/activex-pjsua/activex-pjsua.cpp @@ -0,0 +1,72 @@ +// ActivePJSUA.cpp : Implementation of DLL Exports. + + +// Note: Proxy/Stub Information +// To build a separate proxy/stub DLL, +// run nmake -f ActivePJSUAps.mk in the project directory. + +#include "stdafx.h" +#include "resource.h" +#include +#include "activex-pjsua.h" + +#include "activex-pjsua_i.c" +#include "app.h" + + +CComModule _Module; + +BEGIN_OBJECT_MAP(ObjectMap) +OBJECT_ENTRY(CLSID_App, CApp) +END_OBJECT_MAP() + +///////////////////////////////////////////////////////////////////////////// +// DLL Entry Point + +extern "C" +BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID /*lpReserved*/) +{ + if (dwReason == DLL_PROCESS_ATTACH) + { + _Module.Init(ObjectMap, hInstance, &LIBID_ACTIVEPJSUALib); + DisableThreadLibraryCalls(hInstance); + } + else if (dwReason == DLL_PROCESS_DETACH) + _Module.Term(); + return TRUE; // ok +} + +///////////////////////////////////////////////////////////////////////////// +// Used to determine whether the DLL can be unloaded by OLE + +STDAPI DllCanUnloadNow(void) +{ + return (_Module.GetLockCount()==0) ? S_OK : S_FALSE; +} + +///////////////////////////////////////////////////////////////////////////// +// Returns a class factory to create an object of the requested type + +STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv) +{ + return _Module.GetClassObject(rclsid, riid, ppv); +} + +///////////////////////////////////////////////////////////////////////////// +// DllRegisterServer - Adds entries to the system registry + +STDAPI DllRegisterServer(void) +{ + // registers object, typelib and all interfaces in typelib + return _Module.RegisterServer(TRUE); +} + +///////////////////////////////////////////////////////////////////////////// +// DllUnregisterServer - Removes entries from the system registry + +STDAPI DllUnregisterServer(void) +{ + return _Module.UnregisterServer(TRUE); +} + + diff --git a/pjsip-apps/src/activex-pjsua/activex-pjsua.def b/pjsip-apps/src/activex-pjsua/activex-pjsua.def new file mode 100644 index 000000000..3ed6a66b6 --- /dev/null +++ b/pjsip-apps/src/activex-pjsua/activex-pjsua.def @@ -0,0 +1,9 @@ +; ActivePJSUA.def : Declares the module parameters. + +LIBRARY "activex-pjsua.DLL" + +EXPORTS + DllCanUnloadNow @1 PRIVATE + DllGetClassObject @2 PRIVATE + DllRegisterServer @3 PRIVATE + DllUnregisterServer @4 PRIVATE diff --git a/pjsip-apps/src/activex-pjsua/activex-pjsua.idl b/pjsip-apps/src/activex-pjsua/activex-pjsua.idl new file mode 100644 index 000000000..6b980efab --- /dev/null +++ b/pjsip-apps/src/activex-pjsua/activex-pjsua.idl @@ -0,0 +1,112 @@ +// ActivePJSUA.idl : IDL source for ActivePJSUA.dll +// + +// This file will be processed by the MIDL tool to +// produce the type library (ActivePJSUA.tlb) and marshalling code. + +import "oaidl.idl"; +import "ocidl.idl"; +import "../src/activex-pjsua/pjsua-structs.idl"; + + + [ + object, + uuid(93462247-DA4E-4602-817B-26BA0C824E23), + dual, + helpstring("IApp Interface"), + pointer_default(unique) + ] + interface IApp : IDispatch + { + [id(1), helpstring("method app_create")] HRESULT app_create([out,retval] Pj_Status *retStatus); + [id(2), helpstring("method app_default_config")] HRESULT app_default_config([out] Pjsua_Config *pConfig); + [id(3), helpstring("method app_test_config")] HRESULT app_test_config([in] Pjsua_Config *pConfig, [out,retval] BSTR *errmsg); + [id(4), helpstring("method app_init")] HRESULT app_init([in] Pjsua_Config *pConfig, [out,retval] Pj_Status *pStatus); + [id(5), helpstring("method app_start")] HRESULT app_start([out,retval] Pj_Status *retStatus); + [id(6), helpstring("method app_destroy")] HRESULT app_destroy([out,retval] Pj_Status *retStatus); + [id(7), helpstring("method call_get_max_count")] HRESULT call_get_max_count([out,retval] int *retCount); + [id(8), helpstring("method call_get_count")] HRESULT call_get_count([out,retval] int *retCount); + [id(9), helpstring("method call_is_active")] HRESULT call_is_active([in] int call_index, [out,retval] Pj_Bool *retVal); + [id(10), helpstring("method call_has_media")] HRESULT call_has_media([in] int call_index, [out,retval] Pj_Bool *pRet); + [id(11), helpstring("method call_get_info")] HRESULT call_get_info([in] int call_index, [out] Pjsua_Call_Info *pInfo, [out,retval] Pj_Status *pRet); + [id(12), helpstring("method call_make_call")] HRESULT call_make_call([in] int acc_index, [in,string] Pj_String dst_uri, [out] int *call_index, [out,retval] Pj_Status *pRet); + [id(13), helpstring("method call_answer")] HRESULT call_answer([in] int call_index, [in] int status_code, [out,retval] Pj_Status *pRet); + [id(14), helpstring("method call_hangup")] HRESULT call_hangup([in] int call_index, [out,retval] Pj_Status *pRet); + [id(15), helpstring("method call_set_hold")] HRESULT call_set_hold([in] int call_index, [out,retval] Pj_Status *pRet); + [id(16), helpstring("method call_release_hold")] HRESULT call_release_hold([in] int call_index, [out,retval] Pj_Status *pRet); + [id(17), helpstring("method call_xfer")] HRESULT call_xfer([in] int call_index, [in,string] Pj_String dst_uri, [out,retval] Pj_Status *pRet); + [id(18), helpstring("method call_dial_dtmf")] HRESULT call_dial_dtmf([in] int call_index, [in,string] Pj_String digits, [out,retval] Pj_Status *pRet); + [id(19), helpstring("method call_send_im")] HRESULT call_send_im([in] int call_index, [in,string] Pj_String text, [out,retval] Pj_Status *pRet); + [id(20), helpstring("method call_typing")] HRESULT call_typing([in] int call_index, [in] int is_typing, [out,retval] Pj_Status *pRet); + [id(21), helpstring("method call_hangup_all")] HRESULT call_hangup_all(); + [id(22), helpstring("method acc_get_count")] HRESULT acc_get_count([out,retval] int *pCount); + [id(23), helpstring("method acc_get_info")] HRESULT acc_get_info([in] int acc_index, [out] Pjsua_Acc_Info *pInfo, [out,retval] Pj_Status *pRet); + [id(24), helpstring("method acc_add")] HRESULT acc_add([in] Pjsua_Acc_Config *pConfig, [out] int *pAcc_Index, [out,retval] Pj_Status *pRet); + [id(25), helpstring("method acc_set_online_status")] HRESULT acc_set_online_status([in] int acc_index, [in] int is_online, [out,retval] Pj_Status *pRet); + [id(26), helpstring("method acc_set_registration")] HRESULT acc_set_registration([in] int acc_index, [in] int reg_active, [out,retval] Pj_Status *pRet); + [id(27), helpstring("method buddy_get_count")] HRESULT buddy_get_count([out,retval] int *pCount); + [id(28), helpstring("method buddy_get_info")] HRESULT buddy_get_info([in] int buddy_index, [out] Pjsua_Buddy_Info *pInfo, [out,retval] Pj_Status *pRet); + [id(29), helpstring("method buddy_add")] HRESULT buddy_add([in,string] Pj_String uri, [out] int *pBuddy_Index, [out,retval] Pj_Status *pRet); + [id(30), helpstring("method buddy_subscribe_pres")] HRESULT buddy_subscribe_pres([in] int buddy_index, [in] int subscribe, [out,retval] Pj_Status *pRet); + [id(31), helpstring("method im_send_text")] HRESULT im_send_text([in] int acc_index, [in,string] Pj_String dst_uri, [in,string] Pj_String text, [out,retval] Pj_Status *pRet); + [id(32), helpstring("method im_typing")] HRESULT im_typing([in] int acc_index, [in,string] Pj_URI dst_uri, [in] int is_typing, [out,retval] Pj_Status *pRet); + [id(33), helpstring("method conf_connect")] HRESULT conf_connect([in] int src_port, [in] int sink_port, [out,retval] Pj_Status *pRet); + [id(34), helpstring("method conf_disconnect")] HRESULT conf_disconnect([in] int src_port, [in] int sink_port, [out,retval] Pj_Status *pRet); + [id(35), helpstring("method player_create")] HRESULT player_create([in,string] Pj_String filename, [out] int *pPlayer_Id, [out,retval] Pj_Status *pRet); + [id(36), helpstring("method player_get_conf_port")] HRESULT player_get_conf_port([in] int player_id, [out,retval] int *pPort); + [id(37), helpstring("method player_set_pos")] HRESULT player_set_pos([in] int player_id, [in] int sample_pos, [out,retval] Pj_Status *pRet); + [id(38), helpstring("method player_destroy")] HRESULT player_destroy([in] int player_id, [out,retval] Pj_Status *pRet); + [id(39), helpstring("method recorder_create")] HRESULT recorder_create([in,string] Pj_String filename, [out] int *pRecorder_Id, [out,retval] Pj_Status *pRet); + [id(40), helpstring("method recorder_get_conf_port")] HRESULT recorder_get_conf_port([in] int recorder_id, [out,retval] int *pPort); + [id(41), helpstring("method recorder_destroy")] HRESULT recorder_destroy([in] int recorder_id, [out,retval] Pj_Status *pRet); + [id(42), helpstring("method app_load_config")] HRESULT app_load_config([in,string] Pj_String filename, [out] Pjsua_Config *pConfig, [out,retval] Pj_Status *pRet); + [id(43), helpstring("method app_save_config")] HRESULT app_save_config([in,string] Pj_String filename, [in] Pjsua_Config *pConfig, [out,retval] Pj_Status *pRet); + [id(44), helpstring("method app_get_current_config")] HRESULT app_get_current_config([out,retval] Pjsua_Config *pConfig); + [id(45), helpstring("method app_get_error_msg")] HRESULT app_get_error_msg([in] Pj_Status status, [out,retval] BSTR *errmsg); + [id(46), helpstring("method app_verify_sip_url")] HRESULT app_verify_sip_url([in,string] Pj_String uri, [out,retval] Pj_Status *pRet); + [id(47), helpstring("method call_get_textstat")] HRESULT call_get_textstat([in] int call_index, [out,retval] BSTR *textstat); + [id(48), helpstring("method app_handle_events")] HRESULT app_handle_events([in] int msec_timeout, [out,retval] int *pEvCount); + }; + +[ + uuid(11E70413-8434-41B6-A5B6-F7DF79FEFC1A), + version(1.0), + helpstring("ActivePJSUA 1.0 Type Library") +] +library ACTIVEPJSUALib +{ + importlib("stdole32.tlb"); + importlib("stdole2.tlb"); + + struct Pjsip_Cred_Info; + struct Pjsua_Acc_Config; + struct Pjsua_Config; + struct Pjsua_Call_Info; + struct Pjsua_Buddy_Info; + struct Pjsua_Acc_Info; + + [ + uuid(DC91CBCE-4B9E-4369-80B9-39341EEFD814), + helpstring("_IPjsuaEvents Interface") + ] + dispinterface _IPjsuaEvents + { + properties: + methods: + [id(1), helpstring("method OnCallState")] void OnCallState([in] int call_index, [in] Pjsua_Call_Info *pInfo); + [id(2), helpstring("method OnRegState")] void OnRegState([in] int acc_index); + [id(3), helpstring("method OnBuddyState")] void OnBuddyState([in] int buddy_index); + [id(4), helpstring("method OnIncomingPager")] void OnIncomingPager([in] int call_index, [in] BSTR fromUri, [in] BSTR toURI, [in] BSTR pagerText); + [id(5), helpstring("method OnTypingIndication")] void OnTypingIndication([in] int call_index, [in] BSTR fromUri, [in] BSTR toURI, [in] int isTyping); + }; + + [ + uuid(F89DA516-42E5-43A0-8EF7-A960BA386CAB), + helpstring("App Class") + ] + coclass App + { + [default] interface IApp; + [default, source] dispinterface _IPjsuaEvents; + }; +}; diff --git a/pjsip-apps/src/activex-pjsua/activex-pjsua.rc b/pjsip-apps/src/activex-pjsua/activex-pjsua.rc new file mode 100644 index 000000000..739867e6f --- /dev/null +++ b/pjsip-apps/src/activex-pjsua/activex-pjsua.rc @@ -0,0 +1,124 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "winres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "#include ""winres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "1 TYPELIB ""activex-pjsua.tlb""\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +#ifndef _MAC +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,0,0,1 + PRODUCTVERSION 1,0,0,1 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904B0" + BEGIN + VALUE "CompanyName", "\0" + VALUE "FileDescription", "ActivePJSUA Module\0" + VALUE "FileVersion", "1, 0, 0, 1\0" + VALUE "InternalName", "ActivePJSUA\0" + VALUE "LegalCopyright", "Copyright 2006\0" + VALUE "OriginalFilename", "ActivePJSUA.DLL\0" + VALUE "ProductName", "ActivePJSUA Module\0" + VALUE "ProductVersion", "1, 0, 0, 1\0" + VALUE "OLESelfRegister", "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + +#endif // !_MAC + + +///////////////////////////////////////////////////////////////////////////// +// +// REGISTRY +// + +IDR_APP REGISTRY DISCARDABLE "App.rgs" + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE DISCARDABLE +BEGIN + IDS_PROJNAME "ActivePJSUA" +END + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// +1 TYPELIB "activex-pjsua.tlb" + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/pjsip-apps/src/activex-pjsua/activex-pjsuaCP.h b/pjsip-apps/src/activex-pjsua/activex-pjsuaCP.h new file mode 100644 index 000000000..db150156b --- /dev/null +++ b/pjsip-apps/src/activex-pjsua/activex-pjsuaCP.h @@ -0,0 +1,151 @@ +#ifndef _ACTIVEXPJSUACP_H_ +#define _ACTIVEXPJSUACP_H_ + +//#import "C:\project\pjproject\pjsip-apps\src\activex-pjsua\activex-pjsua.tlb" raw_interfaces_only, raw_native_types, no_namespace, named_guids //"Import typelib" +template +class CProxy_IPjsuaEvents : public IConnectionPointImpl +{ + //Warning this class may be recreated by the wizard. +public: + VOID Fire_OnCallState(INT call_index, Pjsua_Call_Info * pInfo) + { + T* pT = static_cast(this); + int nConnectionIndex; + CComVariant* pvars = new CComVariant[2]; + int nConnections = m_vec.GetSize(); + HRESULT hr; + + IRecordInfo *pRI = NULL; + hr = GetRecordInfoFromGuids( LIBID_ACTIVEPJSUALib, + 1, 0, + 0, + IID_Pjsua_Call_Info, + &pRI ); + assert(SUCCEEDED(hr)); + + pvars[1] = call_index; + + VARIANT v; + memset(&v, 0, sizeof(v)); + v.vt = VT_RECORD; + v.pRecInfo = pRI; + v.pvRecord = pInfo; + + pvars[0] = v; + + for (nConnectionIndex = 0; nConnectionIndex < nConnections; nConnectionIndex++) + { + pT->Lock(); + CComPtr sp = m_vec.GetAt(nConnectionIndex); + pT->Unlock(); + IDispatch* pDispatch = reinterpret_cast(sp.p); + if (pDispatch != NULL) + { + + DISPPARAMS disp = { pvars, NULL, 2, 0 }; + hr = pDispatch->Invoke(0x1, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &disp, NULL, NULL, NULL); + } + } + delete[] pvars; + + } + VOID Fire_OnRegState(INT acc_index) + { + T* pT = static_cast(this); + int nConnectionIndex; + CComVariant* pvars = new CComVariant[1]; + int nConnections = m_vec.GetSize(); + + for (nConnectionIndex = 0; nConnectionIndex < nConnections; nConnectionIndex++) + { + pT->Lock(); + CComPtr sp = m_vec.GetAt(nConnectionIndex); + pT->Unlock(); + IDispatch* pDispatch = reinterpret_cast(sp.p); + if (pDispatch != NULL) + { + pvars[0] = acc_index; + DISPPARAMS disp = { pvars, NULL, 1, 0 }; + pDispatch->Invoke(0x2, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &disp, NULL, NULL, NULL); + } + } + delete[] pvars; + + } + VOID Fire_OnBuddyState(INT buddy_index) + { + T* pT = static_cast(this); + int nConnectionIndex; + CComVariant* pvars = new CComVariant[1]; + int nConnections = m_vec.GetSize(); + + for (nConnectionIndex = 0; nConnectionIndex < nConnections; nConnectionIndex++) + { + pT->Lock(); + CComPtr sp = m_vec.GetAt(nConnectionIndex); + pT->Unlock(); + IDispatch* pDispatch = reinterpret_cast(sp.p); + if (pDispatch != NULL) + { + pvars[0] = buddy_index; + DISPPARAMS disp = { pvars, NULL, 1, 0 }; + pDispatch->Invoke(0x3, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &disp, NULL, NULL, NULL); + } + } + delete[] pvars; + + } + VOID Fire_OnIncomingPager(INT call_index, BSTR fromUri, BSTR toURI, BSTR pagerText) + { + T* pT = static_cast(this); + int nConnectionIndex; + CComVariant* pvars = new CComVariant[4]; + int nConnections = m_vec.GetSize(); + + for (nConnectionIndex = 0; nConnectionIndex < nConnections; nConnectionIndex++) + { + pT->Lock(); + CComPtr sp = m_vec.GetAt(nConnectionIndex); + pT->Unlock(); + IDispatch* pDispatch = reinterpret_cast(sp.p); + if (pDispatch != NULL) + { + pvars[3] = call_index; + pvars[2] = fromUri; + pvars[1] = toURI; + pvars[0] = pagerText; + DISPPARAMS disp = { pvars, NULL, 4, 0 }; + pDispatch->Invoke(0x4, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &disp, NULL, NULL, NULL); + } + } + delete[] pvars; + + } + VOID Fire_OnTypingIndication(INT call_index, BSTR fromUri, BSTR toURI, INT isTyping) + { + T* pT = static_cast(this); + int nConnectionIndex; + CComVariant* pvars = new CComVariant[4]; + int nConnections = m_vec.GetSize(); + + for (nConnectionIndex = 0; nConnectionIndex < nConnections; nConnectionIndex++) + { + pT->Lock(); + CComPtr sp = m_vec.GetAt(nConnectionIndex); + pT->Unlock(); + IDispatch* pDispatch = reinterpret_cast(sp.p); + if (pDispatch != NULL) + { + pvars[3] = call_index; + pvars[2] = fromUri; + pvars[1] = toURI; + pvars[0] = isTyping; + DISPPARAMS disp = { pvars, NULL, 4, 0 }; + pDispatch->Invoke(0x5, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &disp, NULL, NULL, NULL); + } + } + delete[] pvars; + + } +}; +#endif \ No newline at end of file diff --git a/pjsip-apps/src/activex-pjsua/app.cpp b/pjsip-apps/src/activex-pjsua/app.cpp new file mode 100644 index 000000000..bbcb9a38d --- /dev/null +++ b/pjsip-apps/src/activex-pjsua/app.cpp @@ -0,0 +1,858 @@ +// App.cpp : Implementation of CApp +#include "stdafx.h" +#include +#include +#include "activex-pjsua.h" +#include "app.h" + + +///////////////////////////////////////////////////////////////////////////// +// CApp + +// {9CE3052A-7A32-4229-B31C-5E02E0667A77} +static const GUID IID_Pjsip_Cred_Info = +{ 0x9ce3052a, 0x7a32, 0x4229, { 0xb3, 0x1c, 0x5e, 0x2, 0xe0, 0x66, 0x7a, 0x77 } }; + +// {3B12B04F-6E48-46a7-B9E0-6C4BF1594A96} +static const GUID IID_Pjsua_Acc_Config = +{ 0x3b12b04f, 0x6e48, 0x46a7, { 0xb9, 0xe0, 0x6c, 0x4b, 0xf1, 0x59, 0x4a, 0x96 } }; + +// {E4B6573D-CF5E-484d-863F-ADAD5947FBE4} +static const GUID IID_Pjsua_Config = +{ 0xe4b6573d, 0xcf5e, 0x484d, { 0x86, 0x3f, 0xad, 0xad, 0x59, 0x47, 0xfb, 0xe4 } }; + +// {5043AC9E-A417-4f03-927E-D7AE52DDD064} +static const GUID IID_Pjsua_Call_Info = +{ 0x5043ac9e, 0xa417, 0x4f03, { 0x92, 0x7e, 0xd7, 0xae, 0x52, 0xdd, 0xd0, 0x64 } }; + +// {2729F0BC-8A5E-4f3f-BC29-C1740A86393A} +static const GUID IID_Pjsua_Buddy_Info = +{ 0x2729f0bc, 0x8a5e, 0x4f3f, { 0xbc, 0x29, 0xc1, 0x74, 0xa, 0x86, 0x39, 0x3a } }; + +// {8D345956-10B7-4450-8A06-A80D2F319EFD} +static const GUID IID_Pjsua_Acc_Info = +{ 0x8d345956, 0x10b7, 0x4450, { 0x8a, 0x6, 0xa8, 0xd, 0x2f, 0x31, 0x9e, 0xfd } }; + +#define SA_SIZE(lbound,ubound) (ubound-lbound) + + +class Temp_Pool +{ +public: + Temp_Pool() + { + pool_ = pjsip_endpt_create_pool( pjsua_get_pjsip_endpt(), "ActivePJSUA", + 4000, 4000); + } + ~Temp_Pool() + { + pj_pool_release(pool_); + } + + pj_pool_t *get_pool() + { + return pool_; + } + +private: + pj_pool_t *pool_; +}; + +static pj_str_t Pj_str(pj_pool_t *pool, Pj_String s) +{ + pj_str_t ret; + unsigned len; + + len = wcslen(s); + if (len) { + ret.ptr = (char*)pj_pool_alloc(pool, len+1); + ret.slen = len; + pj_unicode_to_ansi(s, len, ret.ptr, len+1); + ret.ptr[ret.slen] = '\0'; + } else { + ret.ptr = NULL; + ret.slen = 0; + } + + return ret; +} + +BSTR str2bstr(const char *str, unsigned len) +{ + if (len == 0) { + return SysAllocString(L""); + } else { + OLECHAR *tmp; + BSTR result; + tmp = (OLECHAR*) malloc((len+1) * sizeof(OLECHAR)); + pj_ansi_to_unicode(str, len, tmp, len+1); + result = SysAllocString(tmp); + free(tmp); + return result; + } +} + +#define Cp(d,s) Cp2(&d,s) +static void Cp2(BSTR *dst, const pj_str_t *src) +{ + *dst = str2bstr(src->ptr, src->slen); +} + + + +static void SafeStringArray2pjstrarray(pj_pool_t *pool, + SAFEARRAY *sa, unsigned *count, + pj_str_t a[]) +{ + if (!sa) + *count = 0; + else { + HRESULT hr; + long lbound; + unsigned i; + + hr = SafeArrayGetLBound(sa, 1, &lbound); + if (FAILED(hr)) + *count = 0; + else { + *count = 0; + for (i=0; icbElements; ++i) { + BSTR str; + long rg = lbound + i; + hr = SafeArrayGetElement(sa, &rg, &str); + if (FAILED(hr)) + break; + a[*count] = Pj_str(pool, str); + *count = *count + 1; + } + } + } +} + +static void pjstrarray2SafeStringArray(unsigned count, const pj_str_t a[], + SAFEARRAY **psa) +{ + unsigned i; + SAFEARRAY *sa; + + sa = SafeArrayCreateVector( VT_BSTR, 0, count); + + for (i=0; iid = Pj_str(pool, c1->acc_uri); + c2->reg_uri = Pj_str(pool, c1->reg_uri); + c2->contact = Pj_str(pool, c1->contact_uri); + c2->proxy = Pj_str(pool, c1->proxy_uri); + c2->reg_timeout = c1->reg_timeout; + + if (c1->cred_info == NULL) { + c2->cred_count = 0; + } else { + unsigned i; + long lbound; + HRESULT hr; + + hr = SafeArrayGetLBound(c1->cred_info, 1, &lbound); + if (FAILED(hr)) { + c2->cred_count = 0; + } else { + c2->cred_count = 0; + for (i=0; icred_info->cbElements; ++i) { + Pjsip_Cred_Info cred_info; + long rg = lbound + i; + hr = SafeArrayGetElement(c1->cred_info, &rg, &cred_info); + if (FAILED(hr)) + break; + c2->cred_info[i].realm = Pj_str(pool, cred_info.realm); + c2->cred_info[i].scheme = Pj_str(pool, cred_info.scheme); + c2->cred_info[i].username = Pj_str(pool, cred_info.username); + c2->cred_info[i].data_type = cred_info.hashed; + c2->cred_info[i].data = Pj_str(pool, cred_info.data); + } + c2->cred_count = i; + } + } +} + +static HRESULT accconfig2AccConfig(pjsua_acc_config *c1, + Pjsua_Acc_Config *c2) +{ + unsigned i; + + //pj_memset(c2, 0, sizeof(Pjsua_Acc_Config)); + + Cp(c2->acc_uri, &c1->id); + Cp(c2->reg_uri, &c1->reg_uri); + Cp(c2->contact_uri, &c1->contact); + Cp(c2->proxy_uri, &c1->proxy); + c2->reg_timeout = c1->reg_timeout; + + + IRecordInfo *pUdtRecordInfo = NULL; + HRESULT hr = GetRecordInfoFromGuids( LIBID_ACTIVEPJSUALib, + 1, 0, + 0, + IID_Pjsip_Cred_Info, + &pUdtRecordInfo ); + if( FAILED( hr ) ) { + return( hr ); //Return original HRESULT hr2 is for debug only + } + + SAFEARRAYBOUND rgsabound[1]; + rgsabound[0].lLbound = 0; + rgsabound[0].cElements = c1->cred_count; + + c2->cred_info = ::SafeArrayCreateEx( VT_RECORD, 1, rgsabound, pUdtRecordInfo ); + + pUdtRecordInfo->Release(); //do not forget to release the interface + + for (i=0; icred_count; ++i) { + Pjsip_Cred_Info cred_info; + + Cp(cred_info.realm, &c1->cred_info[i].realm); + Cp(cred_info.scheme, &c1->cred_info[i].scheme); + Cp(cred_info.username, &c1->cred_info[i].username); + cred_info.hashed = (c1->cred_info[i].data_type != 0); + Cp(cred_info.data, &c1->cred_info[i].data); + + long rg = i; + SafeArrayPutElement(c2->cred_info, &rg, &cred_info); + } + + return S_OK; +} + +static HRESULT Config2config(pj_pool_t *pool, Pjsua_Config *c1, pjsua_config *c2) +{ + pj_memset(c2, 0, sizeof(pjsua_config)); + + c2->udp_port = c1->udp_port; + c2->sip_host = Pj_str(pool, c1->sip_host); + c2->sip_port = c1->sip_port; + c2->start_rtp_port = c1->rtp_port; + c2->max_calls = c1->max_calls; + c2->conf_ports = c1->conf_ports; + c2->thread_cnt = c1->thread_cnt; + c2->stun_srv1 = Pj_str(pool, c1->stun_srv1); + c2->stun_port1 = c1->stun_port1; + c2->stun_srv2 = Pj_str(pool, c1->stun_srv2); + c2->stun_port2 = c1->stun_port2; + c2->snd_player_id = c1->snd_player_id; + c2->snd_capture_id = c1->snd_capture_id; + c2->clock_rate = c1->clock_rate; + c2->null_audio = c1->null_audio; + c2->quality = c1->quality; + c2->complexity = c1->complexity; + + SafeStringArray2pjstrarray(pool, c1->codec_arg, &c2->codec_cnt, c2->codec_arg); + + c2->auto_answer = c1->auto_answer; + c2->uas_refresh = c1->uas_refresh; + c2->outbound_proxy = Pj_str(pool, c1->outbound_proxy); + + if (!c1->acc_config) + c2->acc_cnt = 0; + else { + HRESULT hr; + long lbound; + unsigned i; + + hr = SafeArrayGetLBound(c1->acc_config, 1, &lbound); + if (FAILED(hr)) + c2->acc_cnt = 0; + else { + c2->acc_cnt = 0; + + for (i=0; iacc_config->cbElements; ++i) { + Pjsua_Acc_Config acc_config; + long rg = lbound + i; + hr = SafeArrayGetElement(c1->acc_config, &rg, &acc_config); + if (FAILED(hr)) + break; + AccConfig2accconfig(pool, &acc_config, &c2->acc_config[i]); + } + + c2->acc_cnt = i; + } + } + + c2->log_level = c1->log_level; + c2->app_log_level = c1->app_log_level; + c2->log_decor = c1->log_decor; + c2->log_filename = Pj_str(pool, c1->log_filename); + + SafeStringArray2pjstrarray(pool, c1->buddy_uri, &c2->buddy_cnt, c2->buddy_uri); + + return S_OK; +} + +static HRESULT config2Config(pjsua_config *c1, Pjsua_Config *c2) +{ + unsigned i; + HRESULT hr; + + //pj_memset(c2, 0, sizeof(Pjsua_Config)); + + c2->udp_port = c1->udp_port; + Cp(c2->sip_host, &c1->sip_host); + c2->sip_port = c1->sip_port; + c2->rtp_port = c1->start_rtp_port; + c2->max_calls = c1->max_calls; + c2->conf_ports = c1->conf_ports; + c2->thread_cnt = c1->thread_cnt; + Cp(c2->stun_srv1, &c1->stun_srv1); + c2->stun_port1 = c1->stun_port1; + Cp(c2->stun_srv2, &c1->stun_srv2); + c2->stun_port2 = c1->stun_port2; + c2->snd_player_id = c1->snd_player_id; + c2->snd_capture_id = c1->snd_capture_id; + c2->clock_rate = c1->clock_rate; + c2->null_audio = c1->null_audio; + c2->quality = c1->quality; + c2->complexity = c1->complexity; + + pjstrarray2SafeStringArray(c1->codec_cnt, c1->codec_arg, &c2->codec_arg); + + c2->auto_answer = c1->auto_answer; + c2->uas_refresh = c1->uas_refresh; + + Cp(c2->outbound_proxy, &c1->outbound_proxy); + + IRecordInfo *pUdtRecordInfo = NULL; + hr = GetRecordInfoFromGuids( LIBID_ACTIVEPJSUALib, + 1, 0, + 0, + IID_Pjsua_Acc_Config, + &pUdtRecordInfo ); + if( FAILED( hr ) ) { + return( hr ); //Return original HRESULT hr2 is for debug only + } + + SAFEARRAYBOUND rgsabound[1]; + rgsabound[0].lLbound = 0; + rgsabound[0].cElements = c1->acc_cnt; + + c2->acc_config = ::SafeArrayCreateEx( VT_RECORD, 1, rgsabound, pUdtRecordInfo ); + + pUdtRecordInfo->Release(); //do not forget to release the interface + + for (i=0; iacc_cnt; ++i) { + Pjsua_Acc_Config acc_cfg; + + hr = accconfig2AccConfig(&c1->acc_config[i], &acc_cfg); + if (FAILED(hr)) + return hr; + + long rg = i; + SafeArrayPutElement(c2->acc_config, &rg, &acc_cfg); + } + + + c2->log_level = c1->log_level; + c2->app_log_level = c1->app_log_level; + c2->log_decor = c1->log_decor; + + Cp(c2->log_filename, &c1->log_filename); + + pjstrarray2SafeStringArray(c1->buddy_cnt, c1->buddy_uri, &c2->buddy_uri); + + return S_OK; +} + +static void callinfo2CallInfo(pjsua_call_info *c1, Pjsua_Call_Info *c2) +{ + pj_memset(c2, 0, sizeof(Pjsua_Call_Info)); + + c2->index = c1->index; + c2->active = c1->active; + c2->is_uac = (c1->role == PJSIP_ROLE_UAC); + Cp(c2->local_info, &c1->local_info); + Cp(c2->remote_info, &c1->remote_info); + c2->state = (Pjsua_Call_State)c1->state; + Cp(c2->state_text, &c1->state_text); + c2->connect_duration = c1->connect_duration.sec; + c2->total_duration = c1->total_duration.sec; + c2->cause = c1->cause; + Cp(c2->cause_text, &c1->cause_text); + c2->has_media = c1->has_media; + c2->conf_slot = c1->conf_slot; +} + +static void accinfo2AccInfo(pjsua_acc_info *info1, Pjsua_Acc_Info *info2) +{ + pj_memset(info2, 0, sizeof(Pjsua_Acc_Info)); + + info2->index = info1->index; + Cp(info2->acc_id, &info1->acc_id); + info2->has_registration = info1->has_registration; + info2->expires = info1->expires; + info2->status_code = info1->status; + Cp(info2->status_text, &info1->status_text); + info2->online_status = info1->online_status; +} + +static void buddyinfo2BuddyInfo(pjsua_buddy_info *info1, Pjsua_Buddy_Info *info2) +{ + pj_memset(info2, 0, sizeof(Pjsua_Buddy_Info)); + + info2->index = info1->index; + info2->is_valid = info1->is_valid; + Cp(info2->name, &info1->name); + Cp(info2->display, &info1->display_name); + Cp(info2->host, &info1->host); + info2->port = info1->port; + Cp(info2->uri, &info1->uri); + info2->status = (Pjsua_Buddy_State)info1->status; + Cp(info2->status_text, &info1->status_text); + info2->monitor = info1->monitor; + info2->acc_index = info1->acc_index; +} + +static CApp *CApp_Instance; + +CApp::CApp() +{ + CApp_Instance = this; +} + +STDMETHODIMP CApp::app_create(Pj_Status *ret) +{ + *ret = pjsua_create(); + return S_OK; +} + +STDMETHODIMP CApp::app_default_config(Pjsua_Config *pConfig) +{ + pjsua_config cfg; + pjsua_default_config(&cfg); + return config2Config(&cfg, pConfig); +} + +STDMETHODIMP CApp::app_test_config(Pjsua_Config *pConfig, BSTR *retmsg) +{ + pjsua_config cfg; + HRESULT hr; + Temp_Pool tp; + char errmsg[PJ_ERR_MSG_SIZE]; + + hr = Config2config(tp.get_pool(), pConfig, &cfg); + if (FAILED(hr)) + return hr; + + pjsua_test_config(&cfg, errmsg, sizeof(errmsg)); + *retmsg = str2bstr(errmsg, strlen(errmsg)); + return S_OK; +} + +static void on_call_state(int call_index, pjsip_event *e) +{ + pjsua_call_info call_info; + Pjsua_Call_Info *Call_Info = new Pjsua_Call_Info; + + pjsua_get_call_info(call_index, &call_info); + callinfo2CallInfo(&call_info, Call_Info); + + CApp_Instance->Fire_OnCallState(call_index, Call_Info); +} + +static void on_reg_state(int acc_index) +{ + CApp_Instance->Fire_OnRegState(acc_index); +} + +static void on_buddy_state(int buddy_index) +{ + CApp_Instance->Fire_OnBuddyState(buddy_index); +} + +static void on_pager(int call_index, const pj_str_t *from, + const pj_str_t *to, const pj_str_t *txt) +{ + BSTR fromURI, toURI, imText; + + Cp2(&fromURI, from); + Cp2(&toURI, to); + Cp2(&imText, txt); + + CApp_Instance->Fire_OnIncomingPager(call_index, fromURI, toURI, imText); +} + +static void on_typing(int call_index, const pj_str_t *from, + const pj_str_t *to, pj_bool_t is_typing) +{ + BSTR fromURI, toURI; + + Cp2(&fromURI, from); + Cp2(&toURI, to); + + CApp_Instance->Fire_OnTypingIndication(call_index, fromURI, toURI, is_typing); +} + + +STDMETHODIMP CApp::app_init(Pjsua_Config *pConfig, Pj_Status *pStatus) +{ + pjsua_config cfg; + pjsua_callback cb; + Temp_Pool tp; + HRESULT hr; + + pj_memset(&cb, 0, sizeof(cb)); + cb.on_call_state = &on_call_state; + cb.on_reg_state = &on_reg_state; + cb.on_buddy_state = &on_buddy_state; + cb.on_pager = &on_pager; + cb.on_typing = &on_typing; + + hr = Config2config(tp.get_pool(), pConfig, &cfg); + if (FAILED(hr)) + return hr; + + *pStatus = pjsua_init(&cfg, &cb); + return S_OK; +} + +STDMETHODIMP CApp::app_start(Pj_Status *retStatus) +{ + *retStatus = pjsua_start(); + return S_OK; +} + +STDMETHODIMP CApp::app_destroy(Pj_Status *retStatus) +{ + *retStatus = pjsua_destroy(); + return S_OK; +} + +STDMETHODIMP CApp::call_get_max_count(int *retCount) +{ + *retCount = pjsua_get_max_calls(); + return S_OK; +} + +STDMETHODIMP CApp::call_get_count(int *retCount) +{ + *retCount = pjsua_get_call_count(); + return S_OK; +} + +STDMETHODIMP CApp::call_is_active(int call_index, Pj_Bool *retVal) +{ + *retVal = pjsua_call_is_active(call_index); + return S_OK; +} + +STDMETHODIMP CApp::call_has_media(int call_index, Pj_Bool *pRet) +{ + *pRet = pjsua_call_has_media(call_index); + return S_OK; +} + +STDMETHODIMP CApp::call_get_info(int call_index, Pjsua_Call_Info *pInfo, Pj_Status *pRet) +{ + pjsua_call_info info; + *pRet = pjsua_get_call_info(call_index, &info); + callinfo2CallInfo(&info, pInfo); + return S_OK; +} + +STDMETHODIMP CApp::call_make_call(int acc_index, Pj_String dst_uri, int *call_index, Pj_Status *pRet) +{ + Temp_Pool tp; + pj_str_t tmp = Pj_str(tp.get_pool(), dst_uri); + + *pRet = pjsua_make_call(acc_index, &tmp, call_index); + return S_OK; +} + +STDMETHODIMP CApp::call_answer(int call_index, int status_code, Pj_Status *pRet) +{ + pjsua_call_answer(call_index, status_code); + *pRet = PJ_SUCCESS; + return S_OK; +} + +STDMETHODIMP CApp::call_hangup(int call_index, Pj_Status *pRet) +{ + pjsua_call_hangup(call_index); + *pRet = PJ_SUCCESS; + return S_OK; +} + +STDMETHODIMP CApp::call_set_hold(int call_index, Pj_Status *pRet) +{ + pjsua_call_set_hold(call_index); + *pRet = PJ_SUCCESS; + return S_OK; +} + +STDMETHODIMP CApp::call_release_hold(int call_index, Pj_Status *pRet) +{ + pjsua_call_reinvite(call_index); + *pRet = PJ_SUCCESS; + return S_OK; +} + +STDMETHODIMP CApp::call_xfer(int call_index, Pj_String dst_uri, Pj_Status *pRet) +{ + Temp_Pool tp; + pj_str_t tmp = Pj_str(tp.get_pool(), dst_uri); + pjsua_call_xfer(call_index, &tmp); + *pRet = PJ_SUCCESS; + return S_OK; +} + +STDMETHODIMP CApp::call_dial_dtmf(int call_index, Pj_String digits, Pj_Status *pRet) +{ + Temp_Pool tp; + pj_str_t tmp = Pj_str(tp.get_pool(), digits); + *pRet = pjsua_call_dial_dtmf(call_index, &tmp); + return S_OK; +} + +STDMETHODIMP CApp::call_send_im(int call_index, Pj_String text, Pj_Status *pRet) +{ + Temp_Pool tp; + pj_str_t tmp = Pj_str(tp.get_pool(), text); + pjsua_call_send_im(call_index, &tmp); + *pRet = PJ_SUCCESS; + return S_OK; +} + +STDMETHODIMP CApp::call_typing(int call_index, int is_typing, Pj_Status *pRet) +{ + pjsua_call_typing(call_index, is_typing); + *pRet = PJ_SUCCESS; + return S_OK; +} + +STDMETHODIMP CApp::call_hangup_all() +{ + pjsua_call_hangup_all(); + return S_OK; +} + +STDMETHODIMP CApp::call_get_textstat(int call_index, BSTR *textstat) +{ + char buf[1024]; + pjsua_dump_call(call_index, 1, buf, sizeof(buf), ""); + + OLECHAR wbuf[1024]; + pj_ansi_to_unicode(buf, strlen(buf), wbuf, PJ_ARRAY_SIZE(wbuf)); + *textstat = SysAllocString(wbuf); + return S_OK; +} + + +STDMETHODIMP CApp::acc_get_count(int *pCount) +{ + *pCount = pjsua_get_acc_count(); + return S_OK; +} + +STDMETHODIMP CApp::acc_get_info(int acc_index, Pjsua_Acc_Info *pInfo, Pj_Status *pRet) +{ + pjsua_acc_info info; + *pRet = pjsua_acc_get_info(acc_index, &info); + accinfo2AccInfo(&info, pInfo); + return S_OK; +} + +STDMETHODIMP CApp::acc_add(Pjsua_Acc_Config *pConfig, int *pAcc_Index, Pj_Status *pRet) +{ + Temp_Pool tp; + pjsua_acc_config config; + AccConfig2accconfig(tp.get_pool(), pConfig, &config); + *pRet = pjsua_acc_add(&config, pAcc_Index); + return S_OK; +} + +STDMETHODIMP CApp::acc_set_online_status(int acc_index, int is_online, Pj_Status *pRet) +{ + *pRet = pjsua_acc_set_online_status(acc_index, is_online); + return S_OK; +} + +STDMETHODIMP CApp::acc_set_registration(int acc_index, int reg_active, Pj_Status *pRet) +{ + *pRet = pjsua_acc_set_registration(acc_index, reg_active); + return S_OK; +} + +STDMETHODIMP CApp::buddy_get_count(int *pCount) +{ + *pCount = pjsua_get_buddy_count(); + return S_OK; +} + +STDMETHODIMP CApp::buddy_get_info(int buddy_index, Pjsua_Buddy_Info *pInfo, Pj_Status *pRet) +{ + pjsua_buddy_info info; + *pRet = pjsua_buddy_get_info(buddy_index, &info); + buddyinfo2BuddyInfo(&info, pInfo); + return S_OK; +} + +STDMETHODIMP CApp::buddy_add(Pj_String uri, int *pBuddy_Index, Pj_Status *pRet) +{ + Temp_Pool tp; + pj_str_t tmp = Pj_str(tp.get_pool(), uri); + *pRet = pjsua_buddy_add(&tmp, pBuddy_Index); + return S_OK; +} + +STDMETHODIMP CApp::buddy_subscribe_pres(int buddy_index, int subscribe, Pj_Status *pRet) +{ + *pRet = pjsua_buddy_subscribe_pres(buddy_index, subscribe); + pjsua_pres_refresh(); + return S_OK; +} + +STDMETHODIMP CApp::im_send_text(int acc_index, Pj_String dst_uri, Pj_String text, Pj_Status *pRet) +{ + Temp_Pool tp; + pj_str_t tmp_uri = Pj_str(tp.get_pool(), dst_uri); + pj_str_t tmp_text = Pj_str(tp.get_pool(), text); + *pRet = pjsua_im_send(acc_index, &tmp_uri, &tmp_text); + return S_OK; +} + +STDMETHODIMP CApp::im_typing(int acc_index, Pj_URI dst_uri, int is_typing, Pj_Status *pRet) +{ + Temp_Pool tp; + pj_str_t tmp_uri = Pj_str(tp.get_pool(), dst_uri); + *pRet = pjsua_im_typing(acc_index, &tmp_uri, is_typing); + return S_OK; +} + +STDMETHODIMP CApp::conf_connect(int src_port, int sink_port, Pj_Status *pRet) +{ + *pRet = pjsua_conf_connect(src_port, sink_port); + return S_OK; +} + +STDMETHODIMP CApp::conf_disconnect(int src_port, int sink_port, Pj_Status *pRet) +{ + *pRet = pjsua_conf_disconnect(src_port, sink_port); + return S_OK; +} + +STDMETHODIMP CApp::player_create(Pj_String filename, int *pPlayer_Id, Pj_Status *pRet) +{ + Temp_Pool tp; + pj_str_t tmp = Pj_str(tp.get_pool(), filename); + *pRet = pjsua_player_create(&tmp, pPlayer_Id); + return S_OK; +} + +STDMETHODIMP CApp::player_get_conf_port(int player_id, int *pPort) +{ + *pPort = pjsua_player_get_conf_port(player_id); + return S_OK; +} + +STDMETHODIMP CApp::player_set_pos(int player_id, int pos, Pj_Status *pRet) +{ + *pRet = pjsua_player_set_pos(player_id, pos); + return S_OK; +} + +STDMETHODIMP CApp::player_destroy(int player_id, Pj_Status *pRet) +{ + *pRet = pjsua_player_destroy(player_id); + return S_OK; +} + +STDMETHODIMP CApp::recorder_create(Pj_String filename, int *pRecorder_Id, Pj_Status *pRet) +{ + Temp_Pool tp; + pj_str_t tmp = Pj_str(tp.get_pool(), filename); + *pRet = pjsua_recorder_create(&tmp, pRecorder_Id); + return S_OK; +} + +STDMETHODIMP CApp::recorder_get_conf_port(int recorder_id, int *pPort) +{ + *pPort = pjsua_recorder_get_conf_port(recorder_id); + return S_OK; +} + +STDMETHODIMP CApp::recorder_destroy(int recorder_id, Pj_Status *pRet) +{ + *pRet = pjsua_recorder_destroy(recorder_id); + return S_OK; +} + +STDMETHODIMP CApp::app_load_config(Pj_String filename, Pjsua_Config *pConfig, Pj_Status *pRet) +{ + pjsua_config config; + Temp_Pool tp; + pj_str_t tmp = Pj_str(tp.get_pool(), filename); + pjsua_default_config(&config); + *pRet = pjsua_load_settings(tmp.ptr, &config); + if (*pRet == PJ_SUCCESS) + *pRet = config2Config(&config, pConfig); + return S_OK; +} + +STDMETHODIMP CApp::app_save_config(Pj_String filename, Pjsua_Config *pConfig, Pj_Status *pRet) +{ + Temp_Pool tp; + pjsua_config config; + pj_str_t tmp = Pj_str(tp.get_pool(), filename); + HRESULT hr; + + hr = Config2config(tp.get_pool(), pConfig, &config); + if (FAILED(hr)) + return hr; + + *pRet = pjsua_save_settings(tmp.ptr, &config); + return S_OK; +} + +STDMETHODIMP CApp::app_get_current_config(Pjsua_Config *pConfig) +{ + pjsua_config *config; + config = (pjsua_config*) pjsua_get_config(); + return config2Config(config, pConfig); +} + +STDMETHODIMP CApp::app_get_error_msg(Pj_Status status, BSTR * pRet) +{ + char errmsg[PJ_ERR_MSG_SIZE]; + OLECHAR werrmsg[PJ_ERR_MSG_SIZE]; + pj_strerror(status, errmsg, sizeof(errmsg)); + pj_ansi_to_unicode(errmsg, strlen(errmsg), werrmsg, PJ_ARRAY_SIZE(werrmsg)); + *pRet = SysAllocString(werrmsg); + return S_OK; +} + +STDMETHODIMP CApp::app_verify_sip_url(Pj_String uri, Pj_Status *pRet) +{ + Temp_Pool tp; + pj_str_t tmp = Pj_str(tp.get_pool(), uri); + *pRet = pjsua_verify_sip_url(tmp.ptr); + return S_OK; +} + +STDMETHODIMP CApp::app_handle_events(int msec_timeout, int *pEvCount) +{ + if (msec_timeout < 0) + msec_timeout = 0; + + *pEvCount = pjsua_handle_events(msec_timeout); + return S_OK; +} diff --git a/pjsip-apps/src/activex-pjsua/app.h b/pjsip-apps/src/activex-pjsua/app.h new file mode 100644 index 000000000..ba0f99718 --- /dev/null +++ b/pjsip-apps/src/activex-pjsua/app.h @@ -0,0 +1,91 @@ +// App.h : Declaration of the CApp + +#ifndef __APP_H_ +#define __APP_H_ + +#include "resource.h" // main symbols +#include "..\activex-pjsua\activex-pjsuaCP.h" + + +///////////////////////////////////////////////////////////////////////////// +// CApp +class ATL_NO_VTABLE CApp : + public CComObjectRootEx, + public CComCoClass, + public IConnectionPointContainerImpl, + public IDispatchImpl, + public CProxy_IPjsuaEvents +{ +public: + CApp(); + +DECLARE_REGISTRY_RESOURCEID(IDR_APP) + +DECLARE_PROTECT_FINAL_CONSTRUCT() + +BEGIN_COM_MAP(CApp) + COM_INTERFACE_ENTRY(IApp) + COM_INTERFACE_ENTRY(IDispatch) + COM_INTERFACE_ENTRY(IConnectionPointContainer) + COM_INTERFACE_ENTRY_IMPL(IConnectionPointContainer) +END_COM_MAP() + +BEGIN_CONNECTION_POINT_MAP(CApp) +CONNECTION_POINT_ENTRY(DIID__IPjsuaEvents) +END_CONNECTION_POINT_MAP() + + +// IApp +public: + STDMETHOD(app_handle_events)(/*[in]*/ int msec_timeout, /*[out,retval]*/ int *pEvCount); + STDMETHOD(app_verify_sip_url)(/*[in,string]*/ Pj_String uri, /*[out,retval]*/ Pj_Status *pRet); + STDMETHOD(app_get_error_msg)(/*[in]*/ Pj_Status status, /*[out,retval]*/ BSTR * errmsg); + STDMETHOD(app_get_current_config)(/*[out,retval]*/ Pjsua_Config *pConfig); + STDMETHOD(app_save_config)(/*[in,string]*/ Pj_String filename, /*[in]*/ Pjsua_Config *pConfig, /*[out,retval]*/ Pj_Status *pRet); + STDMETHOD(app_load_config)(/*[in,string]*/ Pj_String filename, /*[out]*/ Pjsua_Config *pConfig, /*[out,retval]*/ Pj_Status *pRet); + STDMETHOD(recorder_destroy)(/*[in]*/ int recorder_id, /*[out,retval]*/ Pj_Status *pRet); + STDMETHOD(recorder_get_conf_port)(/*[in]*/ int recorder_id, /*[out,retval]*/ int *pPort); + STDMETHOD(recorder_create)(/*[in,string]*/ Pj_String filename, /*[out]*/ int *pRecorder_Id, /*[out,retval]*/ Pj_Status *pRet); + STDMETHOD(player_destroy)(/*[in]*/ int player_id, /*[out,retval]*/ Pj_Status *pRet); + STDMETHOD(player_set_pos)(/*[in]*/ int player_id, /*[in]*/ int pos, /*[out,retval]*/ Pj_Status *pRet); + STDMETHOD(player_get_conf_port)(/*[in]*/ int player_id, /*[out,retval]*/ int *pPort); + STDMETHOD(player_create)(/*[in,string]*/ Pj_String filename, /*[out]*/ int *pPlayer_Id, /*[out,retval]*/ Pj_Status *pRet); + STDMETHOD(conf_disconnect)(/*[in]*/ int src_port, /*[in]*/ int sink_port, /*[out,retval]*/ Pj_Status *pRet); + STDMETHOD(conf_connect)(/*[in]*/ int src_port, /*[in]*/ int sink_port, /*[out,retval]*/ Pj_Status *pRet); + STDMETHOD(im_typing)(/*[in]*/ int acc_index, /*[in,string]*/ Pj_URI dst_uri, /*[in]*/ int is_typing, /*[out,retval]*/ Pj_Status *pRet); + STDMETHOD(im_send_text)(/*[in]*/ int acc_index, /*[in,string]*/ Pj_String dst_uri, /*[in,string]*/ Pj_String text, /*[out,retval]*/ Pj_Status *pRet); + STDMETHOD(buddy_subscribe_pres)(/*[in]*/ int buddy_index, /*[in]*/ int subscribe, /*[out,retval]*/ Pj_Status *pRet); + STDMETHOD(buddy_add)(/*[in,string]*/ Pj_String uri, /*[out]*/ int *pBuddy_Index, /*[out,retval]*/ Pj_Status *pRet); + STDMETHOD(buddy_get_info)(/*[in]*/ int buddy_index, /*[out]*/ Pjsua_Buddy_Info *pInfo, /*[out,retval]*/ Pj_Status *pRet); + STDMETHOD(buddy_get_count)(/*[out,retval]*/ int *pCount); + STDMETHOD(acc_set_registration)(/*[in]*/ int acc_index, /*[in]*/ int reg_active, /*[out,retval]*/ Pj_Status *pRet); + STDMETHOD(acc_set_online_status)(/*[in]*/ int acc_index, /*[in]*/ int is_online, /*[out,retval]*/ Pj_Status *pRet); + STDMETHOD(acc_add)(/*[in]*/ Pjsua_Acc_Config *pConfig, /*[out]*/ int *pAcc_Index, /*[out,retval]*/ Pj_Status *pRet); + STDMETHOD(acc_get_info)(/*[in]*/ int acc_index, /*[out]*/ Pjsua_Acc_Info *pInfo, /*[out,retval]*/ Pj_Status *pRet); + STDMETHOD(acc_get_count)(/*[out,retval]*/ int *pCount); + STDMETHOD(call_hangup_all)(); + STDMETHOD(call_typing)(/*[in]*/ int call_index, /*[in]*/ int is_typing, /*[out,retval]*/ Pj_Status *pRet); + STDMETHOD(call_send_im)(/*[in]*/ int call_index, /*[in,string]*/ Pj_String text, /*[out,retval]*/ Pj_Status *pRet); + STDMETHOD(call_dial_dtmf)(/*[in]*/ int call_index, /*[in,string]*/ Pj_String digits, /*[out,retval]*/ Pj_Status *pRet); + STDMETHOD(call_xfer)(/*[in]*/ int call_index, /*[in,string]*/ Pj_String dst_uri, /*[out,retval]*/ Pj_Status *pRet); + STDMETHOD(call_release_hold)(/*[in]*/ int call_index, /*[out,retval]*/ Pj_Status *pRet); + STDMETHOD(call_set_hold)(/*[in]*/ int call_index, /*[out,retval]*/ Pj_Status *pRet); + STDMETHOD(call_hangup)(/*[in]*/ int call_index, /*[out,retval]*/ Pj_Status *pRet); + STDMETHOD(call_answer)(/*[in]*/ int call_index, /*[in]*/ int status_code, /*[out,retval]*/ Pj_Status *pRet); + STDMETHOD(call_make_call)(/*[in]*/ int acc_index, /*[in,string]*/ Pj_String dst_uri, /*[out]*/ int *call_index, /*[out,retval]*/ Pj_Status *pRet); + STDMETHOD(call_get_info)(/*[in]*/ int call_index, /*[out]*/ Pjsua_Call_Info *pInfo, /*[out,retval]*/ Pj_Status *pRet); + STDMETHOD(call_has_media)(/*[in]*/ int call_index, /*[out,retval]*/ Pj_Bool *pRet); + STDMETHOD(call_is_active)(/*[in]*/ int call_index, /*[out,retval]*/ Pj_Bool *retVal); + STDMETHOD(call_get_count)(/*[out,retval]*/ int *retCount); + STDMETHOD(call_get_max_count)(/*[out,retval]*/ int *retCount); + STDMETHOD(app_destroy)(/*[out,retval]*/ Pj_Status *retStatus); + STDMETHOD(app_start)(/*[out,retval]*/ Pj_Status *retStatus); + STDMETHOD(app_init)(/*[in]*/ Pjsua_Config *pConfig, /*[out,retval]*/ Pj_Status *pStatus); + STDMETHOD(app_test_config)(/*[in]*/ Pjsua_Config *pConfig, /*[out,retval,string]*/ BSTR *retmsg); + STDMETHOD(app_default_config)(/*[in,out]*/ Pjsua_Config *pConfig); + STDMETHOD(app_create)(/*[out,retval]*/ Pj_Status *ret); + STDMETHOD(call_get_textstat)(/* [in] */ int call_index, /* [retval][out] */ BSTR *textstat); + +}; + +#endif //__APP_H_ diff --git a/pjsip-apps/src/activex-pjsua/app.rgs b/pjsip-apps/src/activex-pjsua/app.rgs new file mode 100644 index 000000000..0b5322a0c --- /dev/null +++ b/pjsip-apps/src/activex-pjsua/app.rgs @@ -0,0 +1,26 @@ +HKCR +{ + ActivePJSUA.App.1 = s 'App Class' + { + CLSID = s '{F89DA516-42E5-43A0-8EF7-A960BA386CAB}' + } + ActivePJSUA.App = s 'App Class' + { + CLSID = s '{F89DA516-42E5-43A0-8EF7-A960BA386CAB}' + CurVer = s 'ActivePJSUA.App.1' + } + NoRemove CLSID + { + ForceRemove {F89DA516-42E5-43A0-8EF7-A960BA386CAB} = s 'App Class' + { + ProgID = s 'ActivePJSUA.App.1' + VersionIndependentProgID = s 'ActivePJSUA.App' + ForceRemove 'Programmable' + InprocServer32 = s '%MODULE%' + { + val ThreadingModel = s 'Apartment' + } + 'TypeLib' = s '{11E70413-8434-41B6-A5B6-F7DF79FEFC1A}' + } + } +} diff --git a/pjsip-apps/src/activex-pjsua/pjsua-structs.idl b/pjsip-apps/src/activex-pjsua/pjsua-structs.idl new file mode 100644 index 000000000..1c90742f7 --- /dev/null +++ b/pjsip-apps/src/activex-pjsua/pjsua-structs.idl @@ -0,0 +1,156 @@ +import "oaidl.idl"; +import "ocidl.idl"; + +typedef long Pj_Status; +typedef BSTR Pj_URI; +typedef BSTR Pj_String; +typedef int Pj_Bool; + + +[ + uuid(9CE3052A-7A32-4229-B31C-5E02E0667A77), + version(1.0), + helpstring("PJSIP credential information"), +] +typedef struct Pjsip_Cred_Info +{ + Pj_String realm; + Pj_String scheme; + Pj_String username; + int hashed; + Pj_String data; +} Pjsip_Cred_Info; + + +[ + uuid(3B12B04F-6E48-46a7-B9E0-6C4BF1594A96), + version(1.0), + helpstring("PJSUA Account configuration"), +] +typedef struct Pjsua_Acc_Config +{ + Pj_URI acc_uri; + Pj_URI reg_uri; + Pj_URI contact_uri; + Pj_URI proxy_uri; + int reg_timeout; + SAFEARRAY(Pjsip_Cred_Info) cred_info; +} Pjsua_Acc_Config; + +[ + uuid(E4B6573D-CF5E-484d-863F-ADAD5947FBE4), + version(1.0), + helpstring("PJSUA configuration"), +] +typedef struct Pjsua_Config +{ + unsigned int udp_port; + Pj_String sip_host; + unsigned int sip_port; + unsigned int rtp_port; + unsigned int max_calls; + unsigned int conf_ports; + unsigned int thread_cnt; + Pj_String stun_srv1; + unsigned int stun_port1; + Pj_String stun_srv2; + unsigned int stun_port2; + unsigned int snd_player_id; + unsigned int snd_capture_id; + unsigned int clock_rate; + Pj_Bool null_audio; + unsigned int quality; + unsigned int complexity; + SAFEARRAY(Pj_String) codec_arg; + unsigned int auto_answer; + unsigned int uas_refresh; + Pj_String outbound_proxy; + SAFEARRAY(Pjsua_Acc_Config) acc_config; + unsigned int log_level; + unsigned int app_log_level; + unsigned long log_decor; + Pj_String log_filename; + SAFEARRAY(Pj_String) buddy_uri; +} Pjsua_Config; + + +typedef enum Pjsua_Call_State +{ + PJSUA_CALL_STATE_NULL, + PJSUA_CALL_STATE_CALLING, + PJSUA_CALL_STATE_INCOMING, + PJSUA_CALL_STATE_EARLY, + PJSUA_CALL_STATE_CONNECTING, + PJSUA_CALL_STATE_CONFIRMED, + PJSUA_CALL_STATE_DISCONNECTED, +} Pjsua_Call_State; + + +[ + uuid(5043AC9E-A417-4f03-927E-D7AE52DDD064), + version(1.0), + helpstring("PJSUA Call Information"), +] +typedef struct Pjsua_Call_Info +{ + unsigned int index; + Pj_Bool active; + Pj_Bool is_uac; + Pj_String local_info; + Pj_String remote_info; + Pjsua_Call_State state; + Pj_String state_text; + unsigned int connect_duration; + unsigned int total_duration; + unsigned int cause; + Pj_String cause_text; + Pj_Bool has_media; + unsigned int conf_slot; +} Pjsua_Call_Info; + + +typedef enum Pjsua_Buddy_State +{ + PJSUA_BUDDY_STATE_UNKNOWN, + PJSUA_BUDDY_STATE_ONLINE, + PJSUA_BUDDY_STATE_OFFLINE, +} Pjsua_Buddy_State; + + +[ + uuid(2729F0BC-8A5E-4f3f-BC29-C1740A86393A), + version(1.0), + helpstring("PJSUA Buddy Information"), +] +typedef struct Pjsua_Buddy_Info +{ + unsigned int index; + Pj_Bool is_valid; + Pj_String name; + Pj_String display; + Pj_String host; + unsigned int port; + Pj_URI uri; + Pjsua_Buddy_State status; + Pj_String status_text; + Pj_Bool monitor; + int acc_index; +} Pjsua_Buddy_Info; + + +[ + uuid(8D345956-10B7-4450-8A06-A80D2F319EFD), + version(1.0), + helpstring("PJSUA Account Information"), +] +typedef struct Pjsua_Acc_Info +{ + unsigned int index; + Pj_URI acc_id; + Pj_Bool has_registration; + int expires; + unsigned int status_code; + Pj_String status_text; + Pj_Bool online_status; +} Pjsua_Acc_Info; + diff --git a/pjsip-apps/src/activex-pjsua/stdafx.cpp b/pjsip-apps/src/activex-pjsua/stdafx.cpp new file mode 100644 index 000000000..a5eea178f --- /dev/null +++ b/pjsip-apps/src/activex-pjsua/stdafx.cpp @@ -0,0 +1,12 @@ +// stdafx.cpp : source file that includes just the standard includes +// stdafx.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + +#ifdef _ATL_STATIC_REGISTRY +#include +#include +#endif + +#include diff --git a/pjsip-apps/src/activex-pjsua/stdafx.h b/pjsip-apps/src/activex-pjsua/stdafx.h new file mode 100644 index 000000000..fba5b6c94 --- /dev/null +++ b/pjsip-apps/src/activex-pjsua/stdafx.h @@ -0,0 +1,27 @@ +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, +// but are changed infrequently + +#if !defined(AFX_STDAFX_H__D1920725_3220_40F4_9B04_762A3AB60D6C__INCLUDED_) +#define AFX_STDAFX_H__D1920725_3220_40F4_9B04_762A3AB60D6C__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#define STRICT +#ifndef _WIN32_WINNT +#define _WIN32_WINNT 0x0400 +#endif +#define _ATL_APARTMENT_THREADED + +#include +//You may derive a class from CComModule and use it if you want to override +//something, but do not change the name of _Module +extern CComModule _Module; +#include + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_STDAFX_H__D1920725_3220_40F4_9B04_762A3AB60D6C__INCLUDED) diff --git a/pjsip-apps/src/pjsua/main.c b/pjsip-apps/src/pjsua/main.c index 5355975f2..03e5eb6ca 100644 --- a/pjsip-apps/src/pjsua/main.c +++ b/pjsip-apps/src/pjsua/main.c @@ -42,11 +42,6 @@ int main(int argc, char *argv[]) return 1; - /* Init logging: */ - if (pjsua_console_app_logging_init(&cfg) != PJ_SUCCESS) - return 1; - - /* Init pjsua */ if (pjsua_init(&cfg, &console_callback) != PJ_SUCCESS) return 1; @@ -82,10 +77,6 @@ int main(int argc, char *argv[]) pjsua_destroy(); - /* Close logging: */ - pjsua_console_app_logging_shutdown(); - - /* Exit... */ return 0; diff --git a/pjsip/include/pjsua-lib/pjsua.h b/pjsip/include/pjsua-lib/pjsua.h index cb2e8b7a7..622991f68 100644 --- a/pjsip/include/pjsua-lib/pjsua.h +++ b/pjsip/include/pjsua-lib/pjsua.h @@ -143,9 +143,15 @@ struct pjsua_config */ unsigned conf_ports; - /** Number of worker threads (default: 1) */ + /** Number of worker threads (value >=0, default: 1) */ unsigned thread_cnt; + /** Separate ioqueue for media? (default: yes) */ + pj_bool_t media_has_ioqueue; + + /** Number of worker thread for media (value >=0, default: 1) */ + unsigned media_thread_cnt; + /** First STUN server IP address. When STUN is configured, then the * two STUN server settings must be fully set. * (default: none) @@ -359,6 +365,7 @@ struct pjsua_buddy_info pjsua_buddy_status status; pj_str_t status_text; pj_bool_t monitor; + int acc_index; }; typedef struct pjsua_buddy_info pjsua_buddy_info; @@ -438,6 +445,12 @@ PJ_DECL(pj_status_t) pjsua_start(void); */ PJ_DECL(pj_status_t) pjsua_destroy(void); +/** + * Poll pjsua. + */ +PJ_DECL(int) pjsua_handle_events(unsigned msec_timeout); + + /** * Get SIP endpoint instance. * Only valid after pjsua_init(). @@ -560,6 +573,14 @@ PJ_DECL(void) pjsua_call_typing(int call_index, pj_bool_t is_typing); PJ_DECL(void) pjsua_call_hangup_all(void); +/** + * Dump call and media statistics to string. + */ +PJ_DECL(void) pjsua_dump_call(int call_index, int with_media, + char *buffer, unsigned maxlen, + const char *indent); + + /***************************************************************************** * PJSUA Account and Client Registration API (defined in pjsua_reg.c). */ @@ -598,7 +619,7 @@ PJ_DECL(pj_status_t) pjsua_acc_set_online_status(unsigned acc_index, * Update registration or perform unregistration. If renew argument is zero, * this will start unregistration process. */ -PJ_DECL(void) pjsua_acc_set_registration(unsigned acc_index, pj_bool_t renew); +PJ_DECL(pj_status_t) pjsua_acc_set_registration(unsigned acc_index, pj_bool_t renew); @@ -637,7 +658,7 @@ PJ_DECL(pj_status_t) pjsua_buddy_subscribe_pres(unsigned buddy_index, /** * Refresh both presence client and server subscriptions. */ -PJ_DECL(void) pjsua_pres_refresh(int acc_index); +PJ_DECL(void) pjsua_pres_refresh(void); /** * Dump presence subscriptions. @@ -712,7 +733,7 @@ PJ_DECL(pj_status_t) pjsua_player_create(const pj_str_t *filename, /** * Get conference port associated with player. */ -PJ_DECL(unsigned) pjsua_player_get_conf_port(pjsua_player_id id); +PJ_DECL(int) pjsua_player_get_conf_port(pjsua_player_id id); /** @@ -739,7 +760,7 @@ PJ_DECL(pj_status_t) pjsua_recorder_create(const pj_str_t *filename, /** * Get conference port associated with recorder. */ -PJ_DECL(unsigned) pjsua_recorder_get_conf_port(pjsua_recorder_id id); +PJ_DECL(int) pjsua_recorder_get_conf_port(pjsua_recorder_id id); /** diff --git a/pjsip/include/pjsua-lib/pjsua_console_app.h b/pjsip/include/pjsua-lib/pjsua_console_app.h index 058d0637d..ee7213ed0 100644 --- a/pjsip/include/pjsua-lib/pjsua_console_app.h +++ b/pjsip/include/pjsua-lib/pjsua_console_app.h @@ -20,9 +20,6 @@ #define __PJSUA_CONSOLE_APP_H__ -pj_status_t pjsua_console_app_logging_init(const pjsua_config *cfg); -void pjsua_console_app_logging_shutdown(void); - void pjsua_console_app_main(void); extern pjsip_module pjsua_console_app_msg_logger; diff --git a/pjsip/src/pjsua-lib/pjsua_console_app.c b/pjsip/src/pjsua-lib/pjsua_console_app.c index 62069b9ad..58f64c7fc 100644 --- a/pjsip/src/pjsua-lib/pjsua_console_app.c +++ b/pjsip/src/pjsua-lib/pjsua_console_app.c @@ -781,7 +781,7 @@ void pjsua_console_app_main(void) pjsua_buddy_subscribe_pres(result.nb_result-1, (menuin[0]=='s')); } - pjsua_pres_refresh(current_acc); + pjsua_pres_refresh(); } else if (result.uri_result) { puts("Sorry, can only subscribe to buddy's presence, " @@ -814,7 +814,7 @@ void pjsua_console_app_main(void) printf("Setting %s online status to %s\n", acc_info.acc_id.ptr, (acc_info.online_status?"online":"offline")); - pjsua_pres_refresh(current_acc); + pjsua_pres_refresh(); break; case 'c': @@ -970,59 +970,6 @@ pjsip_module pjsua_console_app_msg_logger = -/***************************************************************************** - * Console application custom logging: - */ - - -static FILE *log_file; - - -static void app_log_writer(int level, const char *buffer, int len) -{ - /* Write to both stdout and file. */ - - if (level <= (int)pjsua_get_config()->app_log_level) - pj_log_write(level, buffer, len); - - if (log_file) { - fwrite(buffer, len, 1, log_file); - fflush(log_file); - } -} - - -pj_status_t pjsua_console_app_logging_init(const pjsua_config *cfg) -{ - /* Redirect log function to ours */ - - pj_log_set_log_func( &app_log_writer ); - - /* If output log file is desired, create the file: */ - - if (cfg->log_filename.slen) { - log_file = fopen(cfg->log_filename.ptr, "wt"); - if (log_file == NULL) { - PJ_LOG(1,(THIS_FILE, "Unable to open log file %s", - cfg->log_filename.ptr)); - return -1; - } - } - - return PJ_SUCCESS; -} - - -void pjsua_console_app_logging_shutdown(void) -{ - /* Close logging file, if any: */ - - if (log_file) { - fclose(log_file); - log_file = NULL; - } -} - /***************************************************************************** * Error display: */ diff --git a/pjsip/src/pjsua-lib/pjsua_core.c b/pjsip/src/pjsua-lib/pjsua_core.c index 3ec5947f1..3f63ce8ff 100644 --- a/pjsip/src/pjsua-lib/pjsua_core.c +++ b/pjsip/src/pjsua-lib/pjsua_core.c @@ -51,6 +51,8 @@ PJ_DEF(void) pjsua_default_config(pjsua_config *cfg) pj_memset(cfg, 0, sizeof(pjsua_config)); cfg->thread_cnt = 1; + cfg->media_has_ioqueue = 1; + cfg->media_thread_cnt = 1; cfg->udp_port = 5060; cfg->start_rtp_port = 4000; cfg->max_calls = 4; @@ -246,6 +248,25 @@ static int PJ_THREAD_FUNC pjsua_poll(void *arg) return 0; } +/** + * Poll pjsua. + */ +PJ_DECL(int) pjsua_handle_events(unsigned msec_timeout) +{ + unsigned count = 0; + pj_time_val tv; + pj_status_t status; + + tv.sec = 0; + tv.msec = msec_timeout; + pj_time_val_normalize(&tv); + + status = pjsip_endpt_handle_events2(pjsua.endpt, &tv, &count); + if (status != PJ_SUCCESS) + return -status; + + return count; +} #define pjsua_has_stun() (pjsua.config.stun_port1 && \ @@ -504,7 +525,9 @@ PJ_DEF(pj_status_t) pjsua_create(void) /* Must create media endpoint too */ status = pjmedia_endpt_create(&pjsua.cp.factory, - pjsip_endpt_get_ioqueue(pjsua.endpt), 0, + pjsua.config.media_has_ioqueue? NULL : + pjsip_endpt_get_ioqueue(pjsua.endpt), + pjsua.config.media_thread_cnt, &pjsua.med_endpt); if (status != PJ_SUCCESS) { pjsua_perror(THIS_FILE, @@ -754,6 +777,57 @@ static void copy_config(pj_pool_t *pool, pjsua_config *dst, } +/***************************************************************************** + * Console application custom logging: + */ + + +static void log_writer(int level, const char *buffer, int len) +{ + /* Write to both stdout and file. */ + + if (level <= (int)pjsua.config.app_log_level) + pj_log_write(level, buffer, len); + + if (pjsua.log_file) { + fwrite(buffer, len, 1, pjsua.log_file); + fflush(pjsua.log_file); + } +} + + +static pj_status_t logging_init() +{ + /* Redirect log function to ours */ + + pj_log_set_log_func( &log_writer ); + + /* If output log file is desired, create the file: */ + + if (pjsua.config.log_filename.slen) { + pjsua.log_file = fopen(pjsua.config.log_filename.ptr, "wt"); + if (pjsua.log_file == NULL) { + PJ_LOG(1,(THIS_FILE, "Unable to open log file %s", + pjsua.config.log_filename.ptr)); + return -1; + } + } + + return PJ_SUCCESS; +} + + +static void logging_shutdown(void) +{ + /* Close logging file, if any: */ + + if (pjsua.log_file) { + fclose(pjsua.log_file); + pjsua.log_file = NULL; + } +} + + /* * Initialize pjsua application. * This will initialize all libraries, create endpoint instance, and register @@ -807,6 +881,10 @@ PJ_DECL(pj_status_t) pjsua_init(const pjsua_config *cfg, pj_log_set_level(pjsua.config.log_level); pj_log_set_decor(pjsua.config.log_decor); + status = logging_init(); + if (status != PJ_SUCCESS) + goto on_error; + /* Create SIP UDP socket */ if (pjsua.config.udp_port) { @@ -853,7 +931,7 @@ PJ_DECL(pj_status_t) pjsua_init(const pjsua_config *cfg, goto on_error; } status = pjmedia_transport_udp_attach(pjsua.med_endpt, NULL, - &pjsua.calls[i].skinfo, + &pjsua.calls[i].skinfo, 0, &pjsua.calls[i].med_tp); } @@ -1368,7 +1446,7 @@ PJ_DEF(pj_status_t) pjsua_player_create( const pj_str_t *filename, /** * Get conference port associated with player. */ -PJ_DEF(unsigned) pjsua_player_get_conf_port(pjsua_player_id id) +PJ_DEF(int) pjsua_player_get_conf_port(pjsua_player_id id) { PJ_ASSERT_RETURN(id>=0 && id < PJ_ARRAY_SIZE(pjsua.player), PJ_EINVAL); return pjsua.player[id].slot; @@ -1452,7 +1530,7 @@ PJ_DEF(pj_status_t) pjsua_recorder_create( const pj_str_t *filename, /** * Get conference port associated with recorder. */ -PJ_DEF(unsigned) pjsua_recorder_get_conf_port(pjsua_recorder_id id) +PJ_DEF(int) pjsua_recorder_get_conf_port(pjsua_recorder_id id) { PJ_ASSERT_RETURN(id>=0 && id < PJ_ARRAY_SIZE(pjsua.recorder), PJ_EINVAL); return pjsua.recorder[id].slot; @@ -1521,19 +1599,6 @@ PJ_DEF(pj_status_t) pjsua_destroy(void) /* Signal threads to quit: */ pjsua.quit_flag = 1; - /* Terminate all calls. */ - pjsua_call_hangup_all(); - - /* Terminate all presence subscriptions. */ - pjsua_pres_shutdown(); - - /* Unregister, if required: */ - for (i=0; i<(int)pjsua.config.acc_cnt; ++i) { - if (pjsua.acc[i].regc) { - pjsua_acc_set_registration(i, PJ_FALSE); - } - } - /* Wait worker threads to quit: */ for (i=0; i<(int)pjsua.config.thread_cnt; ++i) { @@ -1544,9 +1609,22 @@ PJ_DEF(pj_status_t) pjsua_destroy(void) } } - - /* Wait for some time to allow unregistration to complete: */ + if (pjsua.endpt) { + /* Terminate all calls. */ + pjsua_call_hangup_all(); + + /* Terminate all presence subscriptions. */ + pjsua_pres_shutdown(); + + /* Unregister, if required: */ + for (i=0; i<(int)pjsua.config.acc_cnt; ++i) { + if (pjsua.acc[i].regc) { + pjsua_acc_set_registration(i, PJ_FALSE); + } + } + + /* Wait for some time to allow unregistration to complete: */ PJ_LOG(4,(THIS_FILE, "Shutting down...")); busy_sleep(1000); } @@ -1629,6 +1707,11 @@ PJ_DEF(pj_status_t) pjsua_destroy(void) pj_caching_pool_destroy(&pjsua.cp); + PJ_LOG(4,(THIS_FILE, "PJSUA destroyed...")); + + /* End logging */ + logging_shutdown(); + /* Done. */ return PJ_SUCCESS; diff --git a/pjsip/src/pjsua-lib/pjsua_imp.h b/pjsip/src/pjsua-lib/pjsua_imp.h index 208c999d7..ec1918d34 100644 --- a/pjsip/src/pjsua-lib/pjsua_imp.h +++ b/pjsip/src/pjsua-lib/pjsua_imp.h @@ -126,6 +126,9 @@ struct pjsua /* Config: */ pjsua_config config; /**< PJSUA configs */ + /* Log file: */ + FILE *log_file; /**< Log file. */ + /* Application callback : */ pjsua_callback cb; /**< Application callback. */ diff --git a/pjsip/src/pjsua-lib/pjsua_pres.c b/pjsip/src/pjsua-lib/pjsua_pres.c index fe6eedce2..c76d3cbb3 100644 --- a/pjsip/src/pjsua-lib/pjsua_pres.c +++ b/pjsip/src/pjsua-lib/pjsua_pres.c @@ -471,6 +471,7 @@ PJ_DEF(pj_status_t) pjsua_buddy_get_info(unsigned index, info->status_text = pj_str("Offline"); } + info->acc_index = buddy->acc_index; return PJ_SUCCESS; } @@ -549,10 +550,14 @@ PJ_DEF(pj_status_t) pjsua_acc_set_online_status( unsigned acc_index, /* * Refresh presence */ -PJ_DEF(void) pjsua_pres_refresh(int acc_index) +PJ_DEF(void) pjsua_pres_refresh() { + unsigned i; + refresh_client_subscription(); - refresh_server_subscription(acc_index); + + for (i=0; i end-p) { + *p = '\0'; + return; + } + + p += len; + *p++ = '\n'; + *p = '\0'; if (stat.rx.update_cnt == 0) strcpy(last_update, "never"); @@ -737,39 +748,48 @@ static void dump_media_session(pjmedia_session *session) now.msec); } - PJ_LOG(3,(THIS_FILE, - " RX pt=%d, stat last update: %s\n" - " total %spkt %sB (%sB +IP hdr)%s\n" - " pkt loss=%d (%3.1f%%), dup=%d (%3.1f%%), reorder=%d (%3.1f%%)%s\n" - " (msec) min avg max last\n" - " loss period: %7.3f %7.3f %7.3f %7.3f%s\n" - " jitter : %7.3f %7.3f %7.3f %7.3f%s", - info.stream_info[i].fmt.pt, + len = pj_ansi_snprintf(p, end-p, + "%s RX pt=%d, stat last update: %s\n" + "%s total %spkt %sB (%sB +IP hdr)\n" + "%s pkt loss=%d (%3.1f%%), dup=%d (%3.1f%%), reorder=%d (%3.1f%%)\n" + "%s (msec) min avg max last\n" + "%s loss period: %7.3f %7.3f %7.3f %7.3f\n" + "%s jitter : %7.3f %7.3f %7.3f %7.3f%s", + indent, info.stream_info[i].fmt.pt, last_update, + indent, good_number(packets, stat.rx.pkt), good_number(bytes, stat.rx.bytes), good_number(ipbytes, stat.rx.bytes + stat.rx.pkt * 32), - "", + indent, stat.rx.loss, stat.rx.loss * 100.0 / stat.rx.pkt, stat.rx.dup, stat.rx.dup * 100.0 / stat.rx.pkt, stat.rx.reorder, stat.rx.reorder * 100.0 / stat.rx.pkt, - "", + indent, indent, stat.rx.loss_period.min / 1000.0, stat.rx.loss_period.avg / 1000.0, stat.rx.loss_period.max / 1000.0, stat.rx.loss_period.last / 1000.0, - "", + indent, stat.rx.jitter.min / 1000.0, stat.rx.jitter.avg / 1000.0, stat.rx.jitter.max / 1000.0, stat.rx.jitter.last / 1000.0, "" - )); + ); + if (len < 1 || len > end-p) { + *p = '\0'; + return; + } + p += len; + *p++ = '\n'; + *p = '\0'; + if (stat.tx.update_cnt == 0) strcpy(last_update, "never"); else { @@ -782,60 +802,152 @@ static void dump_media_session(pjmedia_session *session) now.msec); } - PJ_LOG(3,(THIS_FILE, - " TX pt=%d, ptime=%dms, stat last update: %s\n" - " total %spkt %sB (%sB +IP hdr)%s\n" - " pkt loss=%d (%3.1f%%), dup=%d (%3.1f%%), reorder=%d (%3.1f%%)%s\n" - " (msec) min avg max last\n" - " loss period: %7.3f %7.3f %7.3f %7.3f%s\n" - " jitter : %7.3f %7.3f %7.3f %7.3f%s", + len = pj_ansi_snprintf(p, end-p, + "%s TX pt=%d, ptime=%dms, stat last update: %s\n" + "%s total %spkt %sB (%sB +IP hdr)\n" + "%s pkt loss=%d (%3.1f%%), dup=%d (%3.1f%%), reorder=%d (%3.1f%%)\n" + "%s (msec) min avg max last\n" + "%s loss period: %7.3f %7.3f %7.3f %7.3f\n" + "%s jitter : %7.3f %7.3f %7.3f %7.3f%s", + indent, info.stream_info[i].tx_pt, info.stream_info[i].param->info.frm_ptime * info.stream_info[i].param->setting.frm_per_pkt, last_update, + + indent, good_number(packets, stat.tx.pkt), good_number(bytes, stat.tx.bytes), good_number(ipbytes, stat.tx.bytes + stat.tx.pkt * 32), - "", + + indent, stat.tx.loss, stat.tx.loss * 100.0 / stat.tx.pkt, stat.tx.dup, stat.tx.dup * 100.0 / stat.tx.pkt, stat.tx.reorder, stat.tx.reorder * 100.0 / stat.tx.pkt, - "", + + indent, indent, stat.tx.loss_period.min / 1000.0, stat.tx.loss_period.avg / 1000.0, stat.tx.loss_period.max / 1000.0, stat.tx.loss_period.last / 1000.0, - "", + indent, stat.tx.jitter.min / 1000.0, stat.tx.jitter.avg / 1000.0, stat.tx.jitter.max / 1000.0, stat.tx.jitter.last / 1000.0, "" - )); + ); + if (len < 1 || len > end-p) { + *p = '\0'; + return; + } - PJ_LOG(3,(THIS_FILE, - " RTT msec : %7.3f %7.3f %7.3f %7.3f%s", + p += len; + *p++ = '\n'; + *p = '\0'; + + len = pj_ansi_snprintf(p, end-p, + "%s RTT msec : %7.3f %7.3f %7.3f %7.3f", + indent, stat.rtt.min / 1000.0, stat.rtt.avg / 1000.0, stat.rtt.max / 1000.0, - stat.rtt.last / 1000.0, - "" - )); + stat.rtt.last / 1000.0 + ); + if (len < 1 || len > end-p) { + *p = '\0'; + return; + } + p += len; + *p++ = '\n'; + *p = '\0'; } } +PJ_DEF(void) pjsua_dump_call(int call_index, int with_media, + char *buffer, unsigned maxlen, + const char *indent) +{ + pjsua_call *call = &pjsua.calls[call_index]; + pj_time_val duration, res_delay, con_delay; + char tmp[128]; + char *p, *end; + int len; + + *buffer = '\0'; + p = buffer; + end = buffer + maxlen; + len = 0; + + PJ_ASSERT_ON_FAIL(call_index >= 0 && + call_index < PJ_ARRAY_SIZE(pjsua.calls), return); + + if (call->inv == NULL) + return; + + print_call(indent, call_index, tmp, sizeof(tmp)); + + len = pj_ansi_strlen(tmp); + pj_ansi_strcpy(buffer, tmp); + + p += len; + *p++ = '\r'; + *p++ = '\n'; + + /* Calculate call duration */ + if (call->inv->state >= PJSIP_INV_STATE_CONFIRMED) { + pj_gettimeofday(&duration); + PJ_TIME_VAL_SUB(duration, call->conn_time); + con_delay = call->conn_time; + PJ_TIME_VAL_SUB(con_delay, call->start_time); + } else { + duration.sec = duration.msec = 0; + con_delay.sec = con_delay.msec = 0; + } + + /* Calculate first response delay */ + if (call->inv->state >= PJSIP_INV_STATE_EARLY) { + res_delay = call->res_time; + PJ_TIME_VAL_SUB(res_delay, call->start_time); + } else { + res_delay.sec = res_delay.msec = 0; + } + + /* Print duration */ + len = pj_ansi_snprintf(p, end-p, + "%s Call time: %02dh:%02dm:%02ds, " + "1st res in %d ms, conn in %dms", + indent, + (duration.sec / 3600), + ((duration.sec % 3600)/60), + (duration.sec % 60), + PJ_TIME_VAL_MSEC(res_delay), + PJ_TIME_VAL_MSEC(con_delay)); + + if (len > 0 && len < end-p) { + p += len; + *p++ = '\n'; + *p = '\0'; + } + + /* Dump session statistics */ + if (with_media && call->session) + dump_media_session(indent, p, end-p, call->session); + +} + /* * Dump application states. */ PJ_DEF(void) pjsua_dump(pj_bool_t detail) { - char buf[128]; unsigned old_decor; + char buf[1024]; PJ_LOG(3,(THIS_FILE, "Start dumping application states:")); @@ -862,48 +974,10 @@ PJ_DEF(void) pjsua_dump(pj_bool_t detail) unsigned i; for (i=0; iinv == NULL) - continue; - - print_call(" ", i, buf, sizeof(buf)); - PJ_LOG(3,(THIS_FILE, "%s", buf)); - - /* Calculate call duration */ - if (call->inv->state >= PJSIP_INV_STATE_CONFIRMED) { - pj_gettimeofday(&duration); - PJ_TIME_VAL_SUB(duration, call->conn_time); - con_delay = call->conn_time; - PJ_TIME_VAL_SUB(con_delay, call->start_time); - } else { - duration.sec = duration.msec = 0; - con_delay.sec = con_delay.msec = 0; + if (pjsua.calls[i].inv) { + pjsua_dump_call(i, detail, buf, sizeof(buf), " "); + PJ_LOG(3,(THIS_FILE, "%s", buf)); } - - /* Calculate first response delay */ - if (call->inv->state >= PJSIP_INV_STATE_EARLY) { - res_delay = call->res_time; - PJ_TIME_VAL_SUB(res_delay, call->start_time); - } else { - res_delay.sec = res_delay.msec = 0; - } - - /* Print duration */ - PJ_LOG(3,(THIS_FILE, - " Call time: %02dh:%02dm:%02ds, " - "1st res in %d ms, conn in %dms", - (duration.sec / 3600), - ((duration.sec % 3600)/60), - (duration.sec % 60), - PJ_TIME_VAL_MSEC(res_delay), - PJ_TIME_VAL_MSEC(con_delay))); - - /* Dump session statistics */ - if (call->session) - dump_media_session(call->session); } } @@ -924,7 +998,7 @@ PJ_DECL(pj_status_t) pjsua_load_settings(const char *filename, int argc = 3; char *argv[4] = { "pjsua", "--config-file", NULL, NULL}; - argv[3] = (char*)filename; + argv[2] = (char*)filename; return pjsua_parse_args(argc, argv, cfg); } @@ -1103,12 +1177,16 @@ PJ_DEF(int) pjsua_dump_settings(const pjsua_config *config, /* Encoding quality and complexity */ - pj_ansi_sprintf(line, "--quality %d\n", - config->quality); - pj_strcat2(&cfg, line); - pj_ansi_sprintf(line, "--complexity %d\n", - config->complexity); - pj_strcat2(&cfg, line); + if (config->quality > 0) { + pj_ansi_sprintf(line, "--quality %d\n", + config->quality); + pj_strcat2(&cfg, line); + } + if (config->complexity > 0) { + pj_ansi_sprintf(line, "--complexity %d\n", + config->complexity); + pj_strcat2(&cfg, line); + } /* ptime */ if (config->ptime) {