Index: pjproject/branches/projects/pjsua2/pjsip-apps/src/pygui/account.py
===================================================================
--- pjproject/branches/projects/pjsua2/pjsip-apps/src/pygui/account.py	(revision 4662)
+++ pjproject/branches/projects/pjsua2/pjsip-apps/src/pygui/account.py	(revision 4663)
@@ -34,4 +34,5 @@
 import accountsetting
 import application
+import call
 
 # Account class
@@ -47,4 +48,5 @@
 		self.cfgChanged = False
 		self.buddyList = []
+                self.callList = []
 
 	def statusText(self):
@@ -73,7 +75,28 @@
 			status = '- not created -'
 		return status
+        
+        def makeCall(self):
+                mycall = call.Call(self.app, self, pj.PJSUA_INVALID_ID)
+                callPrm = pj.CallOpParam()
+                callPrm.opt.audioCount = 1
+                callPrm.opt.videoCount = 0
+                mycall.uri = "sip:test1@pjsip.org"
+                self.callList.append(mycall)
+                mycall.makeCall(mycall.uri, callPrm)
 	
 	def onRegState(self, prm):
 		self.app.updateAccount(self)
+
+        def onIncomingCall(self, prm):
+                mycall = call.Call(self.app, self, prm.callId)
+                self.callList.append(mycall)
+                self.app.updateCall(self)
+                callPrm = pj.CallOpParam()
+                msg = "Incoming call for account '%s'" % self.cfg.idUri
+		if msgbox.askquestion(msg, 'Accept call?', default=msgbox.YES) == u'yes':
+                        callPrm.statusCode = 200
+                        mycall.answer(callPrm)
+                else:
+                        mycall.hangup(callPrm)
 
 
Index: pjproject/branches/projects/pjsua2/pjsip-apps/src/pygui/application.py
===================================================================
--- pjproject/branches/projects/pjsua2/pjsip-apps/src/pygui/application.py	(revision 4662)
+++ pjproject/branches/projects/pjsua2/pjsip-apps/src/pygui/application.py	(revision 4663)
@@ -191,4 +191,14 @@
 		self._onTimer()
 
+        def updateCall(self, acc):
+                iid = str(acc.randId)
+                for call in acc.callList:
+                        calliid = str(call.randId)
+                        uri, status = call.statusText()
+                        if self.tv.exists(calliid):
+                                self.tv.item(call.iid, text=uri, values=(status,))
+                        else:
+                                call.iid = self.tv.insert(iid, 0, calliid, open=True, text=uri, values=(status,))
+
 	def updateAccount(self, acc):
 		iid = str(acc.randId)
@@ -270,5 +280,5 @@
 		self.accMenu = tk.Menu(top, tearoff=False)
 		# Labels, must match with _onAccContextMenu()
