1/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.net.sip;
18
19import android.os.RemoteException;
20import android.util.Log;
21
22/**
23 * Represents a SIP session that is associated with a SIP dialog or a standalone
24 * transaction not within a dialog.
25 * <p>You can get a {@link SipSession} from {@link SipManager} with {@link
26 * SipManager#createSipSession createSipSession()} (when initiating calls) or {@link
27 * SipManager#getSessionFor getSessionFor()} (when receiving calls).</p>
28 */
29public final class SipSession {
30    private static final String TAG = "SipSession";
31
32    /**
33     * Defines SIP session states, such as "registering", "outgoing call", and "in call".
34     */
35    public static class State {
36        /** When session is ready to initiate a call or transaction. */
37        public static final int READY_TO_CALL = 0;
38
39        /** When the registration request is sent out. */
40        public static final int REGISTERING = 1;
41
42        /** When the unregistration request is sent out. */
43        public static final int DEREGISTERING = 2;
44
45        /** When an INVITE request is received. */
46        public static final int INCOMING_CALL = 3;
47
48        /** When an OK response is sent for the INVITE request received. */
49        public static final int INCOMING_CALL_ANSWERING = 4;
50
51        /** When an INVITE request is sent. */
52        public static final int OUTGOING_CALL = 5;
53
54        /** When a RINGING response is received for the INVITE request sent. */
55        public static final int OUTGOING_CALL_RING_BACK = 6;
56
57        /** When a CANCEL request is sent for the INVITE request sent. */
58        public static final int OUTGOING_CALL_CANCELING = 7;
59
60        /** When a call is established. */
61        public static final int IN_CALL = 8;
62
63        /** When an OPTIONS request is sent. */
64        public static final int PINGING = 9;
65
66        /** When ending a call. @hide */
67        public static final int ENDING_CALL = 10;
68
69        /** Not defined. */
70        public static final int NOT_DEFINED = 101;
71
72        /**
73         * Converts the state to string.
74         */
75        public static String toString(int state) {
76            switch (state) {
77                case READY_TO_CALL:
78                    return "READY_TO_CALL";
79                case REGISTERING:
80                    return "REGISTERING";
81                case DEREGISTERING:
82                    return "DEREGISTERING";
83                case INCOMING_CALL:
84                    return "INCOMING_CALL";
85                case INCOMING_CALL_ANSWERING:
86                    return "INCOMING_CALL_ANSWERING";
87                case OUTGOING_CALL:
88                    return "OUTGOING_CALL";
89                case OUTGOING_CALL_RING_BACK:
90                    return "OUTGOING_CALL_RING_BACK";
91                case OUTGOING_CALL_CANCELING:
92                    return "OUTGOING_CALL_CANCELING";
93                case IN_CALL:
94                    return "IN_CALL";
95                case PINGING:
96                    return "PINGING";
97                default:
98                    return "NOT_DEFINED";
99            }
100        }
101
102        private State() {
103        }
104    }
105
106    /**
107     * Listener for events relating to a SIP session, such as when a session is being registered
108     * ("on registering") or a call is outgoing ("on calling").
109     * <p>Many of these events are also received by {@link SipAudioCall.Listener}.</p>
110     */
111    public static class Listener {
112        /**
113         * Called when an INVITE request is sent to initiate a new call.
114         *
115         * @param session the session object that carries out the transaction
116         */
117        public void onCalling(SipSession session) {
118        }
119
120        /**
121         * Called when an INVITE request is received.
122         *
123         * @param session the session object that carries out the transaction
124         * @param caller the SIP profile of the caller
125         * @param sessionDescription the caller's session description
126         */
127        public void onRinging(SipSession session, SipProfile caller,
128                String sessionDescription) {
129        }
130
131        /**
132         * Called when a RINGING response is received for the INVITE request sent
133         *
134         * @param session the session object that carries out the transaction
135         */
136        public void onRingingBack(SipSession session) {
137        }
138
139        /**
140         * Called when the session is established.
141         *
142         * @param session the session object that is associated with the dialog
143         * @param sessionDescription the peer's session description
144         */
145        public void onCallEstablished(SipSession session,
146                String sessionDescription) {
147        }
148
149        /**
150         * Called when the session is terminated.
151         *
152         * @param session the session object that is associated with the dialog
153         */
154        public void onCallEnded(SipSession session) {
155        }
156
157        /**
158         * Called when the peer is busy during session initialization.
159         *
160         * @param session the session object that carries out the transaction
161         */
162        public void onCallBusy(SipSession session) {
163        }
164
165        /**
166         * Called when the call is being transferred to a new one.
167         *
168         * @hide
169         * @param newSession the new session that the call will be transferred to
170         * @param sessionDescription the new peer's session description
171         */
172        public void onCallTransferring(SipSession newSession,
173                String sessionDescription) {
174        }
175
176        /**
177         * Called when an error occurs during session initialization and
178         * termination.
179         *
180         * @param session the session object that carries out the transaction
181         * @param errorCode error code defined in {@link SipErrorCode}
182         * @param errorMessage error message
183         */
184        public void onError(SipSession session, int errorCode,
185                String errorMessage) {
186        }
187
188        /**
189         * Called when an error occurs during session modification negotiation.
190         *
191         * @param session the session object that carries out the transaction
192         * @param errorCode error code defined in {@link SipErrorCode}
193         * @param errorMessage error message
194         */
195        public void onCallChangeFailed(SipSession session, int errorCode,
196                String errorMessage) {
197        }
198
199        /**
200         * Called when a registration request is sent.
201         *
202         * @param session the session object that carries out the transaction
203         */
204        public void onRegistering(SipSession session) {
205        }
206
207        /**
208         * Called when registration is successfully done.
209         *
210         * @param session the session object that carries out the transaction
211         * @param duration duration in second before the registration expires
212         */
213        public void onRegistrationDone(SipSession session, int duration) {
214        }
215
216        /**
217         * Called when the registration fails.
218         *
219         * @param session the session object that carries out the transaction
220         * @param errorCode error code defined in {@link SipErrorCode}
221         * @param errorMessage error message
222         */
223        public void onRegistrationFailed(SipSession session, int errorCode,
224                String errorMessage) {
225        }
226
227        /**
228         * Called when the registration gets timed out.
229         *
230         * @param session the session object that carries out the transaction
231         */
232        public void onRegistrationTimeout(SipSession session) {
233        }
234    }
235
236    private final ISipSession mSession;
237    private Listener mListener;
238
239    SipSession(ISipSession realSession) {
240        mSession = realSession;
241        if (realSession != null) {
242            try {
243                realSession.setListener(createListener());
244            } catch (RemoteException e) {
245                Log.e(TAG, "SipSession.setListener(): " + e);
246            }
247        }
248    }
249
250    SipSession(ISipSession realSession, Listener listener) {
251        this(realSession);
252        setListener(listener);
253    }
254
255    /**
256     * Gets the IP address of the local host on which this SIP session runs.
257     *
258     * @return the IP address of the local host
259     */
260    public String getLocalIp() {
261        try {
262            return mSession.getLocalIp();
263        } catch (RemoteException e) {
264            Log.e(TAG, "getLocalIp(): " + e);
265            return "127.0.0.1";
266        }
267    }
268
269    /**
270     * Gets the SIP profile that this session is associated with.
271     *
272     * @return the SIP profile that this session is associated with
273     */
274    public SipProfile getLocalProfile() {
275        try {
276            return mSession.getLocalProfile();
277        } catch (RemoteException e) {
278            Log.e(TAG, "getLocalProfile(): " + e);
279            return null;
280        }
281    }
282
283    /**
284     * Gets the SIP profile that this session is connected to. Only available
285     * when the session is associated with a SIP dialog.
286     *
287     * @return the SIP profile that this session is connected to
288     */
289    public SipProfile getPeerProfile() {
290        try {
291            return mSession.getPeerProfile();
292        } catch (RemoteException e) {
293            Log.e(TAG, "getPeerProfile(): " + e);
294            return null;
295        }
296    }
297
298    /**
299     * Gets the session state. The value returned must be one of the states in
300     * {@link State}.
301     *
302     * @return the session state
303     */
304    public int getState() {
305        try {
306            return mSession.getState();
307        } catch (RemoteException e) {
308            Log.e(TAG, "getState(): " + e);
309            return State.NOT_DEFINED;
310        }
311    }
312
313    /**
314     * Checks if the session is in a call.
315     *
316     * @return true if the session is in a call
317     */
318    public boolean isInCall() {
319        try {
320            return mSession.isInCall();
321        } catch (RemoteException e) {
322            Log.e(TAG, "isInCall(): " + e);
323            return false;
324        }
325    }
326
327    /**
328     * Gets the call ID of the session.
329     *
330     * @return the call ID
331     */
332    public String getCallId() {
333        try {
334            return mSession.getCallId();
335        } catch (RemoteException e) {
336            Log.e(TAG, "getCallId(): " + e);
337            return null;
338        }
339    }
340
341
342    /**
343     * Sets the listener to listen to the session events. A {@code SipSession}
344     * can only hold one listener at a time. Subsequent calls to this method
345     * override the previous listener.
346     *
347     * @param listener to listen to the session events of this object
348     */
349    public void setListener(Listener listener) {
350        mListener = listener;
351    }
352
353
354    /**
355     * Performs registration to the server specified by the associated local
356     * profile. The session listener is called back upon success or failure of
357     * registration. The method is only valid to call when the session state is
358     * in {@link State#READY_TO_CALL}.
359     *
360     * @param duration duration in second before the registration expires
361     * @see Listener
362     */
363    public void register(int duration) {
364        try {
365            mSession.register(duration);
366        } catch (RemoteException e) {
367            Log.e(TAG, "register(): " + e);
368        }
369    }
370
371    /**
372     * Performs unregistration to the server specified by the associated local
373     * profile. Unregistration is technically the same as registration with zero
374     * expiration duration. The session listener is called back upon success or
375     * failure of unregistration. The method is only valid to call when the
376     * session state is in {@link State#READY_TO_CALL}.
377     *
378     * @see Listener
379     */
380    public void unregister() {
381        try {
382            mSession.unregister();
383        } catch (RemoteException e) {
384            Log.e(TAG, "unregister(): " + e);
385        }
386    }
387
388    /**
389     * Initiates a call to the specified profile. The session listener is called
390     * back upon defined session events. The method is only valid to call when
391     * the session state is in {@link State#READY_TO_CALL}.
392     *
393     * @param callee the SIP profile to make the call to
394     * @param sessionDescription the session description of this call
395     * @param timeout the session will be timed out if the call is not
396     *        established within {@code timeout} seconds. Default value (defined
397     *        by SIP protocol) is used if {@code timeout} is zero or negative.
398     * @see Listener
399     */
400    public void makeCall(SipProfile callee, String sessionDescription,
401            int timeout) {
402        try {
403            mSession.makeCall(callee, sessionDescription, timeout);
404        } catch (RemoteException e) {
405            Log.e(TAG, "makeCall(): " + e);
406        }
407    }
408
409    /**
410     * Answers an incoming call with the specified session description. The
411     * method is only valid to call when the session state is in
412     * {@link State#INCOMING_CALL}.
413     *
414     * @param sessionDescription the session description to answer this call
415     * @param timeout the session will be timed out if the call is not
416     *        established within {@code timeout} seconds. Default value (defined
417     *        by SIP protocol) is used if {@code timeout} is zero or negative.
418     */
419    public void answerCall(String sessionDescription, int timeout) {
420        try {
421            mSession.answerCall(sessionDescription, timeout);
422        } catch (RemoteException e) {
423            Log.e(TAG, "answerCall(): " + e);
424        }
425    }
426
427    /**
428     * Ends an established call, terminates an outgoing call or rejects an
429     * incoming call. The method is only valid to call when the session state is
430     * in {@link State#IN_CALL},
431     * {@link State#INCOMING_CALL},
432     * {@link State#OUTGOING_CALL} or
433     * {@link State#OUTGOING_CALL_RING_BACK}.
434     */
435    public void endCall() {
436        try {
437            mSession.endCall();
438        } catch (RemoteException e) {
439            Log.e(TAG, "endCall(): " + e);
440        }
441    }
442
443    /**
444     * Changes the session description during a call. The method is only valid
445     * to call when the session state is in {@link State#IN_CALL}.
446     *
447     * @param sessionDescription the new session description
448     * @param timeout the session will be timed out if the call is not
449     *        established within {@code timeout} seconds. Default value (defined
450     *        by SIP protocol) is used if {@code timeout} is zero or negative.
451     */
452    public void changeCall(String sessionDescription, int timeout) {
453        try {
454            mSession.changeCall(sessionDescription, timeout);
455        } catch (RemoteException e) {
456            Log.e(TAG, "changeCall(): " + e);
457        }
458    }
459
460    ISipSession getRealSession() {
461        return mSession;
462    }
463
464    private ISipSessionListener createListener() {
465        return new ISipSessionListener.Stub() {
466            public void onCalling(ISipSession session) {
467                if (mListener != null) {
468                    mListener.onCalling(SipSession.this);
469                }
470            }
471
472            public void onRinging(ISipSession session, SipProfile caller,
473                    String sessionDescription) {
474                if (mListener != null) {
475                    mListener.onRinging(SipSession.this, caller,
476                            sessionDescription);
477                }
478            }
479
480            public void onRingingBack(ISipSession session) {
481                if (mListener != null) {
482                    mListener.onRingingBack(SipSession.this);
483                }
484            }
485
486            public void onCallEstablished(ISipSession session,
487                    String sessionDescription) {
488                if (mListener != null) {
489                    mListener.onCallEstablished(SipSession.this,
490                            sessionDescription);
491                }
492            }
493
494            public void onCallEnded(ISipSession session) {
495                if (mListener != null) {
496                    mListener.onCallEnded(SipSession.this);
497                }
498            }
499
500            public void onCallBusy(ISipSession session) {
501                if (mListener != null) {
502                    mListener.onCallBusy(SipSession.this);
503                }
504            }
505
506            public void onCallTransferring(ISipSession session,
507                    String sessionDescription) {
508                if (mListener != null) {
509                    mListener.onCallTransferring(
510                            new SipSession(session, SipSession.this.mListener),
511                            sessionDescription);
512
513                }
514            }
515
516            public void onCallChangeFailed(ISipSession session, int errorCode,
517                    String message) {
518                if (mListener != null) {
519                    mListener.onCallChangeFailed(SipSession.this, errorCode,
520                            message);
521                }
522            }
523
524            public void onError(ISipSession session, int errorCode, String message) {
525                if (mListener != null) {
526                    mListener.onError(SipSession.this, errorCode, message);
527                }
528            }
529
530            public void onRegistering(ISipSession session) {
531                if (mListener != null) {
532                    mListener.onRegistering(SipSession.this);
533                }
534            }
535
536            public void onRegistrationDone(ISipSession session, int duration) {
537                if (mListener != null) {
538                    mListener.onRegistrationDone(SipSession.this, duration);
539                }
540            }
541
542            public void onRegistrationFailed(ISipSession session, int errorCode,
543                    String message) {
544                if (mListener != null) {
545                    mListener.onRegistrationFailed(SipSession.this, errorCode,
546                            message);
547                }
548            }
549
550            public void onRegistrationTimeout(ISipSession session) {
551                if (mListener != null) {
552                    mListener.onRegistrationTimeout(SipSession.this);
553                }
554            }
555        };
556    }
557}
558