Changeset 5017 for pjproject/trunk
- Timestamp:
- Mar 22, 2015 10:22:44 AM (10 years ago)
- Location:
- pjproject/trunk/pjsip-apps/src/swig/java/android/src/org/pjsip/pjsua2/app
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
pjproject/trunk/pjsip-apps/src/swig/java/android/src/org/pjsip/pjsua2/app/CallActivity.java
r5014 r5017 32 32 33 33 public class CallActivity extends Activity 34 implements Handler.Callback, SurfaceHolder.Callback34 implements Handler.Callback, SurfaceHolder.Callback 35 35 { 36 37 public static Handler handler_; 38 39 private final Handler handler = new Handler(this); 40 private static CallInfo lastCallInfo; 41 42 @Override 43 protected void onCreate(Bundle savedInstanceState) { 44 super.onCreate(savedInstanceState); 45 setContentView(R.layout.activity_call); 46 47 SurfaceView surfaceView = (SurfaceView)findViewById(R.id.surfaceIncomingVideo); 48 if (MainActivity.currentCall == null || 49 MainActivity.currentCall.vidWin == null) 50 { 51 surfaceView.setVisibility(View.GONE); 52 } 53 surfaceView.getHolder().addCallback(this); 54 55 handler_ = handler; 56 if (MainActivity.currentCall != null) { 57 try { 58 lastCallInfo = MainActivity.currentCall.getInfo(); 59 updateCallState(lastCallInfo); 60 } catch (Exception e) { 61 System.out.println(e); 62 } 63 } else { 64 updateCallState(lastCallInfo); 65 } 66 } 36 37 public static Handler handler_; 38 39 private final Handler handler = new Handler(this); 40 private static CallInfo lastCallInfo; 67 41 68 42 @Override 69 protected void onDestroy() { 70 super.onDestroy(); 71 handler_ = null; 72 } 73 74 private void updateVideoWindow(SurfaceHolder holder) { 75 if (MainActivity.currentCall != null && 76 MainActivity.currentCall.vidWin != null) 77 { 78 VideoWindowHandle vidWH = new VideoWindowHandle(); 79 if (holder == null) 80 vidWH.getHandle().setWindow(null); 81 else 82 vidWH.getHandle().setWindow(holder.getSurface()); 83 try { 84 MainActivity.currentCall.vidWin.setWindow(vidWH); 85 } catch (Exception e) {} 86 } 87 } 88 89 public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { 90 updateVideoWindow(holder); 91 } 92 93 public void surfaceCreated(SurfaceHolder holder) { 94 } 95 96 public void surfaceDestroyed(SurfaceHolder holder) { 97 updateVideoWindow(null); 98 } 99 100 public void acceptCall(View view) { 101 CallOpParam prm = new CallOpParam(); 102 prm.setStatusCode(pjsip_status_code.PJSIP_SC_OK); 103 try { 104 MainActivity.currentCall.answer(prm); 105 } catch (Exception e) { 106 System.out.println(e); 107 } 108 109 view.setVisibility(View.GONE); 110 } 111 112 public void hangupCall(View view) { 113 handler_ = null; 114 finish(); 115 116 if (MainActivity.currentCall != null) { 117 CallOpParam prm = new CallOpParam(); 118 prm.setStatusCode(pjsip_status_code.PJSIP_SC_DECLINE); 119 try { 120 MainActivity.currentCall.hangup(prm); 121 } catch (Exception e) { 122 System.out.println(e); 123 } 124 } 125 } 126 127 private void setupVideoSurface() { 128 129 SurfaceView surfaceView = (SurfaceView)findViewById(R.id.surfaceIncomingVideo); 130 surfaceView.setVisibility(View.VISIBLE); 131 updateVideoWindow(surfaceView.getHolder()); 132 133 } 134 135 @Override 136 public boolean handleMessage(Message m) { 137 138 if (m.what == MainActivity.MSG_TYPE.CALL_STATE) { 139 140 lastCallInfo = (CallInfo) m.obj; 141 updateCallState(lastCallInfo); 142 143 } else if (m.what == MainActivity.MSG_TYPE.CALL_MEDIA_STATE) { 144 145 if (MainActivity.currentCall.vidWin != null) { 146 /* If there's incoming video, display it. */ 147 setupVideoSurface(); 148 } 149 150 } else { 151 152 /* Message not handled */ 153 return false; 154 155 } 156 157 return true; 158 } 159 160 private void updateCallState(CallInfo ci) { 161 TextView tvPeer = (TextView) findViewById(R.id.textViewPeer); 162 TextView tvState = (TextView) findViewById(R.id.textViewCallState); 163 Button buttonHangup = (Button) findViewById(R.id.buttonHangup); 164 Button buttonAccept = (Button) findViewById(R.id.buttonAccept); 165 String call_state = ""; 166 167 if (ci.getRole() == pjsip_role_e.PJSIP_ROLE_UAC) { 168 buttonAccept.setVisibility(View.GONE); 169 } 170 171 if (ci.getState().swigValue() < pjsip_inv_state.PJSIP_INV_STATE_CONFIRMED.swigValue()) 172 { 173 if (ci.getRole() == pjsip_role_e.PJSIP_ROLE_UAS) { 174 call_state = "Incoming call.."; 175 /* Default button texts are already 'Accept' & 'Reject' */ 176 } else { 177 buttonHangup.setText("Cancel"); 178 call_state = ci.getStateText(); 179 } 180 } 181 else if (ci.getState().swigValue() >= pjsip_inv_state.PJSIP_INV_STATE_CONFIRMED.swigValue()) 182 { 183 buttonAccept.setVisibility(View.GONE); 184 call_state = ci.getStateText(); 185 if (ci.getState() == pjsip_inv_state.PJSIP_INV_STATE_CONFIRMED) { 186 buttonHangup.setText("Hangup"); 187 } else if (ci.getState() == pjsip_inv_state.PJSIP_INV_STATE_DISCONNECTED) { 188 buttonHangup.setText("OK"); 189 call_state = "Call disconnected: " + ci.getLastReason(); 190 } 191 } 192 193 tvPeer.setText(ci.getRemoteUri()); 194 tvState.setText(call_state); 195 } 43 protected void onCreate(Bundle savedInstanceState) 44 { 45 super.onCreate(savedInstanceState); 46 setContentView(R.layout.activity_call); 47 48 SurfaceView surfaceView = (SurfaceView) 49 findViewById(R.id.surfaceIncomingVideo); 50 if (MainActivity.currentCall == null || 51 MainActivity.currentCall.vidWin == null) 52 { 53 surfaceView.setVisibility(View.GONE); 54 } 55 surfaceView.getHolder().addCallback(this); 56 57 handler_ = handler; 58 if (MainActivity.currentCall != null) { 59 try { 60 lastCallInfo = MainActivity.currentCall.getInfo(); 61 updateCallState(lastCallInfo); 62 } catch (Exception e) { 63 System.out.println(e); 64 } 65 } else { 66 updateCallState(lastCallInfo); 67 } 68 } 69 70 @Override 71 protected void onDestroy() 72 { 73 super.onDestroy(); 74 handler_ = null; 75 } 76 77 private void updateVideoWindow(SurfaceHolder holder) 78 { 79 if (MainActivity.currentCall != null && 80 MainActivity.currentCall.vidWin != null) 81 { 82 VideoWindowHandle vidWH = new VideoWindowHandle(); 83 if (holder == null) 84 vidWH.getHandle().setWindow(null); 85 else 86 vidWH.getHandle().setWindow(holder.getSurface()); 87 try { 88 MainActivity.currentCall.vidWin.setWindow(vidWH); 89 } catch (Exception e) {} 90 } 91 } 92 93 public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) 94 { 95 updateVideoWindow(holder); 96 } 97 98 public void surfaceCreated(SurfaceHolder holder) 99 { 100 } 101 102 public void surfaceDestroyed(SurfaceHolder holder) 103 { 104 updateVideoWindow(null); 105 } 106 107 public void acceptCall(View view) 108 { 109 CallOpParam prm = new CallOpParam(); 110 prm.setStatusCode(pjsip_status_code.PJSIP_SC_OK); 111 try { 112 MainActivity.currentCall.answer(prm); 113 } catch (Exception e) { 114 System.out.println(e); 115 } 116 117 view.setVisibility(View.GONE); 118 } 119 120 public void hangupCall(View view) 121 { 122 handler_ = null; 123 finish(); 124 125 if (MainActivity.currentCall != null) { 126 CallOpParam prm = new CallOpParam(); 127 prm.setStatusCode(pjsip_status_code.PJSIP_SC_DECLINE); 128 try { 129 MainActivity.currentCall.hangup(prm); 130 } catch (Exception e) { 131 System.out.println(e); 132 } 133 } 134 } 135 136 private void setupVideoSurface() 137 { 138 SurfaceView surfaceView = (SurfaceView) 139 findViewById(R.id.surfaceIncomingVideo); 140 surfaceView.setVisibility(View.VISIBLE); 141 updateVideoWindow(surfaceView.getHolder()); 142 } 143 144 @Override 145 public boolean handleMessage(Message m) 146 { 147 if (m.what == MainActivity.MSG_TYPE.CALL_STATE) { 148 149 lastCallInfo = (CallInfo) m.obj; 150 updateCallState(lastCallInfo); 151 152 } else if (m.what == MainActivity.MSG_TYPE.CALL_MEDIA_STATE) { 153 154 if (MainActivity.currentCall.vidWin != null) { 155 /* If there's incoming video, display it. */ 156 setupVideoSurface(); 157 } 158 159 } else { 160 161 /* Message not handled */ 162 return false; 163 164 } 165 166 return true; 167 } 168 169 private void updateCallState(CallInfo ci) { 170 TextView tvPeer = (TextView) findViewById(R.id.textViewPeer); 171 TextView tvState = (TextView) findViewById(R.id.textViewCallState); 172 Button buttonHangup = (Button) findViewById(R.id.buttonHangup); 173 Button buttonAccept = (Button) findViewById(R.id.buttonAccept); 174 String call_state = ""; 175 176 if (ci.getRole() == pjsip_role_e.PJSIP_ROLE_UAC) { 177 buttonAccept.setVisibility(View.GONE); 178 } 179 180 if (ci.getState().swigValue() < 181 pjsip_inv_state.PJSIP_INV_STATE_CONFIRMED.swigValue()) 182 { 183 if (ci.getRole() == pjsip_role_e.PJSIP_ROLE_UAS) { 184 call_state = "Incoming call.."; 185 /* Default button texts are already 'Accept' & 'Reject' */ 186 } else { 187 buttonHangup.setText("Cancel"); 188 call_state = ci.getStateText(); 189 } 190 } 191 else if (ci.getState().swigValue() >= 192 pjsip_inv_state.PJSIP_INV_STATE_CONFIRMED.swigValue()) 193 { 194 buttonAccept.setVisibility(View.GONE); 195 call_state = ci.getStateText(); 196 if (ci.getState() == pjsip_inv_state.PJSIP_INV_STATE_CONFIRMED) { 197 buttonHangup.setText("Hangup"); 198 } else if (ci.getState() == 199 pjsip_inv_state.PJSIP_INV_STATE_DISCONNECTED) 200 { 201 buttonHangup.setText("OK"); 202 call_state = "Call disconnected: " + ci.getLastReason(); 203 } 204 } 205 206 tvPeer.setText(ci.getRemoteUri()); 207 tvState.setText(call_state); 208 } 196 209 } -
pjproject/trunk/pjsip-apps/src/swig/java/android/src/org/pjsip/pjsua2/app/MainActivity.java
r4997 r5017 44 44 import org.pjsip.pjsua2.*; 45 45 46 public class MainActivity extends Activity implements Handler.Callback, MyAppObserver { 47 public static MyApp app = null; 48 public static MyCall currentCall = null; 49 public static MyAccount account = null; 50 public static AccountConfig accCfg = null; 51 52 private ListView buddyListView; 53 private SimpleAdapter buddyListAdapter; 54 private int buddyListSelectedIdx = -1; 46 public class MainActivity extends Activity 47 implements Handler.Callback, MyAppObserver 48 { 49 public static MyApp app = null; 50 public static MyCall currentCall = null; 51 public static MyAccount account = null; 52 public static AccountConfig accCfg = null; 53 54 private ListView buddyListView; 55 private SimpleAdapter buddyListAdapter; 56 private int buddyListSelectedIdx = -1; 55 57 ArrayList<Map<String, String>> buddyList; 56 58 private String lastRegStatus = ""; 57 59 58 private final Handler handler = new Handler(this); 59 public class MSG_TYPE { 60 public final static int INCOMING_CALL = 1; 61 public final static int CALL_STATE = 2; 62 public final static int REG_STATE = 3; 63 public final static int BUDDY_STATE = 4; 64 public final static int CALL_MEDIA_STATE = 5; 65 } 66 67 private HashMap<String, String> putData(String uri, String status) { 68 HashMap<String, String> item = new HashMap<String, String>(); 69 item.put("uri", uri); 70 item.put("status", status); 71 return item; 72 } 73 74 private void showCallActivity() { 75 Intent intent = new Intent(this, CallActivity.class); 76 intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); 77 startActivity(intent); 78 } 79 80 @Override 81 protected void onCreate(Bundle savedInstanceState) { 82 super.onCreate(savedInstanceState); 83 setContentView(R.layout.activity_main); 84 85 if (app == null) { 86 app = new MyApp(); 87 /* Wait for GDB to init */ 88 if ((getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) { 89 try { 90 Thread.sleep(5000); 91 } catch (InterruptedException e) {} 60 private final Handler handler = new Handler(this); 61 public class MSG_TYPE 62 { 63 public final static int INCOMING_CALL = 1; 64 public final static int CALL_STATE = 2; 65 public final static int REG_STATE = 3; 66 public final static int BUDDY_STATE = 4; 67 public final static int CALL_MEDIA_STATE = 5; 68 } 69 70 private HashMap<String, String> putData(String uri, String status) 71 { 72 HashMap<String, String> item = new HashMap<String, String>(); 73 item.put("uri", uri); 74 item.put("status", status); 75 return item; 76 } 77 78 private void showCallActivity() 79 { 80 Intent intent = new Intent(this, CallActivity.class); 81 intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); 82 startActivity(intent); 83 } 84 85 @Override 86 protected void onCreate(Bundle savedInstanceState) 87 { 88 super.onCreate(savedInstanceState); 89 setContentView(R.layout.activity_main); 90 91 if (app == null) { 92 app = new MyApp(); 93 // Wait for GDB to init, for native debugging only 94 if (false && 95 (getApplicationInfo().flags & 96 ApplicationInfo.FLAG_DEBUGGABLE) != 0) 97 { 98 try { 99 Thread.sleep(5000); 100 } catch (InterruptedException e) {} 101 } 102 103 app.init(this, getFilesDir().getAbsolutePath()); 104 } 105 106 if (app.accList.size() == 0) { 107 accCfg = new AccountConfig(); 108 accCfg.setIdUri("sip:localhost"); 109 accCfg.getNatConfig().setIceEnabled(true); 110 account = app.addAcc(accCfg); 111 } else { 112 account = app.accList.get(0); 113 accCfg = account.cfg; 114 } 115 116 buddyList = new ArrayList<Map<String, String>>(); 117 for (int i = 0; i < account.buddyList.size(); i++) { 118 buddyList.add(putData(account.buddyList.get(i).cfg.getUri(), 119 account.buddyList.get(i).getStatusText())); 120 } 121 122 String[] from = { "uri", "status" }; 123 int[] to = { android.R.id.text1, android.R.id.text2 }; 124 buddyListAdapter = new SimpleAdapter( 125 this, buddyList, 126 android.R.layout.simple_list_item_2, 127 from, to); 128 129 buddyListView = (ListView) findViewById(R.id.listViewBuddy);; 130 buddyListView.setAdapter(buddyListAdapter); 131 buddyListView.setOnItemClickListener( 132 new AdapterView.OnItemClickListener() 133 { 134 @Override 135 public void onItemClick(AdapterView<?> parent, 136 final View view, 137 int position, long id) 138 { 139 view.setSelected(true); 140 buddyListSelectedIdx = position; 141 } 142 } 143 ); 144 145 } 146 147 @Override 148 public boolean onCreateOptionsMenu(Menu menu) 149 { 150 // Inflate the menu; this adds items to the action bar 151 // if it is present. 152 getMenuInflater().inflate(R.menu.main, menu); 153 return true; 154 } 155 156 @Override 157 public boolean onOptionsItemSelected(MenuItem item) 158 { 159 switch (item.getItemId()) { 160 case R.id.action_acc_config: 161 dlgAccountSetting(); 162 break; 163 164 case R.id.action_quit: 165 Message m = Message.obtain(handler, 0); 166 m.sendToTarget(); 167 break; 168 169 default: 170 break; 171 } 172 173 return true; 174 } 175 176 @Override 177 public boolean handleMessage(Message m) 178 { 179 if (m.what == 0) { 180 181 app.deinit(); 182 finish(); 183 Runtime.getRuntime().gc(); 184 android.os.Process.killProcess(android.os.Process.myPid()); 185 186 } else if (m.what == MSG_TYPE.CALL_STATE) { 187 188 CallInfo ci = (CallInfo) m.obj; 189 190 /* Forward the message to CallActivity */ 191 if (CallActivity.handler_ != null) { 192 Message m2 = Message.obtain(CallActivity.handler_, 193 MSG_TYPE.CALL_STATE, ci); 194 m2.sendToTarget(); 195 } 196 197 } else if (m.what == MSG_TYPE.CALL_MEDIA_STATE) { 198 199 /* Forward the message to CallActivity */ 200 if (CallActivity.handler_ != null) { 201 Message m2 = Message.obtain(CallActivity.handler_, 202 MSG_TYPE.CALL_MEDIA_STATE, 203 null); 204 m2.sendToTarget(); 205 } 206 207 } else if (m.what == MSG_TYPE.BUDDY_STATE) { 208 209 MyBuddy buddy = (MyBuddy) m.obj; 210 int idx = account.buddyList.indexOf(buddy); 211 212 /* Update buddy status text, if buddy is valid and 213 * the buddy lists in account and UI are sync-ed. 214 */ 215 if (idx >= 0 && account.buddyList.size() == buddyList.size()) 216 { 217 buddyList.get(idx).put("status", buddy.getStatusText()); 218 buddyListAdapter.notifyDataSetChanged(); 219 // TODO: selection color/mark is gone after this, 220 // dont know how to return it back. 221 //buddyListView.setSelection(buddyListSelectedIdx); 222 //buddyListView.performItemClick(buddyListView, 223 // buddyListSelectedIdx, 224 // buddyListView. 225 // getItemIdAtPosition(buddyListSelectedIdx)); 226 227 /* Return back Call activity */ 228 notifyCallState(currentCall); 229 } 230 231 } else if (m.what == MSG_TYPE.REG_STATE) { 232 233 String msg_str = (String) m.obj; 234 lastRegStatus = msg_str; 235 236 } else if (m.what == MSG_TYPE.INCOMING_CALL) { 237 238 /* Incoming call */ 239 final MyCall call = (MyCall) m.obj; 240 CallOpParam prm = new CallOpParam(); 241 242 /* Only one call at anytime */ 243 if (currentCall != null) { 244 /* 245 prm.setStatusCode(pjsip_status_code.PJSIP_SC_BUSY_HERE); 246 try { 247 call.hangup(prm); 248 } catch (Exception e) {} 249 */ 250 // TODO: set status code 251 call.delete(); 252 return true; 253 } 254 255 /* Answer with ringing */ 256 prm.setStatusCode(pjsip_status_code.PJSIP_SC_RINGING); 257 try { 258 call.answer(prm); 259 } catch (Exception e) {} 260 261 currentCall = call; 262 showCallActivity(); 263 264 } else { 265 266 /* Message not handled */ 267 return false; 268 269 } 270 271 return true; 272 } 273 274 275 private void dlgAccountSetting() 276 { 277 LayoutInflater li = LayoutInflater.from(this); 278 View view = li.inflate(R.layout.dlg_account_config, null); 279 280 if (lastRegStatus.length()!=0) { 281 TextView tvInfo = (TextView)view.findViewById(R.id.textViewInfo); 282 tvInfo.setText("Last status: " + lastRegStatus); 283 } 284 285 AlertDialog.Builder adb = new AlertDialog.Builder(this); 286 adb.setView(view); 287 adb.setTitle("Account Settings"); 288 289 final EditText etId = (EditText)view.findViewById(R.id.editTextId); 290 final EditText etReg = (EditText)view.findViewById(R.id.editTextRegistrar); 291 final EditText etProxy = (EditText)view.findViewById(R.id.editTextProxy); 292 final EditText etUser = (EditText)view.findViewById(R.id.editTextUsername); 293 final EditText etPass = (EditText)view.findViewById(R.id.editTextPassword); 294 295 etId. setText(accCfg.getIdUri()); 296 etReg. setText(accCfg.getRegConfig().getRegistrarUri()); 297 StringVector proxies = accCfg.getSipConfig().getProxies(); 298 if (proxies.size() > 0) 299 etProxy.setText(proxies.get(0)); 300 else 301 etProxy.setText(""); 302 AuthCredInfoVector creds = accCfg.getSipConfig().getAuthCreds(); 303 if (creds.size() > 0) { 304 etUser. setText(creds.get(0).getUsername()); 305 etPass. setText(creds.get(0).getData()); 306 } else { 307 etUser. setText(""); 308 etPass. setText(""); 309 } 310 311 adb.setCancelable(false); 312 adb.setPositiveButton("OK", 313 new DialogInterface.OnClickListener() 314 { 315 public void onClick(DialogInterface dialog,int id) 316 { 317 String acc_id = etId.getText().toString(); 318 String registrar = etReg.getText().toString(); 319 String proxy = etProxy.getText().toString(); 320 String username = etUser.getText().toString(); 321 String password = etPass.getText().toString(); 322 323 accCfg.setIdUri(acc_id); 324 accCfg.getRegConfig().setRegistrarUri(registrar); 325 AuthCredInfoVector creds = accCfg.getSipConfig(). 326 getAuthCreds(); 327 creds.clear(); 328 if (username.length() != 0) { 329 creds.add(new AuthCredInfo("Digest", "*", username, 0, 330 password)); 331 } 332 StringVector proxies = accCfg.getSipConfig().getProxies(); 333 proxies.clear(); 334 if (proxy.length() != 0) { 335 proxies.add(proxy); 336 } 337 338 /* Enable ICE */ 339 accCfg.getNatConfig().setIceEnabled(true); 340 341 /* Finally */ 342 lastRegStatus = ""; 343 try { 344 account.modify(accCfg); 345 } catch (Exception e) {} 346 } 347 } 348 ); 349 adb.setNegativeButton("Cancel", 350 new DialogInterface.OnClickListener() 351 { 352 public void onClick(DialogInterface dialog,int id) 353 { 354 dialog.cancel(); 355 } 356 } 357 ); 358 359 AlertDialog ad = adb.create(); 360 ad.show(); 361 } 362 363 364 public void makeCall(View view) 365 { 366 if (buddyListSelectedIdx == -1) 367 return; 368 369 /* Only one call at anytime */ 370 if (currentCall != null) { 371 return; 372 } 373 374 HashMap<String, String> item = (HashMap<String, String>) buddyListView. 375 getItemAtPosition(buddyListSelectedIdx); 376 String buddy_uri = item.get("uri"); 377 378 MyCall call = new MyCall(account, -1); 379 CallOpParam prm = new CallOpParam(true); 380 381 try { 382 call.makeCall(buddy_uri, prm); 383 } catch (Exception e) { 384 call.delete(); 385 return; 386 } 387 388 currentCall = call; 389 showCallActivity(); 390 } 391 392 private void dlgAddEditBuddy(BuddyConfig initial) 393 { 394 final BuddyConfig cfg = new BuddyConfig(); 395 final BuddyConfig old_cfg = initial; 396 final boolean is_add = initial == null; 397 398 LayoutInflater li = LayoutInflater.from(this); 399 View view = li.inflate(R.layout.dlg_add_buddy, null); 400 401 AlertDialog.Builder adb = new AlertDialog.Builder(this); 402 adb.setView(view); 403 404 final EditText etUri = (EditText)view.findViewById(R.id.editTextUri); 405 final CheckBox cbSubs = (CheckBox)view.findViewById(R.id.checkBoxSubscribe); 406 407 if (is_add) { 408 adb.setTitle("Add Buddy"); 409 } else { 410 adb.setTitle("Edit Buddy"); 411 etUri. setText(initial.getUri()); 412 cbSubs.setChecked(initial.getSubscribe()); 413 } 414 415 adb.setCancelable(false); 416 adb.setPositiveButton("OK", 417 new DialogInterface.OnClickListener() 418 { 419 public void onClick(DialogInterface dialog,int id) 420 { 421 cfg.setUri(etUri.getText().toString()); 422 cfg.setSubscribe(cbSubs.isChecked()); 423 424 if (is_add) { 425 account.addBuddy(cfg); 426 buddyList.add(putData(cfg.getUri(), "")); 427 buddyListAdapter.notifyDataSetChanged(); 428 buddyListSelectedIdx = -1; 429 } else { 430 if (!old_cfg.getUri().equals(cfg.getUri())) { 431 account.delBuddy(buddyListSelectedIdx); 432 account.addBuddy(cfg); 433 buddyList.remove(buddyListSelectedIdx); 434 buddyList.add(putData(cfg.getUri(), "")); 435 buddyListAdapter.notifyDataSetChanged(); 436 buddyListSelectedIdx = -1; 437 } else if (old_cfg.getSubscribe() != 438 cfg.getSubscribe()) 439 { 440 MyBuddy bud = account.buddyList.get( 441 buddyListSelectedIdx); 442 try { 443 bud.subscribePresence(cfg.getSubscribe()); 444 } catch (Exception e) {} 92 445 } 93 94 app.init(this, getFilesDir().getAbsolutePath()); 446 } 95 447 } 96 97 if (app.accList.size() == 0) { 98 accCfg = new AccountConfig(); 99 accCfg.setIdUri("sip:localhost"); 100 accCfg.getNatConfig().setIceEnabled(true); 101 account = app.addAcc(accCfg); 102 } else { 103 account = app.accList.get(0); 104 accCfg = account.cfg; 105 } 106 107 buddyList = new ArrayList<Map<String, String>>(); 108 for (int i = 0; i < account.buddyList.size(); i++) { 109 buddyList.add(putData(account.buddyList.get(i).cfg.getUri(), 110 account.buddyList.get(i).getStatusText())); 448 } 449 ); 450 adb.setNegativeButton("Cancel", 451 new DialogInterface.OnClickListener() 452 { 453 public void onClick(DialogInterface dialog,int id) { 454 dialog.cancel(); 111 455 } 112 113 String[] from = { "uri", "status" }; 114 int[] to = { android.R.id.text1, android.R.id.text2 }; 115 buddyListAdapter = new SimpleAdapter(this, buddyList, android.R.layout.simple_list_item_2, from, to); 116 117 buddyListView = (ListView) findViewById(R.id.listViewBuddy);; 118 buddyListView.setAdapter(buddyListAdapter); 119 buddyListView.setOnItemClickListener(new AdapterView.OnItemClickListener() { 120 @Override 121 public void onItemClick(AdapterView<?> parent, final View view, 122 int position, long id) 123 { 124 view.setSelected(true); 125 buddyListSelectedIdx = position; 126 } 127 }); 128 129 } 130 131 @Override 132 public boolean onCreateOptionsMenu(Menu menu) { 133 // Inflate the menu; this adds items to the action bar if it is present. 134 getMenuInflater().inflate(R.menu.main, menu); 135 return true; 136 } 137 138 @Override 139 public boolean onOptionsItemSelected(MenuItem item) { 140 switch (item.getItemId()) { 141 case R.id.action_acc_config: 142 dlgAccountSetting(); 456 } 457 ); 458 459 AlertDialog ad = adb.create(); 460 ad.show(); 461 } 462 463 public void addBuddy(View view) 464 { 465 dlgAddEditBuddy(null); 466 } 467 468 public void editBuddy(View view) 469 { 470 if (buddyListSelectedIdx == -1) 471 return; 472 473 BuddyConfig old_cfg = account.buddyList.get(buddyListSelectedIdx).cfg; 474 dlgAddEditBuddy(old_cfg); 475 } 476 477 public void delBuddy(View view) { 478 if (buddyListSelectedIdx == -1) 479 return; 480 481 final HashMap<String, String> item = (HashMap<String, String>) 482 buddyListView.getItemAtPosition(buddyListSelectedIdx); 483 String buddy_uri = item.get("uri"); 484 485 DialogInterface.OnClickListener ocl = 486 new DialogInterface.OnClickListener() 487 { 488 @Override 489 public void onClick(DialogInterface dialog, int which) 490 { 491 switch (which) { 492 case DialogInterface.BUTTON_POSITIVE: 493 account.delBuddy(buddyListSelectedIdx); 494 buddyList.remove(item); 495 buddyListAdapter.notifyDataSetChanged(); 496 buddyListSelectedIdx = -1; 143 497 break; 144 145 case R.id.action_quit: 146 Message m = Message.obtain(handler, 0); 147 m.sendToTarget(); 148 break; 149 150 default: 498 case DialogInterface.BUTTON_NEGATIVE: 151 499 break; 152 500 } 153 154 return true; 155 } 156 157 @Override 158 public boolean handleMessage(Message m) { 159 160 if (m.what == 0) { 161 162 app.deinit(); 163 finish(); 164 Runtime.getRuntime().gc(); 165 android.os.Process.killProcess(android.os.Process.myPid()); 166 167 } else if (m.what == MSG_TYPE.CALL_STATE) { 168 169 CallInfo ci = (CallInfo) m.obj; 170 171 /* Forward the message to CallActivity */ 172 if (CallActivity.handler_ != null) { 173 Message m2 = Message.obtain(CallActivity.handler_, MSG_TYPE.CALL_STATE, ci); 174 m2.sendToTarget(); 175 } 176 177 } else if (m.what == MSG_TYPE.CALL_MEDIA_STATE) { 178 179 /* Forward the message to CallActivity */ 180 if (CallActivity.handler_ != null) { 181 Message m2 = Message.obtain(CallActivity.handler_, MSG_TYPE.CALL_MEDIA_STATE, null); 182 m2.sendToTarget(); 183 } 184 185 } else if (m.what == MSG_TYPE.BUDDY_STATE) { 186 187 MyBuddy buddy = (MyBuddy) m.obj; 188 int idx = account.buddyList.indexOf(buddy); 189 190 /* Update buddy status text, if buddy is valid and 191 * the buddy lists in account and UI are sync-ed. 192 */ 193 if (idx >= 0 && account.buddyList.size() == buddyList.size()) { 194 buddyList.get(idx).put("status", buddy.getStatusText()); 195 buddyListAdapter.notifyDataSetChanged(); 196 // TODO: selection color/mark is gone after this, 197 // dont know how to return it back. 198 //buddyListView.setSelection(buddyListSelectedIdx); 199 //buddyListView.performItemClick(buddyListView, buddyListSelectedIdx, 200 // buddyListView.getItemIdAtPosition(buddyListSelectedIdx)); 201 202 /* Return back Call activity */ 203 notifyCallState(currentCall); 204 } 205 206 } else if (m.what == MSG_TYPE.REG_STATE) { 207 208 String msg_str = (String) m.obj; 209 lastRegStatus = msg_str; 210 211 } else if (m.what == MSG_TYPE.INCOMING_CALL) { 212 213 /* Incoming call */ 214 final MyCall call = (MyCall) m.obj; 215 CallOpParam prm = new CallOpParam(); 216 217 /* Only one call at anytime */ 218 if (currentCall != null) { 219 /* 220 prm.setStatusCode(pjsip_status_code.PJSIP_SC_BUSY_HERE); 221 try { 222 call.hangup(prm); 223 } catch (Exception e) {} 224 */ 225 // TODO: set status code 226 call.delete(); 227 return true; 228 } 229 230 /* Answer with ringing */ 231 prm.setStatusCode(pjsip_status_code.PJSIP_SC_RINGING); 232 try { 233 call.answer(prm); 234 } catch (Exception e) {} 235 236 currentCall = call; 237 showCallActivity(); 238 239 } else { 240 241 /* Message not handled */ 242 return false; 243 244 } 245 246 return true; 247 } 248 249 250 private void dlgAccountSetting() { 251 252 LayoutInflater li = LayoutInflater.from(this); 253 View view = li.inflate(R.layout.dlg_account_config, null); 254 255 if (lastRegStatus.length()!=0) { 256 TextView tvInfo = (TextView)view.findViewById(R.id.textViewInfo); 257 tvInfo.setText("Last status: " + lastRegStatus); 258 } 259 260 AlertDialog.Builder adb = new AlertDialog.Builder(this); 261 adb.setView(view); 262 adb.setTitle("Account Settings"); 263 264 final EditText etId = (EditText)view.findViewById(R.id.editTextId); 265 final EditText etReg = (EditText)view.findViewById(R.id.editTextRegistrar); 266 final EditText etProxy = (EditText)view.findViewById(R.id.editTextProxy); 267 final EditText etUser = (EditText)view.findViewById(R.id.editTextUsername); 268 final EditText etPass = (EditText)view.findViewById(R.id.editTextPassword); 269 270 etId. setText(accCfg.getIdUri()); 271 etReg. setText(accCfg.getRegConfig().getRegistrarUri()); 272 StringVector proxies = accCfg.getSipConfig().getProxies(); 273 if (proxies.size() > 0) 274 etProxy.setText(proxies.get(0)); 275 else 276 etProxy.setText(""); 277 AuthCredInfoVector creds = accCfg.getSipConfig().getAuthCreds(); 278 if (creds.size() > 0) { 279 etUser. setText(creds.get(0).getUsername()); 280 etPass. setText(creds.get(0).getData()); 281 } else { 282 etUser. setText(""); 283 etPass. setText(""); 284 } 285 286 adb.setCancelable(false); 287 adb.setPositiveButton("OK", 288 new DialogInterface.OnClickListener() { 289 public void onClick(DialogInterface dialog,int id) { 290 String acc_id = etId.getText().toString(); 291 String registrar = etReg.getText().toString(); 292 String proxy = etProxy.getText().toString(); 293 String username = etUser.getText().toString(); 294 String password = etPass.getText().toString(); 295 296 accCfg.setIdUri(acc_id); 297 accCfg.getRegConfig().setRegistrarUri(registrar); 298 AuthCredInfoVector creds = accCfg.getSipConfig().getAuthCreds(); 299 creds.clear(); 300 if (username.length() != 0) { 301 creds.add(new AuthCredInfo("Digest", "*", username, 0, password)); 302 } 303 StringVector proxies = accCfg.getSipConfig().getProxies(); 304 proxies.clear(); 305 if (proxy.length() != 0) { 306 proxies.add(proxy); 307 } 308 309 /* Enable ICE */ 310 accCfg.getNatConfig().setIceEnabled(true); 311 312 /* Finally */ 313 lastRegStatus = ""; 314 try { 315 account.modify(accCfg); 316 } catch (Exception e) {} 317 } 318 }); 319 adb.setNegativeButton("Cancel", 320 new DialogInterface.OnClickListener() { 321 public void onClick(DialogInterface dialog,int id) { 322 dialog.cancel(); 323 } 324 }); 325 326 AlertDialog ad = adb.create(); 327 ad.show(); 328 } 329 330 331 public void makeCall(View view) { 332 if (buddyListSelectedIdx == -1) 333 return; 334 335 /* Only one call at anytime */ 336 if (currentCall != null) { 337 return; 338 } 339 340 HashMap<String, String> item = (HashMap<String, String>) buddyListView.getItemAtPosition(buddyListSelectedIdx); 341 String buddy_uri = item.get("uri"); 342 343 MyCall call = new MyCall(account, -1); 344 CallOpParam prm = new CallOpParam(true); 345 346 try { 347 call.makeCall(buddy_uri, prm); 348 } catch (Exception e) { 349 call.delete(); 350 return; 351 } 352 353 currentCall = call; 354 showCallActivity(); 355 } 356 357 private void dlgAddEditBuddy(BuddyConfig initial) { 358 final BuddyConfig cfg = new BuddyConfig(); 359 final BuddyConfig old_cfg = initial; 360 final boolean is_add = initial == null; 361 362 LayoutInflater li = LayoutInflater.from(this); 363 View view = li.inflate(R.layout.dlg_add_buddy, null); 364 365 AlertDialog.Builder adb = new AlertDialog.Builder(this); 366 adb.setView(view); 367 368 final EditText etUri = (EditText)view.findViewById(R.id.editTextUri); 369 final CheckBox cbSubs = (CheckBox)view.findViewById(R.id.checkBoxSubscribe); 370 371 if (is_add) { 372 adb.setTitle("Add Buddy"); 373 } else { 374 adb.setTitle("Edit Buddy"); 375 etUri. setText(initial.getUri()); 376 cbSubs.setChecked(initial.getSubscribe()); 377 } 378 379 adb.setCancelable(false); 380 adb.setPositiveButton("OK", 381 new DialogInterface.OnClickListener() { 382 public void onClick(DialogInterface dialog,int id) { 383 cfg.setUri(etUri.getText().toString()); 384 cfg.setSubscribe(cbSubs.isChecked()); 385 386 if (is_add) { 387 account.addBuddy(cfg); 388 buddyList.add(putData(cfg.getUri(), "")); 389 buddyListAdapter.notifyDataSetChanged(); 390 buddyListSelectedIdx = -1; 391 } else { 392 if (!old_cfg.getUri().equals(cfg.getUri())) { 393 account.delBuddy(buddyListSelectedIdx); 394 account.addBuddy(cfg); 395 buddyList.remove(buddyListSelectedIdx); 396 buddyList.add(putData(cfg.getUri(), "")); 397 buddyListAdapter.notifyDataSetChanged(); 398 buddyListSelectedIdx = -1; 399 } else if (old_cfg.getSubscribe() != cfg.getSubscribe()) { 400 MyBuddy bud = account.buddyList.get(buddyListSelectedIdx); 401 try { 402 bud.subscribePresence(cfg.getSubscribe()); 403 } catch (Exception e) {} 404 } 405 } 406 } 407 }); 408 adb.setNegativeButton("Cancel", 409 new DialogInterface.OnClickListener() { 410 public void onClick(DialogInterface dialog,int id) { 411 dialog.cancel(); 412 } 413 }); 414 415 AlertDialog ad = adb.create(); 416 ad.show(); 417 } 418 419 public void addBuddy(View view) { 420 dlgAddEditBuddy(null); 421 } 422 423 public void editBuddy(View view) { 424 if (buddyListSelectedIdx == -1) 425 return; 426 427 BuddyConfig old_cfg = account.buddyList.get(buddyListSelectedIdx).cfg; 428 dlgAddEditBuddy(old_cfg); 429 } 430 431 public void delBuddy(View view) { 432 if (buddyListSelectedIdx == -1) 433 return; 434 435 final HashMap<String, String> item = (HashMap<String, String>) buddyListView.getItemAtPosition(buddyListSelectedIdx); 436 String buddy_uri = item.get("uri"); 437 438 DialogInterface.OnClickListener ocl = new DialogInterface.OnClickListener() { 439 @Override 440 public void onClick(DialogInterface dialog, int which) { 441 switch (which) { 442 case DialogInterface.BUTTON_POSITIVE: 443 account.delBuddy(buddyListSelectedIdx); 444 buddyList.remove(item); 445 buddyListAdapter.notifyDataSetChanged(); 446 buddyListSelectedIdx = -1; 447 break; 448 case DialogInterface.BUTTON_NEGATIVE: 449 break; 450 } 451 } 452 }; 453 454 AlertDialog.Builder adb = new AlertDialog.Builder(this); 455 adb.setTitle(buddy_uri); 456 adb.setMessage("\nDelete this buddy?\n"); 457 adb.setPositiveButton("Yes", ocl); 458 adb.setNegativeButton("No", ocl); 459 adb.show(); 460 } 461 462 463 /* 464 * === MyAppObserver === 465 * 466 * As we cannot do UI from worker thread, the callbacks mostly just send 467 * a message to UI/main thread. 468 */ 469 470 public void notifyIncomingCall(MyCall call) { 471 Message m = Message.obtain(handler, MSG_TYPE.INCOMING_CALL, call); 472 m.sendToTarget(); 473 } 474 475 public void notifyRegState(pjsip_status_code code, String reason, int expiration) { 476 String msg_str = ""; 477 if (expiration == 0) 478 msg_str += "Unregistration"; 479 else 480 msg_str += "Registration"; 481 482 if (code.swigValue()/100 == 2) 483 msg_str += " successful"; 484 else 485 msg_str += " failed: " + reason; 486 487 Message m = Message.obtain(handler, MSG_TYPE.REG_STATE, msg_str); 488 m.sendToTarget(); 489 } 490 491 public void notifyCallState(MyCall call) { 492 if (currentCall == null || call.getId() != currentCall.getId()) 493 return; 494 495 CallInfo ci; 496 try { 497 ci = call.getInfo(); 498 } catch (Exception e) { 499 ci = null; 500 } 501 Message m = Message.obtain(handler, MSG_TYPE.CALL_STATE, ci); 502 m.sendToTarget(); 503 504 if (ci != null && 505 ci.getState() == pjsip_inv_state.PJSIP_INV_STATE_DISCONNECTED) 506 { 507 currentCall = null; 508 } 509 } 510 511 public void notifyCallMediaState(MyCall call) { 512 Message m = Message.obtain(handler, MSG_TYPE.CALL_MEDIA_STATE, null); 513 m.sendToTarget(); 514 } 515 516 public void notifyBuddyState(MyBuddy buddy) { 517 Message m = Message.obtain(handler, MSG_TYPE.BUDDY_STATE, buddy); 518 m.sendToTarget(); 519 } 520 521 /* === end of MyAppObserver ==== */ 501 } 502 }; 503 504 AlertDialog.Builder adb = new AlertDialog.Builder(this); 505 adb.setTitle(buddy_uri); 506 adb.setMessage("\nDelete this buddy?\n"); 507 adb.setPositiveButton("Yes", ocl); 508 adb.setNegativeButton("No", ocl); 509 adb.show(); 510 } 511 512 513 /* 514 * === MyAppObserver === 515 * 516 * As we cannot do UI from worker thread, the callbacks mostly just send 517 * a message to UI/main thread. 518 */ 519 520 public void notifyIncomingCall(MyCall call) 521 { 522 Message m = Message.obtain(handler, MSG_TYPE.INCOMING_CALL, call); 523 m.sendToTarget(); 524 } 525 526 public void notifyRegState(pjsip_status_code code, String reason, 527 int expiration) 528 { 529 String msg_str = ""; 530 if (expiration == 0) 531 msg_str += "Unregistration"; 532 else 533 msg_str += "Registration"; 534 535 if (code.swigValue()/100 == 2) 536 msg_str += " successful"; 537 else 538 msg_str += " failed: " + reason; 539 540 Message m = Message.obtain(handler, MSG_TYPE.REG_STATE, msg_str); 541 m.sendToTarget(); 542 } 543 544 public void notifyCallState(MyCall call) 545 { 546 if (currentCall == null || call.getId() != currentCall.getId()) 547 return; 548 549 CallInfo ci; 550 try { 551 ci = call.getInfo(); 552 } catch (Exception e) { 553 ci = null; 554 } 555 Message m = Message.obtain(handler, MSG_TYPE.CALL_STATE, ci); 556 m.sendToTarget(); 557 558 if (ci != null && 559 ci.getState() == pjsip_inv_state.PJSIP_INV_STATE_DISCONNECTED) 560 { 561 currentCall = null; 562 } 563 } 564 565 public void notifyCallMediaState(MyCall call) 566 { 567 Message m = Message.obtain(handler, MSG_TYPE.CALL_MEDIA_STATE, null); 568 m.sendToTarget(); 569 } 570 571 public void notifyBuddyState(MyBuddy buddy) 572 { 573 Message m = Message.obtain(handler, MSG_TYPE.BUDDY_STATE, buddy); 574 m.sendToTarget(); 575 } 576 577 /* === end of MyAppObserver ==== */ 522 578 523 579 } -
pjproject/trunk/pjsip-apps/src/swig/java/android/src/org/pjsip/pjsua2/app/MyApp.java
r5016 r5017 26 26 27 27 /* Interface to separate UI & engine a bit better */ 28 interface MyAppObserver { 29 abstract void notifyRegState(pjsip_status_code code, String reason, int expiration); 30 abstract void notifyIncomingCall(MyCall call); 31 abstract void notifyCallState(MyCall call); 32 abstract void notifyCallMediaState(MyCall call); 33 abstract void notifyBuddyState(MyBuddy buddy); 34 } 35 36 37 class MyLogWriter extends LogWriter { 38 @Override 39 public void write(LogEntry entry) { 40 System.out.println(entry.getMsg()); 41 } 42 } 43 44 45 class MyCall extends Call { 46 public VideoWindow vidWin; 47 48 MyCall(MyAccount acc, int call_id) { 49 super(acc, call_id); 50 vidWin = null; 51 } 52 53 @Override 54 public void onCallState(OnCallStateParam prm) { 55 MyApp.observer.notifyCallState(this); 28 interface MyAppObserver 29 { 30 abstract void notifyRegState(pjsip_status_code code, String reason, 31 int expiration); 32 abstract void notifyIncomingCall(MyCall call); 33 abstract void notifyCallState(MyCall call); 34 abstract void notifyCallMediaState(MyCall call); 35 abstract void notifyBuddyState(MyBuddy buddy); 36 } 37 38 39 class MyLogWriter extends LogWriter 40 { 41 @Override 42 public void write(LogEntry entry) 43 { 44 System.out.println(entry.getMsg()); 45 } 46 } 47 48 49 class MyCall extends Call 50 { 51 public VideoWindow vidWin; 52 53 MyCall(MyAccount acc, int call_id) 54 { 55 super(acc, call_id); 56 vidWin = null; 57 } 58 59 @Override 60 public void onCallState(OnCallStateParam prm) 61 { 62 MyApp.observer.notifyCallState(this); 63 try { 64 CallInfo ci = getInfo(); 65 if (ci.getState() == 66 pjsip_inv_state.PJSIP_INV_STATE_DISCONNECTED) 67 { 68 this.delete(); 69 } 70 } catch (Exception e) { 71 return; 72 } 73 } 74 75 @Override 76 public void onCallMediaState(OnCallMediaStateParam prm) 77 { 78 CallInfo ci; 79 try { 80 ci = getInfo(); 81 } catch (Exception e) { 82 return; 83 } 84 85 CallMediaInfoVector cmiv = ci.getMedia(); 86 87 for (int i = 0; i < cmiv.size(); i++) { 88 CallMediaInfo cmi = cmiv.get(i); 89 if (cmi.getType() == pjmedia_type.PJMEDIA_TYPE_AUDIO && 90 (cmi.getStatus() == 91 pjsua_call_media_status.PJSUA_CALL_MEDIA_ACTIVE || 92 cmi.getStatus() == 93 pjsua_call_media_status.PJSUA_CALL_MEDIA_REMOTE_HOLD)) 94 { 95 // unfortunately, on Java too, the returned Media cannot be 96 // downcasted to AudioMedia 97 Media m = getMedia(i); 98 AudioMedia am = AudioMedia.typecastFromMedia(m); 99 100 // connect ports 56 101 try { 57 CallInfo ci = getInfo();58 if (ci.getState() == pjsip_inv_state.PJSIP_INV_STATE_DISCONNECTED) {59 this.delete();60 }102 MyApp.ep.audDevManager().getCaptureDevMedia(). 103 startTransmit(am); 104 am.startTransmit(MyApp.ep.audDevManager(). 105 getPlaybackDevMedia()); 61 106 } catch (Exception e) { 62 return;107 continue; 63 108 } 64 } 65 66 @Override 67 public void onCallMediaState(OnCallMediaStateParam prm) { 68 CallInfo ci; 109 } else if (cmi.getType() == pjmedia_type.PJMEDIA_TYPE_VIDEO && 110 cmi.getStatus() == 111 pjsua_call_media_status.PJSUA_CALL_MEDIA_ACTIVE && 112 cmi.getVideoIncomingWindowId() != pjsua2.INVALID_ID) 113 { 114 vidWin = new VideoWindow(cmi.getVideoIncomingWindowId()); 115 } 116 } 117 118 MyApp.observer.notifyCallMediaState(this); 119 } 120 } 121 122 123 class MyAccount extends Account 124 { 125 public ArrayList<MyBuddy> buddyList = new ArrayList<MyBuddy>(); 126 public AccountConfig cfg; 127 128 MyAccount(AccountConfig config) 129 { 130 super(); 131 cfg = config; 132 } 133 134 public MyBuddy addBuddy(BuddyConfig bud_cfg) 135 { 136 /* Create Buddy */ 137 MyBuddy bud = new MyBuddy(bud_cfg); 138 try { 139 bud.create(this, bud_cfg); 140 } catch (Exception e) { 141 bud.delete(); 142 bud = null; 143 } 144 145 if (bud != null) { 146 buddyList.add(bud); 147 if (bud_cfg.getSubscribe()) 69 148 try { 70 ci = getInfo(); 71 } catch (Exception e) { 72 return; 149 bud.subscribePresence(true); 150 } catch (Exception e) {} 151 } 152 153 return bud; 154 } 155 156 public void delBuddy(MyBuddy buddy) 157 { 158 buddyList.remove(buddy); 159 buddy.delete(); 160 } 161 162 public void delBuddy(int index) 163 { 164 MyBuddy bud = buddyList.get(index); 165 buddyList.remove(index); 166 bud.delete(); 167 } 168 169 @Override 170 public void onRegState(OnRegStateParam prm) 171 { 172 MyApp.observer.notifyRegState(prm.getCode(), prm.getReason(), 173 prm.getExpiration()); 174 } 175 176 @Override 177 public void onIncomingCall(OnIncomingCallParam prm) 178 { 179 System.out.println("======== Incoming call ======== "); 180 MyCall call = new MyCall(this, prm.getCallId()); 181 MyApp.observer.notifyIncomingCall(call); 182 } 183 184 @Override 185 public void onInstantMessage(OnInstantMessageParam prm) 186 { 187 System.out.println("======== Incoming pager ======== "); 188 System.out.println("From : " + prm.getFromUri()); 189 System.out.println("To : " + prm.getToUri()); 190 System.out.println("Contact : " + prm.getContactUri()); 191 System.out.println("Mimetype : " + prm.getContentType()); 192 System.out.println("Body : " + prm.getMsgBody()); 193 } 194 } 195 196 197 class MyBuddy extends Buddy 198 { 199 public BuddyConfig cfg; 200 201 MyBuddy(BuddyConfig config) 202 { 203 super(); 204 cfg = config; 205 } 206 207 String getStatusText() 208 { 209 BuddyInfo bi; 210 211 try { 212 bi = getInfo(); 213 } catch (Exception e) { 214 return "?"; 215 } 216 217 String status = ""; 218 if (bi.getSubState() == pjsip_evsub_state.PJSIP_EVSUB_STATE_ACTIVE) { 219 if (bi.getPresStatus().getStatus() == 220 pjsua_buddy_status.PJSUA_BUDDY_STATUS_ONLINE) 221 { 222 status = bi.getPresStatus().getStatusText(); 223 if (status == null || status.length()==0) { 224 status = "Online"; 73 225 } 74 75 CallMediaInfoVector cmiv = ci.getMedia(); 76 77 for (int i = 0; i < cmiv.size(); i++) { 78 CallMediaInfo cmi = cmiv.get(i); 79 if (cmi.getType() == pjmedia_type.PJMEDIA_TYPE_AUDIO && 80 (cmi.getStatus() == pjsua_call_media_status.PJSUA_CALL_MEDIA_ACTIVE || 81 cmi.getStatus() == pjsua_call_media_status.PJSUA_CALL_MEDIA_REMOTE_HOLD)) 82 { 83 // unfortunately, on Java too, the returned Media cannot be downcasted to AudioMedia 84 Media m = getMedia(i); 85 AudioMedia am = AudioMedia.typecastFromMedia(m); 86 87 // connect ports 88 try { 89 MyApp.ep.audDevManager().getCaptureDevMedia().startTransmit(am); 90 am.startTransmit(MyApp.ep.audDevManager().getPlaybackDevMedia()); 91 } catch (Exception e) { 92 continue; 93 } 94 } else if (cmi.getType() == pjmedia_type.PJMEDIA_TYPE_VIDEO && 95 cmi.getStatus() == pjsua_call_media_status.PJSUA_CALL_MEDIA_ACTIVE && 96 cmi.getVideoIncomingWindowId() != pjsua2.INVALID_ID) 97 { 98 vidWin = new VideoWindow(cmi.getVideoIncomingWindowId()); 99 } 100 } 101 102 MyApp.observer.notifyCallMediaState(this); 103 } 104 } 105 106 107 class MyAccount extends Account { 108 public ArrayList<MyBuddy> buddyList = new ArrayList<MyBuddy>(); 109 public AccountConfig cfg; 110 111 MyAccount(AccountConfig config) { 112 super(); 113 cfg = config; 114 } 115 116 public MyBuddy addBuddy(BuddyConfig bud_cfg) 117 { 118 /* Create Buddy */ 119 MyBuddy bud = new MyBuddy(bud_cfg); 120 try { 121 bud.create(this, bud_cfg); 122 } catch (Exception e) { 123 bud.delete(); 124 bud = null; 125 } 126 127 if (bud != null) { 128 buddyList.add(bud); 129 if (bud_cfg.getSubscribe()) 130 try { 131 bud.subscribePresence(true); 132 } catch (Exception e) {} 133 } 134 135 return bud; 136 } 137 138 public void delBuddy(MyBuddy buddy) { 139 buddyList.remove(buddy); 140 buddy.delete(); 141 } 142 143 public void delBuddy(int index) { 144 MyBuddy bud = buddyList.get(index); 145 buddyList.remove(index); 146 bud.delete(); 147 } 148 149 @Override 150 public void onRegState(OnRegStateParam prm) { 151 MyApp.observer.notifyRegState(prm.getCode(), prm.getReason(), prm.getExpiration()); 152 } 153 154 @Override 155 public void onIncomingCall(OnIncomingCallParam prm) { 156 System.out.println("======== Incoming call ======== "); 157 MyCall call = new MyCall(this, prm.getCallId()); 158 MyApp.observer.notifyIncomingCall(call); 159 } 160 161 @Override 162 public void onInstantMessage(OnInstantMessageParam prm) { 163 System.out.println("======== Incoming pager ======== "); 164 System.out.println("From : " + prm.getFromUri()); 165 System.out.println("To : " + prm.getToUri()); 166 System.out.println("Contact : " + prm.getContactUri()); 167 System.out.println("Mimetype : " + prm.getContentType()); 168 System.out.println("Body : " + prm.getMsgBody()); 169 } 170 } 171 172 173 class MyBuddy extends Buddy { 174 public BuddyConfig cfg; 175 176 MyBuddy(BuddyConfig config) { 177 super(); 178 cfg = config; 179 } 180 181 String getStatusText() { 182 BuddyInfo bi; 183 184 try { 185 bi = getInfo(); 186 } catch (Exception e) { 187 return "?"; 188 } 189 190 String status = ""; 191 if (bi.getSubState() == pjsip_evsub_state.PJSIP_EVSUB_STATE_ACTIVE) { 192 if (bi.getPresStatus().getStatus() == pjsua_buddy_status.PJSUA_BUDDY_STATUS_ONLINE) { 193 status = bi.getPresStatus().getStatusText(); 194 if (status == null || status.length()==0) { 195 status = "Online"; 196 } 197 } else if (bi.getPresStatus().getStatus() == pjsua_buddy_status.PJSUA_BUDDY_STATUS_OFFLINE) { 198 status = "Offline"; 199 } else { 200 status = "Unknown"; 201 } 202 } 203 return status; 204 } 205 206 @Override 207 public void onBuddyState() { 208 MyApp.observer.notifyBuddyState(this); 209 } 210 211 } 212 213 214 class MyAccountConfig { 215 public AccountConfig accCfg = new AccountConfig(); 216 public ArrayList<BuddyConfig> buddyCfgs = new ArrayList<BuddyConfig>(); 217 218 public void readObject(ContainerNode node) { 219 try { 220 ContainerNode acc_node = node.readContainer("Account"); 221 accCfg.readObject(acc_node); 222 ContainerNode buddies_node = acc_node.readArray("buddies"); 223 buddyCfgs.clear(); 224 while (buddies_node.hasUnread()) { 225 BuddyConfig bud_cfg = new BuddyConfig(); 226 bud_cfg.readObject(buddies_node); 227 buddyCfgs.add(bud_cfg); 228 } 229 } catch (Exception e) {} 230 } 231 232 public void writeObject(ContainerNode node) { 233 try { 234 ContainerNode acc_node = node.writeNewContainer("Account"); 235 accCfg.writeObject(acc_node); 236 ContainerNode buddies_node = acc_node.writeNewArray("buddies"); 237 for (int j = 0; j < buddyCfgs.size(); j++) { 238 buddyCfgs.get(j).writeObject(buddies_node); 239 } 240 } catch (Exception e) {} 241 } 226 } else if (bi.getPresStatus().getStatus() == 227 pjsua_buddy_status.PJSUA_BUDDY_STATUS_OFFLINE) 228 { 229 status = "Offline"; 230 } else { 231 status = "Unknown"; 232 } 233 } 234 return status; 235 } 236 237 @Override 238 public void onBuddyState() 239 { 240 MyApp.observer.notifyBuddyState(this); 241 } 242 243 } 244 245 246 class MyAccountConfig 247 { 248 public AccountConfig accCfg = new AccountConfig(); 249 public ArrayList<BuddyConfig> buddyCfgs = new ArrayList<BuddyConfig>(); 250 251 public void readObject(ContainerNode node) 252 { 253 try { 254 ContainerNode acc_node = node.readContainer("Account"); 255 accCfg.readObject(acc_node); 256 ContainerNode buddies_node = acc_node.readArray("buddies"); 257 buddyCfgs.clear(); 258 while (buddies_node.hasUnread()) { 259 BuddyConfig bud_cfg = new BuddyConfig(); 260 bud_cfg.readObject(buddies_node); 261 buddyCfgs.add(bud_cfg); 262 } 263 } catch (Exception e) {} 264 } 265 266 public void writeObject(ContainerNode node) 267 { 268 try { 269 ContainerNode acc_node = node.writeNewContainer("Account"); 270 accCfg.writeObject(acc_node); 271 ContainerNode buddies_node = acc_node.writeNewArray("buddies"); 272 for (int j = 0; j < buddyCfgs.size(); j++) { 273 buddyCfgs.get(j).writeObject(buddies_node); 274 } 275 } catch (Exception e) {} 276 } 242 277 } 243 278 244 279 245 280 class MyApp { 246 static { 247 try{ 248 System.loadLibrary("openh264"); 249 System.loadLibrary("yuv"); 250 } catch (UnsatisfiedLinkError e) { 251 System.out.println("UnsatisfiedLinkError: " + e.getMessage()); 252 System.out.println("This could be safely ignored if you " + 253 "don't need video."); 254 } 255 System.loadLibrary("pjsua2"); 256 System.out.println("Library loaded"); 257 } 258 259 public static Endpoint ep = new Endpoint(); 260 public static MyAppObserver observer; 261 public ArrayList<MyAccount> accList = new ArrayList<MyAccount>(); 262 263 private ArrayList<MyAccountConfig> accCfgs = new ArrayList<MyAccountConfig>(); 264 private EpConfig epConfig = new EpConfig(); 265 private TransportConfig sipTpConfig = new TransportConfig(); 266 private String appDir; 267 268 /* Maintain reference to log writer to avoid premature cleanup by GC */ 269 private MyLogWriter logWriter; 270 271 private final String configName = "pjsua2.json"; 272 private final int SIP_PORT = 6000; 273 private final int LOG_LEVEL = 4; 274 275 public void init(MyAppObserver obs, String app_dir) { 276 init(obs, app_dir, false); 277 } 278 279 public void init(MyAppObserver obs, String app_dir, boolean own_worker_thread) { 280 observer = obs; 281 appDir = app_dir; 282 283 /* Create endpoint */ 284 try { 285 ep.libCreate(); 286 } catch (Exception e) { 287 return; 288 } 289 290 291 /* Load config */ 292 String configPath = appDir + "/" + configName; 293 File f = new File(configPath); 294 if (f.exists()) { 295 loadConfig(configPath); 296 } else { 297 /* Set 'default' values */ 298 sipTpConfig.setPort(SIP_PORT); 299 } 300 301 /* Override log level setting */ 302 epConfig.getLogConfig().setLevel(LOG_LEVEL); 303 epConfig.getLogConfig().setConsoleLevel(LOG_LEVEL); 304 305 /* Set log config. */ 306 LogConfig log_cfg = epConfig.getLogConfig(); 307 logWriter = new MyLogWriter(); 308 log_cfg.setWriter(logWriter); 309 log_cfg.setDecor(log_cfg.getDecor() & 310 ~(pj_log_decoration.PJ_LOG_HAS_CR.swigValue() | 311 pj_log_decoration.PJ_LOG_HAS_NEWLINE.swigValue())); 312 313 /* Set ua config. */ 314 UaConfig ua_cfg = epConfig.getUaConfig(); 315 ua_cfg.setUserAgent("Pjsua2 Android " + ep.libVersion().getFull()); 316 StringVector stun_servers = new StringVector(); 317 stun_servers.add("stun.pjsip.org"); 318 ua_cfg.setStunServer(stun_servers); 319 if (own_worker_thread) { 320 ua_cfg.setThreadCnt(0); 321 ua_cfg.setMainThreadOnly(true); 322 } 323 324 /* Init endpoint */ 325 try { 326 ep.libInit(epConfig); 327 } catch (Exception e) { 328 return; 329 } 330 331 /* Create transports. */ 332 try { 333 ep.transportCreate(pjsip_transport_type_e.PJSIP_TRANSPORT_UDP, sipTpConfig); 334 } catch (Exception e) { 335 System.out.println(e); 336 } 337 338 try { 339 ep.transportCreate(pjsip_transport_type_e.PJSIP_TRANSPORT_TCP, sipTpConfig); 340 } catch (Exception e) { 341 System.out.println(e); 342 } 343 344 /* Create accounts. */ 345 for (int i = 0; i < accCfgs.size(); i++) { 346 MyAccountConfig my_cfg = accCfgs.get(i); 347 MyAccount acc = addAcc(my_cfg.accCfg); 348 if (acc == null) 349 continue; 350 351 /* Add Buddies */ 352 for (int j = 0; j < my_cfg.buddyCfgs.size(); j++) { 353 BuddyConfig bud_cfg = my_cfg.buddyCfgs.get(j); 354 acc.addBuddy(bud_cfg); 355 } 356 } 357 358 /* Start. */ 359 try { 360 ep.libStart(); 361 } catch (Exception e) { 362 return; 363 } 364 } 365 366 public MyAccount addAcc(AccountConfig cfg) { 367 MyAccount acc = new MyAccount(cfg); 368 try { 369 acc.create(cfg); 370 } catch (Exception e) { 371 acc = null; 372 return null; 373 } 374 375 accList.add(acc); 376 return acc; 377 } 378 379 public void delAcc(MyAccount acc) { 380 accList.remove(acc); 381 } 382 383 private void loadConfig(String filename) { 384 JsonDocument json = new JsonDocument(); 385 386 try { 387 /* Load file */ 388 json.loadFile(filename); 389 ContainerNode root = json.getRootContainer(); 390 391 /* Read endpoint config */ 392 epConfig.readObject(root); 393 394 /* Read transport config */ 395 ContainerNode tp_node = root.readContainer("SipTransport"); 396 sipTpConfig.readObject(tp_node); 397 398 /* Read account configs */ 399 accCfgs.clear(); 400 ContainerNode accs_node = root.readArray("accounts"); 401 while (accs_node.hasUnread()) { 402 MyAccountConfig acc_cfg = new MyAccountConfig(); 403 acc_cfg.readObject(accs_node); 404 accCfgs.add(acc_cfg); 405 } 406 } catch (Exception e) { 407 System.out.println(e); 408 } 409 410 /* Force delete json now, as I found that Java somehow destroys it 411 * after lib has been destroyed and from non-registered thread. 412 */ 413 json.delete(); 414 } 415 416 private void buildAccConfigs() { 417 /* Sync accCfgs from accList */ 418 accCfgs.clear(); 419 for (int i = 0; i < accList.size(); i++) { 420 MyAccount acc = accList.get(i); 421 MyAccountConfig my_acc_cfg = new MyAccountConfig(); 422 my_acc_cfg.accCfg = acc.cfg; 423 424 my_acc_cfg.buddyCfgs.clear(); 425 for (int j = 0; j < acc.buddyList.size(); j++) { 426 MyBuddy bud = acc.buddyList.get(j); 427 my_acc_cfg.buddyCfgs.add(bud.cfg); 428 } 429 430 accCfgs.add(my_acc_cfg); 431 } 432 } 433 434 private void saveConfig(String filename) { 435 JsonDocument json = new JsonDocument(); 436 437 try { 438 /* Write endpoint config */ 439 json.writeObject(epConfig); 440 441 /* Write transport config */ 442 ContainerNode tp_node = json.writeNewContainer("SipTransport"); 443 sipTpConfig.writeObject(tp_node); 444 445 /* Write account configs */ 446 buildAccConfigs(); 447 ContainerNode accs_node = json.writeNewArray("accounts"); 448 for (int i = 0; i < accCfgs.size(); i++) { 449 accCfgs.get(i).writeObject(accs_node); 450 } 451 452 /* Save file */ 453 json.saveFile(filename); 454 } catch (Exception e) {} 455 456 /* Force delete json now, as I found that Java somehow destroys it 457 * after lib has been destroyed and from non-registered thread. 458 */ 459 json.delete(); 460 } 461 462 public void deinit() { 463 String configPath = appDir + "/" + configName; 464 saveConfig(configPath); 465 466 /* Try force GC to avoid late destroy of PJ objects as they should be 467 * deleted before lib is destroyed. 468 */ 469 Runtime.getRuntime().gc(); 470 471 /* Shutdown pjsua. Note that Endpoint destructor will also invoke 472 * libDestroy(), so this will be a test of double libDestroy(). 473 */ 474 try { 475 ep.libDestroy(); 476 } catch (Exception e) {} 477 478 /* Force delete Endpoint here, to avoid deletion from a non- 479 * registered thread (by GC?). 480 */ 481 ep.delete(); 482 ep = null; 483 } 484 } 281 static { 282 try{ 283 System.loadLibrary("openh264"); 284 System.loadLibrary("yuv"); 285 } catch (UnsatisfiedLinkError e) { 286 System.out.println("UnsatisfiedLinkError: " + e.getMessage()); 287 System.out.println("This could be safely ignored if you " + 288 "don't need video."); 289 } 290 System.loadLibrary("pjsua2"); 291 System.out.println("Library loaded"); 292 } 293 294 public static Endpoint ep = new Endpoint(); 295 public static MyAppObserver observer; 296 public ArrayList<MyAccount> accList = new ArrayList<MyAccount>(); 297 298 private ArrayList<MyAccountConfig> accCfgs = 299 new ArrayList<MyAccountConfig>(); 300 private EpConfig epConfig = new EpConfig(); 301 private TransportConfig sipTpConfig = new TransportConfig(); 302 private String appDir; 303 304 /* Maintain reference to log writer to avoid premature cleanup by GC */ 305 private MyLogWriter logWriter; 306 307 private final String configName = "pjsua2.json"; 308 private final int SIP_PORT = 6000; 309 private final int LOG_LEVEL = 4; 310 311 public void init(MyAppObserver obs, String app_dir) 312 { 313 init(obs, app_dir, false); 314 } 315 316 public void init(MyAppObserver obs, String app_dir, 317 boolean own_worker_thread) 318 { 319 observer = obs; 320 appDir = app_dir; 321 322 /* Create endpoint */ 323 try { 324 ep.libCreate(); 325 } catch (Exception e) { 326 return; 327 } 328 329 330 /* Load config */ 331 String configPath = appDir + "/" + configName; 332 File f = new File(configPath); 333 if (f.exists()) { 334 loadConfig(configPath); 335 } else { 336 /* Set 'default' values */ 337 sipTpConfig.setPort(SIP_PORT); 338 } 339 340 /* Override log level setting */ 341 epConfig.getLogConfig().setLevel(LOG_LEVEL); 342 epConfig.getLogConfig().setConsoleLevel(LOG_LEVEL); 343 344 /* Set log config. */ 345 LogConfig log_cfg = epConfig.getLogConfig(); 346 logWriter = new MyLogWriter(); 347 log_cfg.setWriter(logWriter); 348 log_cfg.setDecor(log_cfg.getDecor() & 349 ~(pj_log_decoration.PJ_LOG_HAS_CR.swigValue() | 350 pj_log_decoration.PJ_LOG_HAS_NEWLINE.swigValue())); 351 352 /* Set ua config. */ 353 UaConfig ua_cfg = epConfig.getUaConfig(); 354 ua_cfg.setUserAgent("Pjsua2 Android " + ep.libVersion().getFull()); 355 StringVector stun_servers = new StringVector(); 356 stun_servers.add("stun.pjsip.org"); 357 ua_cfg.setStunServer(stun_servers); 358 if (own_worker_thread) { 359 ua_cfg.setThreadCnt(0); 360 ua_cfg.setMainThreadOnly(true); 361 } 362 363 /* Init endpoint */ 364 try { 365 ep.libInit(epConfig); 366 } catch (Exception e) { 367 return; 368 } 369 370 /* Create transports. */ 371 try { 372 ep.transportCreate(pjsip_transport_type_e.PJSIP_TRANSPORT_UDP, 373 sipTpConfig); 374 } catch (Exception e) { 375 System.out.println(e); 376 } 377 378 try { 379 ep.transportCreate(pjsip_transport_type_e.PJSIP_TRANSPORT_TCP, 380 sipTpConfig); 381 } catch (Exception e) { 382 System.out.println(e); 383 } 384 385 /* Create accounts. */ 386 for (int i = 0; i < accCfgs.size(); i++) { 387 MyAccountConfig my_cfg = accCfgs.get(i); 388 MyAccount acc = addAcc(my_cfg.accCfg); 389 if (acc == null) 390 continue; 391 392 /* Add Buddies */ 393 for (int j = 0; j < my_cfg.buddyCfgs.size(); j++) { 394 BuddyConfig bud_cfg = my_cfg.buddyCfgs.get(j); 395 acc.addBuddy(bud_cfg); 396 } 397 } 398 399 /* Start. */ 400 try { 401 ep.libStart(); 402 } catch (Exception e) { 403 return; 404 } 405 } 406 407 public MyAccount addAcc(AccountConfig cfg) 408 { 409 MyAccount acc = new MyAccount(cfg); 410 try { 411 acc.create(cfg); 412 } catch (Exception e) { 413 acc = null; 414 return null; 415 } 416 417 accList.add(acc); 418 return acc; 419 } 420 421 public void delAcc(MyAccount acc) 422 { 423 accList.remove(acc); 424 } 425 426 private void loadConfig(String filename) 427 { 428 JsonDocument json = new JsonDocument(); 429 430 try { 431 /* Load file */ 432 json.loadFile(filename); 433 ContainerNode root = json.getRootContainer(); 434 435 /* Read endpoint config */ 436 epConfig.readObject(root); 437 438 /* Read transport config */ 439 ContainerNode tp_node = root.readContainer("SipTransport"); 440 sipTpConfig.readObject(tp_node); 441 442 /* Read account configs */ 443 accCfgs.clear(); 444 ContainerNode accs_node = root.readArray("accounts"); 445 while (accs_node.hasUnread()) { 446 MyAccountConfig acc_cfg = new MyAccountConfig(); 447 acc_cfg.readObject(accs_node); 448 accCfgs.add(acc_cfg); 449 } 450 } catch (Exception e) { 451 System.out.println(e); 452 } 453 454 /* Force delete json now, as I found that Java somehow destroys it 455 * after lib has been destroyed and from non-registered thread. 456 */ 457 json.delete(); 458 } 459 460 private void buildAccConfigs() 461 { 462 /* Sync accCfgs from accList */ 463 accCfgs.clear(); 464 for (int i = 0; i < accList.size(); i++) { 465 MyAccount acc = accList.get(i); 466 MyAccountConfig my_acc_cfg = new MyAccountConfig(); 467 my_acc_cfg.accCfg = acc.cfg; 468 469 my_acc_cfg.buddyCfgs.clear(); 470 for (int j = 0; j < acc.buddyList.size(); j++) { 471 MyBuddy bud = acc.buddyList.get(j); 472 my_acc_cfg.buddyCfgs.add(bud.cfg); 473 } 474 475 accCfgs.add(my_acc_cfg); 476 } 477 } 478 479 private void saveConfig(String filename) 480 { 481 JsonDocument json = new JsonDocument(); 482 483 try { 484 /* Write endpoint config */ 485 json.writeObject(epConfig); 486 487 /* Write transport config */ 488 ContainerNode tp_node = json.writeNewContainer("SipTransport"); 489 sipTpConfig.writeObject(tp_node); 490 491 /* Write account configs */ 492 buildAccConfigs(); 493 ContainerNode accs_node = json.writeNewArray("accounts"); 494 for (int i = 0; i < accCfgs.size(); i++) { 495 accCfgs.get(i).writeObject(accs_node); 496 } 497 498 /* Save file */ 499 json.saveFile(filename); 500 } catch (Exception e) {} 501 502 /* Force delete json now, as I found that Java somehow destroys it 503 * after lib has been destroyed and from non-registered thread. 504 */ 505 json.delete(); 506 } 507 508 public void deinit() 509 { 510 String configPath = appDir + "/" + configName; 511 saveConfig(configPath); 512 513 /* Try force GC to avoid late destroy of PJ objects as they should be 514 * deleted before lib is destroyed. 515 */ 516 Runtime.getRuntime().gc(); 517 518 /* Shutdown pjsua. Note that Endpoint destructor will also invoke 519 * libDestroy(), so this will be a test of double libDestroy(). 520 */ 521 try { 522 ep.libDestroy(); 523 } catch (Exception e) {} 524 525 /* Force delete Endpoint here, to avoid deletion from a non- 526 * registered thread (by GC?). 527 */ 528 ep.delete(); 529 ep = null; 530 } 531 }
Note: See TracChangeset
for help on using the changeset viewer.