-		labels = ['Unregister', 'Reregister', 'Add buddy...', '-',
+		labels = ['Call', '-', 'Unregister', 'Reregister', 'Add buddy...', '-',
 			  'Online', 'Invisible', 'Away', 'Busy', '-',
 			  'Settings...', '-',
@@ -351,5 +361,7 @@
 			return
 		
-		if label=='Unregister':
+                if label=='Call':
+                        acc.makeCall()
+		elif label=='Unregister':
 			acc.setRegistration(False)
 		elif label=='Reregister':
Index: pjproject/branches/projects/pjsua2/pjsip-apps/src/pygui/call.py
===================================================================
--- pjproject/branches/projects/pjsua2/pjsip-apps/src/pygui/call.py	(revision 4663)
+++ pjproject/branches/projects/pjsua2/pjsip-apps/src/pygui/call.py	(revision 4663)
@@ -0,0 +1,69 @@
+# $Id$
+#
+# pjsua Python GUI Demo
+#
+# Copyright (C)2013 Teluu Inc. (http://www.teluu.com)
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
+#
+import sys
+if sys.version_info[0] >= 3: # Python 3
+	import tkinter as tk
+	from tkinter import ttk
+	from tkinter import messagebox as msgbox
+else:
+	import Tkinter as tk
+	import tkMessageBox as msgbox
+	import ttk
+
+import random
+import pjsua2 as pj
+import application
+
+# Call class
+class Call(pj.Call):
+	"""
+	High level Python Call object, derived from pjsua2's Call object.
+	"""
+	def __init__(self, app, acc, callId):
+		pj.Call.__init__(self, acc, callId)
+		self.app = app
+                self.acc = acc
+                self.uri = ''
+                self.randId = random.randint(1, 9999)
+
+	def statusText(self):
+                uri = ''
+		status = '?'
+		if self.isActive():
+			ci = self.getInfo()
+                        status = ci.stateText
+                        uri = ci.remoteURI
+		else:
+			status = '- not established -'
+		return uri, status
+	
+	def onCallState(self, prm):
+                ci = self.getInfo()
+                if ci.state == pj.PJSIP_INV_STATE_DISCONNECTED:
+                        iid = str(self.randId)
+			self.acc.callList.remove(self)
+			self.app.tv.delete( (iid,) )
+                        del self
+                else:
+                        self.app.updateCall(self.acc)
+
+if __name__ == '__main__':
+	application.main()
Index: pjproject/branches/projects/pjsua2/pjsip-apps/src/samples/pjsua2_demo.cpp
===================================================================
--- pjproject/branches/projects/pjsua2/pjsip-apps/src/samples/pjsua2_demo.cpp	(revision 4662)
+++ pjproject/branches/projects/pjsua2/pjsip-apps/src/samples/pjsua2_demo.cpp	(revision 4663)
@@ -24,10 +24,48 @@
 using namespace pj;
 
+class MyAccount;
+
+class MyCall : public Call
+{
+private:
+    MyAccount *myAcc;
+
+public:
+    MyCall(Account &acc, int call_id = PJSUA_INVALID_ID)
+    : Call(acc, call_id)
+    {
+        myAcc = (MyAccount *)&acc;
+    }
+    
+    virtual void onCallState(OnCallStateParam &prm);
+};
+
 class MyAccount : public Account
 {
+public:
+    std::vector<Call *> calls;
+    
 public:
     MyAccount()
     {}
 
+    ~MyAccount()
+    {
+        std::cout << "*** Account is being deleted: No of calls="
+                  << calls.size() << std::endl;
+    }
+    
+    void removeCall(Call *call)
+    {
+        for (std::vector<Call *>::iterator it = calls.begin();
+             it != calls.end(); ++it)
+        {
+            if (*it == call) {
+                calls.erase(it);
+                break;
+            }
+        }
+    }
+
     virtual void onRegState(OnRegStateParam &prm)
     {
@@ -36,5 +74,32 @@
 		  << prm.code << std::endl;
     }
+    
+    virtual void onIncomingCall(OnIncomingCallParam &iprm)
+    {
+        Call *call = new MyCall(*this, iprm.callId);
+        CallInfo ci = call->getInfo();
+        CallOpParam prm;
+        
+        std::cout << "*** Incoming Call: " <<  ci.remoteURI << " ["
+                  << ci.stateText << "]" << std::endl;
+        
+        calls.push_back(call);
+        prm.statusCode = (pjsip_status_code)200;
+        call->answer(prm);
+    }
 };
+
+void MyCall::onCallState(OnCallStateParam &prm)
+{
+    CallInfo ci = getInfo();
+    std::cout << "*** Call: " <<  ci.remoteURI << " [" << ci.stateText
+              << "]" << std::endl;
+    
+    if (ci.state == PJSIP_INV_STATE_DISCONNECTED) {
+        myAcc->removeCall(this);
+        /* Delete the call */
+        delete this;
+    }
+}
 
 static void mainProg1() throw(Error)
@@ -65,9 +130,22 @@
     acc_cfg.sipConfig.authCreds.push_back( AuthCredInfo("digest", "*",
                                                         "test1", 0, "test1") );
-    std::auto_ptr<Account> acc(new MyAccount);
+    std::auto_ptr<MyAccount> acc(new MyAccount);
     acc->create(acc_cfg);
-
+    
     pj_thread_sleep(2000);
-
+    
+    // Make outgoing call
+    Call *call = new MyCall(*acc);
+    acc->calls.push_back(call);
+    CallOpParam prm(true);
+    prm.opt.audioCount = 1;
+    prm.opt.videoCount = 0;
+    call->makeCall("sip:test1@pjsip.org", prm);
+    
+    // Hangup all calls
+    pj_thread_sleep(8000);
+    ep.hangupAllCalls();
+    pj_thread_sleep(4000);
+    
     // Destroy library
     std::cout << "*** PJSUA2 SHUTTING DOWN ***" << std::endl;
@@ -190,5 +268,5 @@
 
     try {
-	mainProg();
+	mainProg1();
 	std::cout << "Success" << std::endl;
     } catch (Error & err) {
Index: pjproject/branches/projects/pjsua2/pjsip-apps/src/swig/java/Makefile
===================================================================
--- pjproject/branches/projects/pjsua2/pjsip-apps/src/swig/java/Makefile	(revision 4662)
+++ pjproject/branches/projects/pjsua2/pjsip-apps/src/swig/java/Makefile	(revision 4663)
@@ -1,3 +1,7 @@
 include ../../../../build.mak
+
+ifneq ($(findstring "$(TARGET_NAME)","darwin"),"")
+  OS=darwin
+endif
 
 OUT_DIR=output
@@ -5,5 +9,9 @@
 LIBPJSUA2_SO=$(OUT_DIR)/pjsua2.dll
 else
-LIBPJSUA2_SO=$(OUT_DIR)/libpjsua2.so
+  ifeq ($(OS),darwin)
+    LIBPJSUA2_SO=$(OUT_DIR)/libpjsua2.jnilib
+  else
+    LIBPJSUA2_SO=$(OUT_DIR)/libpjsua2.so
+  endif
 endif
 
@@ -23,10 +31,13 @@
 # OS specific
 ifeq ($(OS),Windows_NT)
-MY_JNI_LDFLAGS	 = -L$(MY_JDK)/lib -Wl,--kill-at
-MY_JNI_LIB       = $(OUT_DIR)/pjsua2.dll
+  MY_JNI_LDFLAGS	 = -L$(MY_JDK)/lib -Wl,--kill-at
+  MY_JNI_LIB       = $(OUT_DIR)/pjsua2.dll
 else
-MY_JNI_LDFLAGS	 = -L$(MY_JDK)/lib -Wl,-soname,pjsua2.so
-MY_JNI_LIB       = $(OUT_DIR)/libpjsua2.so
-MY_JNI_CFLAGS	 := -fPIC
+  MY_JNI_LDFLAGS	 = -L$(MY_JDK)/lib
+  ifneq ($(OS),darwin)
+    MY_JNI_LDFLAGS := $(MY_JNI_LDFLAGS) -Wl,-soname,pjsua2.so
+  endif
+  MY_JNI_LIB       = $(OUT_DIR)/libpjsua2.so
+  MY_JNI_CFLAGS	 := -fPIC $(MY_JNI_CFLAGS)
 endif
 
@@ -34,6 +45,11 @@
 MY_SWIG		 = swig
 MY_JDK		 = $(JAVA_HOME)
-MY_JAVA		 = $(MY_JDK)/bin/java
-MY_JAVAC	 = $(MY_JDK)/bin/javac
+ifneq ($(findstring $(JAVA_BIN), bin),)
+  MY_JAVA	 = $(MY_JDK)/bin/java
+  MY_JAVAC	 = $(MY_JDK)/bin/javac
+else
+  MY_JAVA	 = $(MY_JDK)/java
+  MY_JAVAC	 = $(MY_JDK)/javac
+endif
 MY_JNI_CFLAGS	 := $(MY_JNI_CFLAGS) -I$(MY_JDK)/include -I$(MY_JDK)/include/win32 \
 		   -I$(MY_JDK)/include/linux -I.
Index: pjproject/branches/projects/pjsua2/pjsip-apps/src/swig/pjsua2.i
===================================================================
--- pjproject/branches/projects/pjsua2/pjsip-apps/src/swig/pjsua2.i	(revision 4662)
+++ pjproject/branches/projects/pjsua2/pjsip-apps/src/swig/pjsua2.i	(revision 4663)
@@ -37,4 +37,5 @@
 %feature("director") Endpoint; 
 %feature("director") Account;
+%feature("director") Call;
 %feature("director") Buddy;
 %feature("director") FindBuddyMatch;
@@ -79,4 +80,7 @@
 %include "pjsua2/presence.hpp"
 %include "pjsua2/account.hpp"
+%include "pjsua2/call.hpp"
+
+%template(CallMediaInfoVector)          std::vector<pj::CallMediaInfo>;
 
 %ignore pj::JsonDocument::allocElement;
Index: pjproject/branches/projects/pjsua2/pjsip-apps/src/swig/python/setup.py
===================================================================
--- pjproject/branches/projects/pjsua2/pjsip-apps/src/swig/python/setup.py	(revision 4662)
+++ pjproject/branches/projects/pjsua2/pjsip-apps/src/swig/python/setup.py	(revision 4663)
@@ -93,5 +93,6 @@
     # Mac OS X depedencies
     extra_link_args += ["-framework", "CoreFoundation", 
-                        "-framework", "AudioToolbox"]
+                        "-framework", "AudioToolbox",
+			"-framework", "QTKit"]
     # OS X Lion support
     if platform.mac_ver()[0].startswith("10.7"):
Index: pjproject/branches/projects/pjsua2/pjsip-apps/src/swig/symbols.i
===================================================================
--- pjproject/branches/projects/pjsua2/pjsip-apps/src/swig/symbols.i	(revision 4662)
+++ pjproject/branches/projects/pjsua2/pjsip-apps/src/swig/symbols.i	(revision 4663)
@@ -8,4 +8,8 @@
 
 typedef int pj_int32_t;
+
+typedef unsigned int pj_uint32_t;
+
+typedef unsigned short pj_uint16_t;
 
 enum pj_file_access {PJ_O_RDONLY = 0x1101, PJ_O_WRONLY = 0x1102, PJ_O_RDWR = 0x1103, PJ_O_APPEND = 0x1108};
@@ -33,4 +37,6 @@
 typedef enum pj_turn_tp_type {PJ_TURN_TP_UDP = 17, PJ_TURN_TP_TCP = 6, PJ_TURN_TP_TLS = 255} pj_turn_tp_type;
 
+typedef enum pjmedia_event_type {PJMEDIA_EVENT_NONE, PJMEDIA_EVENT_FMT_CHANGED = ((('H' << 24) | ('C' << 16)) | ('M' << 8)) | 'F', PJMEDIA_EVENT_WND_CLOSING = ((('L' << 24) | ('C' << 16)) | ('N' << 8)) | 'W', PJMEDIA_EVENT_WND_CLOSED = ((('O' << 24) | ('C' << 16)) | ('N' << 8)) | 'W', PJMEDIA_EVENT_WND_RESIZED = ((('Z' << 24) | ('R' << 16)) | ('N' << 8)) | 'W', PJMEDIA_EVENT_MOUSE_BTN_DOWN = ((('N' << 24) | ('D' << 16)) | ('S' << 8)) | 'M', PJMEDIA_EVENT_KEYFRAME_FOUND = ((('F' << 24) | ('R' << 16)) | ('F' << 8)) | 'I', PJMEDIA_EVENT_KEYFRAME_MISSING = ((('M' << 24) | ('R' << 16)) | ('F' << 8)) | 'I', PJMEDIA_EVENT_ORIENT_CHANGED = ((('T' << 24) | ('N' << 16)) | ('R' << 8)) | 'O'} pjmedia_event_type;
+
 typedef enum pjmedia_srtp_use {PJMEDIA_SRTP_DISABLED, PJMEDIA_SRTP_OPTIONAL, PJMEDIA_SRTP_MANDATORY} pjmedia_srtp_use;
 
@@ -47,9 +53,19 @@
 typedef enum pjmedia_type {PJMEDIA_TYPE_NONE, PJMEDIA_TYPE_AUDIO, PJMEDIA_TYPE_VIDEO, PJMEDIA_TYPE_APPLICATION, PJMEDIA_TYPE_UNKNOWN} pjmedia_type;
 
+typedef enum pjmedia_dir {PJMEDIA_DIR_NONE = 0, PJMEDIA_DIR_ENCODING = 1, PJMEDIA_DIR_CAPTURE = PJMEDIA_DIR_ENCODING, PJMEDIA_DIR_DECODING = 2, PJMEDIA_DIR_PLAYBACK = PJMEDIA_DIR_DECODING, PJMEDIA_DIR_RENDER = PJMEDIA_DIR_DECODING, PJMEDIA_DIR_ENCODING_DECODING = 3, PJMEDIA_DIR_CAPTURE_PLAYBACK = PJMEDIA_DIR_ENCODING_DECODING, PJMEDIA_DIR_CAPTURE_RENDER = PJMEDIA_DIR_ENCODING_DECODING} pjmedia_dir;
+
+typedef enum pjmedia_tp_proto {PJMEDIA_TP_PROTO_NONE = 0, PJMEDIA_TP_PROTO_RTP_AVP, PJMEDIA_TP_PROTO_RTP_SAVP, PJMEDIA_TP_PROTO_UNKNOWN} pjmedia_tp_proto;
+
 typedef enum pjmedia_format_id {PJMEDIA_FORMAT_L16 = 0, PJMEDIA_FORMAT_PCM = PJMEDIA_FORMAT_L16, PJMEDIA_FORMAT_PCMA = ((('W' << 24) | ('A' << 16)) | ('L' << 8)) | 'A', PJMEDIA_FORMAT_ALAW = PJMEDIA_FORMAT_PCMA, PJMEDIA_FORMAT_PCMU = ((('W' << 24) | ('A' << 16)) | ('L' << 8)) | 'u', PJMEDIA_FORMAT_ULAW = PJMEDIA_FORMAT_PCMU, PJMEDIA_FORMAT_AMR = ((('R' << 24) | ('M' << 16)) | ('A' << 8)) | ' ', PJMEDIA_FORMAT_G729 = ((('9' << 24) | ('2' << 16)) | ('7' << 8)) | 'G', PJMEDIA_FORMAT_ILBC = ((('C' << 24) | ('B' << 16)) | ('L' << 8)) | 'I', PJMEDIA_FORMAT_RGB24 = ((('3' << 24) | ('B' << 16)) | ('G' << 8)) | 'R', PJMEDIA_FORMAT_RGBA = ((('A' << 24) | ('B' << 16)) | ('G' << 8)) | 'R', PJMEDIA_FORMAT_BGRA = ((('A' << 24) | ('R' << 16)) | ('G' << 8)) | 'B', PJMEDIA_FORMAT_RGB32 = PJMEDIA_FORMAT_RGBA, PJMEDIA_FORMAT_DIB = (((' ' << 24) | ('B' << 16)) | ('I' << 8)) | 'D', PJMEDIA_FORMAT_GBRP = ((('P' << 24) | ('R' << 16)) | ('B' << 8)) | 'G', PJMEDIA_FORMAT_AYUV = ((('V' << 24) | ('U' << 16)) | ('Y' << 8)) | 'A', PJMEDIA_FORMAT_YUY2 = ((('2' << 24) | ('Y' << 16)) | ('U' << 8)) | 'Y', PJMEDIA_FORMAT_UYVY = ((('Y' << 24) | ('V' << 16)) | ('Y' << 8)) | 'U', PJMEDIA_FORMAT_YVYU = ((('U' << 24) | ('Y' << 16)) | ('V' << 8)) | 'Y', PJMEDIA_FORMAT_I420 = ((('0' << 24) | ('2' << 16)) | ('4' << 8)) | 'I', PJMEDIA_FORMAT_IYUV = PJMEDIA_FORMAT_I420, PJMEDIA_FORMAT_YV12 = ((('2' << 24) | ('1' << 16)) | ('V' << 8)) | 'Y', PJMEDIA_FORMAT_I422 = ((('2' << 24) | ('2' << 16)) | ('4' << 8)) | 'I', PJMEDIA_FORMAT_I420JPEG = ((('0' << 24) | ('2' << 16)) | ('4' << 8)) | 'J', PJMEDIA_FORMAT_I422JPEG = ((('2' << 24) | ('2' << 16)) | ('4' << 8)) | 'J', PJMEDIA_FORMAT_H261 = ((('1' << 24) | ('6' << 16)) | ('2' << 8)) | 'H', PJMEDIA_FORMAT_H263 = ((('3' << 24) | ('6' << 16)) | ('2' << 8)) | 'H', PJMEDIA_FORMAT_H263P = ((('3' << 24) | ('6' << 16)) | ('2' << 8)) | 'P', PJMEDIA_FORMAT_H264 = ((('4' << 24) | ('6' << 16)) | ('2' << 8)) | 'H', PJMEDIA_FORMAT_MJPEG = ((('G' << 24) | ('P' << 16)) | ('J' << 8)) | 'M', PJMEDIA_FORMAT_MPEG1VIDEO = ((('V' << 24) | ('1' << 16)) | ('P' << 8)) | 'M', PJMEDIA_FORMAT_MPEG2VIDEO = ((('V' << 24) | ('2' << 16)) | ('P' << 8)) | 'M', PJMEDIA_FORMAT_MPEG4 = ((('4' << 24) | ('G' << 16)) | ('P' << 8)) | 'M'} pjmedia_format_id;
 
 typedef enum pjsip_cred_data_type {PJSIP_CRED_DATA_PLAIN_PASSWD = 0, PJSIP_CRED_DATA_DIGEST = 1, PJSIP_CRED_DATA_EXT_AKA = 16} pjsip_cred_data_type;
 
+typedef enum pjsip_dialog_cap_status {PJSIP_DIALOG_CAP_UNSUPPORTED = 0, PJSIP_DIALOG_CAP_SUPPORTED = 1, PJSIP_DIALOG_CAP_UNKNOWN = 2} pjsip_dialog_cap_status;
+
+typedef enum pjsip_event_id_e {PJSIP_EVENT_UNKNOWN, PJSIP_EVENT_TIMER, PJSIP_EVENT_TX_MSG, PJSIP_EVENT_RX_MSG, PJSIP_EVENT_TRANSPORT_ERROR, PJSIP_EVENT_TSX_STATE, PJSIP_EVENT_USER} pjsip_event_id_e;
+
 typedef enum pjsip_status_code {PJSIP_SC_TRYING = 100, PJSIP_SC_RINGING = 180, PJSIP_SC_CALL_BEING_FORWARDED = 181, PJSIP_SC_QUEUED = 182, PJSIP_SC_PROGRESS = 183, PJSIP_SC_OK = 200, PJSIP_SC_ACCEPTED = 202, PJSIP_SC_MULTIPLE_CHOICES = 300, PJSIP_SC_MOVED_PERMANENTLY = 301, PJSIP_SC_MOVED_TEMPORARILY = 302, PJSIP_SC_USE_PROXY = 305, PJSIP_SC_ALTERNATIVE_SERVICE = 380, PJSIP_SC_BAD_REQUEST = 400, PJSIP_SC_UNAUTHORIZED = 401, PJSIP_SC_PAYMENT_REQUIRED = 402, PJSIP_SC_FORBIDDEN = 403, PJSIP_SC_NOT_FOUND = 404, PJSIP_SC_METHOD_NOT_ALLOWED = 405, PJSIP_SC_NOT_ACCEPTABLE = 406, PJSIP_SC_PROXY_AUTHENTICATION_REQUIRED = 407, PJSIP_SC_REQUEST_TIMEOUT = 408, PJSIP_SC_GONE = 410, PJSIP_SC_REQUEST_ENTITY_TOO_LARGE = 413, PJSIP_SC_REQUEST_URI_TOO_LONG = 414, PJSIP_SC_UNSUPPORTED_MEDIA_TYPE = 415, PJSIP_SC_UNSUPPORTED_URI_SCHEME = 416, PJSIP_SC_BAD_EXTENSION = 420, PJSIP_SC_EXTENSION_REQUIRED = 421, PJSIP_SC_SESSION_TIMER_TOO_SMALL = 422, PJSIP_SC_INTERVAL_TOO_BRIEF = 423, PJSIP_SC_TEMPORARILY_UNAVAILABLE = 480, PJSIP_SC_CALL_TSX_DOES_NOT_EXIST = 481, PJSIP_SC_LOOP_DETECTED = 482, PJSIP_SC_TOO_MANY_HOPS = 483, PJSIP_SC_ADDRESS_INCOMPLETE = 484, PJSIP_AC_AMBIGUOUS = 485, PJSIP_SC_BUSY_HERE = 486, PJSIP_SC_REQUEST_TERMINATED = 487, PJSIP_SC_NOT_ACCEPTABLE_HERE = 488, PJSIP_SC_BAD_EVENT = 489, PJSIP_SC_REQUEST_UPDATED = 490, PJSIP_SC_REQUEST_PENDING = 491, PJSIP_SC_UNDECIPHERABLE = 493, PJSIP_SC_INTERNAL_SERVER_ERROR = 500, PJSIP_SC_NOT_IMPLEMENTED = 501, PJSIP_SC_BAD_GATEWAY = 502, PJSIP_SC_SERVICE_UNAVAILABLE = 503, PJSIP_SC_SERVER_TIMEOUT = 504, PJSIP_SC_VERSION_NOT_SUPPORTED = 505, PJSIP_SC_MESSAGE_TOO_LARGE = 513, PJSIP_SC_PRECONDITION_FAILURE = 580, PJSIP_SC_BUSY_EVERYWHERE = 600, PJSIP_SC_DECLINE = 603, PJSIP_SC_DOES_NOT_EXIST_ANYWHERE = 604, PJSIP_SC_NOT_ACCEPTABLE_ANYWHERE = 606, PJSIP_SC_TSX_TIMEOUT = PJSIP_SC_REQUEST_TIMEOUT, PJSIP_SC_TSX_TRANSPORT_ERROR = PJSIP_SC_SERVICE_UNAVAILABLE, PJSIP_SC__force_32bit = 0x7FFFFFFF} pjsip_status_code;
+
+typedef enum pjsip_hdr_e {PJSIP_H_ACCEPT, PJSIP_H_ACCEPT_ENCODING_UNIMP, PJSIP_H_ACCEPT_LANGUAGE_UNIMP, PJSIP_H_ALERT_INFO_UNIMP, PJSIP_H_ALLOW, PJSIP_H_AUTHENTICATION_INFO_UNIMP, PJSIP_H_AUTHORIZATION, PJSIP_H_CALL_ID, PJSIP_H_CALL_INFO_UNIMP, PJSIP_H_CONTACT, PJSIP_H_CONTENT_DISPOSITION_UNIMP, PJSIP_H_CONTENT_ENCODING_UNIMP, PJSIP_H_CONTENT_LANGUAGE_UNIMP, PJSIP_H_CONTENT_LENGTH, PJSIP_H_CONTENT_TYPE, PJSIP_H_CSEQ, PJSIP_H_DATE_UNIMP, PJSIP_H_ERROR_INFO_UNIMP, PJSIP_H_EXPIRES, PJSIP_H_FROM, PJSIP_H_IN_REPLY_TO_UNIMP, PJSIP_H_MAX_FORWARDS, PJSIP_H_MIME_VERSION_UNIMP, PJSIP_H_MIN_EXPIRES, PJSIP_H_ORGANIZATION_UNIMP, PJSIP_H_PRIORITY_UNIMP, PJSIP_H_PROXY_AUTHENTICATE, PJSIP_H_PROXY_AUTHORIZATION, PJSIP_H_PROXY_REQUIRE_UNIMP, PJSIP_H_RECORD_ROUTE, PJSIP_H_REPLY_TO_UNIMP, PJSIP_H_REQUIRE, PJSIP_H_RETRY_AFTER, PJSIP_H_ROUTE, PJSIP_H_SERVER_UNIMP, PJSIP_H_SUBJECT_UNIMP, PJSIP_H_SUPPORTED, PJSIP_H_TIMESTAMP_UNIMP, PJSIP_H_TO, PJSIP_H_UNSUPPORTED, PJSIP_H_USER_AGENT_UNIMP, PJSIP_H_VIA, PJSIP_H_WARNING_UNIMP, PJSIP_H_WWW_AUTHENTICATE, PJSIP_H_OTHER} pjsip_hdr_e;
 
 typedef enum pjsip_transport_type_e {PJSIP_TRANSPORT_UNSPECIFIED, PJSIP_TRANSPORT_UDP, PJSIP_TRANSPORT_TCP, PJSIP_TRANSPORT_TLS, PJSIP_TRANSPORT_SCTP, PJSIP_TRANSPORT_LOOP, PJSIP_TRANSPORT_LOOP_DGRAM, PJSIP_TRANSPORT_START_OTHER, PJSIP_TRANSPORT_IPV6 = 128, PJSIP_TRANSPORT_UDP6 = PJSIP_TRANSPORT_UDP + PJSIP_TRANSPORT_IPV6, PJSIP_TRANSPORT_TCP6 = PJSIP_TRANSPORT_TCP + PJSIP_TRANSPORT_IPV6, PJSIP_TRANSPORT_TLS6 = PJSIP_TRANSPORT_TLS + PJSIP_TRANSPORT_IPV6} pjsip_transport_type_e;
@@ -61,7 +77,15 @@
 typedef enum pjsip_ssl_method {PJSIP_SSL_UNSPECIFIED_METHOD = 0, PJSIP_TLSV1_METHOD = 31, PJSIP_SSLV2_METHOD = 20, PJSIP_SSLV3_METHOD = 30, PJSIP_SSLV23_METHOD = 23} pjsip_ssl_method;
 
+typedef enum pjsip_tsx_state_e {PJSIP_TSX_STATE_NULL, PJSIP_TSX_STATE_CALLING, PJSIP_TSX_STATE_TRYING, PJSIP_TSX_STATE_PROCEEDING, PJSIP_TSX_STATE_COMPLETED, PJSIP_TSX_STATE_CONFIRMED, PJSIP_TSX_STATE_TERMINATED, PJSIP_TSX_STATE_DESTROYED, PJSIP_TSX_STATE_MAX} pjsip_tsx_state_e;
+
+typedef enum pjsip_role_e {PJSIP_ROLE_UAC, PJSIP_ROLE_UAS, PJSIP_UAC_ROLE = PJSIP_ROLE_UAC, PJSIP_UAS_ROLE = PJSIP_ROLE_UAS} pjsip_role_e;
+
+typedef enum pjsip_redirect_op {PJSIP_REDIRECT_REJECT, PJSIP_REDIRECT_ACCEPT, PJSIP_REDIRECT_ACCEPT_REPLACE, PJSIP_REDIRECT_PENDING, PJSIP_REDIRECT_STOP} pjsip_redirect_op;
+
 typedef enum pjrpid_activity {PJRPID_ACTIVITY_UNKNOWN, PJRPID_ACTIVITY_AWAY, PJRPID_ACTIVITY_BUSY} pjrpid_activity;
 
 typedef enum pjsip_evsub_state {PJSIP_EVSUB_STATE_NULL, PJSIP_EVSUB_STATE_SENT, PJSIP_EVSUB_STATE_ACCEPTED, PJSIP_EVSUB_STATE_PENDING, PJSIP_EVSUB_STATE_ACTIVE, PJSIP_EVSUB_STATE_TERMINATED, PJSIP_EVSUB_STATE_UNKNOWN} pjsip_evsub_state;
+
+typedef enum pjsip_inv_state {PJSIP_INV_STATE_NULL, PJSIP_INV_STATE_CALLING, PJSIP_INV_STATE_INCOMING, PJSIP_INV_STATE_EARLY, PJSIP_INV_STATE_CONNECTING, PJSIP_INV_STATE_CONFIRMED, PJSIP_INV_STATE_DISCONNECTED} pjsip_inv_state;
 
 enum pjsua_invalid_id_const_ {PJSUA_INVALID_ID = -1};
@@ -85,2 +109,18 @@
 typedef enum pjsua_buddy_status {PJSUA_BUDDY_STATUS_UNKNOWN, PJSUA_BUDDY_STATUS_ONLINE, PJSUA_BUDDY_STATUS_OFFLINE} pjsua_buddy_status;
 
+typedef enum pjsua_call_media_status {PJSUA_CALL_MEDIA_NONE, PJSUA_CALL_MEDIA_ACTIVE, PJSUA_CALL_MEDIA_LOCAL_HOLD, PJSUA_CALL_MEDIA_REMOTE_HOLD, PJSUA_CALL_MEDIA_ERROR} pjsua_call_media_status;
+
+typedef int pjsua_vid_win_id;
+
+typedef int pjsua_call_id;
+
+typedef enum pjsua_med_tp_st {PJSUA_MED_TP_NULL, PJSUA_MED_TP_CREATING, PJSUA_MED_TP_IDLE, PJSUA_MED_TP_INIT, PJSUA_MED_TP_RUNNING, PJSUA_MED_TP_DISABLED} pjsua_med_tp_st;
+
+typedef enum pjsua_call_vid_strm_op {PJSUA_CALL_VID_STRM_NO_OP, PJSUA_CALL_VID_STRM_ADD, PJSUA_CALL_VID_STRM_REMOVE, PJSUA_CALL_VID_STRM_CHANGE_DIR, PJSUA_CALL_VID_STRM_CHANGE_CAP_DEV, PJSUA_CALL_VID_STRM_START_TRANSMIT, PJSUA_CALL_VID_STRM_STOP_TRANSMIT, PJSUA_CALL_VID_STRM_SEND_KEYFRAME} pjsua_call_vid_strm_op;
+
+typedef enum pjsua_vid_req_keyframe_method {PJSUA_VID_REQ_KEYFRAME_SIP_INFO = 1, PJSUA_VID_REQ_KEYFRAME_RTCP_PLI = 2} pjsua_vid_req_keyframe_method;
+
+typedef enum pjsua_call_flag {PJSUA_CALL_UNHOLD = 1, PJSUA_CALL_UPDATE_CONTACT = 2, PJSUA_CALL_INCLUDE_DISABLED_MEDIA = 4} pjsua_call_flag;
+
+typedef enum pjsua_create_media_transport_flag {PJSUA_MED_TP_CLOSE_MEMBER = 1} pjsua_create_media_transport_flag;
+
Index: pjproject/branches/projects/pjsua2/pjsip-apps/src/swig/symbols.lst
===================================================================
--- pjproject/branches/projects/pjsua2/pjsip-apps/src/swig/symbols.lst	(revision 4662)
+++ pjproject/branches/projects/pjsua2/pjsip-apps/src/swig/symbols.lst	(revision 4663)
@@ -1,3 +1,3 @@
-pj/types.h			pj_status_t pj_constants_ pj_uint8_t pj_int32_t         
+pj/types.h			pj_status_t pj_constants_ pj_uint8_t pj_int32_t pj_uint32_t pj_uint16_t
 pj/file_io.h			pj_file_access
 pj/log.h			pj_log_decoration
@@ -8,18 +8,26 @@
 pjnath/turn_session.h          	pj_turn_tp_type
 
-pjmedia/transport_srtp.h     	pjmedia_srtp_use
-pjmedia/vid_stream.h          	pjmedia_vid_stream_rc_method
-pjmedia-videodev/videodev.h     pjmedia_vid_dev_index pjmedia_vid_dev_std_index
+pjmedia/event.h                 pjmedia_event_type
+pjmedia/transport_srtp.h	pjmedia_srtp_use
+pjmedia/vid_stream.h		pjmedia_vid_stream_rc_method
+pjmedia-videodev/videodev.h	pjmedia_vid_dev_index pjmedia_vid_dev_std_index
 pjmedia/wav_port.h              pjmedia_file_writer_option pjmedia_file_player_option
-pjmedia/types.h                 pjmedia_type
+pjmedia/types.h                 pjmedia_type pjmedia_dir pjmedia_tp_proto
 pjmedia/format.h		pjmedia_format_id
 
-pjsip/sip_auth.h          	pjsip_cred_data_type
-pjsip/sip_msg.h               	pjsip_status_code
-pjsip/sip_transport.h          	pjsip_transport_type_e pjsip_transport_flags_e pjsip_transport_state
-pjsip/sip_transport_tls.h     	pjsip_ssl_method
+pjsip/sip_auth.h		pjsip_cred_data_type
+pjsip/sip_dialog.h              pjsip_dialog_cap_status
+pjsip/sip_event.h               pjsip_event_id_e
+pjsip/sip_msg.h			pjsip_status_code pjsip_hdr_e
+pjsip/sip_transport.h		pjsip_transport_type_e pjsip_transport_flags_e pjsip_transport_state
+pjsip/sip_transport_tls.h	pjsip_ssl_method
+pjsip/sip_transaction.h         pjsip_tsx_state_e
+pjsip/sip_types.h               pjsip_role_e
+pjsip/sip_util.h                pjsip_redirect_op
 
 pjsip-simple/rpid.h          	pjrpid_activity
 pjsip-simple/evsub.h		pjsip_evsub_state
 
-pjsua-lib/pjsua.h		pjsua_invalid_id_const_ pjsua_state pjsua_stun_use pjsua_call_hold_type pjsua_acc_id pjsua_destroy_flag pjsua_100rel_use pjsua_sip_timer_use pjsua_ipv6_use pjsua_buddy_status
+pjsip-ua/sip_inv.h              pjsip_inv_state
+
+pjsua-lib/pjsua.h		pjsua_invalid_id_const_ pjsua_state pjsua_stun_use pjsua_call_hold_type pjsua_acc_id pjsua_destroy_flag pjsua_100rel_use pjsua_sip_timer_use pjsua_ipv6_use pjsua_buddy_status pjsua_call_media_status pjsua_vid_win_id pjsua_call_id pjsua_med_tp_st pjsua_call_vid_strm_op pjsua_vid_req_keyframe_method pjsua_call_flag pjsua_create_media_transport_flag
Index: pjproject/branches/projects/pjsua2/pjsip/build/Makefile
===================================================================
--- pjproject/branches/projects/pjsua2/pjsip/build/Makefile	(revision 4662)
+++ pjproject/branches/projects/pjsua2/pjsip/build/Makefile	(revision 4663)
@@ -91,5 +91,5 @@
 export PJSUA2_LIB_OBJS += $(OS_OBJS) $(M_OBJS) $(CC_OBJS) $(HOST_OBJS) \
 			   account.o endpoint.o json.o persistent.o types.o \
-			   siptypes.o presence.o media.o
+			   siptypes.o call.o presence.o media.o
 export PJSUA2_LIB_CFLAGS += $(_CFLAGS) $(PJ_VIDEO_CFLAGS)
 export PJSUA2_LIB_CXXFLAGS = $(PJSUA2_LIB_CFLAGS) 
Index: pjproject/branches/projects/pjsua2/pjsip/include/pjsua2.hpp
===================================================================
--- pjproject/branches/projects/pjsua2/pjsip/include/pjsua2.hpp	(revision 4662)
+++ pjproject/branches/projects/pjsua2/pjsip/include/pjsua2.hpp	(revision 4663)
@@ -22,4 +22,5 @@
 #include <pjsua2/endpoint.hpp>
 #include <pjsua2/account.hpp>
+#include <pjsua2/call.hpp>
 #include <pjsua2/presence.hpp>
 #include <pjsua2/media.hpp>
Index: pjproject/branches/projects/pjsua2/pjsip/include/pjsua2/call.hpp
===================================================================
--- pjproject/branches/projects/pjsua2/pjsip/include/pjsua2/call.hpp	(revision 4663)
+++ pjproject/branches/projects/pjsua2/pjsip/include/pjsua2/call.hpp	(revision 4663)
@@ -0,0 +1,1683 @@
+/* $Id$ */
+/*
+ * Copyright (C) 2012-2013 Teluu Inc. (http://www.teluu.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#ifndef __PJSUA2_CALL_HPP__
+#define __PJSUA2_CALL_HPP__
+
+/**
+ * @file pjsua2/call.hpp
+ * @brief PJSUA2 Call manipulation
+ */
+#include <pjsua-lib/pjsua.h>
+#include <pjsua2/media.hpp>
+
+/**
+ * @defgroup PJSUA2_CALL Call
+ * @ingroup PJSUA2_Ref
+ */
+
+/**
+ * @defgroup PJSUA2_Call_Data_Structure Data Structure
+ * @ingroup PJSUA2_Ref
+ * @{
+ */
+
+/** PJSUA2 API is inside pj namespace */
+namespace pj
+{
+using std::string;
+using std::vector;
+
+//////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Codec parameters, corresponds to pjmedia_codec_param or
+ * pjmedia_vid_codec_param.
+ */
+typedef void *CodecParam;
+
+/**
+ * Media stream, corresponds to pjmedia_stream
+ */
+typedef void *MediaStream;
+
+/**
+ * Media transport, corresponds to pjmedia_transport
+ */
+typedef void *MediaTransport;
+
+/**
+ * This structure describes statistics state.
+ */
+struct MathStat
+{
+    int n;      /**< number of samples  */
+    int max;    /**< maximum value      */
+    int min;    /**< minimum value      */
+    int last;   /**< last value         */
+    int mean;   /**< mean               */
+
+public:
+    /**
+     * Default constructor
+     */
+    MathStat();
+    
+    /**
+     * Convert from pjsip
+     */
+    void fromPj(const pj_math_stat &prm);
+};
+
+/**
+ * Unidirectional RTP stream statistics.
+ */
+struct RtcpStreamStat
+{
+    TimeValue	    update;	/**< Time of last update.		    */
+    unsigned	    updateCount;/**< Number of updates (to calculate avg)   */
+    unsigned	    pkt;	/**< Total number of packets		    */
+    unsigned	    bytes;	/**< Total number of payload/bytes	    */
+    unsigned	    discard;	/**< Total number of discarded packets.	    */
+    unsigned	    loss;	/**< Total number of packets lost	    */
+    unsigned	    reorder;	/**< Total number of out of order packets   */
+    unsigned	    dup;	/**< Total number of duplicates packets	    */
+    
+    MathStat        lossPeriodUsec; /**< Loss period statistics 	    */
+
+    struct {
+        unsigned    burst;	/**< Burst/sequential packet lost detected  */
+        unsigned    random;	/**< Random packet lost detected.	    */
+    } lossType;                 /**< Types of loss detected.                */
+    
+    MathStat        jitterUsec;	/**< Jitter statistics                      */
+    
+public:
+    /**
+     * Convert from pjsip
+     */
+    void fromPj(const pjmedia_rtcp_stream_stat &prm);
+};
+
+/**
+ * RTCP SDES structure.
+ */
+struct RtcpSdes
+{
+    string	cname;		/**< RTCP SDES type CNAME.	*/
+    string	name;		/**< RTCP SDES type NAME.	*/
+    string	email;		/**< RTCP SDES type EMAIL.	*/
+    string	phone;		/**< RTCP SDES type PHONE.	*/
+    string	loc;		/**< RTCP SDES type LOC.	*/
+    string	tool;		/**< RTCP SDES type TOOL.	*/
+    string	note;		/**< RTCP SDES type NOTE.	*/
+
+public:
+    /**
+     * Convert from pjsip
+     */
+    void fromPj(const pjmedia_rtcp_sdes &prm);
+};
+    
+/**
+ * Bidirectional RTP stream statistics.
+ */
+struct RtcpStat
+{
+    TimeValue           start;          /**< Time when session was created  */
+    
+    RtcpStreamStat      txStat;         /**< Encoder stream statistics.	    */
+    RtcpStreamStat      rxStat;         /**< Decoder stream statistics.	    */
+    
+    MathStat            rttUsec;        /**< Round trip delay statistic.    */
+    
+    pj_uint32_t		rtpTxLastTs;    /**< Last TX RTP timestamp.         */
+    pj_uint16_t		rtpTxLastSeq;   /**< Last TX RTP sequence.          */
+
+    MathStat            rxIpdvUsec;     /**< Statistics of IP packet delay
+                                             variation in receiving
+                                             direction. It is only used when
+                                             PJMEDIA_RTCP_STAT_HAS_IPDV is
+                                             set to non-zero.               */
+
+    MathStat            rxRawJitterUsec;/**< Statistic of raw jitter in
+                                             receiving direction. It is only 
+                                             used when
+                                             PJMEDIA_RTCP_STAT_HAS_RAW_JITTER
+                                             is set to non-zero.            */
+    
+    RtcpSdes            peerSdes;       /**< Peer SDES.			    */
+
+public:
+    /**
+     * Convert from pjsip
+     */
+    void fromPj(const pjmedia_rtcp_stat &prm);
+};
+
+/**
+ * This structure describes jitter buffer state.
+ */
+struct JbufState
+{
+    /* Setting */
+    unsigned	frameSize;	    /**< Individual frame size, in bytes.   */
+    unsigned	minPrefetch;	    /**< Minimum allowed prefetch, in frms. */
+    unsigned	maxPrefetch;	    /**< Maximum allowed prefetch, in frms. */
+    
+    /* Status */
+    unsigned	burst;		    /**< Current burst level, in frames	    */
+    unsigned	prefetch;	    /**< Current prefetch value, in frames  */
+    unsigned	size;		    /**< Current buffer size, in frames.    */
+    
+    /* Statistic */
+    unsigned	avgDelayMsec;	    /**< Average delay, in ms.		    */
+    unsigned	minDelayMsec;	    /**< Minimum delay, in ms.		    */
+    unsigned	maxDelayMsec;	    /**< Maximum delay, in ms.		    */
+    unsigned	devDelayMsec;	    /**< Standard deviation of delay, in ms.*/
+    unsigned	avgBurst;	    /**< Average burst, in frames.	    */
+    unsigned	lost;		    /**< Number of lost frames.		    */
+    unsigned	discard;	    /**< Number of discarded frames.	    */
+    unsigned	empty;		    /**< Number of empty on GET events.	    */
+    
+public:
+    /**
+     * Convert from pjsip
+     */
+    void fromPj(const pjmedia_jb_state &prm);
+};
+
+/**
+ * This structure describes SDP session description. It corresponds to the
+ * pjmedia_sdp_session structure.
+ */
+struct SdpSession
+{
+    /**
+     * The whole SDP as a string.
+     */
+    string  wholeSdp;
+    
+    /**
+     * Pointer to its original pjmedia_sdp_session. Only valid when the struct
+     * is converted from PJSIP's pjmedia_sdp_session.
+     */
+    void   *pjSdpSession;
+
+public:
+    /**
+     * Convert from pjsip
+     */
+    void fromPj(const pjmedia_sdp_session &sdp);
+};
+
+/**
+ * This structure describes a media format changed event.
+ */
+struct MediaFmtChangedEvent
+{
+    unsigned newWidth;      /**< The new width.     */
+    unsigned newHeight;     /**< The new height.    */
+};
+
+/**
+ * This structure describes a media event. It corresponds to the
+ * pjmedia_event structure.
+ */
+struct MediaEvent
+{
+    /**
+     * The event type.
+     */
+    pjmedia_event_type          type;
+
+    /**
+     * Additional data/parameters about the event. The type of data
+     * will be specific to the event type being reported.
+     */
+    union {
+	/**
+         * Media format changed event data.
+         */
+	MediaFmtChangedEvent    fmtChanged;
+        
+	/**
+         * Pointer to storage to user event data, if it's outside
+	 * this struct
+	 */
+	GenericData		ptr;
+    } data;
+    
+    /**
+     * Pointer to original pjmedia_event. Only valid when the struct
+     * is converted from PJSIP's pjmedia_event.
+     */
+    void                       *pjMediaEvent;
+
+public:
+    /**
+     * Convert from pjsip
+     */
+    void fromPj(const pjmedia_event &ev);
+};
+
+/**
+ * This structure describes media transport informations. It corresponds to the
+ * pjmedia_transport_info structure.
+ */
+struct MediaTransportInfo
+{
+    /**
+     * Remote address where RTP originated from.
+     */
+    SocketAddress   srcRtpName;
+
+    /**
+     * Remote address where RTCP originated from.
+     */
+    SocketAddress   srcRtcpName;
+    
+public:
+    /**
+     * Convert from pjsip
+     */
+    void fromPj(const pjmedia_transport_info &info);
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Call settings.
+ */
+struct CallSetting
+{
+    /**
+     * Bitmask of #pjsua_call_flag constants.
+     *
+     * Default: PJSUA_CALL_INCLUDE_DISABLED_MEDIA
+     */
+    unsigned	    flag;
+    
+    /**
+     * This flag controls what methods to request keyframe are allowed on
+     * the call. Value is bitmask of #pjsua_vid_req_keyframe_method.
+     *
+     * Default: PJSUA_VID_REQ_KEYFRAME_SIP_INFO |
+     *          PJSUA_VID_REQ_KEYFRAME_RTCP_PLI
+     */
+    unsigned	    reqKeyframeMethod;
+    
+    /**
+     * Number of simultaneous active audio streams for this call. Setting
+     * this to zero will disable audio in this call.
+     *
+     * Default: 1
+     */
+    unsigned        audioCount;
+    
+    /**
+     * Number of simultaneous active video streams for this call. Setting
+     * this to zero will disable video in this call.
+     *
+     * Default: 1 (if video feature is enabled, otherwise it is zero)
+     */
+    unsigned        videoCount;
+    
+public:
+    /**
+     * Default constructor initializes with empty or default values.
+     */
+    CallSetting(pj_bool_t useDefaultValues = false);
+
+    /**
+     * Check if the settings are set with empty values.
+     *
+     * @return      True if the settings are empty.
+     */
+    bool isEmpty() const;
+
+    /**
+     * Convert from pjsip
+     */
+    void fromPj(const pjsua_call_setting &prm);
+
+    /**
+     * Convert to pjsip
+     */
+    pjsua_call_setting toPj() const;
+};
+
+/**
+ * Call media information.
+ */
+struct CallMediaInfo
+{
+    /**
+     * Media index in SDP.
+     */
+    unsigned                index;
+    
+    /**
+     * Media type.
+     */
+    pjmedia_type            type;
+    
+    /**
+     * Media direction.
+     */
+    pjmedia_dir             dir;
+    
+    /**
+     * Call media status.
+     */
+    pjsua_call_media_status status;
+    
+    /**
+     * The conference port number for the call. Only valid if the media type
+     * is audio.
+     */
+    int                     audioConfSlot;
+    
+    /**
+     * The window id for incoming video, if any, or
+     * PJSUA_INVALID_ID. Only valid if the media type is video.
+     */
+    pjsua_vid_win_id	    videoIncomingWindowId;
+    
+    /**
+     * The video capture device for outgoing transmission, if any,
+     * or PJMEDIA_VID_INVALID_DEV. Only valid if the media type is video.
+     */
+    pjmedia_vid_dev_index   videoCapDev;
+    
+public:
+    /**
+     * Default constructor
+     */
+    CallMediaInfo();
+    
+    /**
+     * Convert from pjsip
+     */
+    void fromPj(const pjsua_call_media_info &prm);
+};
+    
+/** Array of call media info */
+typedef std::vector<CallMediaInfo> CallMediaInfoVector;
+
+/**
+ * Call information. Application can query the call information
+ * by calling Call::getInfo().
+ */
+struct CallInfo
+{
+    /**
+     * Call identification.
+     */
+    pjsua_call_id	id;
+    
+    /**
+     * Initial call role (UAC == caller)
+     */
+    pjsip_role_e	role;
+    
+    /**
+     * The account ID where this call belongs.
+     */
+    pjsua_acc_id	accId;
+    
+    /**
+     * Local URI
+     */
+    string		localURI;
+    
+    /**
+     * Local Contact
+     */
+    string		localContact;
+    
+    /**
+     * Remote URI
+     */
+    string		remoteURI;
+    
+    /**
+     * Remote contact
+     */
+    string		remoteContact;
+    
+    /**
+     * Dialog Call-ID string.
+     */
+    string		callIdString;
+    
+    /**
+     * Call setting
+     */
+    CallSetting         setting;
+    
+    /**
+     * Call state
+     */
+    pjsip_inv_state	state;
+    
+    /**
+     * Text describing the state
+     */
+    string		stateText;
+    
+    /**
+     * Last status code heard, which can be used as cause code
+     */
+    pjsip_status_code	lastStatusCode;
+    
+    /**
+     * The reason phrase describing the last status.
+     */
+    string		lastReason;
+    
+    /**
+     * Array of active media information.
+     */
+    CallMediaInfoVector media;
+
+    /**
+     * Array of provisional media information. This contains the media info
+     * in the provisioning state, that is when the media session is being
+     * created/updated (SDP offer/answer is on progress).
+     */
+    CallMediaInfoVector provMedia;
+    
+    /**
+     * Up-to-date call connected duration (zero when call is not
+     * established)
+     */
+    TimeValue		connectDuration;
+    
+    /**
+     * Total call duration, including set-up time
+     */
+    TimeValue		totalDuration;
+    
+    /**
+     * Flag if remote was SDP offerer
+     */
+    bool		remOfferer;
+    
+    /**
+     * Number of audio streams offered by remote
+     */
+    unsigned		remAudioCount;
+    
+    /**
+     * Number of video streams offered by remote
+     */
+    unsigned		remVideoCount;
+
+public:
+    /**
+     * Convert from pjsip
+     */
+    void fromPj(const pjsua_call_info &pci);
+};
+
+/**
+ * Media stream info.
+ */
+struct StreamInfo
+{
+    /**
+     * Media type of this stream.
+     */
+    pjmedia_type        type;
+
+    /**
+     * Transport protocol (RTP/AVP, etc.)
+     */
+    pjmedia_tp_proto	proto;
+    
+    /**
+     * Media direction.
+     */
+    pjmedia_dir		dir;
+    
+    /**
+     * Remote RTP address
+     */
+    SocketAddress	remoteRtpAddress;
+    
+    /**
+     * Optional remote RTCP address
+     */
+    SocketAddress	remoteRtcpAddress;
+    
+    /**
+     * Outgoing codec payload type.
+     */
+    unsigned		txPt;
+    
+    /**
+     * Incoming codec payload type.
+     */
+    unsigned		rxPt;
+    
+    /**
+     * Codec name.
+     */
+    string              codecName;
+    
+    /**
+     * Codec clock rate.
+     */
+    unsigned            codecClockRate;
+    
+    /**
+     * Optional codec param.
+     */
+    CodecParam          codecParam;
+
+public:
+    /**
+     * Convert from pjsip
+     */
+    void fromPj(const pjsua_stream_info &info);
+};
+
+/**
+ * Media stream statistic.
+ */
+struct StreamStat
+{
+    /**
+     * RTCP statistic.
+     */
+    RtcpStat	rtcp;
+    
+    /**
+     * Jitter buffer statistic.
+     */
+    JbufState	jbuf;
+
+public:
+    /**
+     * Convert from pjsip
+     */
+    void fromPj(const pjsua_stream_stat &prm);
+};
+
+/**
+ * This structure contains parameters for onCallState() callback.
+ */
+struct OnCallStateParam
+{
+    /**
+     * Event which causes the call state to change.
+     */
+    SipEvent    e;
+};
+
+/**
+ * This structure contains parameters for onCallTsxState() callback.
+ */
+struct OnCallTsxStateParam
+{
+    /**
+     * Transaction event that caused the state change.
+     */
+    SipEvent    e;
+};
+
+/**
+ * This structure contains parameters for onCallMediaState() callback.
+ */
+struct OnCallMediaStateParam
+{
+};
+
+/**
+ * This structure contains parameters for onCallSdpCreated() callback.
+ */
+struct OnCallSdpCreatedParam
+{
+    /**
+     * The SDP has just been created.
+     */
+    SdpSession sdp;
+
+    /**
+     * The remote SDP, will be empty if local is SDP offerer.
+     */
+    SdpSession remSdp;
+};
+
+/**
+ * This structure contains parameters for onStreamCreated() callback.
+ */
+struct OnStreamCreatedParam
+{
+    /**
+     * Media stream.
+     */
+    MediaStream stream;
+    
+    /**
+     * Stream index in the media session.
+     */
+    unsigned    streamIdx;
+    
+    /**
+     * On input, it specifies the media port of the stream. Application
+     * may modify this pointer to point to different media port to be
+     * registered to the conference bridge.
+     */
+    MediaPort   pPort;
+};
+
+/**
+ * This structure contains parameters for onStreamDestroyed() callback.
+ */
+struct OnStreamDestroyedParam
+{
+    /**
+     * Media stream.
+     */
+    MediaStream stream;
+    
+    /**
+     * Stream index in the media session.
+     */
+    unsigned    streamIdx;
+};
+
+/**
+ * This structure contains parameters for onDtmfDigit() callback.
+ */
+struct OnDtmfDigitParam
+{
+    /**
+     * DTMF ASCII digit.
+     */
+    string      digit;
+};
+
+/**
+ * This structure contains parameters for onCallTransferRequest() callback.
+ */
+struct OnCallTransferRequestParam
+{
+    /**
+     * The destination where the call will be transfered to.
+     */
+    string              dstUri;
+    
+    /**
+     * Status code to be returned for the call transfer request. On input,
+     * it contains status code 200.
+     */
+    pjsip_status_code   statusCode;
+    
+    /**
+     * The current call setting, application can update this setting
+     * for the call being transfered.
+     */
+    CallSetting         opt;
+};
+
+/**
+ * This structure contains parameters for onCallTransferStatus() callback.
+ */
+struct OnCallTransferStatusParam
+{
+    /**
+     * Status progress of the transfer request.
+     */
+    pjsip_status_code   statusCode;
+    
+    /**
+     * Status progress reason.
+     */
+    string              reason;
+    
+    /**
+     * If true, no further notification will be reported. The statusCode
+     * specified in this callback is the final status.
+     */
+    bool                finalNotify;
+    
+    /**
+     * Initially will be set to true, application can set this to false
+     * if it no longer wants to receive further notification (for example,
+     * after it hangs up the call).
+     */
+    bool                cont;
+};
+
+/**
+ * This structure contains parameters for onCallReplaceRequest() callback.
+ */
+struct OnCallReplaceRequestParam
+{
+    /**
+     * The incoming INVITE request to replace the call.
+     */
+    SipRxData           rdata;
+    
+    /**
+     * Status code to be set by application. Application should only
+     * return a final status (200-699)
+     */
+    pjsip_status_code   statusCode;
+    
+    /**
+     * Optional status text to be set by application.
+     */
+    string              reason;
+    
+    /**
+     * The current call setting, application can update this setting for
+     * the call being replaced.
+     */
+    CallSetting         opt;
+};
+
+/**
+ * This structure contains parameters for onCallReplaced() callback.
+ */
+struct OnCallReplacedParam
+{
+    /**
+     * The new call id.
+     */
+    pjsua_call_id       newCallId;
+};
+
+/**
+ * This structure contains parameters for onCallRxOffer() callback.
+ */
+struct OnCallRxOfferParam
+{
+    /**
+     * The new offer received.
+     */
+    SdpSession          offer;
+    
+    /**
+     * Status code to be returned for answering the offer. On input,
+     * it contains status code 200. Currently, valid values are only
+     * 200 and 488.
+     */
+    pjsip_status_code   statusCode;
+    
+    /**
+     * The current call setting, application can update this setting for
+     * answering the offer.
+     */
+    CallSetting         opt;
+};
+
+struct OnCallRedirectedParam
+{
+    /**
+     * The current target to be tried.
+     */
+    string          targetUri;
+    
+    /**
+     * The event that caused this callback to be called.
+     * This could be the receipt of 3xx response, or 4xx/5xx response
+     * received for the INVITE sent to subsequent targets, or empty
+     * (e.type == PJSIP_EVENT_UNKNOWN)
+     * if this callback is called from within #Call::processRedirect()
+     * context.
+     */
+    SipEvent        e;
+};
+
+/**
+ * This structure contains parameters for onCallMediaEvent() callback.
+ */
+struct OnCallMediaEventParam
+{
+    /**
+     * The media stream index.
+     */
+    unsigned        medIdx;
+    
+    /**
+     * The media event.
+     */
+    MediaEvent      ev;
+};
+
+/**
+ * This structure contains parameters for onCallMediaTransportState() callback.
+ */
+struct OnCallMediaTransportStateParam
+{
+    /**
+     * The media index.
+     */
+    unsigned        medIdx;
+    
+    /**
+     * The media transport state
+     */
+    pjsua_med_tp_st state;
+    
+    /**
+     * The last error code related to the media transport state.
+     */
+    pj_status_t     status;
+    
+    /**
+     * Optional SIP error code.
+     */
+    int             sipErrorCode;
+};
+
+/**
+ * This structure contains parameters for onCreateMediaTransport() callback.
+ */
+struct OnCreateMediaTransportParam
+{
+    /**
+     * The media index in the SDP for which this media transport will be used.
+     */
+    unsigned        mediaIdx;
+    
+    /**
+     * The media transport which otherwise will be used by the call has this
+     * callback not been implemented. Application can change this to its own
+     * instance of media transport to be used by the call.
+     */
+    MediaTransport  mediaTp;
+    
+    /**
+     * Bitmask from pjsua_create_media_transport_flag.
+     */
+    unsigned        flags;
+};
+
+/**
+ * @}  // PJSUA2_Call_Data_Structure
+ */
+
+/**
+ * @addtogroup PJSUA2_CALL
+ * @{
+ */
+
+/**
+ * This structure contains parameters for Call::answer(), Call::hangup(),
+ * Call::reinvite(), Call::update(), Call::xfer(), Call::xferReplaces(),
+ * Call::setHold().
+ */
+struct CallOpParam
+{
+    /**
+     * The call setting.
+     */
+    CallSetting         opt;
+    
+    /**
+     * Status code.
+     */
+    pjsip_status_code   statusCode;
+    
+    /**
+     * Reason phrase.
+     */
+    string              reason;
+    
+    /**
+     * Options.
+     */
+    unsigned            options;
+    
+    /**
+     * List of headers etc to be added to outgoing response message.
+     * Note that this message data will be persistent in all next
+     * answers/responses for this INVITE request.
+     */
+    SipTxOption         txOption;
+    
+public:
+    /**
+     * Default constructor initializes with zero/empty values.
+     * Setting useDefaultCallSetting to true will initialize opt with default
+     * call setting values.
+     */
+    CallOpParam(bool useDefaultCallSetting = false);
+};
+
+/**
+ * This structure contains parameters for Call::sendRequest()
+ */
+struct CallSendRequestParam
+{
+    /**
+     * SIP method of the request.
+     */
+    string       method;
+    
+    /**
+     * Message body and/or list of headers etc to be included in
+     * outgoing request.
+     */
+    SipTxOption  txOption;
+    
+public:
+    /**
+     * Default constructor initializes with zero/empty values.
+     */
+    CallSendRequestParam();
+};
+
+/**
+ * This structure contains parameters for Call::vidSetStream()
+ */
+struct CallVidSetStreamParam
+{
+    /**
+     * Specify the media stream index. This can be set to -1 to denote
+     * the default video stream in the call, which is the first active
+     * video stream or any first video stream if none is active.
+     *
+     * This field is valid for all video stream operations, except
+     * PJSUA_CALL_VID_STRM_ADD.
+     *
+     * Default: -1 (first active video stream, or any first video stream
+     *              if none is active)
+     */
+    int                     medIdx;
+    
+    /**
+     * Specify the media stream direction.
+     *
+     * This field is valid for the following video stream operations:
+     * PJSUA_CALL_VID_STRM_ADD and PJSUA_CALL_VID_STRM_CHANGE_DIR.
+     *
+     * Default: PJMEDIA_DIR_ENCODING_DECODING
+     */
+    pjmedia_dir             dir;
+    
+    /**
+     * Specify the video capture device ID. This can be set to
+     * PJMEDIA_VID_DEFAULT_CAPTURE_DEV to specify the default capture
+     * device as configured in the account.
+     *
+     * This field is valid for the following video stream operations:
+     * PJSUA_CALL_VID_STRM_ADD and PJSUA_CALL_VID_STRM_CHANGE_CAP_DEV.
+     *
+     * Default: PJMEDIA_VID_DEFAULT_CAPTURE_DEV.
+     */
+    pjmedia_vid_dev_index   capDev;
+    
+public:
+    /**
+     * Default constructor
+     */
+    CallVidSetStreamParam();
+};
+
+/**
+ * Call.
+ */
+class Call
+{
+public:
+    /**
+     * Constructor.
+     */
+    Call(Account& acc, int call_id = PJSUA_INVALID_ID);
+
+    /**
+     * Destructor.
+     */
+    virtual ~Call();
+
+    /**
+     * Obtain detail information about this call.
+     *
+     * @return              Call info.
+     */
+    CallInfo getInfo() const throw(Error);
+    
+    /**
+     * Check if this call has active INVITE session and the INVITE
+     * session has not been disconnected.
+     *
+     * @return              True if call is active.
+     */
+    bool isActive() const;
+
+    /**
+     * Get PJSUA-LIB call ID or index associated with this call.
+     *
+     * @return              Integer greater than or equal to zero.
+     */
+    int getId() const;
+    
+    /**
+     * Get the Call class for the specified call Id.
+     *
+     * @param call_id       The call ID to lookup
+     *
+     * @return              The Call instance or NULL if not found.
+     */
+    static Call *lookup(int call_id);
+
+    /**
+     * Check if call has an active media session.
+     *
+     * @return              True if yes.
+     */
+    bool hasMedia() const;
+
+    /**
+     * Check if remote peer support the specified capability.
+     *
+     * @param htype         The header type (pjsip_hdr_e) to be checked, which
+     *                      value may be:
+     *                      - PJSIP_H_ACCEPT
+     *                      - PJSIP_H_ALLOW
+     *                      - PJSIP_H_SUPPORTED
+     * @param hname         If htype specifies PJSIP_H_OTHER, then the header
+     *                      name must be supplied in this argument. Otherwise
+     *                      the value must be set to empty string ("").
+     * @param token         The capability token to check. For example, if \a
+     *                      htype is PJSIP_H_ALLOW, then \a token specifies the
+     *                      method names; if \a htype is PJSIP_H_SUPPORTED, then
+     *                      \a token specifies the extension names such as
+     *                      "100rel".
+     *
+     * @return              PJSIP_DIALOG_CAP_SUPPORTED if the specified
+     *                      capability is explicitly supported, see
+     *                      @pjsip_dialog_cap_status for more info.
+     */
+    pjsip_dialog_cap_status remoteHasCap(int htype,
+                                         const string &hname,
+                                         const string &token) const;
+    
+    /**
+     * Attach application specific data to the call. Application can then
+     * inspect this data by calling #Call::getUserData().
+     *
+     * @param user_data     Arbitrary data to be attached to the call.
+     */
+    void setUserData(Token user_data);
+    
+    /**
+     * Get user data attached to the call, which has been previously set with
+     * #Call::setUserData().
+     *
+     * @return              The user data.
+     */
+    Token getUserData() const;
+    
+    /**
+     * Get the NAT type of remote's endpoint. This is a proprietary feature
+     * of PJSUA-LIB which sends its NAT type in the SDP when \a natTypeInSdp
+     * is set in #UaConfig.
+     *
+     * This function can only be called after SDP has been received from remote,
+     * which means for incoming call, this function can be called as soon as
+     * call is received as long as incoming call contains SDP, and for outgoing
+     * call, this function can be called only after SDP is received (normally in
+     * 200/OK response to INVITE). As a general case, application should call
+     * this function after or in \a onCallMediaState() callback.
+     *
+     * @return              The NAT type.
+     *
+     * @see Endpoint::natGetType(), natTypeInSdp
+     */
+    pj_stun_nat_type getRemNatType() throw(Error);
+
+    /**
+     * Make outgoing call to the specified URI.
+     *
+     * @param dst_uri       URI to be put in the To header (normally is the same
+     *                      as the target URI).
+     * @param prm.opt       Optional call setting.
+     * @param prm.txOption  Optional headers etc to be added to outgoing INVITE
+     *                      request.
+     */
+    void makeCall(const string &dst_uri, const CallOpParam &prm) throw(Error);
+
+    /**
+     * Send response to incoming INVITE request with call setting param.
+     * Depending on the status code specified as parameter, this function may
+     * send provisional response, establish the call, or terminate the call.
+     * Notes about call setting:
+     *  - if call setting is changed in the subsequent call to this function,
+     *    only the first call setting supplied will applied. So normally
+     *    application will not supply call setting before getting confirmation
+     *    from the user.
+     *  - if no call setting is supplied when SDP has to be sent, i.e: answer
+     *    with status code 183 or 2xx, the default call setting will be used,
+     *    check #CallSetting for its default values.
+     *
+     * @param prm.opt       Optional call setting.
+     * @param prm.statusCode    
+     *                      Status code, (100-699).
+     * @param prm.reason    Optional reason phrase. If empty, default text
+     *                      will be used.
+     * @param prm.txOption  Optional list of headers etc to be added to outgoing
+     *                      response message. Note that this message data will
+     *                      be persistent in all next answers/responses for this
+     *                      INVITE request.
+     */
+    void answer(const CallOpParam &prm) throw(Error);
+    
+    /**
+     * Hangup call by using method that is appropriate according to the
+     * call state. This function is different than answering the call with
+     * 3xx-6xx response (with #Call::answer()), in that this function
+     * will hangup the call regardless of the state and role of the call,
+     * while #Call::answer() only works with incoming calls on EARLY
+     * state.
+     *
+     * @param prm.statusCode
+     *                      Optional status code to be sent when we're rejecting
+     *                      incoming call. If the value is zero, "603/Decline"
+     *                      will be sent.
+     * @param prm.reason    Optional reason phrase to be sent when we're
+     *                      rejecting incoming call. If empty, default text
+     *                      will be used.
+     * @param prm.txOption  Optional list of headers etc to be added to outgoing
+     *                      request/response message.
+     */
+    void hangup(const CallOpParam &prm) throw(Error);
+    
+    /**
+     * Put the specified call on hold. This will send re-INVITE with the
+     * appropriate SDP to inform remote that the call is being put on hold.
+     * The final status of the request itself will be reported on the
+     * \a onCallMediaState() callback, which inform the application that
+     * the media state of the call has changed.
+     *
+     * @param prm.options   Bitmask of pjsua_call_flag constants. Currently,
+     *                      only the flag PJSUA_CALL_UPDATE_CONTACT can be used.
+     * @param prm.txOption  Optional message components to be sent with
+     *                      the request.
+     */
+    void setHold(const CallOpParam &prm) throw(Error);
+    
+    /**
+     * Send re-INVITE to release hold.
+     * The final status of the request itself will be reported on the
+     * \a onCallMediaState() callback, which inform the application that
+     * the media state of the call has changed.
+     *
+     * @param prm.opt       Optional call setting, if empty, the current call
+     *                      setting will remain unchanged.
+     * @param prm.txOption  Optional message components to be sent with
+     *                      the request.
+     */
+    void reinvite(const CallOpParam &prm) throw(Error);
+    
+    /**
+     * Send UPDATE request.
+     *
+     * @param prm.opt       Optional call setting, if empty, the current call
+     *                      setting will remain unchanged.
+     * @param prm.txOption  Optional message components to be sent with
+     *                      the request.
+     */
+    void update(const CallOpParam &prm) throw(Error);
+    
+    /**
+     * Initiate call transfer to the specified address. This function will send
+     * REFER request to instruct remote call party to initiate a new INVITE
+     * session to the specified destination/target.
+     *
+     * If application is interested to monitor the successfulness and
+     * the progress of the transfer request, it can implement
+     * \a onCallTransferStatus() callback which will report the progress
+     * of the call transfer request.
+     *
+     * @param dest          URI of new target to be contacted. The URI may be
+     *                      in name address or addr-spec format.
+     * @param prm.txOption  Optional message components to be sent with
+     *                      the request.
+     */
+    void xfer(const string &dest, const CallOpParam &prm) throw(Error);
+
+    /**
+     * Initiate attended call transfer. This function will send REFER request
+     * to instruct remote call party to initiate new INVITE session to the URL
+     * of \a destCall. The party at \a dest_call then should "replace"
+     * the call with us with the new call from the REFER recipient.
+     *
+     * @param dest_call     The call to be replaced.
+     * @param prm.options   Application may specify
+     *                      PJSUA_XFER_NO_REQUIRE_REPLACES to suppress the 
+     *                      inclusion of "Require: replaces" in
+     *                      the outgoing INVITE request created by the REFER
+     *                      request.
+     * @param prm.txOption  Optional message components to be sent with
+     *                      the request.
+     */
+    void xferReplaces(const Call& dest_call,
+                      const CallOpParam &prm) throw(Error);
+    
+    /**
+     * Accept or reject redirection response. Application MUST call this
+     * function after it signaled PJSIP_REDIRECT_PENDING in the 
+     * \a onCallRedirected() callback,
+     * to notify the call whether to accept or reject the redirection
+     * to the current target. Application can use the combination of
+     * PJSIP_REDIRECT_PENDING command in \a onCallRedirected() callback and
+     * this function to ask for user permission before redirecting the call.
+     *
+     * Note that if the application chooses to reject or stop redirection (by
+     * using PJSIP_REDIRECT_REJECT or PJSIP_REDIRECT_STOP respectively), the
+     * call disconnection callback will be called before this function returns.
+     * And if the application rejects the target, the \a onCallRedirected()
+     * callback may also be called before this function returns if there is
+     * another target to try.
+     *
+     * @param cmd           Redirection operation to be applied to the current
+     *                      target. The semantic of this argument is similar
+     *                      to the description in the \a onCallRedirected()
+     *                      callback, except that the PJSIP_REDIRECT_PENDING is
+     *                      not accepted here.
+     */
+    void processRedirect(pjsip_redirect_op cmd) throw(Error);
+
+    /**
+     * Send DTMF digits to remote using RFC 2833 payload formats.
+     *
+     * @param digits        DTMF string digits to be sent.
+     */
+    void dialDtmf(const string &digits) throw(Error);
+    
+    /**
+     * Send instant messaging inside INVITE session.
+     *
+     * @param prm.contentType
+     *                      MIME type.
+     * @param prm.content   The message content.
+     * @param prm.txOption  Optional list of headers etc to be included in
+     *                      outgoing request. The body descriptor in the
+     *                      txOption is ignored.
+     * @param prm.userData  Optional user data, which will be given back when
+     *                      the IM callback is called.
+     */
+    void sendInstantMessage(const SendInstantMessageParam& prm) throw(Error);
+    
+    /**
+     * Send IM typing indication inside INVITE session.
+     *
+     * @param prm.isTyping  True to indicate to remote that local person is
+     *                      currently typing an IM.
+     * @param prm.txOption  Optional list of headers etc to be included in
+     *                      outgoing request.
+     */
+    void sendTypingIndication(const SendTypingIndicationParam &prm)
+         throw(Error);
+    
+    /**
+     * Send arbitrary request with the call. This is useful for example to send
+     * INFO request. Note that application should not use this function to send
+     * requests which would change the invite session's state, such as
+     * re-INVITE, UPDATE, PRACK, and BYE.
+     *
+     * @param prm.method    SIP method of the request.
+     * @param prm.txOption  Optional message body and/or list of headers to be
+     *                      included in outgoing request.
+     */
+    void sendRequest(const CallSendRequestParam &prm) throw(Error);
+    
+    /**
+     * Dump call and media statistics to string.
+     *
+     * @param with_media    True to include media information too.
+     * @param indent        Spaces for left indentation.
+     *
+     * @return              Call dump and media statistics string.
+     */
+    string dump(bool with_media, const string indent) throw(Error);
+    
+    /**
+     * Get the media stream index of the default video stream in the call.
+     * Typically this will just retrieve the stream index of the first
+     * activated video stream in the call. If none is active, it will return
+     * the first inactive video stream.
+     *
+     * @return              The media stream index or -1 if no video stream
+     *                      is present in the call.
+     */
+    int vidGetStreamIdx() const;
+    
+    /**
+     * Determine if video stream for the specified call is currently running
+     * (i.e. has been created, started, and not being paused) for the specified
+     * direction.
+     *
+     * @param med_idx       Media stream index, or -1 to specify default video
+     *                      media.
+     * @param dir           The direction to be checked.
+     *
+     * @return              True if stream is currently running for the
+     *                      specified direction.
+     */
+    bool vidStreamIsRunning(int med_idx, pjmedia_dir dir) const;
+    
+    /**
+     * Add, remove, modify, and/or manipulate video media stream for the
+     * specified call. This may trigger a re-INVITE or UPDATE to be sent
+     * for the call.
+     *
+     * @param op            The video stream operation to be performed,
+     *                      possible values are #pjsua_call_vid_strm_op.
+     * @param param         The parameters for the video stream operation
+     *                      (see #CallVidSetStreamParam).
+     */
+    void vidSetStream(pjsua_call_vid_strm_op op,
+                      const CallVidSetStreamParam &param) throw(Error);
+
+    /**
+     * Get media stream info for the specified media index.
+     *
+     * @param med_idx       Media stream index.
+     *
+     * @return              The stream info.
+     */
+    StreamInfo getStreamInfo(unsigned med_idx) const throw(Error);
+    
+    /**
+     * Get media stream statistic for the specified media index.
+     *
+     * @param med_idx       Media stream index.
+     *
+     * @return              The stream statistic.
+     */
+    StreamStat getStreamStat(unsigned med_idx) const throw(Error);
+    
+    /**
+     * Get media transport info for the specified media index.
+     *
+     * @param med_idx       Media stream index.
+     *
+     * @return              The transport info.
+     */
+    MediaTransportInfo getMedTransportInfo(unsigned med_idx) const throw(Error);
+
+public:
+    /*
+     * Callbacks
+     */
+    /**
+     * Notify application when call state has changed.
+     * Application may then query the call info to get the
+     * detail call states by calling Call::getInfo() function.
+     *
+     * @param prm	Callback parameter.
+     */
+    virtual void onCallState(OnCallStateParam &prm)
+    {}
+    
+    /**
+     * This is a general notification callback which is called whenever
+     * a transaction within the call has changed state. Application can
+     * implement this callback for example to monitor the state of
+     * outgoing requests, or to answer unhandled incoming requests
+     * (such as INFO) with a final response.
+     *
+     * @param prm	Callback parameter.
+     */
+    virtual void onCallTsxState(OnCallTsxStateParam &prm)
+    {}
+    
+    /**
+     * Notify application when media state in the call has changed.
+     * Normal application would need to implement this callback, e.g.
+     * to connect the call's media to sound device. When ICE is used,
+     * this callback will also be called to report ICE negotiation
+     * failure.
+     *
+     * @param prm	Callback parameter.
+     */
+    virtual void onCallMediaState(OnCallMediaStateParam &prm)
+    {}
+    
+    /**
+     * Notify application when a call has just created a local SDP (for
+     * initial or subsequent SDP offer/answer). Application can implement
+     * this callback to modify the SDP, before it is being sent and/or
+     * negotiated with remote SDP, for example to apply per account/call
+     * basis codecs priority or to add custom/proprietary SDP attributes.
+     *
+     * @param prm	Callback parameter.
+     */
+    virtual void onCallSdpCreated(OnCallSdpCreatedParam &prm)
+    {}
+    
+    /**
+     * Notify application when media session is created and before it is
+     * registered to the conference bridge. Application may return different
+     * media port if it has added media processing port to the stream. This
+     * media port then will be added to the conference bridge instead.
+     *
+     * @param prm	Callback parameter.
+     */
+    virtual void onStreamCreated(OnStreamCreatedParam &prm)
+    {}
+    
+    /**
+     * Notify application when media session has been unregistered from the
+     * conference bridge and about to be destroyed.
+     *
+     * @param prm	Callback parameter.
+     */
+    virtual void onStreamDestroyed(OnStreamDestroyedParam &prm)
+    {}
+    
+    /**
+     * Notify application upon incoming DTMF digits.
+     *
+     * @param prm	Callback parameter.
+     */
+    virtual void onDtmfDigit(OnDtmfDigitParam &prm)
+    {}
+    
+    /**
+     * Notify application on call being transfered (i.e. REFER is received).
+     * Application can decide to accept/reject transfer request
+     * by setting the code (default is 202). When this callback
+     * is not implemented, the default behavior is to accept the
+     * transfer.
+     *
+     * @param prm	Callback parameter.
+     */
+    virtual void onCallTransferRequest(OnCallTransferRequestParam &prm)
+    {}
+    
+    /**
+     * Notify application of the status of previously sent call
+     * transfer request. Application can monitor the status of the
+     * call transfer request, for example to decide whether to
+     * terminate existing call.
+     *
+     * @param prm	Callback parameter.
+     */
+    virtual void onCallTransferStatus(OnCallTransferStatusParam &prm)
+    {}
+    
+    /**
+     * Notify application about incoming INVITE with Replaces header.
+     * Application may reject the request by setting non-2xx code.
+     *
+     * @param prm	Callback parameter.
+     */
+    virtual void onCallReplaceRequest(OnCallReplaceRequestParam &prm)
+    {}
+    
+    /**
+     * Notify application that an existing call has been replaced with
+     * a new call. This happens when PJSUA-API receives incoming INVITE
+     * request with Replaces header.
+     *
+     * After this callback is called, normally PJSUA-API will disconnect
+     * this call and establish a new call \a newCallId.
+     *
+     * @param prm	Callback parameter.
+     */
+    virtual void onCallReplaced(OnCallReplacedParam &prm)
+    {}
+    
+    /**
+     * Notify application when call has received new offer from remote
+     * (i.e. re-INVITE/UPDATE with SDP is received). Application can
+     * decide to accept/reject the offer by setting the code (default
+     * is 200). If the offer is accepted, application can update the
+     * call setting to be applied in the answer. When this callback is
+     * not implemented, the default behavior is to accept the offer using
+     * current call setting.
+     *
+     * @param prm	Callback parameter.
+     */
+    virtual void onCallRxOffer(OnCallRxOfferParam &prm)
+    {}
+    
+    /**
+     * Notify application on incoming MESSAGE request.
+     *
+     * @param prm	Callback parameter.
+     */
+    virtual void onInstantMessage(OnInstantMessageParam &prm)
+    {}
+    
+    /**
+     * Notify application about the delivery status of outgoing MESSAGE
+     * request.
+     *
+     * @param prm	Callback parameter.
+     */
+    virtual void onInstantMessageStatus(OnInstantMessageStatusParam &prm)
+    {}
+    
+    /**
+     * Notify application about typing indication.
+     *
+     * @param prm	Callback parameter.
+     */
+    virtual void onTypingIndication(OnTypingIndicationParam &prm)
+    {}
+    
+    /**
+     * This callback is called when the call is about to resend the
+     * INVITE request to the specified target, following the previously
+     * received redirection response.
+     *
+     * Application may accept the redirection to the specified target,
+     * reject this target only and make the session continue to try the next
+     * target in the list if such target exists, stop the whole
+     * redirection process altogether and cause the session to be
+     * disconnected, or defer the decision to ask for user confirmation.
+     *
+     * This callback is optional,
+     * the default behavior is to NOT follow the redirection response.
+     *
+     * @param prm	Callback parameter.
+     *
+     * @return		Action to be performed for the target. Set this
+     *			parameter to one of the value below:
+     *			- PJSIP_REDIRECT_ACCEPT: immediately accept the
+     *			  redirection. When set, the call will immediately
+     *			  resend INVITE request to the target.
+     *			- PJSIP_REDIRECT_ACCEPT_REPLACE: immediately accept
+     *			  the redirection and replace the To header with the
+     *			  current target. When set, the call will immediately
+     *			  resend INVITE request to the target.
+     *			- PJSIP_REDIRECT_REJECT: immediately reject this
+     *			  target. The call will continue retrying with
+     *			  next target if present, or disconnect the call
+     *			  if there is no more target to try.
+     *			- PJSIP_REDIRECT_STOP: stop the whole redirection
+     *			  process and immediately disconnect the call. The
+     *			  onCallState() callback will be called with
+     *			  PJSIP_INV_STATE_DISCONNECTED state immediately
+     *			  after this callback returns.
+     *			- PJSIP_REDIRECT_PENDING: set to this value if
+     *			  no decision can be made immediately (for example
+     *			  to request confirmation from user). Application
+     *			  then MUST call #Call::processRedirect()
+     *			  to either accept or reject the redirection upon
+     *			  getting user decision.
+     */
+    virtual pjsip_redirect_op onCallRedirected(OnCallRedirectedParam &prm)
+    {
+        return PJSIP_REDIRECT_STOP;
+    }
+    
+    /**
+     * This callback is called when media transport state is changed.
+     *
+     * @param prm	Callback parameter.
+     */
+    virtual void onCallMediaTransportState(OnCallMediaTransportStateParam &prm)
+    {}
+    
+    /**
+     * Notification about media events such as video notifications. This
+     * callback will most likely be called from media threads, thus
+     * application must not perform heavy processing in this callback.
+     * Especially, application must not destroy the call or media in this
+     * callback. If application needs to perform more complex tasks to
+     * handle the event, it should post the task to another thread.
+     *
+     * @param prm	Callback parameter.
+     */
+    virtual void onCallMediaEvent(OnCallMediaEventParam &prm)
+    {}
+    
+    /**
+     * This callback can be used by application to implement custom media
+     * transport adapter for the call, or to replace the media transport
+     * with something completely new altogether.
+     *
+     * This callback is called when a new call is created. The library has
+     * created a media transport for the call, and it is provided as the
+     * \a mediaTp argument of this callback. The callback may change it
+     * with the instance of media transport to be used by the call.
+     *
+     * @param prm	Callback parameter.
+     */
+    virtual void
+    onCreateMediaTransport(OnCreateMediaTransportParam &prm)
+    {}
+
+protected:
+    friend class Endpoint;
+    
+private:
+    Account             &acc;
+    pjsua_call_id 	 id;
+    Token                userData;
+};
+
+} // namespace pj
+
+/**
+ * @}  // PJSUA2_CALL
+ */
+
+#endif	/* __PJSUA2_CALL_HPP__ */
+
Index: pjproject/branches/projects/pjsua2/pjsip/include/pjsua2/endpoint.hpp
===================================================================
--- pjproject/branches/projects/pjsua2/pjsip/include/pjsua2/endpoint.hpp	(revision 4662)
+++ pjproject/branches/projects/pjsua2/pjsip/include/pjsua2/endpoint.hpp	(revision 4663)
@@ -947,4 +947,14 @@
     void transportClose(TransportId id) throw(Error);
 
+    /*************************************************************************
+     * Call operations
+     */
+    
+    /**
+     * Terminate all calls. This will initiate call hangup for all
+     * currently active calls.
+     */
+    void hangupAllCalls(void);
+    
     /*************************************************************************
      * Media operations
@@ -1123,4 +1133,64 @@
 
     static void on_buddy_state(pjsua_buddy_id buddy_id);
+    // Call callbacks
+    static void on_call_state(pjsua_call_id call_id, pjsip_event *e);
+    static void on_call_tsx_state(pjsua_call_id call_id,
+                                  pjsip_transaction *tsx,
+                                  pjsip_event *e);
+    static void on_call_media_state(pjsua_call_id call_id);
+    static void on_call_sdp_created(pjsua_call_id call_id,
+                                    pjmedia_sdp_session *sdp,
+                                    pj_pool_t *pool,
+                                    const pjmedia_sdp_session *rem_sdp);
+    static void on_stream_created(pjsua_call_id call_id,
+                                  pjmedia_stream *strm,
+                                  unsigned stream_idx,
+                                  pjmedia_port **p_port);
+    static void on_stream_destroyed(pjsua_call_id call_id,
+                                    pjmedia_stream *strm,
+                                    unsigned stream_idx);
+    static void on_dtmf_digit(pjsua_call_id call_id, int digit);
+    static void on_call_transfer_request(pjsua_call_id call_id,
+                                         const pj_str_t *dst,
+                                         pjsip_status_code *code);
+    static void on_call_transfer_request2(pjsua_call_id call_id,
+                                          const pj_str_t *dst,
+                                          pjsip_status_code *code,
+                                          pjsua_call_setting *opt);
+    static void on_call_transfer_status(pjsua_call_id call_id,
+                                        int st_code,
+                                        const pj_str_t *st_text,
+                                        pj_bool_t final,
+                                        pj_bool_t *p_cont);
+    static void on_call_replace_request(pjsua_call_id call_id,
+                                        pjsip_rx_data *rdata,
+                                        int *st_code,
+                                        pj_str_t *st_text);
+    static void on_call_replace_request2(pjsua_call_id call_id,
+                                         pjsip_rx_data *rdata,
+                                         int *st_code,
+                                         pj_str_t *st_text,
+                                         pjsua_call_setting *opt);
+    static void on_call_replaced(pjsua_call_id old_call_id,
+                                 pjsua_call_id new_call_id);
+    static void on_call_rx_offer(pjsua_call_id call_id,
+                                 const pjmedia_sdp_session *offer,
+                                 void *reserved,
+                                 pjsip_status_code *code,
+                                 pjsua_call_setting *opt);
+    static pjsip_redirect_op on_call_redirected(pjsua_call_id call_id,
+                                                const pjsip_uri *target,
+                                                const pjsip_event *e);
+    static pj_status_t
+    on_call_media_transport_state(pjsua_call_id call_id,
+                                  const pjsua_med_tp_state_info *info);
+    static void on_call_media_event(pjsua_call_id call_id,
+                                    unsigned med_idx,
+                                    pjmedia_event *event);
+    static pjmedia_transport*
+    on_create_media_transport(pjsua_call_id call_id,
+                              unsigned media_idx,
+                              pjmedia_transport *base_tp,
+                              unsigned flags);
 };
 
Index: pjproject/branches/projects/pjsua2/pjsip/include/pjsua2/media.hpp
===================================================================
--- pjproject/branches/projects/pjsua2/pjsip/include/pjsua2/media.hpp	(revision 4662)
+++ pjproject/branches/projects/pjsua2/pjsip/include/pjsua2/media.hpp	(revision 4663)
@@ -126,5 +126,8 @@
 };
 
-typedef void* MediaPort;
+/**
+ * Media port, corresponds to pjmedia_port
+ */
+typedef void *MediaPort;
 
 /**
Index: pjproject/branches/projects/pjsua2/pjsip/include/pjsua2/siptypes.hpp
===================================================================
--- pjproject/branches/projects/pjsua2/pjsip/include/pjsua2/siptypes.hpp	(revision 4662)
+++ pjproject/branches/projects/pjsua2/pjsip/include/pjsua2/siptypes.hpp	(revision 4663)
@@ -394,4 +394,5 @@
     unsigned		    usageCount;
 
+public:
     /** Construct from pjsua_transport_info */
     void fromPj(const pjsua_transport_info &info);
@@ -419,13 +420,15 @@
 
     /**
-     * Source IP address of the message.
-     */
-    string		srcIp;
-
-    /**
-     * Source port number of the message.
-     */
-    unsigned		srcPort;
-
+     * Source address of the message.
+     */
+    SocketAddress       srcAddress;
+
+    /**
+     * Pointer to original pjsip_rx_data. Only valid when the struct
+     * is constructed from PJSIP's pjsip_rx_data.
+     */
+    void               *pjRxData;
+
+public:
     /**
      * Construct from PJSIP's pjsip_rx_data
@@ -434,4 +437,196 @@
 };
 
+/**
+ * This structure describes an outgoing SIP message. It corresponds to the
+ * pjsip_tx_data structure in PJSIP library.
+ */
+struct SipTxData
+{
+    /**
+     * A short info string describing the request, which normally contains
+     * the request method and its CSeq.
+     */
+    string		info;
+    
+    /**
+     * The whole message data as a string, containing both the header section
+     * and message body section.
+     */
+    string		wholeMsg;
+    
+    /**
+     * Destination address of the message.
+     */
+    SocketAddress	dstAddress;
+    
+    /**
+     * Pointer to original pjsip_tx_data. Only valid when the struct
+     * is constructed from PJSIP's pjsip_tx_data.
+     */
+    void               *pjTxData;
+    
+public:
+    /**
+     * Construct from PJSIP's pjsip_tx_data
+     */
+    void fromPj(pjsip_tx_data &tdata);
+};
+
+/**
+ * This structure describes SIP transaction object. It corresponds to the
+ * pjsip_transaction structure in PJSIP library.
+ */
+struct SipTransaction
+{
+    /* Transaction identification. */
+    pjsip_role_e        role;           /**< Role (UAS or UAC)      */
+    string              method;         /**< The method.            */
+    
+    /* State and status. */
+    int			statusCode;     /**< Last status code seen. */
+    string		statusText;     /**< Last reason phrase.    */
+    pjsip_tsx_state_e	state;          /**< State.                 */
+    
+    /* Messages and timer. */
+    SipTxData           lastTx;         /**< Msg kept for retrans.  */
+    
+    /* Original pjsip_transaction. */
+    void               *pjTransaction;  /**< pjsip_transaction.     */
+    
+public:
+    /**
+     * Construct from PJSIP's pjsip_transaction
+     */
+    void fromPj(pjsip_transaction &tsx);
+};
+
+/**
+ * This structure describes timer event.
+ */
+struct TimerEvent
+{
+    TimerEntry          entry;          /**< The timer entry.           */
+};
+
+/**
+ * This structure describes transaction state changed event.
+ */
+struct TsxStateEvent
+{
+    struct
+    {
+        SipRxData       rdata;          /**< The incoming message.      */
+        SipTxData       tdata;          /**< The outgoing message.      */
+        TimerEntry      timer;          /**< The timer.                 */
+        pj_status_t     status;         /**< Transport error status.    */
+        GenericData     data;           /**< Generic data.              */
+    } src;                              /**< Event source.              */
+    SipTransaction      tsx;            /**< The transaction.           */
+    pjsip_tsx_state_e   prevState;      /**< Previous state.            */
+    pjsip_event_id_e    type;           /**< Type of event source:
+                                         *     - PJSIP_EVENT_TX_MSG
+                                         *     - PJSIP_EVENT_RX_MSG,
+                                         *     - PJSIP_EVENT_TRANSPORT_ERROR
+                                         *     - PJSIP_EVENT_TIMER
+                                         *     - PJSIP_EVENT_USER
+                                         */
+};
+
+/**
+ * This structure describes message transmission event.
+ */
+struct TxMsgEvent
+{
+    SipTxData           tdata;          /**< The transmit data buffer.  */
+};
+
+/**
+ * This structure describes transmission error event.
+ */
+struct TxErrorEvent
+{
+    SipTxData           tdata;          /**< The transmit data.         */
+    SipTransaction      tsx;            /**< The transaction.           */
+};
+
+/**
+ * This structure describes message arrival event.
+ */
+struct RxMsgEvent
+{
+    SipRxData           rdata;          /**< The receive data buffer.   */
+};
+
+/**
+ * This structure describes user event.
+ */
+struct UserEvent
+{
+    GenericData         user1;          /**< User data 1.               */
+    GenericData         user2;          /**< User data 2.               */
+    GenericData         user3;          /**< User data 3.               */
+    GenericData         user4;          /**< User data 4.               */
+};
+
+/**
+ * This structure describe event descriptor to fully identify a SIP event. It
+ * corresponds to the pjsip_event structure in PJSIP library.
+ */
+struct SipEvent
+{
+    /**
+     * The event type, can be any value of \b pjsip_event_id_e.
+     */
+    pjsip_event_id_e    type;
+    
+    /**
+     * The event body, which fields depends on the event type.
+     */
+    struct
+    {
+        /**
+         * Timer event.
+         */
+        TimerEvent      timer;
+        
+        /**
+         * Transaction state has changed event.
+         */
+        TsxStateEvent   tsxState;
+        
+        /**
+         * Message transmission event.
+         */
+        TxMsgEvent      txMsg;
+        
+        /**
+         * Transmission error event.
+         */
+        TxErrorEvent    txError;
+        
+        /**
+         * Message arrival event.
+         */
+        RxMsgEvent      rxMsg;
+        
+        /**
+         * User event.
+         */
+        UserEvent       user;
+        
+    } body;
+    
+    /**
+     * Pointer to its original pjsip_event. Only valid when the struct is
+     * constructed from PJSIP's pjsip_event.
+     */
+    void               *pjEvent;
+    
+public:
+    /**
+     * Construct from PJSIP's pjsip_event
+     */
+    void fromPj(const pjsip_event &ev);
+};
 
 //////////////////////////////////////////////////////////////////////////////
@@ -449,4 +644,5 @@
     string		subType;
 
+public:
     /**
      * Construct from PJSIP's pjsip_media_type
@@ -475,4 +671,5 @@
     string		hValue;
 
+public:
     /**
      * Initiaize from PJSIP header.
@@ -514,4 +711,5 @@
     string		body;
 
+public:
     /**
      * Initiaize from PJSIP's pjsip_multipart_part.
@@ -540,14 +738,14 @@
 {
     /**
-     * Optional remote target URI (i.e. Target header). If NULL, the target
-     * will be set to the remote URI (To header). At the moment this field
-     * is only used when sending initial INVITE and MESSAGE requests.
-     */
-    string		targetUri;
+     * Optional remote target URI (i.e. Target header). If empty (""), the
+     * target will be set to the remote URI (To header). At the moment this
+     * field is only used when sending initial INVITE and MESSAGE requests.
+     */
+    string                  targetUri;
 
     /**
      * Additional message headers to be included in the outgoing message.
      */
-    SipHeaderVector	headers;
+    SipHeaderVector         headers;
 
     /**
@@ -555,5 +753,5 @@
      * in this structure.
      */
-    string		contentType;
+    string                  contentType;
 
     /**
@@ -561,5 +759,5 @@
      * message doesn't have a body.
      */
-    string		msgBody;
+    string                  msgBody;
 
     /**
@@ -569,5 +767,5 @@
      * contains a body, the body will be added to the multipart bodies.
      */
-    SipMediaType	multipartContentType;
+    SipMediaType            multipartContentType;
 
     /**
@@ -577,6 +775,16 @@
      * the body will be added to the multipart bodies.
      */
-    SipMultipartPartVector	multipartParts;
-
+    SipMultipartPartVector  multipartParts;
+
+public:
+    /**
+     * Check if the options are empty. If the options are set with empty
+     * values, there will be no additional information sent with outgoing
+     * SIP message.
+     *
+     * @return              True if the options are empty.
+     */
+    bool isEmpty() const;
+    
     /**
      * Initiaize from PJSUA's pjsua_msg_data.
@@ -590,4 +798,5 @@
 };
 
+//////////////////////////////////////////////////////////////////////////////
 
 /**
@@ -600,10 +809,10 @@
      * MIME type. Default is "text/plain".
      */
-    string contentType;
+    string      contentType;
     
     /**
      * The message content.
      */
-    string content;
+    string      content;
     
     /**
@@ -611,9 +820,15 @@
      */
     SipTxOption txOption;
-
+    
     /**
      * User data, which will be given back when the IM callback is called.
      */
-    Token userData;
+    Token       userData;
+    
+public:
+    /**
+     * Default constructor initializes with zero/empty values.
+     */
+    SendInstantMessageParam();
 };
 
@@ -628,10 +843,16 @@
      * True to indicate to remote that local person is currently typing an IM.
      */
-    bool isTyping;
+    bool         isTyping;
     
     /**
      * List of headers etc to be included in outgoing request.
      */
-    SipTxOption txOption;
+    SipTxOption  txOption;
+    
+public:
+    /**
+     * Default constructor initializes with zero/empty values.
+     */
+    SendTypingIndicationParam();
 };
 
Index: pjproject/branches/projects/pjsua2/pjsip/include/pjsua2/types.hpp
===================================================================
--- pjproject/branches/projects/pjsua2/pjsip/include/pjsua2/types.hpp	(revision 4662)
+++ pjproject/branches/projects/pjsua2/pjsip/include/pjsua2/types.hpp	(revision 4663)
@@ -74,4 +74,14 @@
 typedef void *TransportHandle;
 
+/**
+ * Timer entry, corresponds to pj_timer_entry
+ */
+typedef void *TimerEntry;
+
+/**
+ * Generic data
+ */
+typedef void *GenericData;
+
 /*
  * Forward declaration of Account to be used
@@ -211,4 +221,27 @@
 };
 
+//////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Representation of time value.
+ */
+struct TimeValue
+{
+    /**
+     * The seconds part of the time.
+     */
+    long sec;
+    
+    /**
+     * The miliseconds fraction of the time.
+     */
+    long msec;
+    
+public:
+    /**
+     * Convert from pjsip
+     */
+    void fromPj(const pj_time_val &prm);
+};
 
 } // namespace pj
