Added samples (finally!!)
git-svn-id: https://svn.pjsip.org/repos/pjproject/trunk@328 74dad513-b988-da41-8d7b-12977e46ad98
This commit is contained in:
parent
a5829a8d4a
commit
6107a00d90
|
@ -67,7 +67,7 @@ export PJMEDIA_OBJS += $(OS_OBJS) $(M_OBJS) $(CC_OBJS) $(HOST_OBJS) \
|
|||
codec.o conference.o endpoint.o errno.o file_port.o \
|
||||
g711.o jbuf.o null_port.o pasound.o port.o resample.o rtcp.o \
|
||||
rtp.o sdp.o sdp_cmp.o sdp_neg.o session.o silencedet.o \
|
||||
stream.o $(SOUND_OBJS)
|
||||
sound_port.o stream.o $(SOUND_OBJS) $(NULLSOUND_OBJS)
|
||||
|
||||
export PJMEDIA_CFLAGS += $(_CFLAGS)
|
||||
|
||||
|
|
|
@ -50,7 +50,7 @@ BSC32=bscmake.exe
|
|||
# ADD BSC32 /nologo
|
||||
LIB32=link.exe -lib
|
||||
# ADD BASE LIB32 /nologo
|
||||
# ADD LIB32 /nologo /out:"..\lib\pjmedia-codec-i386-vc6-release.lib"
|
||||
# ADD LIB32 /nologo /out:"..\lib\pjmedia-codec-i386-win32-vc6-release.lib"
|
||||
|
||||
!ELSEIF "$(CFG)" == "pjmedia_codec - Win32 Debug"
|
||||
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
|
||||
MACHINE_NAME = i386
|
||||
OS_NAME = win32
|
||||
CC_NAME = vc6-$(BUILD_MODE)
|
||||
LIBEXT = .lib
|
||||
|
||||
!if "$(BUILD_MODE)" == "debug"
|
||||
BUILD_FLAGS = /MTd /Od /Zi
|
||||
!else
|
||||
BUILD_FLAGS = /Ox /MD /DNDEBUG
|
||||
!endif
|
||||
|
||||
PJLIB_LIB = ..\..\pjlib\lib\pjlib-$(MACHINE_NAME)-$(OS_NAME)-$(CC_NAME)$(LIBEXT)
|
||||
PJLIB_UTIL_LIB = ..\..\pjlib-util\lib\pjlib-util-$(MACHINE_NAME)-$(OS_NAME)-$(CC_NAME)$(LIBEXT)
|
||||
PJMEDIA_LIB = ..\..\pjmedia\lib\pjmedia-$(MACHINE_NAME)-$(OS_NAME)-$(CC_NAME)$(LIBEXT)
|
||||
PJMEDIA_CODEC_LIB = ..\..\pjmedia\lib\pjmedia-codec-$(MACHINE_NAME)-$(OS_NAME)-$(CC_NAME)$(LIBEXT)
|
||||
PJSIP_LIB = ..\..\pjsip\lib\pjsip-core-$(MACHINE_NAME)-$(OS_NAME)-$(CC_NAME)$(LIBEXT)
|
||||
PJSIP_UA_LIB = ..\..\pjsip\lib\pjsip-ua-$(MACHINE_NAME)-$(OS_NAME)-$(CC_NAME)$(LIBEXT)
|
||||
PJSIP_SIMPLE_LIB = ..\..\pjsip\lib\pjsip-simple-$(MACHINE_NAME)-$(OS_NAME)-$(CC_NAME)$(LIBEXT)
|
||||
PJSUA_LIB_LIB = ..\..\pjsip\lib\pjsua-lib-$(MACHINE_NAME)-$(OS_NAME)-$(CC_NAME)$(LIBEXT)
|
||||
|
||||
LIBS = $(PJSUA_LIB_LIB) $(PJSIP_UA_LIB) $(PJSIP_SIMPLE_LIB) \
|
||||
$(PJSIP_LIB) $(PJMEDIA_CODEC_LIB) $(PJMEDIA_LIB) \
|
||||
$(PJLIB_UTIL_LIB) $(PJLIB_LIB)
|
||||
|
||||
CFLAGS = /DPJ_WIN32=1 /DPJ_M_I386=1 \
|
||||
$(BUILD_FLAGS) \
|
||||
-I..\..\pjsip\include \
|
||||
-I..\..\pjlib\include -I..\..\pjlib-util\include \
|
||||
-I..\..\pjmedia\include
|
||||
LDFLAGS = $(BUILD_FLAGS) $(LIBS) \
|
||||
ole32.lib user32.lib dsound.lib dxguid.lib netapi32.lib \
|
||||
mswsock.lib ws2_32.lib
|
||||
|
||||
SRCDIR = ..\src\samples
|
||||
OBJDIR = .\output\samples-$(MACHINE_NAME)-$(OS_NAME)-$(CC_NAME)
|
||||
BINDIR = ..\bin\samples
|
||||
|
||||
|
||||
SAMPLES = $(BINDIR)\simpleua.exe
|
||||
|
||||
all: $(OBJDIR) $(SAMPLES)
|
||||
|
||||
$(SAMPLES): $(SRCDIR)\$(@B).c $(LIBS) Samples-vc.mak
|
||||
cl -nologo -c $(SRCDIR)\$(@B).c /Fo$(OBJDIR)\$(@B).obj $(CFLAGS)
|
||||
cl /nologo $(OBJDIR)\$(@B).obj /Fe$@ /Fm$(OBJDIR)\$(@B).map $(LDFLAGS)
|
||||
|
||||
$(OBJDIR):
|
||||
mkdir $(OBJDIR)
|
||||
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
|
||||
include ../../build/common.mak
|
||||
|
||||
PJLIB_LIB:=../../pjlib/lib/libpj-$(MACHINE_NAME)-$(OS_NAME)-$(CC_NAME)$(LIBEXT)
|
||||
PJLIB_UTIL_LIB:=../../pjlib-util/lib/libpjlib-util-$(MACHINE_NAME)-$(OS_NAME)-$(CC_NAME)$(LIBEXT)
|
||||
PJMEDIA_LIB:=../../pjmedia/lib/libpjmedia-$(MACHINE_NAME)-$(OS_NAME)-$(CC_NAME)$(LIBEXT)
|
||||
PJMEDIA_CODEC_LIB:=../../pjmedia/lib/libpjmedia-codec-$(MACHINE_NAME)-$(OS_NAME)-$(CC_NAME)$(LIBEXT)
|
||||
PJSIP_LIB:=../../pjsip/lib/libpjsip-$(MACHINE_NAME)-$(OS_NAME)-$(CC_NAME)$(LIBEXT)
|
||||
PJSIP_UA_LIB:=../../pjsip/lib/libpjsip-ua-$(MACHINE_NAME)-$(OS_NAME)-$(CC_NAME)$(LIBEXT)
|
||||
PJSIP_SIMPLE_LIB:=../../pjsip/lib/libpjsip-simple-$(MACHINE_NAME)-$(OS_NAME)-$(CC_NAME)$(LIBEXT)
|
||||
PJSUA_LIB_LIB=../../pjsip/lib/libpjsua-$(MACHINE_NAME)-$(OS_NAME)-$(CC_NAME)$(LIBEXT)
|
||||
|
||||
|
||||
###############################################################################
|
||||
# Gather all flags.
|
||||
#
|
||||
export _CFLAGS := $(CC_CFLAGS) $(OS_CFLAGS) $(HOST_CFLAGS) $(M_CFLAGS) \
|
||||
$(CFLAGS) $(CC_INC)../../pjsip/include $(CC_INC)../../pjlib/include \
|
||||
$(CC_INC)../../pjlib-util/include $(CC_INC)../../pjmedia/include
|
||||
export _CXXFLAGS:= $(_CFLAGS) $(CC_CXXFLAGS) $(OS_CXXFLAGS) $(M_CXXFLAGS) \
|
||||
$(HOST_CXXFLAGS) $(CXXFLAGS)
|
||||
export _LDFLAGS := $(subst /,$(HOST_PSEP),$(PJSUA_LIB_LIB)) \
|
||||
$(subst /,$(HOST_PSEP),$(PJSIP_UA_LIB)) \
|
||||
$(subst /,$(HOST_PSEP),$(PJSIP_SIMPLE_LIB)) \
|
||||
$(subst /,$(HOST_PSEP),$(PJSIP_LIB)) \
|
||||
$(subst /,$(HOST_PSEP),$(PJMEDIA_CODEC_LIB)) \
|
||||
$(subst /,$(HOST_PSEP),$(PJMEDIA_LIB)) \
|
||||
$(subst /,$(HOST_PSEP),$(PJLIB_UTIL_LIB)) \
|
||||
$(subst /,$(HOST_PSEP),$(PJLIB_LIB)) \
|
||||
$(CC_LDFLAGS) $(OS_LDFLAGS) $(M_LDFLAGS) $(HOST_LDFLAGS) \
|
||||
$(LDFLAGS) -lm
|
||||
|
||||
SRCDIR := ../src/samples
|
||||
OBJDIR := ./output/samples-$(MACHINE_NAME)-$(OS_NAME)-$(CC_NAME)
|
||||
BINDIR := ../bin/samples
|
||||
|
||||
CFLAGS = $(_CFLAGS)
|
||||
LDFLAGS = $(_LDFLAGS)
|
||||
|
||||
SAMPLES := simpleua
|
||||
EXES := $(foreach file, $(SAMPLES), $(BINDIR)/$(file)-$(MACHINE_NAME)-$(OS_NAME)-$(CC_NAME)$(HOST_EXE))
|
||||
|
||||
all: $(OBJDIR) $(EXES)
|
||||
|
||||
$(BINDIR)/%-$(MACHINE_NAME)-$(OS_NAME)-$(CC_NAME)$(HOST_EXE): $(OBJDIR)/%$(OBJEXT)
|
||||
$(LD) $(LDOUT)$(subst /,$(HOST_PSEP),$@) \
|
||||
$(subst /,$(HOST_PSEP),$<) \
|
||||
$(_LDFLAGS)
|
||||
|
||||
$(OBJDIR)/%$(OBJEXT): $(SRCDIR)/%.c
|
||||
$(CC) $(CFLAGS) \
|
||||
$(CC_OUT)$(subst /,$(HOST_PSEP),$@) \
|
||||
$(subst /,$(HOST_PSEP),$<)
|
||||
|
||||
$(OBJDIR):
|
||||
$(subst @@,$(subst /,$(HOST_PSEP),$@),$(HOST_MKDIR))
|
||||
|
||||
clean:
|
||||
$(subst @@,$(subst /,$(HOST_PSEP),$(OBJDIR)/*),$(HOST_RMR))
|
||||
$(subst @@,$(subst /,$(HOST_PSEP),$(OBJDIR)),$(HOST_RMDIR))
|
||||
|
||||
distclean realclean: clean
|
||||
$(subst @@,$(EXES),$(HOST_RM))
|
||||
# $(subst @@,$(subst /,$(HOST_PSEP),$(EXES)) $(subst /,$(HOST_PSEP),$(EXES)),$(HOST_RM))
|
||||
# $(subst @@,$(DEP_FILE),$(HOST_RM))
|
||||
|
|
@ -168,6 +168,42 @@ Package=<4>
|
|||
|
||||
###############################################################################
|
||||
|
||||
Project: "samples"=".\samples.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
|
||||
}}}
|
||||
|
||||
###############################################################################
|
||||
|
||||
Global:
|
||||
|
||||
Package=<5>
|
||||
|
|
|
@ -0,0 +1,108 @@
|
|||
# Microsoft Developer Studio Project File - Name="samples" - Package Owner=<4>
|
||||
# Microsoft Developer Studio Generated Build File, Format Version 6.00
|
||||
# ** DO NOT EDIT **
|
||||
|
||||
# TARGTYPE "Win32 (x86) External Target" 0x0106
|
||||
|
||||
CFG=samples - 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 "samples.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 "samples.mak" CFG="samples - Win32 Debug"
|
||||
!MESSAGE
|
||||
!MESSAGE Possible choices for configuration are:
|
||||
!MESSAGE
|
||||
!MESSAGE "samples - Win32 Release" (based on "Win32 (x86) External Target")
|
||||
!MESSAGE "samples - Win32 Debug" (based on "Win32 (x86) External Target")
|
||||
!MESSAGE
|
||||
|
||||
# Begin Project
|
||||
# PROP AllowPerConfigDependencies 0
|
||||
# PROP Scc_ProjName ""
|
||||
# PROP Scc_LocalPath ""
|
||||
|
||||
!IF "$(CFG)" == "samples - Win32 Release"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 0
|
||||
# PROP BASE Output_Dir "./output/samples-i386-win32-vc6-release"
|
||||
# PROP BASE Intermediate_Dir "./output/samples-i386-win32-vc6-release"
|
||||
# PROP BASE Cmd_Line "NMAKE /f samples.mak"
|
||||
# PROP BASE Rebuild_Opt "/a"
|
||||
# PROP BASE Target_File "samples.exe"
|
||||
# PROP BASE Bsc_Name "samples.bsc"
|
||||
# PROP BASE Target_Dir ""
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 0
|
||||
# PROP Output_Dir "./output/samples-i386-win32-vc6-release"
|
||||
# PROP Intermediate_Dir "./output/samples-i386-win32-vc6-release"
|
||||
# PROP Cmd_Line "nmake /f Samples-vc.mak BUILD_MODE=release"
|
||||
# PROP Rebuild_Opt "/a"
|
||||
# PROP Bsc_Name ""
|
||||
# PROP Target_Dir ""
|
||||
|
||||
!ELSEIF "$(CFG)" == "samples - Win32 Debug"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 1
|
||||
# PROP BASE Output_Dir "./output/samples-i386-win32-vc6-debug"
|
||||
# PROP BASE Intermediate_Dir "./output/samples-i386-win32-vc6-debug"
|
||||
# PROP BASE Cmd_Line "NMAKE /f samples.mak"
|
||||
# PROP BASE Rebuild_Opt "/a"
|
||||
# PROP BASE Target_File "samples.exe"
|
||||
# PROP BASE Bsc_Name "samples.bsc"
|
||||
# PROP BASE Target_Dir ""
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 1
|
||||
# PROP Output_Dir "./output/samples-i386-win32-vc6-debug"
|
||||
# PROP Intermediate_Dir "./output/samples-i386-win32-vc6-debug"
|
||||
# PROP Cmd_Line "nmake /NOLOGO /S /f Samples-vc.mak BUILD_MODE=debug"
|
||||
# PROP Rebuild_Opt "/a"
|
||||
# PROP Target_File "../bin/samples/simpleua.exe"
|
||||
# PROP Bsc_Name ""
|
||||
# PROP Target_Dir ""
|
||||
|
||||
!ENDIF
|
||||
|
||||
# Begin Target
|
||||
|
||||
# Name "samples - Win32 Release"
|
||||
# Name "samples - Win32 Debug"
|
||||
|
||||
!IF "$(CFG)" == "samples - Win32 Release"
|
||||
|
||||
!ELSEIF "$(CFG)" == "samples - Win32 Debug"
|
||||
|
||||
!ENDIF
|
||||
|
||||
# Begin Group "Source Files"
|
||||
|
||||
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\src\samples\simpleua.c
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "Header Files"
|
||||
|
||||
# PROP Default_Filter "h;hpp;hxx;hm;inl"
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\src\samples\util.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"
|
||||
# End Group
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=".\Samples-vc.mak"
|
||||
# End Source File
|
||||
# End Target
|
||||
# End Project
|
|
@ -165,7 +165,7 @@ static pj_bool_t mod_call_on_rx_request(pjsip_rx_data *rdata)
|
|||
// TODO: Need to delete dialog
|
||||
|
||||
} else {
|
||||
status = pjsip_inv_send_msg(inv, response, NULL);
|
||||
status = pjsip_inv_send_msg(inv, response);
|
||||
if (status != PJ_SUCCESS)
|
||||
app_perror(THIS_FILE, "Unable to send 100 response", status);
|
||||
}
|
||||
|
@ -247,7 +247,7 @@ pj_status_t call_spawn_test( const pj_str_t *target,
|
|||
|
||||
|
||||
/* Send initial INVITE: */
|
||||
status = pjsip_inv_send_msg(inv, tdata, NULL);
|
||||
status = pjsip_inv_send_msg(inv, tdata);
|
||||
if (status != PJ_SUCCESS) {
|
||||
app_perror( THIS_FILE, "Unable to send initial INVITE request",
|
||||
status);
|
||||
|
@ -283,7 +283,7 @@ static void bye_callback( pj_timer_heap_t *ht, pj_timer_entry *e)
|
|||
return;
|
||||
}
|
||||
|
||||
status = pjsip_inv_send_msg(call_data->inv, tdata, NULL);
|
||||
status = pjsip_inv_send_msg(call_data->inv, tdata);
|
||||
if (status != PJ_SUCCESS) {
|
||||
app_perror(THIS_FILE, "Unable to send BYE", status);
|
||||
return;
|
||||
|
@ -391,7 +391,7 @@ pj_status_t call_handler_init(void)
|
|||
inv_cb.on_new_session = &call_on_forked;
|
||||
|
||||
/* Initialize invite session module: */
|
||||
status = pjsip_inv_usage_init(settings.endpt, &mod_call, &inv_cb);
|
||||
status = pjsip_inv_usage_init(settings.endpt, &inv_cb);
|
||||
if (status != PJ_SUCCESS) {
|
||||
app_perror( THIS_FILE, "Unable to initialize INVITE session module",
|
||||
status);
|
||||
|
|
|
@ -0,0 +1,519 @@
|
|||
|
||||
/* Include all PJSIP core headers. */
|
||||
#include <pjsip.h>
|
||||
|
||||
/* Include all PJMEDIA headers. */
|
||||
#include <pjmedia.h>
|
||||
|
||||
/* Include all PJMEDIA-CODEC headers. */
|
||||
#include <pjmedia-codec.h>
|
||||
|
||||
/* Include all PJSIP-UA headers */
|
||||
#include <pjsip_ua.h>
|
||||
|
||||
/* Include all PJSIP-SIMPLE headers */
|
||||
#include <pjsip_simple.h>
|
||||
|
||||
/* Include all PJLIB-UTIL headers. */
|
||||
#include <pjlib-util.h>
|
||||
|
||||
/* Include all PJLIB headers. */
|
||||
#include <pjlib.h>
|
||||
|
||||
|
||||
#define THIS_FILE "simpleua.c"
|
||||
|
||||
|
||||
/*
|
||||
* Static variables.
|
||||
*/
|
||||
static pj_bool_t g_complete;
|
||||
|
||||
/* Global endpoint instance. */
|
||||
static pjsip_endpoint *g_endpt;
|
||||
|
||||
/* Global caching pool factory. */
|
||||
static pj_caching_pool cp;
|
||||
|
||||
/* Global media endpoint. */
|
||||
static pjmedia_endpt *g_med_endpt;
|
||||
static pjmedia_sock_info g_med_skinfo;
|
||||
|
||||
/* Call variables. */
|
||||
static pjsip_inv_session *g_inv;
|
||||
static pjmedia_session *g_med_session;
|
||||
static pjmedia_snd_port *g_snd_player;
|
||||
static pjmedia_snd_port *g_snd_rec;
|
||||
|
||||
|
||||
/*
|
||||
* Prototypes.
|
||||
*/
|
||||
static void call_on_media_update( pjsip_inv_session *inv,
|
||||
pj_status_t status);
|
||||
static void call_on_state_changed( pjsip_inv_session *inv,
|
||||
pjsip_event *e);
|
||||
static void call_on_forked(pjsip_inv_session *inv, pjsip_event *e);
|
||||
static pj_bool_t on_rx_request( pjsip_rx_data *rdata );
|
||||
|
||||
|
||||
/* Module to receive incoming requests (e.g. INVITE). */
|
||||
static pjsip_module mod_simpleua =
|
||||
{
|
||||
NULL, NULL, /* prev, next. */
|
||||
{ "mod-simpleua", 12 }, /* Name. */
|
||||
-1, /* Id */
|
||||
PJSIP_MOD_PRIORITY_APPLICATION, /* Priority */
|
||||
NULL, /* load() */
|
||||
NULL, /* start() */
|
||||
NULL, /* stop() */
|
||||
NULL, /* unload() */
|
||||
&on_rx_request, /* on_rx_request() */
|
||||
NULL, /* on_rx_response() */
|
||||
NULL, /* on_tx_request. */
|
||||
NULL, /* on_tx_response() */
|
||||
NULL, /* on_tsx_state() */
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Show error.
|
||||
*/
|
||||
static int app_perror( const char *sender, const char *title,
|
||||
pj_status_t status)
|
||||
{
|
||||
char errmsg[PJ_ERR_MSG_SIZE];
|
||||
|
||||
pj_strerror(status, errmsg, sizeof(errmsg));
|
||||
|
||||
PJ_LOG(1,(sender, "%s: %s [code=%d]", title, errmsg, status));
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* main()
|
||||
*/
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
pj_status_t status;
|
||||
|
||||
/* Init PJLIB */
|
||||
status = pj_init();
|
||||
PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
|
||||
|
||||
/* Init PJLIB-UTIL: */
|
||||
status = pjlib_util_init();
|
||||
PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
|
||||
|
||||
|
||||
/* Init memory pool: */
|
||||
|
||||
/* Init caching pool. */
|
||||
pj_caching_pool_init(&cp, &pj_pool_factory_default_policy, 0);
|
||||
|
||||
/* Create global endpoint: */
|
||||
{
|
||||
const pj_str_t *hostname;
|
||||
const char *endpt_name;
|
||||
|
||||
/* Endpoint MUST be assigned a globally unique name.
|
||||
* The name will be used as the hostname in Warning header.
|
||||
*/
|
||||
|
||||
/* For this implementation, we'll use hostname for simplicity */
|
||||
hostname = pj_gethostname();
|
||||
endpt_name = hostname->ptr;
|
||||
|
||||
/* Create the endpoint: */
|
||||
|
||||
status = pjsip_endpt_create(&cp.factory, endpt_name,
|
||||
&g_endpt);
|
||||
PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Add UDP transport.
|
||||
*/
|
||||
{
|
||||
pj_sockaddr_in addr;
|
||||
|
||||
addr.sin_family = PJ_AF_INET;
|
||||
addr.sin_addr.s_addr = 0;
|
||||
addr.sin_port = pj_htons(5060);
|
||||
|
||||
status = pjsip_udp_transport_start( g_endpt, &addr, NULL, 1, NULL);
|
||||
if (status != PJ_SUCCESS) {
|
||||
app_perror(THIS_FILE, "Unable to start UDP transport", status);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Init transaction layer.
|
||||
*/
|
||||
status = pjsip_tsx_layer_init_module(g_endpt);
|
||||
PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
|
||||
|
||||
/*
|
||||
* Initialize UA layer module:
|
||||
*/
|
||||
status = pjsip_ua_init_module( g_endpt, NULL );
|
||||
PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
|
||||
|
||||
/*
|
||||
* Init invite session module.
|
||||
*/
|
||||
{
|
||||
pjsip_inv_callback inv_cb;
|
||||
|
||||
/* Init the callback for INVITE session: */
|
||||
pj_memset(&inv_cb, 0, sizeof(inv_cb));
|
||||
inv_cb.on_state_changed = &call_on_state_changed;
|
||||
inv_cb.on_new_session = &call_on_forked;
|
||||
inv_cb.on_media_update = &call_on_media_update;
|
||||
|
||||
/* Initialize invite session module: */
|
||||
status = pjsip_inv_usage_init(g_endpt, &inv_cb);
|
||||
PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Register module to receive incoming requests.
|
||||
*/
|
||||
status = pjsip_endpt_register_module( g_endpt, &mod_simpleua);
|
||||
PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
|
||||
|
||||
|
||||
/*
|
||||
* Init media endpoint:
|
||||
*/
|
||||
status = pjmedia_endpt_create(&cp.factory, &g_med_endpt);
|
||||
PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
|
||||
|
||||
/*
|
||||
* Add PCMA/PCMU codec to the media endpoint.
|
||||
*/
|
||||
status = pjmedia_codec_g711_init(g_med_endpt);
|
||||
PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
|
||||
|
||||
/*
|
||||
* Initialize RTP socket info for the media.
|
||||
*/
|
||||
status = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &g_med_skinfo.rtp_sock);
|
||||
PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
|
||||
|
||||
pj_sockaddr_in_init( &g_med_skinfo.rtp_addr_name,
|
||||
pjsip_endpt_name(g_endpt), 4000);
|
||||
|
||||
status = pj_sock_bind(g_med_skinfo.rtp_sock, &g_med_skinfo.rtp_addr_name,
|
||||
sizeof(pj_sockaddr_in));
|
||||
if (status != PJ_SUCCESS) {
|
||||
app_perror( THIS_FILE,
|
||||
"Unable to bind RTP socket",
|
||||
status);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* For simplicity, ignore RTCP socket. */
|
||||
g_med_skinfo.rtcp_sock = PJ_INVALID_SOCKET;
|
||||
g_med_skinfo.rtcp_addr_name = g_med_skinfo.rtp_addr_name;
|
||||
|
||||
|
||||
/*
|
||||
* If URL is specified, then make call immediately.
|
||||
*/
|
||||
if (argc > 1) {
|
||||
char temp[80];
|
||||
pj_str_t dst_uri = pj_str(argv[1]);
|
||||
pj_str_t local_uri;
|
||||
pjsip_dialog *dlg;
|
||||
pjmedia_sdp_session *local_sdp;
|
||||
pjsip_tx_data *tdata;
|
||||
|
||||
pj_ansi_sprintf(temp, "sip:simpleuac@%s", pjsip_endpt_name(g_endpt)->ptr);
|
||||
local_uri = pj_str(temp);
|
||||
|
||||
/* Create UAC dialog */
|
||||
status = pjsip_dlg_create_uac( pjsip_ua_instance(),
|
||||
&local_uri, /* local URI */
|
||||
NULL, /* local Contact */
|
||||
&dst_uri, /* remote URI */
|
||||
&dst_uri, /* remote target */
|
||||
&dlg); /* dialog */
|
||||
if (status != PJ_SUCCESS) {
|
||||
app_perror(THIS_FILE, "Unable to create UAC dialog", status);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Get media capability from media endpoint: */
|
||||
status = pjmedia_endpt_create_sdp( g_med_endpt, dlg->pool, 1,
|
||||
&g_med_skinfo, &local_sdp);
|
||||
PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
|
||||
|
||||
|
||||
/* Create the INVITE session: */
|
||||
status = pjsip_inv_create_uac( dlg, local_sdp, 0, &g_inv);
|
||||
PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
|
||||
|
||||
|
||||
/* Create initial INVITE request: */
|
||||
status = pjsip_inv_invite(g_inv, &tdata);
|
||||
PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
|
||||
|
||||
/* Send initial INVITE request: */
|
||||
status = pjsip_inv_send_msg(g_inv, tdata);
|
||||
PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
|
||||
|
||||
} else {
|
||||
PJ_LOG(3,(THIS_FILE, "Ready to accept incoming calls..."));
|
||||
}
|
||||
|
||||
|
||||
/* Loop until one call is completed */
|
||||
for (;!g_complete;) {
|
||||
pj_time_val timeout = {0, 10};
|
||||
pjsip_endpt_handle_events(g_endpt, &timeout);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Callback when INVITE session state has changed.
|
||||
*/
|
||||
static void call_on_state_changed( pjsip_inv_session *inv,
|
||||
pjsip_event *e)
|
||||
{
|
||||
if (inv->state == PJSIP_INV_STATE_DISCONNECTED) {
|
||||
|
||||
PJ_LOG(3,(THIS_FILE, "Call DISCONNECTED [reason=%d (%s)]",
|
||||
inv->cause,
|
||||
pjsip_get_status_text(inv->cause)->ptr));
|
||||
|
||||
PJ_LOG(3,(THIS_FILE, "One call completed, application quitting..."));
|
||||
g_complete = 1;
|
||||
|
||||
} else {
|
||||
|
||||
PJ_LOG(3,(THIS_FILE, "Call state changed to %s",
|
||||
pjsip_inv_state_name(inv->state)));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Callback when media negotiation has completed.
|
||||
*/
|
||||
static void call_on_media_update( pjsip_inv_session *inv,
|
||||
pj_status_t status)
|
||||
{
|
||||
const pjmedia_sdp_session *local_sdp;
|
||||
const pjmedia_sdp_session *remote_sdp;
|
||||
pjmedia_port *media_port;
|
||||
|
||||
if (status != PJ_SUCCESS) {
|
||||
|
||||
app_perror(THIS_FILE, "SDP negotiation has failed", status);
|
||||
|
||||
/* Here we should disconnect call if we're not in the middle
|
||||
* of initializing an UAS dialog and if this is not a re-INVITE.
|
||||
*/
|
||||
return;
|
||||
}
|
||||
|
||||
/* Get local and remote SDP */
|
||||
|
||||
status = pjmedia_sdp_neg_get_active_local(inv->neg, &local_sdp);
|
||||
|
||||
status = pjmedia_sdp_neg_get_active_remote(inv->neg, &remote_sdp);
|
||||
|
||||
/* Create new media session.
|
||||
* The media session is active immediately.
|
||||
*/
|
||||
status = pjmedia_session_create( g_med_endpt, 1,
|
||||
&g_med_skinfo,
|
||||
local_sdp, remote_sdp,
|
||||
NULL, &g_med_session );
|
||||
if (status != PJ_SUCCESS) {
|
||||
app_perror( THIS_FILE, "Unable to create media session", status);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Get the port interface of the first stream in the session. */
|
||||
pjmedia_session_get_port(g_med_session, 0, &media_port);
|
||||
|
||||
/* Create a sound Player device and connect the media port to the
|
||||
* sound device.
|
||||
*/
|
||||
status = pjmedia_snd_port_create_player(
|
||||
inv->pool, /* pool */
|
||||
-1, /* sound dev id */
|
||||
media_port->info.sample_rate, /* clock rate */
|
||||
media_port->info.channel_count, /* channel count */
|
||||
media_port->info.samples_per_frame, /* samples per frame*/
|
||||
media_port->info.bits_per_sample, /* bits per sample */
|
||||
0, /* options */
|
||||
&g_snd_player);
|
||||
if (status != PJ_SUCCESS) {
|
||||
app_perror( THIS_FILE, "Unable to create sound player", status);
|
||||
PJ_LOG(3,(THIS_FILE, "%d %d %d %d",
|
||||
media_port->info.sample_rate, /* clock rate */
|
||||
media_port->info.channel_count, /* channel count */
|
||||
media_port->info.samples_per_frame, /* samples per frame*/
|
||||
media_port->info.bits_per_sample /* bits per sample */
|
||||
));
|
||||
return;
|
||||
}
|
||||
|
||||
status = pjmedia_snd_port_connect(g_snd_player, media_port);
|
||||
|
||||
|
||||
/* Create a sound recorder device and connect the media port to the
|
||||
* sound device.
|
||||
*/
|
||||
status = pjmedia_snd_port_create_rec(
|
||||
inv->pool, /* pool */
|
||||
-1, /* sound dev id */
|
||||
media_port->info.sample_rate, /* clock rate */
|
||||
media_port->info.channel_count, /* channel count */
|
||||
media_port->info.samples_per_frame, /* samples per frame*/
|
||||
media_port->info.bits_per_sample, /* bits per sample */
|
||||
0, /* options */
|
||||
&g_snd_rec);
|
||||
if (status != PJ_SUCCESS) {
|
||||
app_perror( THIS_FILE, "Unable to create sound recorder", status);
|
||||
return;
|
||||
}
|
||||
|
||||
status = pjmedia_snd_port_connect(g_snd_rec, media_port);
|
||||
|
||||
/* Done with media. */
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This callback is called when dialog has forked
|
||||
*/
|
||||
static void call_on_forked(pjsip_inv_session *inv, pjsip_event *e)
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* Callback when incoming requests outside any transactions and any
|
||||
* dialogs are received
|
||||
*/
|
||||
static pj_bool_t on_rx_request( pjsip_rx_data *rdata )
|
||||
{
|
||||
pjsip_dialog *dlg;
|
||||
pjmedia_sdp_session *local_sdp;
|
||||
pjsip_tx_data *tdata;
|
||||
unsigned options = 0;
|
||||
pj_status_t status;
|
||||
|
||||
/*
|
||||
* Respond (statelessly) any non-INVITE requests with 500
|
||||
*/
|
||||
if (rdata->msg_info.msg->line.req.method.id != PJSIP_INVITE_METHOD) {
|
||||
|
||||
pj_str_t reason = pj_str("Simple UA unable to handle this request");
|
||||
|
||||
pjsip_endpt_respond_stateless( g_endpt, rdata,
|
||||
500, &reason,
|
||||
NULL, NULL);
|
||||
return PJ_TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reject INVITE if we already have an INVITE session in progress.
|
||||
*/
|
||||
if (g_inv) {
|
||||
|
||||
pj_str_t reason = pj_str("Another call is in progress");
|
||||
|
||||
pjsip_endpt_respond_stateless( g_endpt, rdata,
|
||||
500, &reason,
|
||||
NULL, NULL);
|
||||
return PJ_TRUE;
|
||||
|
||||
}
|
||||
|
||||
/* Verify that we can handle the request. */
|
||||
status = pjsip_inv_verify_request(rdata, &options, NULL, NULL,
|
||||
g_endpt, NULL);
|
||||
if (status != PJ_SUCCESS) {
|
||||
|
||||
pj_str_t reason = pj_str("Sorry Simple UA can not handle this INVITE");
|
||||
|
||||
pjsip_endpt_respond_stateless( g_endpt, rdata,
|
||||
500, &reason,
|
||||
NULL, NULL);
|
||||
return PJ_TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create UAS dialog.
|
||||
*/
|
||||
status = pjsip_dlg_create_uas( pjsip_ua_instance(),
|
||||
rdata,
|
||||
NULL, /* contact */
|
||||
&dlg);
|
||||
if (status != PJ_SUCCESS) {
|
||||
pjsip_endpt_respond_stateless(g_endpt, rdata, 500, NULL,
|
||||
NULL, NULL);
|
||||
return PJ_TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get media capability from media endpoint:
|
||||
*/
|
||||
|
||||
status = pjmedia_endpt_create_sdp( g_med_endpt, rdata->tp_info.pool, 1,
|
||||
&g_med_skinfo,
|
||||
&local_sdp);
|
||||
PJ_ASSERT_RETURN(status == PJ_SUCCESS, PJ_TRUE);
|
||||
|
||||
/*
|
||||
* Create invite session:
|
||||
*/
|
||||
status = pjsip_inv_create_uas( dlg, rdata, local_sdp, 0, &g_inv);
|
||||
PJ_ASSERT_RETURN(status == PJ_SUCCESS, PJ_TRUE);
|
||||
|
||||
/*
|
||||
* Initially send 180 response.
|
||||
*/
|
||||
status = pjsip_inv_initial_answer(g_inv, rdata,
|
||||
180,
|
||||
NULL, NULL, &tdata);
|
||||
PJ_ASSERT_RETURN(status == PJ_SUCCESS, PJ_TRUE);
|
||||
|
||||
/*
|
||||
* Send the 180 response.
|
||||
*/
|
||||
status = pjsip_inv_send_msg(g_inv, tdata);
|
||||
PJ_ASSERT_RETURN(status == PJ_SUCCESS, PJ_TRUE);
|
||||
|
||||
/*
|
||||
* Now send 200 response.
|
||||
*/
|
||||
status = pjsip_inv_answer( g_inv,
|
||||
200, NULL, /* st_code and st_text */
|
||||
NULL, /* SDP already specified */
|
||||
&tdata);
|
||||
PJ_ASSERT_RETURN(status == PJ_SUCCESS, PJ_TRUE);
|
||||
|
||||
/*
|
||||
* Send the 200 response.
|
||||
*/
|
||||
status = pjsip_inv_send_msg(g_inv, tdata);
|
||||
PJ_ASSERT_RETURN(status == PJ_SUCCESS, PJ_TRUE);
|
||||
|
||||
return PJ_TRUE;
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,123 @@
|
|||
|
||||
/* Include all PJSIP core headers. */
|
||||
#include <pjsip.h>
|
||||
|
||||
/* Include all PJMEDIA headers. */
|
||||
#include <pjmedia.h>
|
||||
|
||||
/* Include all PJMEDIA-CODEC headers. */
|
||||
#include <pjmedia-codec.h>
|
||||
|
||||
/* Include all PJSIP-UA headers */
|
||||
#include <pjsip_ua.h>
|
||||
|
||||
/* Include all PJSIP-SIMPLE headers */
|
||||
#include <pjsip_simple.h>
|
||||
|
||||
/* Include all PJLIB-UTIL headers. */
|
||||
#include <pjlib-util.h>
|
||||
|
||||
/* Include all PJLIB headers. */
|
||||
#include <pjlib.h>
|
||||
|
||||
|
||||
/* Global endpoint instance. */
|
||||
static pjsip_endpoint *g_endpt;
|
||||
|
||||
/* Global caching pool factory. */
|
||||
static pj_caching_pool cp;
|
||||
|
||||
/* Global media endpoint. */
|
||||
static pjmedia_endpt *g_med_endpt;
|
||||
|
||||
/*
|
||||
* Show error.
|
||||
*/
|
||||
static int app_perror( const char *sender, const char *title,
|
||||
pj_status_t status)
|
||||
{
|
||||
char errmsg[PJ_ERR_MSG_SIZE];
|
||||
|
||||
pj_strerror(status, errmsg, sizeof(errmsg));
|
||||
|
||||
PJ_LOG(1,(sender, "%s: %s [code=%d]", title, errmsg, status));
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Perform the very basic initialization:
|
||||
* - init PJLIB.
|
||||
* - init memory pool
|
||||
* - create SIP endpoint instance.
|
||||
*/
|
||||
static pj_status_t util_init(void)
|
||||
{
|
||||
pj_status_t status;
|
||||
|
||||
/* Init PJLIB */
|
||||
status = pj_init();
|
||||
if (status != PJ_SUCCESS) {
|
||||
app_perror(THIS_FILE, "pj_init() error", status);
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Init PJLIB-UTIL: */
|
||||
status = pjlib_util_init();
|
||||
if (status != PJ_SUCCESS) {
|
||||
app_perror(THIS_FILE, "pjlib_util_init() error", status);
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Init memory pool: */
|
||||
|
||||
/* Init caching pool. */
|
||||
pj_caching_pool_init(&cp, &pj_pool_factory_default_policy, 0);
|
||||
|
||||
/* Create global endpoint: */
|
||||
|
||||
{
|
||||
const pj_str_t *hostname;
|
||||
const char *endpt_name;
|
||||
|
||||
/* Endpoint MUST be assigned a globally unique name.
|
||||
* The name will be used as the hostname in Warning header.
|
||||
*/
|
||||
|
||||
/* For this implementation, we'll use hostname for simplicity */
|
||||
hostname = pj_gethostname();
|
||||
endpt_name = hostname->ptr;
|
||||
|
||||
/* Create the endpoint: */
|
||||
|
||||
status = pjsip_endpt_create(&cp.factory, endpt_name,
|
||||
&g_endpt);
|
||||
if (status != PJ_SUCCESS) {
|
||||
app_perror(THIS_FILE, "Unable to create SIP endpoint", status);
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add UDP transport to endpoint.
|
||||
*/
|
||||
static pj_status_t util_add_udp_transport(int port)
|
||||
{
|
||||
pj_sockaddr_in addr;
|
||||
pj_status_t status;
|
||||
|
||||
addr.sin_family = PJ_AF_INET;
|
||||
addr.sin_addr.s_addr = 0;
|
||||
addr.sin_port = port;
|
||||
|
||||
status = pjsip_udp_transport_start( g_endpt, &addr, NULL, 1, NULL);
|
||||
if (status != PJ_SUCCESS) {
|
||||
app_perror(THIS_FILE, "Unable to start UDP transport", status);
|
||||
return status;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
Loading…
Reference in New Issue