blob: 14d907ab8d8ebaef8bb412af1f3ed98e1290dc57 [file] [log] [blame]
Adrien BĂ©raud04d822c2015-04-02 17:44:36 -04001/**
2 * Copyright (C) 2010-2012 Regis Montoya (aka r3gis - www.r3gis.fr)
3 * Copyright (C) 2004-2014 Savoir-Faire Linux Inc.
4 *
5 * Author: Regis Montoya <r3gis.3R@gmail.com>
6 * Author: Emeric Vigier <emeric.vigier@savoirfairelinux.com>
7 * Alexandre Lision <alexandre.lision@savoirfairelinux.com>
8 *
9 * This program is free software: you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation, either version 3 of the License, or
12 * (at your option) any later version.
13 * If you own a pjsip commercial license you can also redistribute it
14 * and/or modify it under the terms of the GNU Lesser General Public License
15 * as an android library.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program. If not, see <http://www.gnu.org/licenses/>.
24 */
25package cx.ring.service;
26
27import android.os.Handler;
28
29import java.util.ArrayList;
30import java.util.HashMap;
31import java.util.Iterator;
32import java.util.List;
33import java.util.Map;
34import java.util.Map.Entry;
35
36import android.app.Service;
37import android.content.Intent;
38import android.os.*;
39import android.util.Log;
40import cx.ring.history.HistoryManager;
41import cx.ring.model.Codec;
42import cx.ring.model.Conference;
43import cx.ring.model.SecureSipCall;
44import cx.ring.model.SipMessage;
45import cx.ring.utils.MediaManager;
46import cx.ring.utils.SipNotifications;
47import cx.ring.utils.SwigNativeConverter;
48import cx.ring.model.SipCall;
49
50
51public class SipService extends Service {
52
53 static final String TAG = "SipService";
54 private SipServiceExecutor mExecutor;
55 private static HandlerThread executorThread;
56
57 private Handler handler = new Handler();
58 private static int POLLING_TIMEOUT = 500;
59 private Runnable pollEvents = new Runnable() {
60 @Override
61 public void run() {
62 Ringservice.sflph_poll_events();
63 handler.postDelayed(this, POLLING_TIMEOUT);
64 }
65 };
66 private boolean isPjSipStackStarted = false;
67
68 protected SipNotifications mNotificationManager;
69 protected HistoryManager mHistoryManager;
70 protected MediaManager mMediaManager;
71
72 private HashMap<String, Conference> mConferences = new HashMap<String, Conference>();
73 private ConfigurationManagerCallback configurationCallback;
74 private CallManagerCallBack callManagerCallBack;
75
76 public HashMap<String, Conference> getConferences() {
77 return mConferences;
78 }
79
80 public void addCallToConference(String confId, String callId) {
81 if(mConferences.get(callId) != null){
82 // We add a simple call to a conference
83 Log.i(TAG, "// We add a simple call to a conference");
84 mConferences.get(confId).addParticipant(mConferences.get(callId).getParticipants().get(0));
85 mConferences.remove(callId);
86 } else {
87 Log.i(TAG, "addCallToConference");
88 for (Entry<String, Conference> stringConferenceEntry : mConferences.entrySet()) {
89 Conference tmp = stringConferenceEntry.getValue();
90 for (SipCall c : tmp.getParticipants()) {
91 if (c.getCallId().contentEquals(callId)) {
92 mConferences.get(confId).addParticipant(c);
93 mConferences.get(tmp.getId()).removeParticipant(c);
94 }
95 }
96 }
97 }
98 }
99
100 public void detachCallFromConference(String confId, SipCall call) {
101 Log.i(TAG, "detachCallFromConference");
102 Conference separate = new Conference(call);
103 mConferences.put(separate.getId(), separate);
104 mConferences.get(confId).removeParticipant(call);
105 }
106
107 @Override
108 public boolean onUnbind(Intent i) {
109 super.onUnbind(i);
110 Log.i(TAG, "onUnbind(intent)");
111 return true;
112 }
113
114 @Override
115 public void onRebind(Intent i) {
116 super.onRebind(i);
117 }
118
119 /* called once by startService() */
120 @Override
121 public void onCreate() {
122 Log.i(TAG, "onCreated");
123 super.onCreate();
124
125 getExecutor().execute(new StartRunnable());
126
127 mNotificationManager = new SipNotifications(this);
128 mMediaManager = new MediaManager(this);
129 mHistoryManager = new HistoryManager(this);
130
131 mNotificationManager.onServiceCreate();
132 mMediaManager.startService();
133
134 }
135
136 /* called for each startService() */
137 @Override
138 public int onStartCommand(Intent intent, int flags, int startId) {
139 Log.i(TAG, "onStarted");
140 super.onStartCommand(intent, flags, startId);
141 return START_STICKY; /* started and stopped explicitly */
142 }
143
144 @Override
145 public void onDestroy() {
146 Log.i(TAG, "onDestroy");
147 /* called once by stopService() */
148 mNotificationManager.onServiceDestroy();
149 mMediaManager.stopService();
150 getExecutor().execute(new FinalizeRunnable());
151 super.onDestroy();
152
153 }
154
155 @Override
156 public IBinder onBind(Intent arg0) {
157 Log.i(TAG, "onBound");
158 return mBinder;
159 }
160
161 private static Looper createLooper() {
162 if (executorThread == null) {
163 Log.d(TAG, "Creating new handler thread");
164 // ADT gives a fake warning due to bad parse rule.
165 executorThread = new HandlerThread("SipService.Executor");
166 executorThread.start();
167 }
168 return executorThread.getLooper();
169 }
170
171 public SipServiceExecutor getExecutor() {
172 // create mExecutor lazily
173 if (mExecutor == null) {
174 mExecutor = new SipServiceExecutor();
175 }
176 return mExecutor;
177 }
178
179 public SipCall getCallById(String callID) {
180 if (getConferences().get(callID) != null) {
181 return getConferences().get(callID).getCallById(callID);
182 } else {
183 // Check if call is in a conference
184 for (Entry<String, Conference> stringConferenceEntry : getConferences().entrySet()) {
185 Conference tmp = stringConferenceEntry.getValue();
186 SipCall c = tmp.getCallById(callID);
187 if (c != null)
188 return c;
189 }
190 }
191 return null;
192 }
193
194 // Executes immediate tasks in a single executorThread.
195 public static class SipServiceExecutor extends Handler {
196
197 SipServiceExecutor() {
198 super(createLooper());
199 }
200
201 public void execute(Runnable task) {
202 // TODO: add wakelock
203 Message.obtain(SipServiceExecutor.this, 0/* don't care */, task).sendToTarget();
204 Log.w(TAG, "SenT!");
205 }
206
207 @Override
208 public void handleMessage(Message msg) {
209 Log.w(TAG, "handleMessage");
210 if (msg.obj instanceof Runnable) {
211 executeInternal((Runnable) msg.obj);
212 } else {
213 Log.w(TAG, "can't handle msg: " + msg);
214 }
215 }
216
217 private void executeInternal(Runnable task) {
218 try {
219 task.run();
220 } catch (Throwable t) {
221 Log.e(TAG, "run task: " + task, t);
222 }
223 }
224 }
225
226 private void stopDaemon() {
227 handler.removeCallbacks(pollEvents);
228 Ringservice.sflph_fini();
229 isPjSipStackStarted = false;
230 }
231
232 private void startPjSipStack() throws SameThreadException {
233 if (isPjSipStackStarted)
234 return;
235
236 try {
237 System.loadLibrary("codec_ulaw");
238 System.loadLibrary("codec_alaw");
239 System.loadLibrary("codec_speex");
240 System.loadLibrary("codec_g729");
241 System.loadLibrary("codec_gsm");
242 System.loadLibrary("codec_opus");
243 System.loadLibrary("sflphonejni");
244 isPjSipStackStarted = true;
245
246 } catch (UnsatisfiedLinkError e) {
247 Log.e(TAG, "Problem with the current Pj stack...", e);
248 isPjSipStackStarted = false;
249 return;
250 } catch (Exception e) {
251 Log.e(TAG, "Problem with the current Pj stack...", e);
252 isPjSipStackStarted = false;
253 }
254
255 configurationCallback = new ConfigurationManagerCallback(this);
256 callManagerCallBack = new CallManagerCallBack(this);
257 Ringservice.init(configurationCallback, callManagerCallBack);
258 handler.postDelayed(pollEvents, POLLING_TIMEOUT);
259 Log.i(TAG, "PjSIPStack started");
260 }
261
262 // Enforce same thread contract to ensure we do not call from somewhere else
263 public class SameThreadException extends Exception {
264 private static final long serialVersionUID = -905639124232613768L;
265
266 public SameThreadException() {
267 super("Should be launched from a single worker thread");
268 }
269 }
270
271 public abstract static class SipRunnable implements Runnable {
272 protected abstract void doRun() throws SameThreadException, RemoteException;
273
274 @Override
275 public void run() {
276 try {
277 doRun();
278 } catch (SameThreadException e) {
279 Log.e(TAG, "Not done from same thread");
280 } catch (RemoteException e) {
281 Log.e(TAG, e.toString());
282 }
283 }
284 }
285
286 public abstract class SipRunnableWithReturn implements Runnable {
287 Object obj = null;
288 boolean done = false;
289
290 protected abstract Object doRun() throws SameThreadException, RemoteException;
291
292 public Object getVal() {
293 return obj;
294 }
295
296 public boolean isDone() {
297 return done;
298 }
299
300 @Override
301 public void run() {
302 try {
303 if (isPjSipStackStarted)
304 obj = doRun();
305 done = true;
306 } catch (SameThreadException e) {
307 Log.e(TAG, "Not done from same thread");
308 } catch (RemoteException e) {
309 Log.e(TAG, e.toString());
310 }
311 }
312 }
313
314 class StartRunnable extends SipRunnable {
315 @Override
316 protected void doRun() throws SameThreadException {
317 startPjSipStack();
318 }
319 }
320
321 class FinalizeRunnable extends SipRunnable {
322 @Override
323 protected void doRun() throws SameThreadException {
324 stopDaemon();
325 }
326 }
327
328 /* ************************************
329 *
330 * Implement public interface for the service
331 *
332 * *********************************
333 */
334
335 private final ISipService.Stub mBinder = new ISipService.Stub() {
336
337 @Override
338 public void placeCall(final SipCall call) {
339
340 getExecutor().execute(new SipRunnable() {
341 @Override
342 protected void doRun() throws SameThreadException {
343 Log.i(TAG, "SipService.placeCall() thread running...");
344 Conference toAdd;
345 if(call.getAccount().useSecureLayer()){
346 SecureSipCall secureCall = new SecureSipCall(call);
347 toAdd = new Conference(secureCall);
348 } else {
349 toAdd = new Conference(call);
350 }
351 mConferences.put(toAdd.getId(), toAdd);
352 mMediaManager.obtainAudioFocus(false);
353 Ringservice.sflph_call_place(call.getAccount().getAccountID(), call.getCallId(), call.getmContact().getPhones().get(0).getNumber());
354 }
355 });
356 }
357
358 @Override
359 public void refuse(final String callID) {
360
361 getExecutor().execute(new SipRunnable() {
362 @Override
363 protected void doRun() throws SameThreadException {
364 Log.i(TAG, "SipService.refuse() thread running...");
365 Ringservice.sflph_call_refuse(callID);
366 }
367 });
368 }
369
370 @Override
371 public void accept(final String callID) {
372 mMediaManager.stopRing();
373 getExecutor().execute(new SipRunnable() {
374 @Override
375 protected void doRun() throws SameThreadException {
376 Log.i(TAG, "SipService.accept() thread running...");
377 Ringservice.sflph_call_accept(callID);
378 mMediaManager.RouteToInternalSpeaker();
379 }
380 });
381 }
382
383 @Override
384 public void hangUp(final String callID) {
385 mMediaManager.stopRing();
386 Log.e(TAG, "HANGING UP");
387 getExecutor().execute(new SipRunnable() {
388 @Override
389 protected void doRun() throws SameThreadException {
390 Log.i(TAG, "SipService.hangUp() thread running...");
391 Ringservice.sflph_call_hang_up(callID);
392 removeCall(callID);
393 if(mConferences.size() == 0) {
394 Log.i(TAG, "No more calls!");
395 mMediaManager.abandonAudioFocus();
396 }
397 }
398 });
399 }
400
401 @Override
402 public void hold(final String callID) {
403 getExecutor().execute(new SipRunnable() {
404 @Override
405 protected void doRun() throws SameThreadException {
406 Log.i(TAG, "SipService.hold() thread running...");
407 Ringservice.sflph_call_hold(callID);
408 }
409 });
410 }
411
412 @Override
413 public void unhold(final String callID) {
414 getExecutor().execute(new SipRunnable() {
415 @Override
416 protected void doRun() throws SameThreadException {
417 Log.i(TAG, "SipService.unhold() thread running...");
418 Ringservice.sflph_call_unhold(callID);
419 }
420 });
421 }
422
423 @Override
424 public HashMap<String, String> getCallDetails(String callID) throws RemoteException {
425 class CallDetails extends SipRunnableWithReturn {
426 private String id;
427
428 CallDetails(String callID) {
429 id = callID;
430 }
431
432 @Override
433 protected StringMap doRun() throws SameThreadException {
434 Log.i(TAG, "SipService.getCallDetails() thread running...");
435 return Ringservice.sflph_call_get_call_details(id);
436 }
437 }
438
439 CallDetails runInstance = new CallDetails(callID);
440 getExecutor().execute(runInstance);
441
442 while (!runInstance.isDone()) {
443 }
444 StringMap swigmap = (StringMap) runInstance.getVal();
445
446 return SwigNativeConverter.convertCallDetailsToNative(swigmap);
447 }
448
449 @Override
450 public void setAudioPlugin(final String audioPlugin) {
451 getExecutor().execute(new SipRunnable() {
452 @Override
453 protected void doRun() throws SameThreadException {
454 Log.i(TAG, "SipService.setAudioPlugin() thread running...");
455 Ringservice.sflph_config_set_audio_plugin(audioPlugin);
456 }
457 });
458 }
459
460 @Override
461 public String getCurrentAudioOutputPlugin() {
462 class CurrentAudioPlugin extends SipRunnableWithReturn {
463 @Override
464 protected String doRun() throws SameThreadException {
465 Log.i(TAG, "SipService.getCurrentAudioOutputPlugin() thread running...");
466 return Ringservice.sflph_config_get_current_audio_output_plugin();
467 }
468 }
469
470 CurrentAudioPlugin runInstance = new CurrentAudioPlugin();
471 getExecutor().execute(runInstance);
472 while (!runInstance.isDone()) {
473 // Log.e(TAG, "Waiting for Nofing");
474 }
475 return (String) runInstance.getVal();
476 }
477
478 @Override
479 public ArrayList<String> getAccountList() {
480 class AccountList extends SipRunnableWithReturn {
481 @Override
482 protected StringVect doRun() throws SameThreadException {
483 Log.i(TAG, "SipService.getAccountList() thread running...");
484 return Ringservice.sflph_config_get_account_list();
485 }
486 }
487 AccountList runInstance = new AccountList();
488 getExecutor().execute(runInstance);
489 while (!runInstance.isDone()) {
490 }
491 StringVect swigvect = (StringVect) runInstance.getVal();
492
493 ArrayList<String> nativelist = new ArrayList<String>();
494
495 for (int i = 0; i < swigvect.size(); i++)
496 nativelist.add(swigvect.get(i));
497
498 return nativelist;
499 }
500
501 @Override
502 public void setAccountOrder(final String order) {
503 getExecutor().execute(new SipRunnable() {
504 @Override
505 protected void doRun() throws SameThreadException {
506 Log.i(TAG, "SipService.setAccountsOrder() thread running...");
507 Ringservice.sflph_config_set_accounts_order(order);
508 }
509 });
510 }
511
512 @Override
513 public HashMap<String, String> getAccountDetails(final String accountID) {
514 class AccountDetails extends SipRunnableWithReturn {
515 private String id;
516
517 AccountDetails(String accountId) {
518 id = accountId;
519 }
520
521 @Override
522 protected StringMap doRun() throws SameThreadException {
523 Log.i(TAG, "SipService.getAccountDetails() thread running...");
524 return Ringservice.sflph_config_get_account_details(id);
525 }
526 }
527
528 AccountDetails runInstance = new AccountDetails(accountID);
529 getExecutor().execute(runInstance);
530
531 while (!runInstance.isDone()) {
532 }
533 StringMap swigmap = (StringMap) runInstance.getVal();
534
535 return SwigNativeConverter.convertAccountToNative(swigmap);
536 }
537
538 @SuppressWarnings("unchecked")
539 // Hashmap runtime cast
540 @Override
541 public void setAccountDetails(final String accountId, final Map map) {
542 HashMap<String, String> nativemap = (HashMap<String, String>) map;
543
544 final StringMap swigmap = SwigNativeConverter.convertFromNativeToSwig(nativemap);
545
546 getExecutor().execute(new SipRunnable() {
547 @Override
548 protected void doRun() throws SameThreadException {
549
550 Ringservice.sflph_config_set_account_details(accountId, swigmap);
551 Log.i(TAG, "SipService.setAccountDetails() thread running...");
552 }
553
554 });
555 }
556
557 @Override
558 public Map getAccountTemplate() throws RemoteException {
559 class AccountTemplate extends SipRunnableWithReturn {
560
561 @Override
562 protected StringMap doRun() throws SameThreadException {
563 Log.i(TAG, "SipService.getAccountTemplate() thread running...");
564 return Ringservice.sflph_config_get_account_template();
565 }
566 }
567
568 AccountTemplate runInstance = new AccountTemplate();
569 getExecutor().execute(runInstance);
570
571 while (!runInstance.isDone()) {
572 }
573 StringMap swigmap = (StringMap) runInstance.getVal();
574
575 return SwigNativeConverter.convertAccountToNative(swigmap);
576 }
577
578 @SuppressWarnings("unchecked")
579 // Hashmap runtime cast
580 @Override
581 public String addAccount(Map map) {
582 class AddAccount extends SipRunnableWithReturn {
583 StringMap map;
584
585 AddAccount(StringMap m) {
586 map = m;
587 }
588
589 @Override
590 protected String doRun() throws SameThreadException {
591 Log.i(TAG, "SipService.addAccount() thread running...");
592 return Ringservice.sflph_config_add_account(map);
593 }
594 }
595
596 final StringMap swigmap = SwigNativeConverter.convertFromNativeToSwig((HashMap<String, String>) map);
597
598 AddAccount runInstance = new AddAccount(swigmap);
599 getExecutor().execute(runInstance);
600 while (!runInstance.isDone()) {
601 }
602 return (String) runInstance.getVal();
603 }
604
605 @Override
606 public void removeAccount(final String accountId) {
607 getExecutor().execute(new SipRunnable() {
608 @Override
609 protected void doRun() throws SameThreadException {
610 Log.i(TAG, "SipService.setAccountDetails() thread running...");
611 Ringservice.sflph_config_remove_account(accountId);
612 }
613 });
614 }
615
616 /*************************
617 * Transfer related API
618 *************************/
619
620 @Override
621 public void transfer(final String callID, final String to) throws RemoteException {
622 getExecutor().execute(new SipRunnable() {
623 @Override
624 protected void doRun() throws SameThreadException, RemoteException {
625 Log.i(TAG, "SipService.transfer() thread running...");
626 if (Ringservice.sflph_call_transfer(callID, to)) {
627 Bundle bundle = new Bundle();
628 bundle.putString("CallID", callID);
629 bundle.putString("State", "HUNGUP");
630 Intent intent = new Intent(CallManagerCallBack.CALL_STATE_CHANGED);
631 intent.putExtra("com.savoirfairelinux.sflphone.service.newstate", bundle);
632 sendBroadcast(intent);
633 } else
634 Log.i(TAG, "NOT OK");
635 }
636 });
637
638 }
639
640 @Override
641 public void attendedTransfer(final String transferID, final String targetID) throws RemoteException {
642 getExecutor().execute(new SipRunnable() {
643 @Override
644 protected void doRun() throws SameThreadException, RemoteException {
645 Log.i(TAG, "SipService.attendedTransfer() thread running...");
646 if (Ringservice.sflph_call_attended_transfer(transferID, targetID)) {
647 Log.i(TAG, "OK");
648 } else
649 Log.i(TAG, "NOT OK");
650 }
651 });
652
653 }
654
655 /*************************
656 * Conference related API
657 *************************/
658
659 @Override
660 public void removeConference(final String confID) throws RemoteException {
661 getExecutor().execute(new SipRunnable() {
662 @Override
663 protected void doRun() throws SameThreadException, RemoteException {
664 Log.i(TAG, "SipService.createConference() thread running...");
665 Ringservice.sflph_call_remove_conference(confID);
666 }
667 });
668
669 }
670
671 @Override
672 public void joinParticipant(final String sel_callID, final String drag_callID) throws RemoteException {
673 getExecutor().execute(new SipRunnable() {
674 @Override
675 protected void doRun() throws SameThreadException, RemoteException {
676 Log.i(TAG, "SipService.joinParticipant() thread running...");
677 Ringservice.sflph_call_join_participant(sel_callID, drag_callID);
678 // Generate a CONF_CREATED callback
679 }
680 });
681 Log.i(TAG, "After joining participants");
682 }
683
684 @Override
685 public void addParticipant(final SipCall call, final String confID) throws RemoteException {
686 getExecutor().execute(new SipRunnable() {
687 @Override
688 protected void doRun() throws SameThreadException, RemoteException {
689 Log.i(TAG, "SipService.addParticipant() thread running...");
690 Ringservice.sflph_call_add_participant(call.getCallId(), confID);
691 mConferences.get(confID).getParticipants().add(call);
692 }
693 });
694
695 }
696
697 @Override
698 public void addMainParticipant(final String confID) throws RemoteException {
699 getExecutor().execute(new SipRunnable() {
700 @Override
701 protected void doRun() throws SameThreadException, RemoteException {
702 Log.i(TAG, "SipService.addMainParticipant() thread running...");
703 Ringservice.sflph_call_add_main_participant(confID);
704 }
705 });
706
707 }
708
709 @Override
710 public void detachParticipant(final String callID) throws RemoteException {
711 getExecutor().execute(new SipRunnable() {
712 @Override
713 protected void doRun() throws SameThreadException, RemoteException {
714 Log.i(TAG, "SipService.detachParticipant() thread running...");
715 Log.i(TAG, "Detaching " + callID);
716 Iterator<Entry<String, Conference>> it = mConferences.entrySet().iterator();
717 Log.i(TAG, "mConferences size " + mConferences.size());
718 while (it.hasNext()) {
719 Conference tmp = it.next().getValue();
720 Log.i(TAG, "conf has " + tmp.getParticipants().size() + " participants");
721 if (tmp.contains(callID)) {
722 Conference toDetach = new Conference(tmp.getCallById(callID));
723 mConferences.put(toDetach.getId(), toDetach);
724 Log.i(TAG, "Call found and put in current_calls");
725 }
726 }
727 Ringservice.sflph_call_detach_participant(callID);
728 }
729 });
730
731 }
732
733 @Override
734 public void joinConference(final String sel_confID, final String drag_confID) throws RemoteException {
735 getExecutor().execute(new SipRunnable() {
736 @Override
737 protected void doRun() throws SameThreadException, RemoteException {
738 Log.i(TAG, "SipService.joinConference() thread running...");
739 Ringservice.sflph_call_join_conference(sel_confID, drag_confID);
740 }
741 });
742
743 }
744
745 @Override
746 public void hangUpConference(final String confID) throws RemoteException {
747 Log.e(TAG, "HANGING UP CONF");
748 getExecutor().execute(new SipRunnable() {
749 @Override
750 protected void doRun() throws SameThreadException, RemoteException {
751 Log.i(TAG, "SipService.joinConference() thread running...");
752 Ringservice.sflph_call_hang_up_conference(confID);
753 }
754 });
755
756 }
757
758 @Override
759 public void holdConference(final String confID) throws RemoteException {
760 getExecutor().execute(new SipRunnable() {
761 @Override
762 protected void doRun() throws SameThreadException, RemoteException {
763 Log.i(TAG, "SipService.holdConference() thread running...");
764 Ringservice.sflph_call_hold_conference(confID);
765 }
766 });
767
768 }
769
770 @Override
771 public void unholdConference(final String confID) throws RemoteException {
772 getExecutor().execute(new SipRunnable() {
773 @Override
774 protected void doRun() throws SameThreadException, RemoteException {
775 Log.i(TAG, "SipService.unholdConference() thread running...");
776 Ringservice.sflph_call_unhold_conference(confID);
777 }
778 });
779
780 }
781
782 @Override
783 public boolean isConferenceParticipant(final String callID) throws RemoteException {
784 class IsParticipant extends SipRunnableWithReturn {
785
786 @Override
787 protected Boolean doRun() throws SameThreadException {
788 Log.i(TAG, "SipService.isRecording() thread running...");
789 return Ringservice.sflph_call_is_conference_participant(callID);
790 }
791 }
792
793 IsParticipant runInstance = new IsParticipant();
794 getExecutor().execute(runInstance);
795 while (!runInstance.isDone()) {
796 }
797
798 return (Boolean) runInstance.getVal();
799 }
800
801 @Override
802 public HashMap<String, Conference> getConferenceList() throws RemoteException {
803 // class ConfList extends SipRunnableWithReturn {
804 // @Override
805 // protected StringVect doRun() throws SameThreadException {
806 // Log.i(TAG, "SipService.getConferenceList() thread running...");
807 // return callManagerJNI.getConferenceList();
808 // }
809 // }
810 // ;
811 // ConfList runInstance = new ConfList();
812 // getExecutor().execute(runInstance);
813 // while (!runInstance.isDone()) {
814 // // Log.w(TAG, "Waiting for getConferenceList");
815 // }
816 // StringVect swigvect = (StringVect) runInstance.getVal();
817 //
818 // ArrayList<String> nativelist = new ArrayList<String>();
819 //
820 // for (int i = 0; i < swigvect.size(); i++)
821 // nativelist.add(swigvect.get(i));
822 //
823 // return nativelist;
824 return mConferences;
825 }
826
827 @Override
828 public List getParticipantList(final String confID) throws RemoteException {
829 class PartList extends SipRunnableWithReturn {
830 @Override
831 protected StringVect doRun() throws SameThreadException {
832 Log.i(TAG, "SipService.getParticipantList() thread running...");
833 return Ringservice.sflph_call_get_participant_list(confID);
834 }
835 }
836 ;
837 PartList runInstance = new PartList();
838 getExecutor().execute(runInstance);
839 while (!runInstance.isDone()) {
840 Log.w(TAG, "getParticipantList");
841 }
842 StringVect swigvect = (StringVect) runInstance.getVal();
843 Log.w(TAG, "After that");
844 ArrayList<String> nativelist = new ArrayList<String>();
845
846 for (int i = 0; i < swigvect.size(); i++)
847 nativelist.add(swigvect.get(i));
848
849 return nativelist;
850 }
851
852 @Override
853 public String getConferenceId(String callID) throws RemoteException {
854 Log.e(TAG, "getConferenceList not implemented");
855 return null;
856 }
857
858 @Override
859 public String getConferenceDetails(final String callID) throws RemoteException {
860 class ConfDetails extends SipRunnableWithReturn {
861 @Override
862 protected StringMap doRun() throws SameThreadException {
863 Log.i(TAG, "SipService.getConferenceDetails() thread running...");
864 return Ringservice.sflph_call_get_conference_details(callID);
865 }
866 }
867 ConfDetails runInstance = new ConfDetails();
868 getExecutor().execute(runInstance);
869 while (!runInstance.isDone()) {
870 // Log.w(TAG, "Waiting for getConferenceList");
871 }
872 StringMap swigvect = (StringMap) runInstance.getVal();
873
874 return swigvect.get("CONF_STATE");
875 }
876
877 @Override
878 public String getRecordPath() throws RemoteException {
879 class RecordPath extends SipRunnableWithReturn {
880
881 @Override
882 protected String doRun() throws SameThreadException {
883 Log.i(TAG, "SipService.getRecordPath() thread running...");
884 return Ringservice.sflph_config_get_record_path();
885 }
886 }
887
888 RecordPath runInstance = new RecordPath();
889 getExecutor().execute(runInstance);
890 while (!runInstance.isDone()) {
891 // Log.w(TAG, "Waiting for getRecordPath");
892 }
893
894 return (String) runInstance.getVal();
895 }
896
897 @Override
898 public boolean toggleRecordingCall(final String id) throws RemoteException {
899
900 class ToggleRecording extends SipRunnableWithReturn {
901
902 @Override
903 protected Boolean doRun() throws SameThreadException {
904 Log.i(TAG, "SipService.toggleRecordingCall() thread running...");
905 boolean result = Ringservice.sflph_call_toggle_recording(id);
906
907 if (getConferences().containsKey(id)) {
908 getConferences().get(id).setRecording(result);
909 } else {
910 for (Conference c : getConferences().values()) {
911 if (c.getCallById(id) != null)
912 c.getCallById(id).setRecording(result);
913 }
914 }
915 return result;
916 }
917 }
918
919 ToggleRecording runInstance = new ToggleRecording();
920 getExecutor().execute(runInstance);
921 while (!runInstance.isDone()) {
922 }
923
924 return (Boolean) runInstance.getVal();
925
926 }
927
928 @Override
929 public boolean startRecordedFilePlayback(final String filepath) throws RemoteException {
930 getExecutor().execute(new SipRunnable() {
931 @Override
932 protected void doRun() throws SameThreadException, RemoteException {
933 Log.i(TAG, "SipService.setRecordingCall() thread running...");
934 Ringservice.sflph_call_play_recorded_file(filepath);
935 }
936 });
937 return false;
938 }
939
940 @Override
941 public void stopRecordedFilePlayback(final String filepath) throws RemoteException {
942 getExecutor().execute(new SipRunnable() {
943 @Override
944 protected void doRun() throws SameThreadException, RemoteException {
945 Log.i(TAG, "SipService.stopRecordedFilePlayback() thread running...");
946 Ringservice.sflph_call_stop_recorded_file(filepath);
947 }
948 });
949 }
950
951 @Override
952 public void setRecordPath(final String path) throws RemoteException {
953 getExecutor().execute(new SipRunnable() {
954 @Override
955 protected void doRun() throws SameThreadException, RemoteException {
956 Log.i(TAG, "SipService.setRecordPath() " + path + " thread running...");
957 Ringservice.sflph_config_set_record_path(path);
958 }
959 });
960 }
961
962 @Override
963 public void sendTextMessage(final String callID, final SipMessage message) throws RemoteException {
964 getExecutor().execute(new SipRunnable() {
965 @Override
966 protected void doRun() throws SameThreadException, RemoteException {
967 Log.i(TAG, "SipService.sendTextMessage() thread running...");
968 Ringservice.sflph_call_send_text_message(callID, message.comment);
969 if (getConferences().get(callID) != null)
970 getConferences().get(callID).addSipMessage(message);
971 }
972 });
973
974 }
975
976 @Override
977 public List getAudioCodecList(final String accountID) throws RemoteException {
978 class AudioCodecList extends SipRunnableWithReturn {
979
980 @Override
981 protected ArrayList<Codec> doRun() throws SameThreadException {
982 Log.i(TAG, "SipService.getAudioCodecList() thread running...");
983 ArrayList<Codec> results = new ArrayList<Codec>();
984
985 IntVect active_payloads = Ringservice.sflph_config_get_active_audio_codec_list(accountID);
986 for (int i = 0; i < active_payloads.size(); ++i) {
987
988 results.add(new Codec(active_payloads.get(i), Ringservice.sflph_config_get_audio_codec_details(active_payloads.get(i)), true));
989
990 }
991 IntVect payloads = Ringservice.sflph_config_get_audio_codec_list();
992
993 for (int i = 0; i < payloads.size(); ++i) {
994 boolean isActive = false;
995 for (Codec co : results) {
996 if (co.getPayload().toString().contentEquals(String.valueOf(payloads.get(i))))
997 isActive = true;
998
999 }
1000 if (isActive)
1001 continue;
1002 else
1003 results.add(new Codec(payloads.get(i), Ringservice.sflph_config_get_audio_codec_details(payloads.get(i)), false));
1004
1005 }
1006
1007 return results;
1008 }
1009 }
1010
1011 AudioCodecList runInstance = new AudioCodecList();
1012 getExecutor().execute(runInstance);
1013 while (!runInstance.isDone()) {
1014 }
1015 return (ArrayList<Codec>) runInstance.getVal();
1016 }
1017
1018 @Override
1019 public Map getRingtoneList() throws RemoteException {
1020 class RingtoneList extends SipRunnableWithReturn {
1021
1022 @Override
1023 protected StringMap doRun() throws SameThreadException {
1024 Log.i(TAG, "SipService.getRingtoneList() thread running...");
1025 return Ringservice.sflph_config_get_ringtone_list();
1026 }
1027 }
1028
1029 RingtoneList runInstance = new RingtoneList();
1030 getExecutor().execute(runInstance);
1031 while (!runInstance.isDone()) {
1032 }
1033 StringMap ringtones = (StringMap) runInstance.getVal();
1034
1035 for (int i = 0; i < ringtones.size(); ++i) {
1036 // Log.i(TAG,"ringtones "+i+" "+ ringtones.);
1037 }
1038
1039 return null;
1040 }
1041
1042 @Override
1043 public boolean checkForPrivateKey(final String pemPath) throws RemoteException {
1044 class hasPrivateKey extends SipRunnableWithReturn {
1045
1046 @Override
1047 protected Boolean doRun() throws SameThreadException {
1048 Log.i(TAG, "SipService.isCaptureMuted() thread running...");
1049 return Ringservice.sflph_config_check_for_private_key(pemPath);
1050 }
1051 }
1052
1053 hasPrivateKey runInstance = new hasPrivateKey();
1054 getExecutor().execute(runInstance);
1055 while (!runInstance.isDone()) {
1056 }
1057
1058 return (Boolean) runInstance.getVal();
1059 }
1060
1061 @Override
1062 public boolean checkCertificateValidity(final String pemPath) throws RemoteException {
1063 class isValid extends SipRunnableWithReturn {
1064
1065 @Override
1066 protected Boolean doRun() throws SameThreadException {
1067 Log.i(TAG, "SipService.isCaptureMuted() thread running...");
1068 return Ringservice.sflph_config_check_certificate_validity(pemPath, pemPath);
1069 }
1070 }
1071
1072 isValid runInstance = new isValid();
1073 getExecutor().execute(runInstance);
1074 while (!runInstance.isDone()) {
1075 }
1076
1077 return (Boolean) runInstance.getVal();
1078 }
1079
1080 @Override
1081 public boolean checkHostnameCertificate(final String certificatePath, final String host, final String port) throws RemoteException {
1082 class isValid extends SipRunnableWithReturn {
1083
1084 @Override
1085 protected Boolean doRun() throws SameThreadException {
1086 Log.i(TAG, "SipService.isCaptureMuted() thread running...");
1087 return Ringservice.sflph_config_check_hostname_certificate(host, port);
1088 }
1089 }
1090
1091 isValid runInstance = new isValid();
1092 getExecutor().execute(runInstance);
1093 while (!runInstance.isDone()) {
1094 }
1095
1096 return (Boolean) runInstance.getVal();
1097 }
1098
1099 @Override
1100 public void setActiveCodecList(final List codecs, final String accountID) throws RemoteException {
1101 getExecutor().execute(new SipRunnable() {
1102 @Override
1103 protected void doRun() throws SameThreadException, RemoteException {
1104 Log.i(TAG, "SipService.setActiveAudioCodecList() thread running...");
1105 StringVect list = new StringVect();
1106 for (Object codec : codecs) {
1107 list.add((String) codec);
1108 }
1109 Ringservice.sflph_config_set_active_audio_codec_list(list, accountID);
1110 }
1111 });
1112 }
1113
1114
1115 @Override
1116 public Conference getCurrentCall() throws RemoteException {
1117 for (Conference conf : mConferences.values()) {
1118 if (conf.isIncoming())
1119 return conf;
1120 }
1121
1122 for (Conference conf : mConferences.values()) {
1123 if (conf.isOnGoing())
1124 return conf;
1125 }
1126
1127 return null;
1128 }
1129
1130 @Override
1131 public void playDtmf(final String key) throws RemoteException {
1132 getExecutor().execute(new SipRunnable() {
1133 @Override
1134 protected void doRun() throws SameThreadException, RemoteException {
1135 Log.i(TAG, "SipService.playDtmf() thread running...");
1136 Ringservice.sflph_call_play_dtmf(key);
1137 }
1138 });
1139 }
1140
1141 @Override
1142 public List getConcurrentCalls() throws RemoteException {
1143 return new ArrayList(mConferences.values());
1144 }
1145
1146 @Override
1147 public Conference getConference(String id) throws RemoteException {
1148 return mConferences.get(id);
1149 }
1150
1151 @Override
1152 public void setMuted(final boolean mute) throws RemoteException {
1153 getExecutor().execute(new SipRunnable() {
1154 @Override
1155 protected void doRun() throws SameThreadException, RemoteException {
1156 Log.i(TAG, "SipService.setMuted() thread running...");
1157 Ringservice.sflph_config_mute_capture(mute);
1158 }
1159 });
1160 }
1161
1162 @Override
1163 public boolean isCaptureMuted() throws RemoteException {
1164 class IsMuted extends SipRunnableWithReturn {
1165
1166 @Override
1167 protected Boolean doRun() throws SameThreadException {
1168 Log.i(TAG, "SipService.isCaptureMuted() thread running...");
1169 return Ringservice.sflph_config_is_capture_muted();
1170 }
1171 }
1172
1173 IsMuted runInstance = new IsMuted();
1174 getExecutor().execute(runInstance);
1175 while (!runInstance.isDone()) {
1176 }
1177
1178 return (Boolean) runInstance.getVal();
1179 }
1180
1181 @Override
1182 public void confirmSAS(final String callID) throws RemoteException {
1183 getExecutor().execute(new SipRunnable() {
1184 @Override
1185 protected void doRun() throws SameThreadException, RemoteException {
1186 Log.i(TAG, "SipService.confirmSAS() thread running...");
1187 SecureSipCall call = (SecureSipCall) getCallById(callID);
1188 call.setSASConfirmed(true);
1189 Ringservice.sflph_call_set_sas_verified(callID);
1190 }
1191 });
1192 }
1193
1194
1195 @Override
1196 public List getTlsSupportedMethods(){
1197 class TlsMethods extends SipRunnableWithReturn {
1198
1199 @Override
1200 protected List doRun() throws SameThreadException {
1201 Log.i(TAG, "SipService.getCredentials() thread running...");
1202 StringVect map = Ringservice.sflph_config_get_supported_tls_method();
1203 return SwigNativeConverter.convertSwigToNative(map);
1204 }
1205 }
1206
1207 TlsMethods runInstance = new TlsMethods();
1208 getExecutor().execute(runInstance);
1209 while (!runInstance.isDone()) {
1210 }
1211 return (List) runInstance.getVal();
1212 }
1213
1214 @Override
1215 public List getCredentials(final String accountID) throws RemoteException {
1216 class Credentials extends SipRunnableWithReturn {
1217
1218 @Override
1219 protected List doRun() throws SameThreadException {
1220 Log.i(TAG, "SipService.getCredentials() thread running...");
1221 VectMap map = Ringservice.sflph_config_get_credentials(accountID);
1222 return SwigNativeConverter.convertCredentialsToNative(map);
1223 }
1224 }
1225
1226 Credentials runInstance = new Credentials();
1227 getExecutor().execute(runInstance);
1228 while (!runInstance.isDone()) {
1229 }
1230 return (List) runInstance.getVal();
1231 }
1232
1233 @Override
1234 public void setCredentials(final String accountID, final List creds) throws RemoteException {
1235 getExecutor().execute(new SipRunnable() {
1236 @Override
1237 protected void doRun() throws SameThreadException, RemoteException {
1238 Log.i(TAG, "SipService.setCredentials() thread running...");
1239 ArrayList<HashMap<String, String>> list = (ArrayList<HashMap<String, String>>) creds;
1240 Ringservice.sflph_config_set_credentials(accountID, SwigNativeConverter.convertFromNativeToSwig(creds));
1241 }
1242 });
1243 }
1244
1245 @Override
1246 public void registerAllAccounts() throws RemoteException {
1247 getExecutor().execute(new SipRunnable() {
1248 @Override
1249 protected void doRun() throws SameThreadException, RemoteException {
1250 Log.i(TAG, "SipService.registerAllAccounts() thread running...");
1251 Ringservice.sflph_config_register_all_accounts();
1252 }
1253 });
1254 }
1255
1256 @Override
1257 public void toggleSpeakerPhone(boolean toggle) throws RemoteException {
1258 if (toggle)
1259 mMediaManager.RouteToSpeaker();
1260 else
1261 mMediaManager.RouteToInternalSpeaker();
1262 }
1263
1264 };
1265
1266 private void removeCall(String callID) {
1267 Conference conf = findConference(callID);
1268 if(conf == null)
1269 return;
1270 if(conf.getParticipants().size() == 1)
1271 getConferences().remove(conf.getId());
1272 else
1273 conf.removeParticipant(conf.getCallById(callID));
1274 }
1275
1276 protected Conference findConference(String callID) {
1277 Conference result = null;
1278 if (getConferences().get(callID) != null) {
1279 result = getConferences().get(callID);
1280 } else {
1281 for (Entry<String, Conference> stringConferenceEntry : getConferences().entrySet()) {
1282 Conference tmp = stringConferenceEntry.getValue();
1283 for (SipCall c : tmp.getParticipants()) {
1284 if (c.getCallId().contentEquals(callID)) {
1285 result = tmp;
1286 }
1287 }
1288 }
1289 }
1290 return result;
1291 }
1292}