Index: pjproject/branches/projects/pjsua2/pjsip/src/pjsua2/call.cpp
===================================================================
--- pjproject/branches/projects/pjsua2/pjsip/src/pjsua2/call.cpp	(revision 4663)
+++ pjproject/branches/projects/pjsua2/pjsip/src/pjsua2/call.cpp	(revision 4663)
@@ -0,0 +1,614 @@
+/* $Id$ */
+/*
+ * Copyright (C) 2012-2013 Teluu Inc. (http://www.teluu.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#include <pjsua2/account.hpp>
+#include <pjsua2/call.hpp>
+#include <pj/ctype.h>
+#include "util.hpp"
+
+using namespace pj;
+using namespace std;
+
+#define THIS_FILE		"call.cpp"
+
+///////////////////////////////////////////////////////////////////////////////
+
+#define SDP_BUFFER_SIZE 1024
+
+MathStat::MathStat()
+: n(0), max(0), min(0), last(0), mean(0)
+{
+}
+
+void MathStat::fromPj(const pj_math_stat &prm)
+{
+    this->n    = prm.n;
+    this->max  = prm.max;
+    this->min  = prm.min;
+    this->last = prm.last;
+    this->mean = prm.mean;
+}
+
+void RtcpStreamStat::fromPj(const pjmedia_rtcp_stream_stat &prm)
+{
+    this->update.fromPj(prm.update);
+    this->updateCount     = prm.update_cnt;
+    this->pkt             = (unsigned)prm.pkt;
+    this->bytes           = (unsigned)prm.bytes;
+    this->discard         = prm.discard;
+    this->loss            = prm.loss;
+    this->reorder         = prm.loss;
+    this->dup             = prm.dup;
+    this->lossPeriodUsec.fromPj(prm.loss_period);
+    this->lossType.burst  = prm.loss_type.burst;
+    this->lossType.random = prm.loss_type.random;
+    this->jitterUsec.fromPj(prm.jitter);
+}
+
+void RtcpSdes::fromPj(const pjmedia_rtcp_sdes &prm)
+{
+    this->cname = pj2Str(prm.cname);
+    this->name  = pj2Str(prm.name);
+    this->email = pj2Str(prm.email);
+    this->phone = pj2Str(prm.phone);
+    this->loc   = pj2Str(prm.loc);
+    this->tool  = pj2Str(prm.tool);
+    this->note  = pj2Str(prm.note);
+}
+
+void RtcpStat::fromPj(const pjmedia_rtcp_stat &prm)
+{
+    this->start.fromPj(prm.start);
+    this->txStat.fromPj(prm.tx);
+    this->rxStat.fromPj(prm.rx);
+    this->rttUsec.fromPj(prm.rtt);
+    this->rtpTxLastTs  = prm.rtp_tx_last_ts;
+    this->rtpTxLastSeq = prm.rtp_tx_last_seq;
+#if defined(PJMEDIA_RTCP_STAT_HAS_IPDV) && PJMEDIA_RTCP_STAT_HAS_IPDV!=0
+    this->rxIpdvUsec.fromPj(prm.rx_ipdv);
+#endif
+#if defined(PJMEDIA_RTCP_STAT_HAS_RAW_JITTER) && \
+    PJMEDIA_RTCP_STAT_HAS_RAW_JITTER!=0
+    this->rxRawJitterUsec.fromPj(prm.rx_raw_jitter);
+#endif
+    this->peerSdes.fromPj(prm.peer_sdes);
+}
+
+void JbufState::fromPj(const pjmedia_jb_state &prm)
+{
+    this->frameSize    = prm.frame_size;
+    this->minPrefetch  = prm.min_prefetch;
+    this->maxPrefetch  = prm.max_prefetch;
+    this->burst        = prm.burst;
+    this->prefetch     = prm.prefetch;
+    this->size         = prm.size;
+    this->avgDelayMsec = prm.avg_delay;
+    this->minDelayMsec = prm.min_delay;
+    this->maxDelayMsec = prm.max_delay;
+    this->devDelayMsec = prm.dev_delay;
+    this->avgBurst     = prm.avg_burst;
+    this->lost         = prm.lost;
+    this->discard      = prm.discard;
+    this->empty        = prm.empty;
+}
+
+void SdpSession::fromPj(const pjmedia_sdp_session &sdp)
+{
+    char buf[SDP_BUFFER_SIZE];
+    int len;
+
+    len = pjmedia_sdp_print(&sdp, buf, sizeof(buf));
+    wholeSdp = (len > -1? string(buf, len): "");
+    pjSdpSession = (void *)&sdp;
+}
+
+void MediaEvent::fromPj(const pjmedia_event &ev)
+{
+    type = ev.type;
+    if (type == PJMEDIA_EVENT_FMT_CHANGED) {
+        data.fmtChanged.newWidth = ev.data.fmt_changed.new_fmt.det.vid.size.w;
+        data.fmtChanged.newHeight = ev.data.fmt_changed.new_fmt.det.vid.size.h;
+    }
+    pjMediaEvent = (void *)&ev;
+}
+
+void MediaTransportInfo::fromPj(const pjmedia_transport_info &info)
+{
+    char straddr[PJ_INET6_ADDRSTRLEN+10];
+    
+    pj_sockaddr_print(&info.src_rtp_name, straddr, sizeof(straddr), 3);
+    srcRtpName = straddr;
+    pj_sockaddr_print(&info.src_rtcp_name, straddr, sizeof(straddr), 3);
+    srcRtcpName = straddr;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+CallOpParam::CallOpParam(bool useDefaultCallSetting)
+: statusCode(pjsip_status_code(0)), reason(""), options(0)
+{
+    if (useDefaultCallSetting)
+        opt = CallSetting(true);
+}
+
+CallSendRequestParam::CallSendRequestParam()
+: method("")
+{
+}
+
+CallVidSetStreamParam::CallVidSetStreamParam()
+{
+    pjsua_call_vid_strm_op_param prm;
+    
+    pjsua_call_vid_strm_op_param_default(&prm);
+    this->medIdx = prm.med_idx;
+    this->dir    = prm.dir;
+    this->capDev = prm.cap_dev;
+}
+
+CallSetting::CallSetting(pj_bool_t useDefaultValues)
+{
+    if (useDefaultValues) {
+        pjsua_call_setting setting;
+    
+        pjsua_call_setting_default(&setting);
+        fromPj(setting);
+    } else {
+        flag                = 0;
+        reqKeyframeMethod   = 0;
+        audioCount          = 0;
+        videoCount          = 0;
+    }
+}
+
+bool CallSetting::isEmpty() const
+{
+    return (flag == 0 && reqKeyframeMethod == 0 && audioCount == 0 &&
+            videoCount == 0);
+}
+
+void CallSetting::fromPj(const pjsua_call_setting &prm)
+{
+    this->flag              = prm.flag;
+    this->reqKeyframeMethod = prm.req_keyframe_method;
+    this->audioCount        = prm.aud_cnt;
+    this->videoCount        = prm.vid_cnt;
+}
+
+pjsua_call_setting CallSetting::toPj() const
+{
+    pjsua_call_setting setting;
+
+    setting.flag                = this->flag;
+    setting.req_keyframe_method = this->reqKeyframeMethod;
+    setting.aud_cnt             = this->audioCount;
+    setting.vid_cnt             = this->videoCount;
+    
+    return setting;
+}
+
+
+CallMediaInfo::CallMediaInfo()
+{
+}
+
+void CallMediaInfo::fromPj(const pjsua_call_media_info &prm)
+{
+    this->index                     = prm.index;
+    this->type                      = prm.type;
+    this->dir                       = prm.dir;
+    this->status                    = prm.status;
+    if (this->type == PJMEDIA_TYPE_AUDIO) {
+        this->audioConfSlot         = (int)prm.stream.aud.conf_slot;
+    } else if (this->type == PJMEDIA_TYPE_VIDEO) {
+        this->videoIncomingWindowId = prm.stream.vid.win_in;
+        this->videoCapDev           = prm.stream.vid.cap_dev;
+    }
+}
+
+void CallInfo::fromPj(const pjsua_call_info &pci)
+{
+    int mi;
+    
+    id 			= pci.id;
+    role                = pci.role;
+    accId               = pci.acc_id;
+    localURI            = pj2Str(pci.local_info);
+    localContact        = pj2Str(pci.local_contact);
+    remoteURI           = pj2Str(pci.remote_info);
+    remoteContact       = pj2Str(pci.remote_contact);
+    callIdString        = pj2Str(pci.call_id);
+    setting.fromPj(pci.setting);
+    state               = pci.state;
+    stateText           = pj2Str(pci.state_text);
+    lastStatusCode      = pci.last_status;
+    lastReason          = pj2Str(pci.last_status_text);
+    connectDuration.fromPj(pci.connect_duration);
+    totalDuration.fromPj(pci.total_duration);
+    remOfferer          = pci.rem_offerer;
+    remAudioCount       = pci.rem_aud_cnt;
+    remVideoCount       = pci.rem_vid_cnt;
+    
+    for (mi = 0; mi < pci.media_cnt; mi++) {
+        CallMediaInfo med;
+        
+        med.fromPj(pci.media[mi]);
+        media.push_back(med);
+    }
+    for (mi = 0; mi < pci.prov_media_cnt; mi++) {
+        CallMediaInfo med;
+        
+        med.fromPj(pci.prov_media[mi]);
+        provMedia.push_back(med);
+    }
+}
+
+void StreamInfo::fromPj(const pjsua_stream_info &info)
+{
+    char straddr[PJ_INET6_ADDRSTRLEN+10];
+
+    type = info.type;
+    if (type == PJMEDIA_TYPE_AUDIO) {
+        proto = info.info.aud.proto;
+        dir = info.info.aud.dir;
+        pj_sockaddr_print(&info.info.aud.rem_addr, straddr, sizeof(straddr), 3);
+        remoteRtpAddress = straddr;
+        pj_sockaddr_print(&info.info.aud.rem_rtcp, straddr, sizeof(straddr), 3);
+        remoteRtcpAddress = straddr;
+        txPt = info.info.aud.tx_pt;
+        rxPt = info.info.aud.rx_pt;
+        codecName = pj2Str(info.info.aud.fmt.encoding_name);
+        codecClockRate = info.info.aud.fmt.clock_rate;
+        codecParam = info.info.aud.param;
+    } else if (type == PJMEDIA_TYPE_VIDEO) {
+        proto = info.info.vid.proto;
+        dir = info.info.vid.dir;
+        pj_sockaddr_print(&info.info.vid.rem_addr, straddr, sizeof(straddr), 3);
+        remoteRtpAddress = straddr;
+        pj_sockaddr_print(&info.info.vid.rem_rtcp, straddr, sizeof(straddr), 3);
+        remoteRtcpAddress = straddr;
+        txPt = info.info.vid.tx_pt;
+        rxPt = info.info.vid.rx_pt;
+        codecName = pj2Str(info.info.vid.codec_info.encoding_name);
+        codecClockRate = info.info.vid.codec_info.clock_rate;
+        codecParam = info.info.vid.codec_param;
+    }
+}
+
+void StreamStat::fromPj(const pjsua_stream_stat &prm)
+{
+    rtcp.fromPj(prm.rtcp);
+    jbuf.fromPj(prm.jbuf);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+struct call_param
+{
+    pjsua_msg_data      msg_data;
+    pjsua_msg_data     *p_msg_data;
+    pjsua_call_setting  opt;
+    pjsua_call_setting *p_opt;
+    pj_str_t            reason;
+    pj_str_t           *p_reason;
+
+public:
+    /**
+     * Default constructors with specified parameters.
+     */
+    call_param(const SipTxOption &tx_option);
+    call_param(const SipTxOption &tx_option, const CallSetting &setting,
+               const string &reason_str);
+};
+
+call_param::call_param(const SipTxOption &tx_option)
+{
+    if (tx_option.isEmpty()) {
+        p_msg_data = NULL;
+    } else {
+        tx_option.toPj(msg_data);
+        p_msg_data = &msg_data;
+    }
+    
+    p_opt = NULL;
+    p_reason = NULL;
+}
+
+call_param::call_param(const SipTxOption &tx_option, const CallSetting &setting,
+                       const string &reason_str)
+{
+    if (tx_option.isEmpty()) {
+        p_msg_data = NULL;
+    } else {
+        tx_option.toPj(msg_data);
+        p_msg_data = &msg_data;
+    }
+    
+    if (setting.isEmpty()) {
+        p_opt = NULL;
+    } else {
+        opt = setting.toPj();
+        p_opt = &opt;
+    }
+    
+    reason = str2Pj(reason_str);
+    p_reason = (reason.slen == 0? NULL: &reason);
+}
+
+Call::Call(Account& account, int call_id)
+: acc(account), id(call_id)
+{
+    if (call_id != PJSUA_INVALID_ID)
+        pjsua_call_set_user_data(call_id, this);
+}
+
+Call::~Call()
+{
+    /**
+     * If this instance is deleted, also hangup the corresponding call in
+     * PJSUA library.
+     */
+    if (id != PJSUA_INVALID_ID && pjsua_get_state() < PJSUA_STATE_CLOSING) {
+	pjsua_call_set_user_data(id, NULL);
+        if (isActive()) {
+            CallOpParam prm;
+            hangup(prm);
+        }
+    }
+}
+
+CallInfo Call::getInfo() const throw(Error)
+{
+    pjsua_call_info pj_ci;
+    CallInfo ci;
+    
+    PJSUA2_CHECK_EXPR( pjsua_call_get_info(id, &pj_ci) );
+    ci.fromPj(pj_ci);
+    return ci;
+}
+
+bool Call::isActive() const
+{
+    if (id == PJSUA_INVALID_ID)
+        return false;
+    
+    return (pjsua_call_is_active(id) != 0);
+}
+
+int Call::getId() const
+{
+    return id;
+}
+
+Call *Call::lookup(int call_id)
+{
+    Call *call = (Call*)pjsua_call_get_user_data(call_id);
+    if (call)
+        call->id = call_id;
+    return call;
+}
+
+bool Call::hasMedia() const
+{
+    return (pjsua_call_has_media(id) != 0);
+}
+
+pjsip_dialog_cap_status Call::remoteHasCap(int htype,
+                                           const string &hname,
+                                           const string &token) const
+{
+    pj_str_t pj_hname = str2Pj(hname);
+    pj_str_t pj_token = str2Pj(token);
+    
+    return pjsua_call_remote_has_cap(id, htype,
+                                     (htype == PJSIP_H_OTHER)? &pj_hname: NULL,
+                                     &pj_token);
+}
+
+void Call::setUserData(Token user_data)
+{
+    userData = user_data;
+}
+
+Token Call::getUserData() const
+{
+    return userData;
+}
+
+pj_stun_nat_type Call::getRemNatType() throw(Error)
+{
+    pj_stun_nat_type nat;
+    
+    PJSUA2_CHECK_EXPR( pjsua_call_get_rem_nat_type(id, &nat) );
+    
+    return nat;
+}
+
+void Call::makeCall(const string &dst_uri, const CallOpParam &prm) throw(Error)
+{
+    pj_str_t pj_dst_uri = str2Pj(dst_uri);
+    call_param param(prm.txOption, prm.opt, prm.reason);
+    
+    PJSUA2_CHECK_EXPR( pjsua_call_make_call(acc.getId(), &pj_dst_uri,
+                                            param.p_opt, this,
+                                            param.p_msg_data, &id) );
+}
+
+void Call::answer(const CallOpParam &prm) throw(Error)
+{
+    call_param param(prm.txOption, prm.opt, prm.reason);
+    
+    PJSUA2_CHECK_EXPR( pjsua_call_answer2(id, param.p_opt, prm.statusCode,
+                                          param.p_reason, param.p_msg_data) );
+}
+
+void Call::hangup(const CallOpParam &prm) throw(Error)
+{
+    call_param param(prm.txOption, prm.opt, prm.reason);
+    
+    PJSUA2_CHECK_EXPR( pjsua_call_hangup(id, prm.statusCode, param.p_reason,
+                                         param.p_msg_data) );
+}
+
+void Call::setHold(const CallOpParam &prm) throw(Error)
+{
+    call_param param(prm.txOption, prm.opt, prm.reason);
+    
+    PJSUA2_CHECK_EXPR( pjsua_call_set_hold2(id, prm.options, param.p_msg_data));
+}
+
+void Call::reinvite(const CallOpParam &prm) throw(Error)
+{
+    call_param param(prm.txOption, prm.opt, prm.reason);
+
+    PJSUA2_CHECK_EXPR( pjsua_call_reinvite2(id, param.p_opt, param.p_msg_data));
+}
+
+void Call::update(const CallOpParam &prm) throw(Error)
+{
+    call_param param(prm.txOption, prm.opt, prm.reason);
+    
+    PJSUA2_CHECK_EXPR( pjsua_call_update2(id, param.p_opt, param.p_msg_data) );
+}
+
+void Call::xfer(const string &dest, const CallOpParam &prm) throw(Error)
+{
+    call_param param(prm.txOption);
+    pj_str_t pj_dest = str2Pj(dest);
+    
+    PJSUA2_CHECK_EXPR( pjsua_call_xfer(id, &pj_dest, param.p_msg_data) );
+}
+
+void Call::xferReplaces(const Call& dest_call,
+                  const CallOpParam &prm) throw(Error)
+{
+    call_param param(prm.txOption);
+    
+    PJSUA2_CHECK_EXPR(pjsua_call_xfer_replaces(id, dest_call.getId(),
+                                               prm.options, param.p_msg_data) );
+}
+
+void Call::processRedirect(pjsip_redirect_op cmd) throw(Error)
+{
+    PJSUA2_CHECK_EXPR(pjsua_call_process_redirect(id, cmd));
+}
+
+void Call::dialDtmf(const string &digits) throw(Error)
+{
+    pj_str_t pj_digits = str2Pj(digits);
+    
+    PJSUA2_CHECK_EXPR(pjsua_call_dial_dtmf(id, &pj_digits));
+}
+
+void Call::sendInstantMessage(const SendInstantMessageParam& prm)
+    throw(Error)
+{
+    pj_str_t mime_type = str2Pj(prm.contentType);
+    pj_str_t content = str2Pj(prm.content);
+    call_param param(prm.txOption);
+
+    PJSUA2_CHECK_EXPR(pjsua_call_send_im(id, &mime_type, &content,
+                                         param.p_msg_data, prm.userData) );
+}
+
+void Call::sendTypingIndication(const SendTypingIndicationParam &prm)
+    throw(Error)
+{
+    call_param param(prm.txOption);
+    
+    PJSUA2_CHECK_EXPR(pjsua_call_send_typing_ind(id,
+                                                 (prm.isTyping?
+                                                  PJ_TRUE: PJ_FALSE),
+                                                 param.p_msg_data) );
+}
+
+void Call::sendRequest(const CallSendRequestParam &prm) throw(Error)
+{
+    pj_str_t method = str2Pj(prm.method);
+    call_param param(prm.txOption);
+    
+    PJSUA2_CHECK_EXPR(pjsua_call_send_request(id, &method, param.p_msg_data) );
+}
+
+string Call::dump(bool with_media, const string indent) throw(Error)
+{
+#if defined(PJMEDIA_HAS_RTCP_XR) && (PJMEDIA_HAS_RTCP_XR != 0)
+    char buffer[1024 * 10];
+#else
+    char buffer[1024 * 3];
+#endif
+
+    PJSUA2_CHECK_EXPR(pjsua_call_dump(id, (with_media? PJ_TRUE: PJ_FALSE),
+                                      buffer, sizeof(buffer),
+                                      indent.c_str()));
+    
+    return buffer;
+}
+
+int Call::vidGetStreamIdx() const
+{
+    return pjsua_call_get_vid_stream_idx(id);
+}
+
+bool Call::vidStreamIsRunning(int med_idx, pjmedia_dir dir) const
+{
+    return pjsua_call_vid_stream_is_running(id, med_idx, dir);
+}
+
+void Call::vidSetStream(pjsua_call_vid_strm_op op,
+                        const CallVidSetStreamParam &param) throw(Error)
+{
+    pjsua_call_vid_strm_op_param prm;
+    
+    prm.med_idx = param.medIdx;
+    prm.dir = param.dir;
+    prm.cap_dev = param.capDev;
+    PJSUA2_CHECK_EXPR( pjsua_call_set_vid_strm(id, op, &prm) );
+}
+
+StreamInfo Call::getStreamInfo(unsigned med_idx) const throw(Error)
+{
+    pjsua_stream_info pj_si;
+    StreamInfo si;
+    
+    PJSUA2_CHECK_EXPR( pjsua_call_get_stream_info(id, med_idx, &pj_si) );
+    si.fromPj(pj_si);
+    return si;
+}
+
+StreamStat Call::getStreamStat(unsigned med_idx) const throw(Error)
+{
+    pjsua_stream_stat pj_ss;
+    StreamStat ss;
+    
+    PJSUA2_CHECK_EXPR( pjsua_call_get_stream_stat(id, med_idx, &pj_ss) );
+    ss.fromPj(pj_ss);
+    return ss;
+}
+
+MediaTransportInfo Call::getMedTransportInfo(unsigned med_idx) const
+    throw(Error)
+{
+    pjmedia_transport_info pj_mti;
+    MediaTransportInfo mti;
+    
+    PJSUA2_CHECK_EXPR( pjsua_call_get_med_transport_info(id, med_idx,
+                                                         &pj_mti) );
+    mti.fromPj(pj_mti);
+    return mti;
+}
Index: pjproject/branches/projects/pjsua2/pjsip/src/pjsua2/endpoint.cpp
===================================================================
--- pjproject/branches/projects/pjsua2/pjsip/src/pjsua2/endpoint.cpp	(revision 4662)
+++ pjproject/branches/projects/pjsua2/pjsip/src/pjsua2/endpoint.cpp	(revision 4663)
@@ -26,4 +26,7 @@
 using namespace std;
 
