summaryrefslogtreecommitdiff
path: root/pjsip-apps/src/swig/java/android/src/org/pjsip/pjsua2/app/MyApp.java
diff options
context:
space:
mode:
Diffstat (limited to 'pjsip-apps/src/swig/java/android/src/org/pjsip/pjsua2/app/MyApp.java')
-rw-r--r--pjsip-apps/src/swig/java/android/src/org/pjsip/pjsua2/app/MyApp.java449
1 files changed, 449 insertions, 0 deletions
diff --git a/pjsip-apps/src/swig/java/android/src/org/pjsip/pjsua2/app/MyApp.java b/pjsip-apps/src/swig/java/android/src/org/pjsip/pjsua2/app/MyApp.java
new file mode 100644
index 00000000..7d7ab5d4
--- /dev/null
+++ b/pjsip-apps/src/swig/java/android/src/org/pjsip/pjsua2/app/MyApp.java
@@ -0,0 +1,449 @@
+/* $Id$ */
+/*
+ * 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
+ */
+package org.pjsip.pjsua2.app;
+
+import java.io.File;
+import java.util.ArrayList;
+import org.pjsip.pjsua2.*;
+
+
+/* Interface to separate UI & engine a bit better */
+interface MyAppObserver {
+ abstract void notifyRegState(pjsip_status_code code, String reason, int expiration);
+ abstract void notifyIncomingCall(MyCall call);
+ abstract void notifyCallState(MyCall call);
+ abstract void notifyBuddyState(MyBuddy buddy);
+}
+
+
+class MyLogWriter extends LogWriter {
+ @Override
+ public void write(LogEntry entry) {
+ System.out.println(entry.getMsg());
+ }
+}
+
+
+class MyCall extends Call {
+ MyCall(MyAccount acc, int call_id) {
+ super(acc, call_id);
+ }
+
+ @Override
+ public void onCallState(OnCallStateParam prm) {
+ MyApp.observer.notifyCallState(this);
+ }
+
+ @Override
+ public void onCallMediaState(OnCallMediaStateParam prm) {
+ CallInfo ci;
+ try {
+ ci = getInfo();
+ } catch (Exception e) {
+ return;
+ }
+
+ CallMediaInfoVector cmiv = ci.getMedia();
+
+ for (int i = 0; i < cmiv.size(); i++) {
+ CallMediaInfo cmi = cmiv.get(i);
+ if (cmi.getType() == pjmedia_type.PJMEDIA_TYPE_AUDIO &&
+ (cmi.getStatus() == pjsua_call_media_status.PJSUA_CALL_MEDIA_ACTIVE ||
+ cmi.getStatus() == pjsua_call_media_status.PJSUA_CALL_MEDIA_REMOTE_HOLD))
+ {
+ // unfortunately, on Java too, the returned Media cannot be downcasted to AudioMedia
+ Media m = getMedia(i);
+ AudioMedia am = AudioMedia.typecastFromMedia(m);
+
+ // connect ports
+ try {
+ MyApp.ep.audDevManager().getCaptureDevMedia().startTransmit(am);
+ am.startTransmit(MyApp.ep.audDevManager().getPlaybackDevMedia());
+ } catch (Exception e) {
+ continue;
+ }
+ }
+ }
+ }
+}
+
+
+class MyAccount extends Account {
+ public ArrayList<MyBuddy> buddyList = new ArrayList<MyBuddy>();
+ public AccountConfig cfg;
+
+ MyAccount(AccountConfig config) {
+ super();
+ cfg = config;
+ }
+
+ public MyBuddy addBuddy(BuddyConfig bud_cfg)
+ {
+ /* Create Buddy */
+ MyBuddy bud = new MyBuddy(bud_cfg);
+ try {
+ bud.create(this, bud_cfg);
+ } catch (Exception e) {
+ bud = null;
+ }
+
+ if (bud != null) {
+ buddyList.add(bud);
+ if (bud_cfg.getSubscribe())
+ try {
+ bud.subscribePresence(true);
+ } catch (Exception e) {}
+ }
+
+ return bud;
+ }
+
+ public void delBuddy(MyBuddy buddy) {
+ buddyList.remove(buddy);
+ }
+
+ public void delBuddy(int index) {
+ buddyList.remove(index);
+ }
+
+ @Override
+ public void onRegState(OnRegStateParam prm) {
+ MyApp.observer.notifyRegState(prm.getCode(), prm.getReason(), prm.getExpiration());
+ }
+
+ @Override
+ public void onIncomingCall(OnIncomingCallParam prm) {
+ System.out.println("======== Incoming call ======== ");
+ MyCall call = new MyCall(this, prm.getCallId());
+ MyApp.observer.notifyIncomingCall(call);
+ }
+
+ @Override
+ public void onInstantMessage(OnInstantMessageParam prm) {
+ System.out.println("======== Incoming pager ======== ");
+ System.out.println("From : " + prm.getFromUri());
+ System.out.println("To : " + prm.getToUri());
+ System.out.println("Contact : " + prm.getContactUri());
+ System.out.println("Mimetype : " + prm.getContentType());
+ System.out.println("Body : " + prm.getMsgBody());
+ }
+}
+
+
+class MyBuddy extends Buddy {
+ public BuddyConfig cfg;
+
+ MyBuddy(BuddyConfig config) {
+ super();
+ cfg = config;
+ }
+
+ String getStatusText() {
+ BuddyInfo bi;
+
+ try {
+ bi = getInfo();
+ } catch (Exception e) {
+ return "?";
+ }
+
+ String status = "";
+ if (bi.getSubState() == pjsip_evsub_state.PJSIP_EVSUB_STATE_ACTIVE) {
+ if (bi.getPresStatus().getStatus() == pjsua_buddy_status.PJSUA_BUDDY_STATUS_ONLINE) {
+ status = bi.getPresStatus().getStatusText();
+ if (status == null || status.isEmpty()) {
+ status = "Online";
+ }
+ } else if (bi.getPresStatus().getStatus() == pjsua_buddy_status.PJSUA_BUDDY_STATUS_OFFLINE) {
+ status = "Offline";
+ } else {
+ status = "Unknown";
+ }
+ }
+ return status;
+ }
+
+ @Override
+ public void onBuddyState() {
+ MyApp.observer.notifyBuddyState(this);
+ }
+
+}
+
+
+class MyAccountConfig {
+ public AccountConfig accCfg = new AccountConfig();
+ public ArrayList<BuddyConfig> buddyCfgs = new ArrayList<BuddyConfig>();
+
+ public void readObject(ContainerNode node) {
+ try {
+ ContainerNode acc_node = node.readContainer("Account");
+ accCfg.readObject(acc_node);
+ ContainerNode buddies_node = acc_node.readArray("buddies");
+ buddyCfgs.clear();
+ while (buddies_node.hasUnread()) {
+ BuddyConfig bud_cfg = new BuddyConfig();
+ bud_cfg.readObject(buddies_node);
+ buddyCfgs.add(bud_cfg);
+ }
+ } catch (Exception e) {}
+ }
+
+ public void writeObject(ContainerNode node) {
+ try {
+ ContainerNode acc_node = node.writeNewContainer("Account");
+ accCfg.writeObject(acc_node);
+ ContainerNode buddies_node = acc_node.writeNewArray("buddies");
+ for (int j = 0; j < buddyCfgs.size(); j++) {
+ buddyCfgs.get(j).writeObject(buddies_node);
+ }
+ } catch (Exception e) {}
+ }
+}
+
+
+class MyApp {
+ static {
+ System.loadLibrary("pjsua2");
+ System.out.println("Library loaded");
+ }
+
+ public static Endpoint ep = new Endpoint();
+ public static MyAppObserver observer;
+ public ArrayList<MyAccount> accList = new ArrayList<MyAccount>();
+
+ private ArrayList<MyAccountConfig> accCfgs = new ArrayList<MyAccountConfig>();
+ private EpConfig epConfig = new EpConfig();
+ private TransportConfig sipTpConfig = new TransportConfig();
+ private String appDir;
+
+ /* Maintain reference to log writer to avoid premature cleanup by GC */
+ private MyLogWriter logWriter;
+
+ private final String configName = "pjsua2.json";
+ private final int SIP_PORT = 6000;
+ private final int LOG_LEVEL = 4;
+
+ public void init(MyAppObserver obs, String app_dir) {
+ init(obs, app_dir, false);
+ }
+
+ public void init(MyAppObserver obs, String app_dir, boolean own_worker_thread) {
+ observer = obs;
+ appDir = app_dir;
+
+ /* Create endpoint */
+ try {
+ ep.libCreate();
+ } catch (Exception e) {
+ return;
+ }
+
+
+ /* Load config */
+ String configPath = appDir + "/" + configName;
+ File f = new File(configPath);
+ if (f.exists()) {
+ loadConfig(configPath);
+ } else {
+ /* Set 'default' values */
+ sipTpConfig.setPort(SIP_PORT);
+ }
+
+ /* Override log level setting */
+ epConfig.getLogConfig().setLevel(LOG_LEVEL);
+ epConfig.getLogConfig().setConsoleLevel(LOG_LEVEL);
+
+ /* Set log config. */
+ LogConfig log_cfg = epConfig.getLogConfig();
+ logWriter = new MyLogWriter();
+ log_cfg.setWriter(logWriter);
+ log_cfg.setDecor(log_cfg.getDecor() &
+ ~(pj_log_decoration.PJ_LOG_HAS_CR.swigValue() |
+ pj_log_decoration.PJ_LOG_HAS_NEWLINE.swigValue()));
+
+ /* Set ua config. */
+ UaConfig ua_cfg = epConfig.getUaConfig();
+ ua_cfg.setUserAgent("Pjsua2And" + ep.libVersion().getFull());
+ if (own_worker_thread) {
+ ua_cfg.setThreadCnt(0);
+ ua_cfg.setMainThreadOnly(true);
+ }
+
+ /* Init endpoint */
+ try {
+ ep.libInit(epConfig);
+ } catch (Exception e) {
+ return;
+ }
+
+ /* Create transports. */
+ try {
+ ep.transportCreate(pjsip_transport_type_e.PJSIP_TRANSPORT_UDP, sipTpConfig);
+ } catch (Exception e) {
+ System.out.println(e);
+ }
+
+ try {
+ ep.transportCreate(pjsip_transport_type_e.PJSIP_TRANSPORT_TCP, sipTpConfig);
+ } catch (Exception e) {
+ System.out.println(e);
+ }
+
+ /* Create accounts. */
+ for (int i = 0; i < accCfgs.size(); i++) {
+ MyAccountConfig my_cfg = accCfgs.get(i);
+ MyAccount acc = addAcc(my_cfg.accCfg);
+ if (acc == null)
+ continue;
+
+ /* Add Buddies */
+ for (int j = 0; j < my_cfg.buddyCfgs.size(); j++) {
+ BuddyConfig bud_cfg = my_cfg.buddyCfgs.get(j);
+ acc.addBuddy(bud_cfg);
+ }
+ }
+
+ /* Start. */
+ try {
+ ep.libStart();
+ } catch (Exception e) {
+ return;
+ }
+ }
+
+ public MyAccount addAcc(AccountConfig cfg) {
+ MyAccount acc = new MyAccount(cfg);
+ try {
+ acc.create(cfg);
+ } catch (Exception e) {
+ acc = null;
+ return null;
+ }
+
+ accList.add(acc);
+ return acc;
+ }
+
+ public void delAcc(MyAccount acc) {
+ accList.remove(acc);
+ }
+
+ private void loadConfig(String filename) {
+ JsonDocument json = new JsonDocument();
+
+ try {
+ /* Load file */
+ json.loadFile(filename);
+ ContainerNode root = json.getRootContainer();
+
+ /* Read endpoint config */
+ epConfig.readObject(root);
+
+ /* Read transport config */
+ ContainerNode tp_node = root.readContainer("SipTransport");
+ sipTpConfig.readObject(tp_node);
+
+ /* Read account configs */
+ accCfgs.clear();
+ ContainerNode accs_node = root.readArray("accounts");
+ while (accs_node.hasUnread()) {
+ MyAccountConfig acc_cfg = new MyAccountConfig();
+ acc_cfg.readObject(accs_node);
+ accCfgs.add(acc_cfg);
+ }
+ } catch (Exception e) {
+ System.out.println(e);
+ }
+
+ /* Force delete json now, as I found that Java somehow destroys it
+ * after lib has been destroyed and from non-registered thread.
+ */
+ json.delete();
+ }
+
+ private void buildAccConfigs() {
+ /* Sync accCfgs from accList */
+ accCfgs.clear();
+ for (int i = 0; i < accList.size(); i++) {
+ MyAccount acc = accList.get(i);
+ MyAccountConfig my_acc_cfg = new MyAccountConfig();
+ my_acc_cfg.accCfg = acc.cfg;
+
+ my_acc_cfg.buddyCfgs.clear();
+ for (int j = 0; j < acc.buddyList.size(); j++) {
+ MyBuddy bud = acc.buddyList.get(j);
+ my_acc_cfg.buddyCfgs.add(bud.cfg);
+ }
+
+ accCfgs.add(my_acc_cfg);
+ }
+ }
+
+ private void saveConfig(String filename) {
+ JsonDocument json = new JsonDocument();
+
+ try {
+ /* Write endpoint config */
+ json.writeObject(epConfig);
+
+ /* Write transport config */
+ ContainerNode tp_node = json.writeNewContainer("SipTransport");
+ sipTpConfig.writeObject(tp_node);
+
+ /* Write account configs */
+ buildAccConfigs();
+ ContainerNode accs_node = json.writeNewArray("accounts");
+ for (int i = 0; i < accCfgs.size(); i++) {
+ accCfgs.get(i).writeObject(accs_node);
+ }
+
+ /* Save file */
+ json.saveFile(filename);
+ } catch (Exception e) {}
+
+ /* Force delete json now, as I found that Java somehow destroys it
+ * after lib has been destroyed and from non-registered thread.
+ */
+ json.delete();
+ }
+
+ public void deinit() {
+ String configPath = appDir + "/" + configName;
+ saveConfig(configPath);
+
+ /* Try force GC to avoid late destroy of PJ objects as they should be
+ * deleted before lib is destroyed.
+ */
+ Runtime.getRuntime().gc();
+
+ /* Shutdown pjsua. Note that Endpoint destructor will also invoke
+ * libDestroy(), so this will be a test of double libDestroy().
+ */
+ try {
+ ep.libDestroy();
+ } catch (Exception e) {}
+
+ /* Force delete Endpoint here, to avoid deletion from a non-
+ * registered thread (by GC?).
+ */
+ ep.delete();
+ ep = null;
+ }
+}