æ¦èª¬SipDemo(Android2.3 SIP APIã試ã)
[,w400,h300]
[Nexus SããHTC Desireã«é»è©±ãã¦ãæ§å]
Android2.3(gingerbread)ã§è¿½å ãããAPIã®ä¸ã¤ã§ããSIP APIã試ãã¦ã¿ã¾ããã
Android SDK 2.3ã«å梱ããã¦ããSipDemoã¨ããããã¸ã§ã¯ãã使ã£ã¦ã©ã®æ§ãªæé ã§SIPé話ãå®ç¾ãã¦ããã解説ãã¾ãã
å®æ½ç°å¢
çºä¿¡å´:
ãã端æ«:Nexus S
ããã¢ããª:SipDemo
çä¿¡å´:
ãã端æ«:HTC Desire (android2.2)
ããã¢ããª:Sipdroid version 2.0.1 beta
æºå
ã¾ãSIPã§é話ããçºã«SIPã¢ã«ã¦ã³ããåå¾ãã¾ãããAndroid2.3ã§ã¯SIPé話ã®çºã®å種APIãæä¾ãã¦ããã¾ãããSIPã¢ã«ã¦ã³ããSIPãããã¤ãã¾ã§ã¯æä¾ãã¦ããã¾ããããã£ãGoogleãSIPãããã¤ãè²·åãã¦çµ±åãã¡ãã£ã¦ãããã¨ãããããã§ããã»ã»ã»ã
ä»åã¯iptel.orgã¨ããç¡æã®SIPãããã¤ããå©ç¨ãã¾ããã
ããã§çºä¿¡ãçä¿¡ç¨ã®äºã¤ã®ã¢ã«ã¦ã³ããä½æãã¾ãããiptel.orgã®ãã¼ã¸ã®ä¸é¨ã®ãSubscribe!ãããæ°è¦ã¢ã«ã¦ã³ãã®ä½æãã§ãã¾ãã
é話ãã¦ã¿ã
ã¨ããããé話ããã¦ã¿ã¾ãã
SipDemoããã«ããã¦Nexus Sã«ã¤ã³ã¹ãã¼ã«ããèµ·åããã¨ä»¥ä¸ã®æ§ãªç»é¢ãç¾ãã¾ãã
[,w320,h480]
èªåã®SIPã¢ã«ã¦ã³ããè¨å®ãã¦ããªãå ´åã¯ä»¥ä¸ã®ãã¤ã¢ãã°ã表示ããã¾ãã
OKãé¸æããã¨ã¢ã«ã¦ã³ãè¨å®ç»é¢ãéãã¾ãã
[,w320,h480]
ã¢ã«ã¦ã³ãè¨å®ç»é¢ã§ãSIPã¢ã«ã¦ã³ãããã¹ã¯ã¼ããSIPãããã¤ãã®ãã¡ã¤ã³ãè¨å®ãã¾ãã
[,w320,h480]
è¨å®ãå®äºããã¨ãSIPãããã¤ãã«REGISTERã試ã¿ã¾ããæåããã¨ããReadyãã®æååã表示ããã¾ãã
[,w320,h480]
ãReadyãã®ç¶æ
ã§ã¡ãã¥ã¼ã表示ãããCall someoneããé¸æãã¾ãã
[,w320,h480]
çºä¿¡ããç¸æå
ãå
¥åãããã¤ã¢ãã°ã表示ããã¾ãã
ããã«ç¸æã®SIPURI(ä¾:moge@sip.hoge.jp)ãå
¥åãããOKããã¿ã³ãæ¼ä¸ããã¨ç¸æã«INVAITEãã¾ãã
[,w320,h480]
é話ã«æåããå ´åããã¤ã¯ãã¿ãããã¦ããéãèªåã®å£°ãç¸æã«éä¿¡ãã¾ãã
[,w320,h480]
SipDemoããã³APIã®èª¬æ
â SipDemoã®å ´æ
ããAndroid SDK Samples for Android API 9, revision 1ããã¤ã³ã¹ãã¼ã«ããã¦ããã°ä¸è¨ã®å ´æã«ããã¸ã§ã¯ããããã¯ãã§ãã
ãããã
â SipDemoã®æ§æ
ãSipDemoã®ãã¡ã¤ã«æ§æã§ããXMLãã¡ã¤ã«é¡ã¯ç¹ã«æ°ã«ãããããªãã®ã¯ç¡ãã£ãã®ã§å²æãã¾ãã
ããIncomingCallReceiver.javaã//çä¿¡ãåããBroadcastReceiver
ããSipSettings.javaã//SIPãããã¡ã¤ã«ã®è¨å®ãè¡ãPreferenceActivity
ããWalkieTalkieActivity.javaã//SIPãããã¡ã¤ã«ã®åæåãREGISTERãçºä¿¡çãè¡ãActivity
â AndroidManifest.xml
ãAndroidã§SIPãå©ç¨ããå ´åãAndroidManifest.xmlã«ä»¥ä¸ã®uses-permissionã追å ãã¦ãããå¿
è¦ãããã¾ãã
ããandroid.permission.USE_SIP
ããandroid.permission.INTERNET
ããandroid.permission.ACCESS_WIFI_STATE
ããandroid.permission.WAKE_LOCK
ããandroid.permission.RECORD_AUDIO
ããandroid.permission.MODIFY_AUDIO_SETTINGS
ãSipDemoã§ã¯ãã®ãã¡ãandroid.permission.MODIFY_AUDIO_SETTINGSãã®è¨å®ãæãã¦ãã¾ãã®ã§è¿½è¨ãã¦ããå¿ è¦ãããã¾ãããandroid.permission.MODIFY_AUDIO_SETTINGSããç¡ãã¦ãåä½ãã¾ãããé³å£°è¨å®å¨ããç¡å¹ã«ãªã£ã¦ãã¾ãã¾ãã
â å©ç¨ããã¯ã©ã¹
ãSIPé話ãè¡ãããã«å©ç¨ããã¯ã©ã¹ã§ãã以ä¸ã®ã¯ã©ã¹ã使ãã ãã§SIPé話ãå®ç¾ããäºãã§ãã¾ãã
ããandroid.net.sip.SipManagerããããããã//SIPãããã¤ãã¸ã®REGISTERãçºä¿¡ãçä¿¡ã管çããã¯ã©ã¹
ããandroid.net.sip.SipProfileãããããããã//èªåã®SIPãããã¡ã¤ã«
ããandroid.net.sip.SipRegistrationListenerã//SIPãããã¤ãã«REGISTERããéã®ãªã¹ã
ããandroid.net.sip.SipAudioCallãããããã//SIPé話ã®é³å£°ã管çãã
ããandroid.net.sip.SipAudioCall.Listenerãã//SIPé話ã®ç¢ºç«ãåæãã¨ã©ã¼çã®ãªã¹ã
ããandroid.net.sip.SipExceptionãããããã//SIPå¨ãã®ä¾å¤
çºä¿¡ã¾ã§ã®æé
ãçºä¿¡ã®å¦çã¯WalkieTalkieActivity.javaã§è¡ã£ã¦ãã¾ãã
- SipManagerãä½æãã
- SipProfileãä½æãã
- SipManager#open(String, SipRegistrationListener)ã§SIPãããã¤ãã«REGISTERãã
- SipManager#makeAudioCall(String ,String, SipAudioCall.Listener, int)ã§ç¸æå ã«é»è©±ãããã
- SipAudioCall.Listener#onCallEstablished(SipAudioCall)ã§é³å£°é話ãéå§ãã
1.SipManagerãä½æãã
ãSipManagerã¯WalkieTalkieActivity.javaã®106è¡ç®ãinitializeManager()ã§ä½æãã¦ãã¾ãã
ãåç´ã«ã¡ã³ãå¤æ°managerãnullã®å ´åSipManager#newInstance(Context)ãå¼ã³åºãã¦ããã ãã§ãã
public void initializeManager() { if(manager == null) { manager = SipManager.newInstance(this); } initializeLocalProfile(); }
2.SipProfileãä½æãã
ãWalkieTalkieActivity.javaã®138è¡ç®ãinitializeLocalProfile()å
ã§SipProfileãä½æãã¦ãã¾ãã
ãSipProfileã®ä½æã¯SipProfile.Builderã¯ã©ã¹ã使ã£ã¦è¡ãã¾ããã³ã³ã¹ãã©ã¯ã¿ã«SIPãããã¤ãã§åå¾ããã¢ã«ã¦ã³ãåãSIPãããã¤ãã®ãã¡ã¤ã³åãè¨å®ãã¾ãã(ä¾:[email protected]ã®å ´åããhogeããã¢ã«ã¦ã³ãåã§ãsip.moge.jpãããã¡ã¤ã³åã¨ãªãã¾ãã)
ãBuilderãnewãããã¨setPassword(String)ã§ã¢ã«ã¦ã³ãã®ãã¹ã¯ã¼ããã»ãããã¾ããæå¾ã«SipProfile.Builder#build()ãå¼ã³åºãSipProfileãä½æãã¾ãã
SipProfile.Builder builder = new SipProfile.Builder(username, domain); builder.setPassword(password); me = builder.build(); //meã¯ã¡ã³ãå¤æ°ãSipProfileå
3.SipManager#open(SipProfile, String, SipRegistrationListener)ã§SIPãããã¤ãã«REGISTERãã
ãWalkieTalkieActivity.javaã®142è¡ç®ãinitializeLocalProfile()å
ã§SipProfileãä½æããå¾ãSipManager#openã§SIPãããã¤ãã«å¯¾ãã¦REGISTERãè¡ãã¾ãã
ãopenããéã«SipRegistrationListenerã§REGISTERã®çµæãåãåãã¾ããä½æ
ããªã¹ãã®ã»ããã¯SipManager#openãå¼ã³åºããå¾ã«ãããã¨ã®äºã
ãSipRegistrationListenerã¯ä»¥ä¸ã®3ã¤ã®ã³ã¼ã«ããã¯ãæã¡ã¾ãã
- public void onRegistering(String localProfileUri)ããããããããããããããããããããããã//REGISTERä¸
- public void onRegistrationDone(String localProfileUri, long expiryTime)ãããããããããããã//REGISTERæå
- public void onRegistrationFailed(String localProfileUri, int errorCode, String errorMessage)ãã//REGISTER失æ
ãSipDemoã§ã¯ãããã®ã³ã¼ã«ããã¯æã«ãç»é¢ã«å種ç¶æ
ã®æååã表示ããã¦ãã¾ãã
ãSipManager#openãããéã«PendingIntentãã»ãããã¦ãã¾ãããããã¯çä¿¡ã®çºã«å©ç¨ãã¾ãã説æã¯å¾ã»ã©ãã¾ãã
Intent i = new Intent();i.setAction("android.SipDemo.INCOMING_CALL"); PendingIntent pi = PendingIntent.getBroadcast(this, 0, i, Intent.FILL_IN_DATA); manager.open(me, pi, null); // This listener must be added AFTER manager.open is called, // Otherwise the methods aren't guaranteed to fire. manager.setRegistrationListener(me.getUriString(), new SipRegistrationListener() { public void onRegistering(String localProfileUri) { updateStatus("Registering with SIP Server..."); } public void onRegistrationDone(String localProfileUri, long expiryTime) { updateStatus("Ready"); } public void onRegistrationFailed(String localProfileUri, int errorCode, String errorMessage) { updateStatus("Registration failed. Please check settings."); } });
4.SipManager#makeAudioCall(String ,String, SipAudioCall.Listener, int)ã§ç¸æå ã«é»è©±ãããã
ãWalkieTalkieActivity.javaã®197è¡ç®ãinitiateCall()å
ã§SipManager#makeAudioCall(String, String, SipAudioCall.Listener, int)ãå¼ã³åºãã¾ããå¼æ°ã¯èªåã®SIPURI, ç¸æã®SIPURI,SipAudioCall.Listener,ã¿ã¤ã ã¢ã¦ãç§ã§ãã
ãSipAudioCall.Listenerã¯ãªã¹ãã¨ããååã®ããã«ã¯ã©ã¹ã§ããã³ã¼ã«ããã¯ã®ç¨®é¡ãçµæ§å¤ãã®ã§interfaceã ã¨ç
©éã ã¨èããã®ã§ããããï¼å¿
è¦ãªã³ã¼ã«ããã¯ã ããªã¼ãã¼ã©ã¤ããã¦å©ç¨ãã¾ããSipDemoã§ã¯ç¸æãçä¿¡å¾200 OKãè¿ããéä¿¡ã確ç«ãããéã«å¼ã³åºãããonCallEstablished(SipAudioCall)ã¨ãé話ãåæããå ´åã«å¼ã³åºãããonCallEnded(SipAudioCall)ããªã¼ãã¼ã©ã¤ããã¦ãã¾ãã
SipAudioCall.Listener listener = new SipAudioCall.Listener() { // Much of the client's interaction with the SIP Stack will // happen via listeners. Even making an outgoing call, don't // forget to set up a listener to set things up once the call is established. @Override public void onCallEstablished(SipAudioCall call) { call.startAudio(); call.setSpeakerMode(true); call.toggleMute(); updateStatus(call); } @Override public void onCallEnded(SipAudioCall call) { updateStatus("Ready."); } }; call = manager.makeAudioCall(me.getUriString(), sipAddress, listener, 30);
5.SipAudioCall.Listener#onCallEstablished(SipAudioCall)ã§é³å£°é話ãéå§ãã
ãWalkieTalkieActivity.javaã®202è¡ç®ãSipAudioCall.Listener#onCallEstablished(SipAudioCall)ã§SipAudioCall#startAudio()ãå¼ã³åºãé³å£°é話ãéå§ãã¾ãã
ãSipAudioCall#setSpeakerMode(boolean)ã«trueãã»ãããã¦ãã¾ããããã§ãã³ãºãªã³ã®ç¶æ
ã§é話ãéå§ããã¾ããã¾ããSipAudipCall#toggleMute()ãå¼ã³åºãã¦ãã¾ããããã§èªåã®é³å£°ã¯ãã¥ã¼ãããã¾ãããã®ãã¥ã¼ãã¯ã¿ããå¦çã®ä¸ã§ãã¿ããããã¦ããéã ããªã³ãã¨ãã£ãæãã§å®è£
ããã¦ãã¾ããæ®éã®é»è©±ã®æ§ãªåä½ã«ãããå ´åã¯call.toggleMute()ã®è¡ã¨ã¿ããã¤ãã³ãã®å¦çãåé¤ããã ãã§å®ç¾ã§ãã¾ãã
@Override public void onCallEstablished(SipAudioCall call) { call.startAudio(); call.setSpeakerMode(true); call.toggleMute(); updateStatus(call); }
çä¿¡-é話ã¾ã§ã®æé
ãçä¿¡ã¯IncomingCallReceiver.javaã§è¡ãã¾ããIncomingCallReceiverã¯BroadcastReceiverãç¶æ¿ãã¦ãããWalkieTalkieActivityãå®è¡ããã¦ããéã ãçä¿¡ãåãã¾ãã
- IncomingCallReceiverãã·ã¹ãã ã«ç»é²ãã
- SipManagerã«çä¿¡æã«å®è¡ãããPendingIntentãç»é²ãã
- SipManagerãä½æãã
- SipProfileãä½æãã
- SipManager#open(String, SipRegistrationListener)ã§SIPãããã¤ãã«REGISTERãã
- IncomingCallReceiver#onReceive(Context, Intent)ã§é話ãéå§ãã
1.IncomingCallReceiverãã·ã¹ãã ã«ç»é²ãã
ãWalkieTalkieActivity.javaã®69è¡ç®ãonCreate(Bundle)å
ã§IncomingCallReceiverãã·ã¹ãã ã«ç»é²ãã¾ãã
ãIntentFilterã«ã¯"android.SipDemo.INCOMING_CALL"ãæå®ãã¦ãã¾ãã"android.SipDemo.INCOMING_CALL"ã®ã¢ã¯ã·ã§ã³ãæã¤IntentãBroadcastãããå ´åã«åãåããã¨ããäºã§ãã
// Set up the intent filter. This will be used to fire an // IncomingCallReceiver when someone calls the SIP address used by this // application. IntentFilter filter = new IntentFilter(); filter.addAction("android.SipDemo.INCOMING_CALL"); callReceiver = new IncomingCallReceiver(); this.registerReceiver(callReceiver, filter);
2.SipManagerã«çä¿¡æã«å®è¡ãããPendingIntentãç»é²ãã
ãWalkieTalkieActivity.javaã®142è¡ç®ãinitializeLocalProfile()å
ã§PendingIntentãä½æããSipManager#openã§ç»é²ãã¦ãã¾ãããã®PendingIntentã¯çä¿¡ããã£ãå ´åã«å®è¡ããã¾ãã
ãSipDemoã§ã¯"android.SipDemo.INCOMING_CALL"ã®ã¢ã¯ã·ã§ã³ãBroadcastããPendingIntentãç»é²ãã¦ãã¾ãããã®ã¢ã¯ã·ã§ã³ã¯IncomingCallReceiverãã·ã¹ãã ã«ç»é²ããéã«æå®ããIntentFilterã¨ä¸è´ãã¾ãã
Intent i = new Intent();i.setAction("android.SipDemo.INCOMING_CALL"); PendingIntent pi = PendingIntent.getBroadcast(this, 0, i, Intent.FILL_IN_DATA); manager.open(me, pi, null);
3.SipManagerãä½æãã
çºä¿¡ã¨åããªã®ã§çç¥
4.SipProfileãä½æãã
çºä¿¡ã¨åããªã®ã§çç¥
5.SipManager#open(String, SipRegistrationListener)ã§SIPãããã¤ãã«REGISTERãã
çºä¿¡ã¨åããªã®ã§çç¥
6.IncomingCallReceiver#onReceive(Context, Intent)ã§é話ãéå§ãã
ãIncomingCallReceiver.javaã®37è¡ç®,onReceive(Context, Intent)ã§çä¿¡ã®å¦çãè¡ã£ã¦ãã¾ãã
ContextãWalkieTalkieActivityã«ãã£ã¹ãããSipManager#takeAudioCall(Intent, SipAudioCall.Listener)ãå¼ã³åºãã¦ãã¾ããSipManager#takeAudioCallãå®è¡ãããã次ã«SipAudioCall.Listener#onRinging(SipAudioCall, SipProfile)ãå¼ã³åºããã¾ããããããå
é¨ã§100 TRYINGã180 RINGINGãçºä¿¡å´ã«è¿ãã¦onRinging(SipAudioCall, SipProfile)ãå¼ã³åºãã¦ããã®ã ã¨æãã¾ããããã§SipAudioCall#answerCall(int)ãå¼ã³åºãã¾ããjavadocãèªãã§ããã¾ãã¡åä½ãä¸æã§ããã200 OKãè¿ãã¦ããã®ã§ã¯ç¡ããã¨æãã¾ããonRingingã®å¾ã«incamingCall.answerCall(30)ãå®è¡ãã¦ãã¾ããæªç¢ºèªã§ããããã®äºåç®ã®answerCallã¯ä¸è¦ãªããããªãããªã¼ã¨æãã¾ãã
ããã®å¾SipAudioCall#startAudio()ã§é話ãéå§ãã¦ãã¾ãã
ãwtActivity.call = incomingCall;ã§WalkieTalkieActivityã®ã¡ã³ãå¤æ°ã«SipAudioCallãè¨å®ãã¦ãã¾ãããWalkieTalkieActivityãçµäºããããã¡ãã¥ã¼ã®ãEnd Current Callããé¸æããæã«SipAudioCall#endCall()ãå®è¡ãããçºã§ãã
@Override public void onReceive(Context context, Intent intent) { SipAudioCall incomingCall = null; try { SipAudioCall.Listener listener = new SipAudioCall.Listener() { @Override public void onRinging(SipAudioCall call, SipProfile caller) { try { call.answerCall(30); } catch (Exception e) { e.printStackTrace(); } } }; WalkieTalkieActivity wtActivity = (WalkieTalkieActivity) context; incomingCall = wtActivity.manager.takeAudioCall(intent, listener); incomingCall.answerCall(30); incomingCall.startAudio(); incomingCall.setSpeakerMode(true); if(incomingCall.isMuted()) { incomingCall.toggleMute(); } wtActivity.call = incomingCall; wtActivity.updateStatus(incomingCall); } catch (Exception e) { if (incomingCall != null) { incomingCall.close(); } } }
æå¾ã«
SIPã«é¢ããé¢åãªã»ã¨ãã©ã®å¦çãSIP APIãæ½è±¡åãã¦ããã¾ããã
ä¸è¨ã§èª¬æããæé ã ãã§SIPé話ãè¡ãã¾ããSIP APIã使ã£ã¦ãä¾ãã°AccountManagerã«ç»é²ããã¦ããGMailã®ã¢ãã¬ã¹ããèªåçã«SIPã¢ã«ã¦ã³ãæãåºããè¡ã£ã¦ããé話ã§ããã¢ããªãã¨ãå²ã¨ç°¡åã«ä½æã§ãããã§ããã
æ責ï¼æè¡é¨ãå «æ¨ ä¿åº (æ°äºº/Androidã¢ããªã±ã¼ã·ã§ã³æè¡è èªå®è©¦é¨ãã¼ã·ãã¯åæ ¼(ç¬)/åå·)