+#include <pjsua2/account.hpp>
+#include <pjsua2/call.hpp>
+
 #define THIS_FILE		"endpoint.cpp"
 #define MAX_STUN_SERVERS	32
@@ -695,4 +698,310 @@
 }
 
+// Call callbacks
+void Endpoint::on_call_state(pjsua_call_id call_id, pjsip_event *e)
+{
+    Call *call = Call::lookup(call_id);
+    if (!call) {
+	return;
+    }
+    
+    OnCallStateParam prm;
+    prm.e.fromPj(*e);
+    
+    call->onCallState(prm);
+    /* If the state is DISCONNECTED, call may have already been deleted
+     * by the application in the callback, so do not access it anymore here.
+     */
+}
+
+void Endpoint::on_call_tsx_state(pjsua_call_id call_id,
+                                 pjsip_transaction *tsx,
+                                 pjsip_event *e)
+{
+    Call *call = Call::lookup(call_id);
+    if (!call) {
+	return;
+    }
+    
+    OnCallTsxStateParam prm;
+    prm.e.fromPj(*e);
+    
+    call->onCallTsxState(prm);
+}
+
+void Endpoint::on_call_media_state(pjsua_call_id call_id)
+{
+    Call *call = Call::lookup(call_id);
+    if (!call) {
+	return;
+    }
+    
+    OnCallMediaStateParam prm;
+    call->onCallMediaState(prm);
+}
+
+void Endpoint::on_call_sdp_created(pjsua_call_id call_id,
+                                   pjmedia_sdp_session *sdp,
+                                   pj_pool_t *pool,
+                                   const pjmedia_sdp_session *rem_sdp)
+{
+    Call *call = Call::lookup(call_id);
+    if (!call) {
+	return;
+    }
+    
+    OnCallSdpCreatedParam prm;
+    string orig_sdp;
+    
+    prm.sdp.fromPj(*sdp);
+    orig_sdp = prm.sdp.wholeSdp;
+    if (rem_sdp)
+        prm.remSdp.fromPj(*rem_sdp);
+    
+    call->onCallSdpCreated(prm);
+    
+    /* Check if application modifies the SDP */
+    if (orig_sdp != prm.sdp.wholeSdp) {
+        pjmedia_sdp_parse(pool, (char*)prm.sdp.wholeSdp.c_str(),
+                          prm.sdp.wholeSdp.size(), &sdp);
+    }
+}
+
+void Endpoint::on_stream_created(pjsua_call_id call_id,
+                                 pjmedia_stream *strm,
+                                 unsigned stream_idx,
+                                 pjmedia_port **p_port)
+{
+    Call *call = Call::lookup(call_id);
+    if (!call) {
+	return;
+    }
+    
+    OnStreamCreatedParam prm;
+    prm.stream = strm;
+    prm.streamIdx = stream_idx;
+    prm.pPort = (void *)*p_port;
+    
+    call->onStreamCreated(prm);
+    
+    if (prm.pPort != (void *)*p_port)
+        *p_port = (pjmedia_port *)prm.pPort;
+}
+
+void Endpoint::on_stream_destroyed(pjsua_call_id call_id,
+                                   pjmedia_stream *strm,
+                                   unsigned stream_idx)
+{
+    Call *call = Call::lookup(call_id);
+    if (!call) {
+	return;
+    }
+    
+    OnStreamDestroyedParam prm;
+    prm.stream = strm;
+    prm.streamIdx = stream_idx;
+    
+    call->onStreamDestroyed(prm);
+}
+
+void Endpoint::on_dtmf_digit(pjsua_call_id call_id, int digit)
+{
+    Call *call = Call::lookup(call_id);
+    if (!call) {
+	return;
+    }
+    
+    OnDtmfDigitParam prm;
+    char buf[10];
+    pj_ansi_sprintf(buf, "%c", digit);
+    prm.digit = (string)buf;
+    
+    call->onDtmfDigit(prm);
+}
+
+void Endpoint::on_call_transfer_request2(pjsua_call_id call_id,
+                                         const pj_str_t *dst,
+                                         pjsip_status_code *code,
+                                         pjsua_call_setting *opt)
+{
+    Call *call = Call::lookup(call_id);
+    if (!call) {
+	return;
+    }
+    
+    OnCallTransferRequestParam prm;
+    prm.dstUri = pj2Str(*dst);
+    prm.statusCode = *code;
+    prm.opt.fromPj(*opt);
+    
+    call->onCallTransferRequest(prm);
+    
+    *code = prm.statusCode;
+    *opt = prm.opt.toPj();
+}
+
+void Endpoint::on_call_transfer_status(pjsua_call_id call_id,
+                                       int st_code,
+                                       const pj_str_t *st_text,
+                                       pj_bool_t final,
+                                       pj_bool_t *p_cont)
+{
+    Call *call = Call::lookup(call_id);
+    if (!call) {
+	return;
+    }
+    
+    OnCallTransferStatusParam prm;
+    prm.statusCode = (pjsip_status_code)st_code;
+    prm.reason = pj2Str(*st_text);
+    prm.finalNotify = final;
+    prm.cont = *p_cont;
+    
+    call->onCallTransferStatus(prm);
+    
+    *p_cont = prm.cont;
+}
+
+void Endpoint::on_call_replace_request2(pjsua_call_id call_id,
+                                        pjsip_rx_data *rdata,
+                                        int *st_code,
+                                        pj_str_t *st_text,
+                                        pjsua_call_setting *opt)
+{
+    Call *call = Call::lookup(call_id);
+    if (!call) {
+	return;
+    }
+    
+    OnCallReplaceRequestParam prm;
+    prm.rdata.fromPj(*rdata);
+    prm.statusCode = (pjsip_status_code)*st_code;
+    prm.reason = pj2Str(*st_text);
+    prm.opt.fromPj(*opt);
+    
+    call->onCallReplaceRequest(prm);
+    
+    *st_code = prm.statusCode;
+    *st_text = str2Pj(prm.reason);
+    *opt = prm.opt.toPj();
+}
+
+void Endpoint::on_call_replaced(pjsua_call_id old_call_id,
+                                pjsua_call_id new_call_id)
+{
+    Call *call = Call::lookup(old_call_id);
+    if (!call) {
+	return;
+    }
+    
+    OnCallReplacedParam prm;
+    prm.newCallId = new_call_id;
+    
+    call->onCallReplaced(prm);
+}
+
+void Endpoint::on_call_rx_offer(pjsua_call_id call_id,
+                                const pjmedia_sdp_session *offer,
+                                void *reserved,
+                                pjsip_status_code *code,
+                                pjsua_call_setting *opt)
+{
+    Call *call = Call::lookup(call_id);
+    if (!call) {
+	return;
+    }
+    
+    OnCallRxOfferParam prm;
+    prm.offer.fromPj(*offer);
+    prm.statusCode = *code;
+    prm.opt.fromPj(*opt);
+    
+    call->onCallRxOffer(prm);
+    
+    *code = prm.statusCode;
+    *opt = prm.opt.toPj();
+}
+
+pjsip_redirect_op Endpoint::on_call_redirected(pjsua_call_id call_id,
+                                               const pjsip_uri *target,
+                                               const pjsip_event *e)
+{
+    Call *call = Call::lookup(call_id);
+    if (!call) {
+	return PJSIP_REDIRECT_STOP;
+    }
+    
+    OnCallRedirectedParam prm;
+    char uristr[PJSIP_MAX_URL_SIZE];
+    int len = pjsip_uri_print(PJSIP_URI_IN_FROMTO_HDR, target, uristr,
+                              sizeof(uristr));
+    if (len < 1) {
+        pj_ansi_strcpy(uristr, "--URI too long--");
+    }
+    prm.targetUri = string(uristr);
+    if (e)
+        prm.e.fromPj(*e);
+    else
+        prm.e.type = PJSIP_EVENT_UNKNOWN;
+    
+    return call->onCallRedirected(prm);
+}
+
+pj_status_t
+Endpoint::on_call_media_transport_state(pjsua_call_id call_id,
+                                        const pjsua_med_tp_state_info *info)
+{
+    Call *call = Call::lookup(call_id);
+    if (!call) {
+	return PJ_SUCCESS;
+    }
+    
+    OnCallMediaTransportStateParam prm;
+    prm.medIdx = info->med_idx;
+    prm.state = info->state;
+    prm.status = info->status;
+    prm.sipErrorCode = info->sip_err_code;
+    
+    call->onCallMediaTransportState(prm);
+    
+    return PJ_SUCCESS;
+}
+
+void Endpoint::on_call_media_event(pjsua_call_id call_id,
+                                   unsigned med_idx,
+                                   pjmedia_event *event)
+{
+    Call *call = Call::lookup(call_id);
+    if (!call) {
+	return;
+    }
+    
+    OnCallMediaEventParam prm;
+    prm.medIdx = med_idx;
+    prm.ev.fromPj(*event);
+    
+    call->onCallMediaEvent(prm);
+}
+
+pjmedia_transport*
+Endpoint::on_create_media_transport(pjsua_call_id call_id,
+                                    unsigned media_idx,
+                                    pjmedia_transport *base_tp,
+                                    unsigned flags)
+{
+    Call *call = Call::lookup(call_id);
+    if (!call) {
+	return base_tp;
+    }
+    
+    OnCreateMediaTransportParam prm;
+    prm.mediaIdx = media_idx;
+    prm.mediaTp = base_tp;
+    prm.flags = flags;
+    
+    call->onCreateMediaTransport(prm);
+    
+    return (pjmedia_transport *)prm.mediaTp;
+}
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -753,4 +1062,23 @@
     ua_cfg.cb.on_buddy_state	= &Endpoint::on_buddy_state;
 
