/**
* Copyright (C) 2010-2012 Regis Montoya (aka r3gis - www.r3gis.fr)
* This file is part of CSipSimple.
*
* CSipSimple 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 3 of the License, or
* (at your option) any later version.
* If you own a pjsip commercial license you can also redistribute it
* and/or modify it under the terms of the GNU Lesser General Public License
* as an android library.
*
* CSipSimple 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 CSipSimple. If not, see <http://www.gnu.org/licenses/>.
*/
package com.csipsimple.pjsip;
import android.content.Context;
import android.os.SystemClock;
import android.text.TextUtils;
import com.csipsimple.service.SipService.SameThreadException;
import com.csipsimple.service.impl.SipCallSessionImpl;
import com.csipsimple.utils.Log;
import org.pjsip.pjsua.pj_time_val;
import org.pjsip.pjsua.pjmedia_dir;
import org.pjsip.pjsua.pjsip_event;
import org.pjsip.pjsua.pjsip_inv_state;
import org.pjsip.pjsua.pjsua;
import org.pjsip.pjsua.pjsuaConstants;
import org.pjsip.pjsua.pjsua_call_info;
import org.pjsip.pjsua.zrtp_state_info;
/**
* Singleton class to manage pjsip calls. It allows to convert retrieve pjsip
* calls information and convert that into objects that can be easily managed on
* Android side
*/
public final class PjSipCalls {
private PjSipCalls() {
}
private static final String THIS_FILE = "PjSipCalls";
/**
* Update the call session infos
*
* @param session The session to update (input/output). Must have a correct
* call id set
* @param service PjSipService Sip service to retrieve pjsip accounts infos
* @throws SameThreadException
*/
public static void updateSessionFromPj(SipCallSessionImpl session, pjsip_event e, Context context)
throws SameThreadException {
Log.d(THIS_FILE, "Update call " + session.getCallId());
pjsua_call_info pjInfo = new pjsua_call_info();
int status = pjsua.call_get_info(session.getCallId(), pjInfo);
if (status == pjsua.PJ_SUCCESS) {
// Transform pjInfo into CallSession object
updateSession(session, pjInfo, context);
// Update state here because we have pjsip_event here and can get q.850 state
if(e != null) {
// Status code
int status_code = pjsua.get_event_status_code(e);
if(status_code == 0) {
try {
status_code = pjInfo.getLast_status().swigValue();
} catch (IllegalArgumentException err) {
// The status code does not exist in enum ignore it
}
}
session.setLastStatusCode(status_code);
Log.d(THIS_FILE, "Last status code is " + status_code);
// TODO - get comment from q.850 state as well
String status_text = PjSipService.pjStrToString(pjInfo.getLast_status_text());
session.setLastStatusComment(status_text);
// Reason code
int reason_code = pjsua.get_event_reason_code(e);
if (reason_code != 0) {
session.setLastReasonCode(reason_code);
}
}
// And now, about secure information
session.setSignalisationSecure(pjsua.call_secure_sig_level(session.getCallId()));
String secureInfo = PjSipService.pjStrToString(pjsua.call_secure_media_info(session
.getCallId()));
session.setMediaSecureInfo(secureInfo);
session.setMediaSecure(!TextUtils.isEmpty(secureInfo));
zrtp_state_info zrtpInfo = pjsua.jzrtp_getInfoFromCall(session.getCallId());
session.setZrtpSASVerified(zrtpInfo.getSas_verified() == pjsuaConstants.PJ_TRUE);
session.setHasZrtp(zrtpInfo.getSecure() == pjsuaConstants.PJ_TRUE);
// About video info
int vidStreamIdx = pjsua.call_get_vid_stream_idx(session.getCallId());
if(vidStreamIdx >= 0) {
int hasVid = pjsua.call_vid_stream_is_running(session.getCallId(), vidStreamIdx, pjmedia_dir.PJMEDIA_DIR_DECODING);
session.setMediaHasVideo((hasVid == pjsuaConstants.PJ_TRUE));
}
} else {
Log.d(THIS_FILE,
"Call info from does not exists in stack anymore - assume it has been disconnected");
session.setCallState(pjsip_inv_state.PJSIP_INV_STATE_DISCONNECTED.swigValue());
}
}
/**
* Copy infos from pjsua call info object to SipCallSession object
*
* @param session the session to copy info to (output)
* @param pjCallInfo the call info from pjsip
* @param service PjSipService Sip service to retrieve pjsip accounts infos
*/
private static void updateSession(SipCallSessionImpl session, pjsua_call_info pjCallInfo,
Context context) {
// Should be unecessary cause we usually copy infos from a valid
session.setCallId(pjCallInfo.getId());
// Nothing to think about here cause we have a
// bijection between int / state
session.setCallState(pjCallInfo.getState().swigValue());
session.setMediaStatus(pjCallInfo.getMedia_status().swigValue());
session.setRemoteContact(PjSipService.pjStrToString(pjCallInfo.getRemote_info()));
session.setConfPort(pjCallInfo.getConf_slot());
// Try to retrieve sip account related to this call
int pjAccId = pjCallInfo.getAcc_id();
session.setAccId(PjSipService.getAccountIdForPjsipId(context, pjAccId));
pj_time_val duration = pjCallInfo.getConnect_duration();
session.setConnectStart(SystemClock.elapsedRealtime() - duration.getSec() * 1000
- duration.getMsec());
}
/**
* Get infos for this pjsip call
*
* @param callId pjsip call id
* @return Serialized information about this call
* @throws SameThreadException
*/
public static String dumpCallInfo(int callId) throws SameThreadException {
return PjSipService.pjStrToString(pjsua.call_dump(callId, pjsua.PJ_TRUE, " "));
}
}