From 0dcbe1ea68c039b92076083137062b4cc6363967 Mon Sep 17 00:00:00 2001 From: Benny Prijono Date: Fri, 17 Mar 2006 18:01:27 +0000 Subject: Added samples (finally!!) git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@328 74dad513-b988-da41-8d7b-12977e46ad98 --- pjmedia/build/Makefile | 2 +- pjmedia/build/pjmedia_codec.dsp | 2 +- pjsip-apps/build/Samples-vc.mak | 51 +++ pjsip-apps/build/Samples.mak | 66 ++++ pjsip-apps/build/pjsip_apps.dsw | 36 +++ pjsip-apps/build/samples.dsp | 108 +++++++ pjsip-apps/src/pjsip-perf/handler_call.c | 8 +- pjsip-apps/src/samples/simpleua.c | 519 +++++++++++++++++++++++++++++++ pjsip-apps/src/samples/util.h | 123 ++++++++ 9 files changed, 909 insertions(+), 6 deletions(-) create mode 100644 pjsip-apps/build/Samples-vc.mak create mode 100644 pjsip-apps/build/Samples.mak create mode 100644 pjsip-apps/build/samples.dsp create mode 100644 pjsip-apps/src/samples/simpleua.c create mode 100644 pjsip-apps/src/samples/util.h diff --git a/pjmedia/build/Makefile b/pjmedia/build/Makefile index 5bf38b1a..94adba10 100644 --- a/pjmedia/build/Makefile +++ b/pjmedia/build/Makefile @@ -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) diff --git a/pjmedia/build/pjmedia_codec.dsp b/pjmedia/build/pjmedia_codec.dsp index 7c2e1ed0..0c762097 100644 --- a/pjmedia/build/pjmedia_codec.dsp +++ b/pjmedia/build/pjmedia_codec.dsp @@ -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" diff --git a/pjsip-apps/build/Samples-vc.mak b/pjsip-apps/build/Samples-vc.mak new file mode 100644 index 00000000..cc80e557 --- /dev/null +++ b/pjsip-apps/build/Samples-vc.mak @@ -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) + + diff --git a/pjsip-apps/build/Samples.mak b/pjsip-apps/build/Samples.mak new file mode 100644 index 00000000..e3d89904 --- /dev/null +++ b/pjsip-apps/build/Samples.mak @@ -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)) + diff --git a/pjsip-apps/build/pjsip_apps.dsw b/pjsip-apps/build/pjsip_apps.dsw index 21645077..63bec1d3 100644 --- a/pjsip-apps/build/pjsip_apps.dsw +++ b/pjsip-apps/build/pjsip_apps.dsw @@ -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> diff --git a/pjsip-apps/build/samples.dsp b/pjsip-apps/build/samples.dsp new file mode 100644 index 00000000..2fb8cddb --- /dev/null +++ b/pjsip-apps/build/samples.dsp @@ -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 diff --git a/pjsip-apps/src/pjsip-perf/handler_call.c b/pjsip-apps/src/pjsip-perf/handler_call.c index 5683ffa9..bc7ae339 100644 --- a/pjsip-apps/src/pjsip-perf/handler_call.c +++ b/pjsip-apps/src/pjsip-perf/handler_call.c @@ -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); diff --git a/pjsip-apps/src/samples/simpleua.c b/pjsip-apps/src/samples/simpleua.c new file mode 100644 index 00000000..d8b551fe --- /dev/null +++ b/pjsip-apps/src/samples/simpleua.c @@ -0,0 +1,519 @@ + +/* Include all PJSIP core headers. */ +#include + +/* Include all PJMEDIA headers. */ +#include + +/* Include all PJMEDIA-CODEC headers. */ +#include + +/* Include all PJSIP-UA headers */ +#include + +/* Include all PJSIP-SIMPLE headers */ +#include + +/* Include all PJLIB-UTIL headers. */ +#include + +/* Include all PJLIB headers. */ +#include + + +#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; +} + + diff --git a/pjsip-apps/src/samples/util.h b/pjsip-apps/src/samples/util.h new file mode 100644 index 00000000..fbe1e04f --- /dev/null +++ b/pjsip-apps/src/samples/util.h @@ -0,0 +1,123 @@ + +/* Include all PJSIP core headers. */ +#include + +/* Include all PJMEDIA headers. */ +#include + +/* Include all PJMEDIA-CODEC headers. */ +#include + +/* Include all PJSIP-UA headers */ +#include + +/* Include all PJSIP-SIMPLE headers */ +#include + +/* Include all PJLIB-UTIL headers. */ +#include + +/* Include all PJLIB headers. */ +#include + + +/* 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; +} + -- cgit v1.2.3