+    /* Call callbacks */
+    ua_cfg.cb.on_call_state             = &Endpoint::on_call_state;
+    ua_cfg.cb.on_call_tsx_state         = &Endpoint::on_call_tsx_state;
+    ua_cfg.cb.on_call_media_state       = &Endpoint::on_call_media_state;
+    ua_cfg.cb.on_call_sdp_created       = &Endpoint::on_call_sdp_created;
+    ua_cfg.cb.on_stream_created         = &Endpoint::on_stream_created;
+    ua_cfg.cb.on_stream_destroyed       = &Endpoint::on_stream_destroyed;
+    ua_cfg.cb.on_dtmf_digit             = &Endpoint::on_dtmf_digit;
+    ua_cfg.cb.on_call_transfer_request2 = &Endpoint::on_call_transfer_request2;
+    ua_cfg.cb.on_call_transfer_status   = &Endpoint::on_call_transfer_status;
+    ua_cfg.cb.on_call_replace_request2  = &Endpoint::on_call_replace_request2;
+    ua_cfg.cb.on_call_replaced          = &Endpoint::on_call_replaced;
+    ua_cfg.cb.on_call_rx_offer          = &Endpoint::on_call_rx_offer;
+    ua_cfg.cb.on_call_redirected        = &Endpoint::on_call_redirected;
+    ua_cfg.cb.on_call_media_transport_state =
+        &Endpoint::on_call_media_transport_state;
+    ua_cfg.cb.on_call_media_event       = &Endpoint::on_call_media_event;
+    ua_cfg.cb.on_create_media_transport = &Endpoint::on_create_media_transport;
+
     /* Init! */
     PJSUA2_CHECK_EXPR( pjsua_init(&ua_cfg, &log_cfg, &med_cfg) );
@@ -977,5 +1305,14 @@
 
 ///////////////////////////////////////////////////////////////////////////////
-
+/*
+ * Call operations
+ */
+
+void Endpoint::hangupAllCalls(void)
+{
+    pjsua_call_hangup_all();
+}
+
+///////////////////////////////////////////////////////////////////////////////
 /*
  * Media API
Index: pjproject/branches/projects/pjsua2/pjsip/src/pjsua2/siptypes.cpp
===================================================================
--- pjproject/branches/projects/pjsua2/pjsip/src/pjsua2/siptypes.cpp	(revision 4662)
+++ pjproject/branches/projects/pjsua2/pjsip/src/pjsua2/siptypes.cpp	(revision 4663)
@@ -324,8 +324,11 @@
 void SipRxData::fromPj(pjsip_rx_data &rdata)
 {
+    char straddr[PJ_INET6_ADDRSTRLEN+10];
+
     info	= pjsip_rx_data_get_info(&rdata);
     wholeMsg	= string(rdata.msg_info.msg_buf, rdata.msg_info.len);
-    srcIp	= rdata.pkt_info.src_name;
-    srcPort	= rdata.pkt_info.src_port;
+    pj_sockaddr_print(&rdata.pkt_info.src_addr, straddr, sizeof(straddr), 3);
+    srcAddress  = straddr;
+    pjRxData    = (void *)&rdata;
 }
 
@@ -424,4 +427,66 @@
 ///////////////////////////////////////////////////////////////////////////////
 
+void SipEvent::fromPj(const pjsip_event &ev)
+{
+    type = ev.type;
+    if (type == PJSIP_EVENT_TIMER) {
+        body.timer.entry = ev.body.timer.entry;
+    } else if (type == PJSIP_EVENT_TSX_STATE) {
+        body.tsxState.prevState = (pjsip_tsx_state_e)
+        ev.body.tsx_state.prev_state;
+        body.tsxState.tsx.fromPj(*ev.body.tsx_state.tsx);
+        if (body.tsxState.type == PJSIP_EVENT_TX_MSG) {
+            body.tsxState.src.tdata.fromPj(*ev.body.tsx_state.src.tdata);
+        } else if (body.tsxState.type == PJSIP_EVENT_RX_MSG) {
+            body.tsxState.src.rdata.fromPj(*ev.body.tsx_state.src.rdata);
+        } else if (body.tsxState.type == PJSIP_EVENT_TRANSPORT_ERROR) {
+            body.tsxState.src.status = ev.body.tsx_state.src.status;
+        } else if (body.tsxState.type == PJSIP_EVENT_TIMER) {
+            body.tsxState.src.timer = ev.body.tsx_state.src.timer;
+        } else if (body.tsxState.type == PJSIP_EVENT_USER) {
+            body.tsxState.src.data = ev.body.tsx_state.src.data;
+        }
+    } else if (type == PJSIP_EVENT_TX_MSG) {
+        body.txMsg.tdata.fromPj(*ev.body.tx_msg.tdata);
+    } else if (type == PJSIP_EVENT_RX_MSG) {
+        body.rxMsg.rdata.fromPj(*ev.body.rx_msg.rdata);
+    } else if (type == PJSIP_EVENT_TRANSPORT_ERROR) {
+        body.txError.tdata.fromPj(*ev.body.tx_error.tdata);
+        body.txError.tsx.fromPj(*ev.body.tx_error.tsx);
+    } else if (type == PJSIP_EVENT_USER) {
+        body.user.user1 = ev.body.user.user1;
+    }
+    pjEvent = (void *)&ev;
+}
+
+void SipTxData::fromPj(pjsip_tx_data &tdata)
+{
+    char straddr[PJ_INET6_ADDRSTRLEN+10];
+    
+    info	= pjsip_tx_data_get_info(&tdata);
+    pjsip_tx_data_encode(&tdata);
+    wholeMsg	= string(tdata.buf.start, tdata.buf.end - tdata.buf.start);
+    pj_sockaddr_print(&tdata.tp_info.dst_addr, straddr, sizeof(straddr), 3);
+    dstAddress  = straddr;
+    pjTxData    = (void *)&tdata;
+}
+
+void SipTransaction::fromPj(pjsip_transaction &tsx)
+{
+    this->role          = tsx.role;
+    this->method        = pj2Str(tsx.method.name);
+    this->statusCode    = tsx.status_code;
+    this->statusText    = pj2Str(tsx.status_text);
+    this->lastTx.fromPj(*tsx.last_tx);
+    this->pjTransaction = (void *)&tsx;
+}
+
+bool SipTxOption::isEmpty() const
+{
+    return (targetUri == "" && headers.size() == 0 && contentType == "" &&
+            msgBody == "" && multipartContentType.type == "" &&
+            multipartContentType.subType == "" && multipartParts.size() == 0);
+}
+
 void SipTxOption::fromPj(const pjsua_msg_data &prm) throw(Error)
 {
@@ -475,2 +540,14 @@
     }
 }
+
+//////////////////////////////////////////////////////////////////////////////
+
+SendInstantMessageParam::SendInstantMessageParam()
+: contentType("text/plain"), content(""), userData(NULL)
+{
+}
+
+SendTypingIndicationParam::SendTypingIndicationParam()
+: isTyping(false)
+{
+}
Index: pjproject/branches/projects/pjsua2/pjsip/src/pjsua2/types.cpp
===================================================================
--- pjproject/branches/projects/pjsua2/pjsip/src/pjsua2/types.cpp	(revision 4662)
+++ pjproject/branches/projects/pjsua2/pjsip/src/pjsua2/types.cpp	(revision 4663)
@@ -86,2 +86,10 @@
 }
 
+///////////////////////////////////////////////////////////////////////////////
+
+void TimeValue::fromPj(const pj_time_val &prm)
+{
+    this->sec  = prm.sec;
+    this->msec = prm.msec;
+}
+
