Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
laboratoare:laborator09 [2016/05/05 20:23]
Andrei Roșu-Cojocaru [Implementarea Nativă din Sistemul de Operare Android]
laboratoare:laborator09 [2017/02/20 20:55] (current)
Line 1: Line 1:
 ====== Laborator 09. Gestiunea Apelurilor Telefonice folosind SIP & VoIP ====== ====== Laborator 09. Gestiunea Apelurilor Telefonice folosind SIP & VoIP ======
 +
 +===== SIP (Session Initiation Protocol) =====
 +
 +SIP (Session Initiation Protocol) este un protocol de nivel aplicație, definit de [[https://​www.ietf.org/​rfc/​rfc3261.txt|RFC 3261]], folosit împreună cu alte protocoale pentru a gestiona sesiunile de comunicație multimedia la nivelul Internetului. Este frecvent folosit în cadrul tehnologiei VoIP, una dintre cele mai ieftine, portabile, flexibile și facile soluții pentru transmiterea de conțiunut audio și video prin intermediul rețelei de calculatoare. Singura cerință impusă pentru folosirea tehnologiei VoIP este existența unei legături la Internet.
 +
 +Prin intermediul SIP sunt gestionate **sesiuni** care reprezintă o legătură punct la punct, un canal de comunicație între două entități. Este încorporat în HTTP și SMTP, de la care a preluat arhitectura client-server,​ respectiv schemelor de codificare ale mesajelor, împărțite în antet și corp. SIP folosește SDP (Session Decription Protocol) pentru a califica o sesiune (unicast sau multicast) și RTP (Real Time Transport Protocol) pentru a transmite conținutul multimedia prin intermediul Internetului.
 +
 +În cadrul infrastructurii de comunicație,​ fiecare element este identificat prin intermediul unui URI (Uniform Resource Identifier),​ având un rol determinat:
 +  * **agent utilizator** (//eng.// user agent) reprezintă o entitate care comunică (telefon mobil, tabletă, calculator):​ aceasta poate porni sau opri o sesiune și de asemenea poate opera modificări asupra ei; poate fi de mai multe tipuri:
 +    * UAC (User Agent Client) - entitatea care trimite cererea și primește răspunsul;
 +    * UAS (User Agent Service) - entutatea care primește cererea și trimite răspunsul;
 +  * **agent intermediar** (//eng.// proxy server) reprezintă un element din cadrul rețelei de calculatoare care retransmite mesajul între agenți; acesta poate înțelege conținutul mesajului, pe baza căruia decide pe ce rută să îl ghideze; numărul de astfel de elemente între doi agenți utilizatori este de maximum 70; poate fi de mai multe tipuri:
 +    * cu stare (//eng.// stateful) - reține informații despre mesajele pe care le-a prelucrat și le poate folosi (în situația în care nu se primește nici un răspuns sau în situația în care mesajul ajunge încă o dată sub aceeași formă);
 +    * fără stare (//eng.// stateless) - nu reține informații despre mesajele pe care le-a prelucrat;
 +  * **serverul de înregistrare** (//eng.// registrar server) reține URI-uri despre entități pe care le stochează într-o bază de date și pe care le partajează cu alte servere de înregistrare din cadrul aceluiași domeniu; prin intermediul său, agenții utilizatori se autentifică în cadrul rețelei de calculatoare;​
 +  * **serverul de redirectare** (//eng.// redirect server) verifică baza de date cu locații, transmițând un răspuns către agentul utilizator;
 +  * **serverul de localizare** (//eng.// location server) oferă informații cu privire la plasarea posibilă a agentului utilizator către serverele intermediare sau serverele de redirectare (doar acestea îl pot accesa)
 +
 +Un **flux operațional** standard al unei sesiuni SIP implică următoarele operații:
 +  - tranzacția 1:
 +    - un agent utilizator (sursă) trimite o cerere de tip ''​INVITE''​ către un agent intermediar în scopul de a contacta un alt agent utilizator (destinație);​
 +    - agentul intermediar
 +      - trimite înapoi (imediat) un răspuns de tip ''​100 Trying''​ către agentul utilizator sursă (pentru ca acesta să nu mai transmită nimic);
 +      - caută agentul utilizator destinație folosind un server locație și îi trimite (mai departe) cererea de tip ''​INVITE'';​
 +    - agentul utilizator destinație transmite, prin intermediul agentului intermediar,​ un răspuns de tipul ''​180 Ringing'',​ către agentul utilizator sursă;
 +  - tranzacția 2: în momentul în care agentul utilizator destinație este contactat, acesta transmite, tot prin intermediul agentului intermediar,​ un răspuns de tipul ''​200 OK'',​ către agentul utilizator sursă și, din acest moment, **conexiunea este realizată**,​ transmițându-se pachete RTP în ambele sensuri;
 +  - tranzacțoa 3: orice participant poate transmite un mesaj de tipul ''​200 BYE''​ pentru a termina legătura, fiind necesar ca acesta să fie confirmat prin ''​200 OK''​ de către cealaltă parte.
 +
 +Se observă faptul că o sesiune de comunicare este împărțită în mai multe **tranzacții** care împreună alcătuiesc un **dialog**.
 +
 +**Mesajele** în protocolul SIP sunt de două tipuri:
 +  * **cereri** au forma ''<​METODĂ>​ <​URI>''​ unde metodele pot fi:
 +    * de bază
 +      * ''​INVITE''​ reprezintă o cerere pentru deschiderea unei sesiuni cu un agent utilizator, putând conține informații de tip multimedia în corpul său; aceasta este considerată că a fost îndeplinită cu succes dacă s-a primit un cod de răspuns de tipul ''​2xx''​ sau s-a transmis un ''​ACK'';​ un dialog stabilit între doi agenți utilizatori continuă până în momentul în care se transmite un mesaj de tipul ''​BYE'';​
 +      * ''​BYE''​ este metoda folosită pentru a închide o sesiune cu un agent utilizator, putând fi trimisă de oricare dintre entitățile din canalul de comunicație,​ fără a trece prin serverul de înregistrare;​
 +      * ''​REGISTER''​ indică o cerere de înregistrare a unui agent utilizator către un server de înregistrare;​ un astfel de mesaj este transmis mai departe până ajunge la o entitate care deține autoritatea de a realiza această operație; o înregistrare poate fi realizată de un agent utilizator în numele altui agent utilizator (//eng.// third party registration);​
 +      * ''​CANCEL''​ este operația folosită pentru a închide o sesiune care nu a fost încă deschisă, putând fi transmisă fie de către un agent utilizator fie de către un agent intermediar;​
 +      * ''​ACK''​ este folosit pentru a confirma o cerere de tip ''​INVITE'';​
 +      * ''​OPTIONS''​ este utilizat pentru a interoga un agent utilizator sau un server intermediar despre capabilitățile sale și pentru a determina disponibilitatea sa, rezultatul fiind o listă a funcționalităților entitpții respective;
 +    * extensii: ''​SUBSCRIBE'',​ ''​NOTIFY'',​ ''​REFER'',​ ''​INFO'',​ ''​UPDATE'',​ ''​PRACK'',​ ''​MESSAGE'';​
 +  * **răspunsuri** reprezintă un mesaj generat de un agent utilizator de tip server sau de un server SIP în replică la o cerere provenită de la un agent utilizator de tip client; acesta poate reprezenta inclusiv o confirmare formală pentru a preveni retransmisiile;​ există mai multe tipuri de coduri de răspuns:
 +
 +^ CLASA ^ TIP ^ DESCRIERE ^ ACȚIUNE ^
 +| 1xx | Provizoriu | Informație | Se precizează starea unui apel înainte ca un rezultat să fie disponibil. |
 +| 2xx | Definitiv | Succes | Cererea a fost procesată cu succes. Pentru cereri de tip ''​INVITE''​ se întoarce ''​ACK''​. Pentru alte tipuri cereri, se oprește retransmiterea acestora. |
 +| 3xx |  ::: | Redirectare | Se indică faptul că au fost furnizate mai multe locații posibile astfel încât ar trebui interogat un alt server pentru a se putea obține informația necesară. |
 +| 4xx |  ::: | Eroare la Client | Cererea nu a fost procesată cu succes datorită unei erori la client, fiind necesar ca aceasta să fie reformulată. |
 +| 5xx |  ::: | Eroare la Server | Cererea nu a fost procesată cu succes datorită unei erori la server, putând fi retransmisă către o altă entitate. |
 +| 6xx |  ::: | Eroare Globală | Cererea a eșuat și nu există nici o șansă de a fi procesată corect pe o altă entitate, nici măcar dacă este reformulată. |
 +
 +Exemple:
 +  * ''​100 Trying'',​ ''​180 Ringing'',​ ''​181 Call is Being Forwarded'',​ ''​182 Call Queue'',​ ''​183 Session Progress'';​
 +  * ''​200 OK'',​ ''​202 Accepted'';​
 +  * ''​300 Multiple Choices'',​ ''​301 Moved Permanently'',​ ''​302 Moved Temporarily'',​ ''​305 Use Proxy'',​ ''​380 Alternative Service'';​
 +  * ''​400 Bad Request'',​ ''​401 Unauthorized'',​ ''​403 Forbidden'',​ ''​404 Not Found'',​ ''​405 Method Not Allowed'',​ ''​406 Not Acceptable'',​ ''​407 Proxy Authentication Required'',​ ''​408 Request Timeout'',​ ''​422 Session Timer Interval Too Small'',​ ''​423 Interval Too Brief'',​ ''​480 Temporarily Unavailable'',​ ''​481 Dialog/​Transaction Does Not Exist'',​ ''​483 Too Many Hops'',​ ''​486 Busy Here'',​ ''​487 Request Terminated'';​
 +  * ''​500 Server Internal Error'',​ ''​501 Not Implemented'',​ ''​502 Bad Gateway'',​ ''​503 Service Unavailable'',​ ''​504 Gateway Timeout'',​ ''​505 Version Not Supported'',​ ''​513 Message Too Large'',​ ''​580 Preconditions Failure'';​
 +  * ''​600 Busy Everywhere'',​ ''​603 Decline'',​ ''​604 Does Not Exist Anywhere'',​ ''​606 Not Acceptable''​.
  
 ===== Configurare ===== ===== Configurare =====
Line 78: Line 135:
 === Adrese SIP pentru Testare === === Adrese SIP pentru Testare ===
  
 +Un contact de tip SIP poate fi realizat folosind aplicația nativă //​Contacts//,​ folosind, în mod obișnuit, opțiunea //Create a New Contact//.
  
 +{{ :​laboratoare:​laborator09:​testcall01.png?​nolink&​300 }}
 +
 +{{ :​laboratoare:​laborator09:​testcall02.png?​nolink&​300 }}
 +
 +Adresa SIP la care se plasează apelul telefonic VoIP va fi plasată în secțiunea //Internet call// sau //SIP// (dacă nu este vizibilă, se poate specifica un alt timp de câmp specific contactului prin opțiunea //Add another field//).
 +
 +{{ :​laboratoare:​laborator09:​testcall03.png?​nolink&​300 }}
 +
 +Pot fi folosite următoarele adrese de test:
 +  * ''​thetestcall@getonsip.com'';​
 +  * ''​904@mouselike.org'';​
 +  * ''​301@ideasip.com'';​
 +  * [[http://​www.voip-info.org/​wiki/​view/​Phone+Numbers|altele]].
 +
 +În agenda telefonică,​ contactul respectiv va fi identificat printr-o pictogramă specifică (indicând faptul că acesta este de tip SIP), fiind apelat în mod implicit folosind protocolul respectiv.
 +
 +{{ :​laboratoare:​laborator09:​testcall04.png?​nolink&​300 }}
  
 === Implementarea Nativă din Sistemul de Operare Android === === Implementarea Nativă din Sistemul de Operare Android ===
Line 128: Line 203:
 === Aplicația CSIPSimple === === Aplicația CSIPSimple ===
  
-  * pentru a testa contul se poate folosi stiva Android ​în Phone/Settings/Internet Calling/​Accounts +În cazul în care în aplicația //Phone//, opțiunea //Internet Calling// / //SIP Accounts// nu este disponibilă, poate fi utilizată aplicația ​CSipSimple ​din Play Store. Ulterior descărcării, utilizatorului îi sunt solicitate acordarea ​de permisiuni pentru ca această aplicație să poată fi instalată.
-  * dacă meniul din Phone nu e disponibil, ​se instalează aplicația ​CSIPsimple ​din playstore +
-     * introduceți contul creat la pasul anterior folosind Generic wizard/​Advanced cu setările:​ +
-     * getonsip.com: server=getonsip.com Username=student SIP authentication ID=getonsip_student Password=parola din View Profile Proxy=sip.onsip.com +
-     * pbxes.org: server=pbxes.org Username=student-100 Password=parola extensiei Proxy=pbxes.org,​ restul câmpurilor default. +
-  * se poate face paste din host  în Genymotion cu long press (left click)  +
-  * se creează un contact nou '​testcall'​, și în loc de număr de telefon se selectează 'Add another field'/​Internet Call și se adaugă adresa thetestcall@getonsip.com +
-  * În agendă, persoana testcall va apărea cu o iconiță SIP, și va fi apelată implicit cu SIP +
-  * alte adrese de test: 904@mouselike.org, 301@ideasip.com +
-  * [[http://​www.voip-info.org/​wiki/​view/​Phone+Numbers|alte numere de test]] +
-  * Troubleshooting +
-    * Registration timeout înseamnă că în NAT/SIP nu se translatează corect adresele interne  +
-    * merge pe RDS/4G  +
-    * SSID-uri care nu crează probleme: ACS-UPB-OPEN,​ eduroam, Java-ED117 +
-    * SSID-uri cu probleme: change  ​+
  
-===== Android NGN stack =====+{{ :​laboratoare:​laborator09:​csipsimple01.png?​nolink&​300 }}
  
-Android are o stivă SIP [[http://​developer.android.com/​guide/​topics/​connectivity/​sip.html|nativă]],​ dar nu are încă toate funcționalitățile implementate (instant messenging, video). Totuși, pentru voce, SIP este după Android 2.3 parte a sistemului, sub numele de "​internet calling"​ în Phone/​Settings.  +{{ :laboratoare:​laborator09:​csipsimple02.png?​nolink&​300 }}
  
-Pentru acest laborator, se va folosi NGN (New Generation Networking) SIP stack, cu documantația pentru API de nivel înalt: https://​imsdroid.googlecode.com/​svn-history/​r381/​branches/​2.0/​android-ngn-stack-00.pdf+{{ :laboratoare:laborator09:​csipsimple03.png?​nolink&​300 }}
  
-Această stivă se utilizează în modul următor: se inițializează stiva //​NgnEngine//,​ și un serviciu SIP +{{ :laboratoare:​laborator09:​csipsimple04.png?​nolink&​300 }}
-//​INgnSipService//​. Se continuă cu operația de signin(SIP Registration),​ apoi se pot deschide sesiuni de audio/video //​NgnAVSession//,​ sau instant messenging //​NgnMessagingSession//​.+
  
-Interacțiunile sunt fie imperative: +{{ :​laboratoare:​laborator09:​csipsimple05.png?​nolink&​300 }} 
-  * //INgnSipService.register()// + 
-  * //NgnAVSession.makeCall()// +Aplicația CSipSimple pune la dispoziția utilizatorilor mai multe șabloane pentru definirea unui cont SIP. Se recomandă să se utilizeze //Generic Wizards// → //​Advanced//​ întrucât permite definirea tuturor parametrilor necesari pentru realizarea conexiunii la serverului care găzduiește un astfel de serviciu: 
-  * //NgnMessagingSession.sendTextMessage()// + 
-fie reactive, prin intermediul unor receivere ​care filtrează următoarele evenimente: +{{ :​laboratoare:​laborator09:​csipsimple06.png?​nolink&​300 }} 
-  ​* //NgnRegistrationEventArgs.ACTION_REGISTRATION_EVENT// primește răspunsurile ​de la signin ​(refuz, timeout, succes) + 
-  ​* //NgnInviteEventArgs.ACTION_INVITE_EVENT// primește ​evenimentele legate ​de apel (sună, apel stabilit, apel terminat)  +{{ :​laboratoare:​laborator09:​csipsimple07.png?​nolink&​300 }} 
-  * //​NgnMessagingEventArgs.ACTION_MESSAGING_EVENT// - tratează sosirea unui mesaj IM + 
 +{{ :​laboratoare:​laborator09:​csipsimple08.png?​nolink&​300 }} 
 + 
 +Pentru **contul de tip ''​getonsip.com''​** se precizează următorii parametri: 
 +  * denumirea contului: ''​informaticamobila2016@getonsip.com''​ 
 +  * adresa serverului care pune la dispoziție serviciile SIP: ''​getonsip.com'';​ 
 +  * numele de utilizator: ''​informaticamobila2016''​ 
 +  * identificatorul folosit pentru autentificare,​ de regulă același cu numele de utilizator, prefixat de șirul de caractere ''​getonsip_'':​ ''​getonsip_informaticamobila2016'';​ 
 +  * parola (din secțiunea ​//View Profile//, nu cea folosită la definirea contului);​ 
 + 
 +<note tip>În situația în care se folosește emulatorul Genymotion, pentru a se evita transcrierea parolelor foarte lungi, se poate realiza operația de tip Copy-Paste din mașina fizică în mașina virtuală folosind operația de tip apăsare cu o durată de timp mai mare (//eng.// long press).</​note>​ 
 + 
 +  * protocoul folosit ​(implicit UDP); 
 +  * proxy-ul folosit pentru conexiuni din afara domeniului: ''​sip.onsip.com''​ 
 + 
 +{{ :​laboratoare:​laborator09:​csipsimple09.png?​nolink&​300 }} 
 + 
 +În secțiunea ​//Accounts//, contul SIP poate fi în orice  moment activat sau dezactivat. Starea acestuia este vizibilă sub denumirea sa, culoarea folosită fiind sugestivă pentru rezultatul operației de înregistrare:​ 
 +  * verde: operația a fost realizată cu succes; 
 +  * roșu: s-a produs o eroare; eroarea de tipul //Registration timeout// denotă faptul că în NAT/SIP nu se translatează corect adresele interne 
 +    * rețeaua Digi.Mobil/4G funcționează corespunzător;​ 
 +    * în facultate, rețelele wireless ''​ACS-UPB-OPEN'',​ ''​eduroam'',​ ''​Java-ED117''​ nu creează probleme; în schimb, rețeaua ''​change''​ blochează anumite porturi ceea ce împiedică comunicația cu serverul SIP. 
 + 
 +{{ :​laboratoare:​laborator09:​csipsimple10.png?​nolink&​300 }} 
 + 
 +Contactele de tip SIP sunt vizibile în meniul aplicației CSipSimple astfel încât să poată fi plasate apeluri de tip SIP / VoIP: 
 + 
 +{{ :​laboratoare:​laborator09:​csipsimple11.png?​nolink&​300 }} 
 + 
 +{{ :​laboratoare:​laborator09:​csipsimple12.png?​nolink&​300 }} 
 + 
 +Pentru **contul de tip PBXes** există un șablon predefinit:​ 
 + 
 +{{ :​laboratoare:​laborator09:​csipsimple13.png?​nolink&​300 }} 
 + 
 +Se recomandă însă să se utilizeze tot un șablon general, astfel încât să poată fi controlați foarte bine toți parametrii:​ 
 + 
 +  * denumirea contului: ''​mobilecomputing''​ 
 +  * adresa serverului care pune la dispoziție serviciile SIP: ''​pbxes.org'';​ 
 +  * numele de utilizator (**se utilizează extensia**):​ ''​mobilecomputing-100''​ 
 +  * identificatorul folosit pentru autentificare,​ de regulă același cu numele de utilizator;​ 
 +  * parola (**se utilizează extensia**);​ 
 +  * protocoul folosit (implicit UDP); 
 +  * proxy-ul folosit pentru conexiuni din afara domeniului: ''​pbxes.org''​ 
 + 
 +{{ :​laboratoare:​laborator09:​csipsimple14.png?​nolink&​300 }} 
 + 
 +===== Android NGN Stack ===== 
 + 
 +[[http://developer.android.com/​guide/​topics/​connectivity/​sip.html|Stiva SIP]] face parte din SDK-ul Android începând cu versiunea 2.3 (Gingerbread,​ API level 9), însă nu dispune încă de toate funcționalitățile (mesagerie instantanee,​ apeluri video). Totuși, poate fi utilizat pentru apeluri audio, funcționalitatea fiind disponibilă în //Phone// → //​Settings//​ → //Internet Calling// (ulterior //SIP Accounts//​). 
 + 
 +Se preferă însă utilizarea API-ului NGN (New Generation Networking), care implementează o stivă SIP completă, dispunând și de documentarea metodelor care pot fi utilizate: https://​imsdroid.googlecode.com/​svn-history/​r381/​branches/​2.0/​android-ngn-stack-00.pdf. 
 + 
 +Inițial, este necesar să se obțină o referință către obiectul de tip ''​NgnEngine''​. Acest lucru poate fi realizat ​prin intermediul ​metodei statice ''​getInstance()''​ (așa cum era de așteptat, ''​NgnEngine''​ este singleton). De regulă, o astfel de operație este realizată pe metoda ''​onCreate()''​ a activității principale a aplicației Android. 
 + 
 +<code java> 
 +ngnEngine = NgnEngine.getInstance();​ 
 +if (ngnEngine == null) { 
 +  Log.i(Constants.TAG,​ "​Failed to obtain the NGN engine!"​);​ 
 +} 
 +</​code>​ 
 + 
 +Motorul NGN trebuie configurat, prin specificarea ​unor parametri, reținuți sub forma unor perechi de tipul (cheie, valoare). Pentru ca serviciul SIP să poată fi accesat, trebuie specificat identificatorul utilizatorului,​ adresa SIP (sub forma ''​sip:<​username>​@<​domain>''​),​ parola, adresa proxy-ului la care se realizează conexiunea și portul pe care se face acest lucru (frecvent, 5060), rețeaua din care face parte. Pot fi indicate și utilizarea rețelei 3G (implicit, dezactivată) precum și timpul de așteptare în cazul operației de înregistrare. 
 + 
 +<code java> 
 +public void configureStack() { 
 +  NgnEngine ngnEngine = NgnEngine.getInstance();​ 
 +  INgnConfigurationService ngnConfigurationService = ngnEngine.getConfigurationService();​ 
 +  ngnConfigurationService.putString(NgnConfigurationEntry.IDENTITY_IMPI,​ Constants.IDENTITY_IMPI);​ 
 +  ngnConfigurationService.putString(NgnConfigurationEntry.IDENTITY_IMPU,​ String.format("​sip:%s@%s",​ Constants.USERNAME,​ Constants.DOMAIN));​ 
 +  ​ngnConfigurationService.putString(NgnConfigurationEntry.IDENTITY_PASSWORD,​ Constants.IDENTITY_PASSWORD);​ 
 +  ngnConfigurationService.putString(NgnConfigurationEntry.NETWORK_PCSCF_HOST,​ Constants.NETWORK_PCSCF_HOST);​ 
 +  ngnConfigurationService.putInt(NgnConfigurationEntry.NETWORK_PCSCF_PORT,​ Constants.NETWORK_PCSCF_PORT);​ 
 +  ngnConfigurationService.putString(NgnConfigurationEntry.NETWORK_REALM,​ Constants.NETWORK_REALM);​ 
 + 
 +  ngnConfigurationService.putBoolean(NgnConfigurationEntry.NETWORK_USE_3G,​ true); 
 +  ngnConfigurationService.putInt(NgnConfigurationEntry.NETWORK_REGISTRATION_TIMEOUT,​ Constants.NETWORK_REGISTRATION_TIMEOUT);​ 
 + 
 +  ngnConfigurationService.commit();​ 
 +} 
 +</code> 
 + 
 +Ulterior, motorul NGN trebuie să fie pornit. 
 + 
 +<code java> 
 +public boolean startNgnEngine() { 
 +  if (!ngnEngine.isStarted()) { 
 +    if (!ngnEngine.start()) { 
 +      Log.e(Constants.TAG,​ "​Failed to start the NGN engine!"​);​ 
 +      return false; 
 +    } 
 +  } 
 +  return true; 
 +} 
 +</code> 
 + 
 +Pe baza acestui obiect, se poate obține un serviciu SIP de tipul ''​INgnSipService''​ care pune la dispoziție metodele pentru obținerea de sesiuni pe baza operațiilor de înregistrare / deînregistrare. 
 + 
 +<code java> 
 +ngnSipService = ngnEngine.getSipService();​ 
 +</code> 
 + 
 +Operația de înregistrare presupune transmiterea unui context (al aplicației Android) care este asociat serviciului SIP. 
 + 
 +<code java> 
 +public void registerSipService() { 
 +  if (!ngnSipService.isRegistered()) { 
 +    ngnSipService.register(this);​ 
 +  } 
 +} 
 +</code> 
 + 
 +Pentru operația (simetrică) de deînregistrare,​ furnizarea unui astfel de argument nu mai este necesară. Utilizatorul este cel care ar trebui să dețină controlul asupra acestui tip de operații, prin intermediul unor elemente din cadrul interfeței grafice. 
 + 
 +<code java> 
 +public void unregisterSipService() { 
 +  if (ngnSipService.isRegistered()) { 
 +    ngnSipService.unRegister();​ 
 +  } 
 +} 
 +</​code>​ 
 + 
 +Motorul NGN trebuie să fie oprit atunci când aplicația Android este terminată. De regulă, o astfel de operație este realizată pe metoda ''​onDestroy()''​ a activității principale. 
 + 
 +<code java> 
 +public boolean stopNgnEngine() { 
 +  if (ngnEngine.isStarted()) { 
 +    if (!ngnEngine.stop()) { 
 +      Log.e(Constants.TAG, "​Failed to stop the NGN engine!"​); 
 +      return false; 
 +    } 
 +  ​} 
 +  return true; 
 +} 
 +</code> 
 + 
 +<note tip>Este mai puțin frecvent ca operațiile de înregistrare ​/ deînregistrare să se realizeze pe metodele ''​onStart()''​ respectiv ''​onStop()''​ deoarece execuția acestora poate fi destul de îndelungată având un impact negativ asupra responsivității sistemului de operare.</note> 
 + 
 +Ulterior, se pot deschide sesiuni audio-video (''​NgnAVSession''​) respectiv pentru mesagerie instantanee (''​NgnMessagingSession''​),​ acestea fiind obiecte partajate la nivelul întregii aplicații întrucât furnizează aproximativ toate metodele pentru gestiunea apelurilor telefonice sau pentru transmiterea de mesaje. 
 + 
 +<code java> 
 +NgnAVSession ngnAVSession = NgnAVSession.createOutgoingSession( 
 +  NgnEngine.getInstance().getSipService().getSipStack(),​ 
 +  NgnMediaType.AudioVideo 
 +); 
 +</code> 
 + 
 +<code java> 
 +NgnMessagingSession instantMessagingSession = NgnMessagingSession.createOutgoingSession( 
 +  NgnEngine.getInstance().getSipService().getSipStack(),​ 
 +  remotePartyUri 
 +); 
 +</​code>​ 
 + 
 +În cazul **operațiilor de înregistrare / deînregistrare**,​ se poate defini un **ascultător pentru mesaje cu difuzare**, care gestionează acțiunile de tipul ''​NgnRegistrationEventArgs.ACTION_REGISTRATION_EVENT''​. 
 + 
 +Evenimentele ce pot fi tratate de un astfel de obiect sunt legate de: 
 +  * rezultatul operației de înregistrare:​ 
 +    * ''​REGISTRATION_NOK''​ 
 +    * ''​REGISTRATION_OK''​ 
 +    * ''​REGISTRATION_INPROGRESS''​ 
 +  * rezultatul operației de deînregistrare:​ 
 +    * ''​UNREGISTRATION_NOK''​ 
 +    * ''​UNREGISTRATION_OK''​ 
 +    * ''​UNREGISTRATION_INPROGRESS''​ 
 + 
 +Pentru gestiunea **apelurilor telefonice** se folosesc metodele ''​makeCall()'',​ respectiv ''​hangUpCall()'',​ puse la dispoziție de obiectul ''​INgnAVSession''​. 
 +  * metoda ''​makeCall()'' ​primește ​ca argument un șir de caractere formatat, reprezentând un URI valid, acesta fiind furnizat prin intermediul metodei statice ''​NgnUriUtils.makeValidSipUri()'';​ de regulă, se respectă formatul protocol:​utilizator@domeniu, în cazul de față protocolul fiind sip; metoda furnizează un rezultat de tip adevărat / fals; 
 +  * metoda ''​hangUpCall()''​ nu primește nici un argument și furnizează un rezultat de tip adevărat / fals. 
 + 
 +În același scop, se poate defini un ascultător pentru mesaje cu difuzare, care gestionează acțiunile de tipul ''​NgnInviteEventArgs.ACTION_INVITE_EVENT''​. Evenimentele ce pot fi tratate de un astfel de obiect sunt: 
 +  * ''​INCOMING''​ 
 +  * ''​INCALL''​ 
 +  * ''​TERMINATED'' ​/ ''​TERMINATING''​ 
 +  * ''​NONE''​ 
 + 
 +Pentru gestiunea **mesajelor ce se doresc a fi transmise instantaneu** se folosește metoda ''​sendTextMessage()'',​ care primește ca argument șirul de caractere care trebuie comunicat. Aceasta furnizează un rezultat de tip adevărat ​/ fals după cum operația a reușit respectiv a eșuat. 
 + 
 +În același scop, se poate defini un ascultător pentru mesaje cu difuzare, care gestionează acțiunile de tipul ''​NgnMessagingEventArgs.ACTION_MESSAGING_EVENT''​. Evenimentele ce pot fi tratate de un astfel de obiect sunt: 
 +  * ''​INCOMING''​ 
 +  * ''​OUTGOING''​ 
 +  * ''​SUCCESS''​ 
 +  * ''​FAILURE''​ 
 + 
 +<note tip>În situația mesageriei instantanee,​ este necesar să se creeze câte o sesiune pentru fiecare ​mesaj gestionat, întrucât acesta reprezintă de fapt o legătură punct la punct între (cel puțin) două sau mai multe entități.</​note>​
  
 ===== Activitate de Laborator ===== ===== Activitate de Laborator =====
  
-Se dorește implementarea unei aplicații Android ​pe baza scheletului. +Se dorește implementarea unei aplicații Android ​care folosește stiva Android NGN pentru a realiza apeluri de voce precum și comunicație prin mesagerie instantanee folosind SIP. 
-  * scheletul va conține ​MainActivity ​și ChatActivity + 
-  * în activitatea principală se implementează signin ​(registration) și apelul vocal +<​html>​ 
-  * dacă este timp, se implementează instant messenging în activitatea ​secundară +<​center>​ 
-  * atenție, conturile ​de pe getonsip.com sunt limitate la numărul de signins ​pe oră :(, altfel conturile sunt avantajoase ​deoarece ​au și webrtc ​  +</​html>​ 
-  * soluție: [[https://github.com/dragos-niculescu/ngnsip|Aplicație]] care implementează punctele 1-8. Țintim ​în 2 ore pentru ​1-6+ 
 +{{:​laboratoare:​laborator09:​activitatedelaborator01.png?​nolink&​300}} {{:​laboratoare:​laborator09:​activitatedelaborator02.png?​nolink&​300}} 
 + 
 +<​html>​ 
 +</​center>​ 
 +</​html>​ 
 + 
 +Proiectul ​conține ​două activități:​ 
 +  * ''​VoiceCallActivity'',​ folosit pentru operații de tip înregistrare / deînregistrare,​ apeluri de voce și transmiterea de coduri DTMF; 
 +  * ''​InstantMessagingActivity'',​ utilizat pentru transferul de mesaje instantanee. 
 + 
 +**1.** În contul Github personal, să se creeze un depozit denumit '​Laborator09'​. Inițial, acesta trebuie să fie gol (nu trebuie să bifați nici adăugarea unui fișier ''​README.md'',​ nici a fișierului ''​.gitignore''​ sau a a fișierului ''​LICENSE''​). 
 + 
 +**2.** Să se cloneze în directorul de pe discul local conținutul depozitului la distanță de la [[https://​www.github.com/​eim2016/​Laborator09|]].  
 + 
 +În urma acestei operații, directorul Laborator09 va trebui să se conțină directoarele ''​labtasks'' ​și ''​solutions''​.  
 + 
 +<​code>​ 
 +student@eim2016:​~$ git clone https://​www.github.com/​eim2016/​Laborator09 
 +</​code>​ 
 + 
 +**3.** Să se încarce conținutul descărcat în cadrul depozitului '​Laborator09'​ de pe contul Github personal. <​code>​ 
 +student@eim2016:​~$ cd Laborator09 
 +student@eim2016:​~/​Laborator09$ git remote add Laborator09_perfectstudent https://​github.com/​perfectstudent/​Laborator09 
 +student@eim2016:​~/​Laborator09$ git push Laborator09_perfectstudent master 
 +</​code>​ 
 + 
 +**4.** Să se importe în mediul integrat de dezvoltare Eclipse proiectul ''​android-ngn-stack'',​ care va fi utilizat ca bibliotecă pentru proiectul ''​ngnsip''​. 
 + 
 +Să se importe în mediul integrat de dezvoltare Eclipse proiectul ''​NgnSIP''​ din directorul ''​labtasks''​. Acesta trebuie să refere biblioteca ''​android-ngn-stack'':​ //Project Properties//​ → //Android// → //Library// → //Add//. 
 + 
 +{{ :​laboratoare:​laborator09:​eclipse_android_library.png?​nolink&​800 }} 
 + 
 +<note warning>​Este necesar ca proiectul ''​android-ngn-stack''​ să fie referit ca bibliotecă și compilat ca atare, întrucât ​dacă se construiește o arhivă .jar pe baza sa, aceasta nu va include și bibliotecile partajate (din subdirectorul ''​libs'',​ având extensia ''​.so''​),​ astfel încât la încercarea de inițializare a stivei NGN vor fi generate excepții de tipul ''​java.lang.UnsatisfiedLinkError''​ datorate faptului că nu pot fi încărcate bibliotecile partajate folosite.</​note>​ 
 + 
 +În interfața ''​Constants.java'',​ să se actualizeaze informațiile specifice contului SIP. 
 + 
 +<​spoiler|Indicații de Rezolvare>​ 
 +Este necesar să se precizeze:​ 
 +  * numele de utilizator: atributul ''​USERNAME'';​ 
 +  * identificatorul utilizatorului:​ atributul ''​IDENTITY_IMPI'';​ 
 +  * parola: atributul ''​IDENTITY_PASSWORD''​. 
 + 
 +Aceste informații pot fi preluate de la furnizorul de servicii SIP. 
 + 
 +<file java Constants.java>​ 
 +public interface Constants { 
 +  final public static String USERNAME = "​...";​ 
 +  final public static String IDENTITY_IMPI = "​...";​ 
 +  final public static String IDENTITY_PASSWORD = "​...";​ 
 +  // ... 
 +} 
 +</​file>​ 
 +</​spoiler>​ 
 + 
 +**5**. În activitatea ​''​VoiceCallActivity'',​ să se implementeze ascultători pentru butoanele //​Register//​ și //​Unregister//:​ 
 +  * //​Register//​ 
 +    - va configura motorul NGN, ai cărui parametri sunt plasați sub forma unor valori asociate unor chei (metoda ''​configureStack()''​);​ 
 +    - va porni motorul NGN (metoda ''​startNgnEngine()''​) și va înregistra activitatea principală la serviciul SIP (metoda ''​registerSipService()''​) 
 +  * //​Unregister//​ va deînregistra serviciul SIP (metoda ''​unregisterSipService()''​). 
 + 
 +În ambele cazuri, în situația în care se produce o eroare, aceasta va fi jurnalizată folosind Logcat. 
 + 
 +<​spoiler|Indicații ​de Rezolvare>​ 
 +<code java> 
 +private class RegisterButtonClickListener implements View.OnClickListener { 
 +  @Override 
 +  public void onClick(View view) { 
 +    configureStack();​ 
 +    if (!startNgnEngine()) { 
 +      return; 
 +    } 
 +    registerSipService();​ 
 +  } 
 +} 
 +</​code>​ 
 + 
 +<code java> 
 +private class UnregisterButtonClickListener implements View.OnClickListener { 
 +  @Override 
 +  public void onClick(View view) { 
 +    unregisterSipService();​ 
 +  } 
 +} 
 +</​code>​ 
 +</​spoiler>​ 
 + 
 +**6.** Să se activeze / dezactiveze ascultătorul pentru mesaje cu difuzare ''​RegistrationBroadcastReceiver'',​ folosind filtrul ''​NgnRegistrationEventArgs.ACTION_REGISTRATION_EVENT''​. Acesta prelucrează mesajele legate ​de operațiile de înregistrare / deînregistrare, ​pe care le jurnalizează în Logcat, utilizatorul putând să le vizualizeze și în interfața grafică prin intermediul unor ferestre de tip ''​Toast''​ precum și într-un câmp text care conține starea curentă (//​Registered//,​ //​Registration in progress//, //​Unregistration in progress//, //​Unregistered//,​ //Failed to register//, //Failed to unregster//​). 
 + 
 +<​spoiler|Indicații de Rezolvare>​ 
 +Operațiile de activare / dezactivare vor fi realizate pe metodele ''​onCreate()''​ respectiv ''​onDestroy()''​. 
 + 
 +<code java> 
 +public void enableRegistrationBroadcastReceiver() { 
 +  registrationBroadcastReceiver = new RegistrationBroadcastReceiver(registrationStatusTextView);​ 
 +  registrationIntentFilter = new IntentFilter();​ 
 +  registrationIntentFilter.addAction(NgnRegistrationEventArgs.ACTION_REGISTRATION_EVENT);​ 
 +  registerReceiver(registrationBroadcastReceiver,​ registrationIntentFilter);​ 
 +} 
 +</​code>​ 
 + 
 +<code java> 
 +public void disableRegistrationBroadcastReceiver() { 
 +  if (registrationBroadcastReceiver != null) { 
 +    unregisterReceiver(registrationBroadcastReceiver);​ 
 +    registrationBroadcastReceiver = null; 
 +  } 
 +} 
 +</​code>​ 
 +</​spoiler>​ 
 + 
 +**7.** În aplicația Android, există un câmp text editabil în care se va preciza adresa SIP destinație,​ precum și două butoane care pornesc / opresc apelul.  
 + 
 +Să se creeaze o sesiune către adresa SIP destinație: 
 + 
 +<code java> 
 +NgnAVSession.createOutgoingSession( 
 +  NgnEngine.getInstance().getSipService().getSipStack(),​ 
 +  NgnMediaType.Audio 
 +); 
 +</​code>​ 
 + 
 +Pe baza acestei sesiuni, să se pornească apelul cu ''​makeCall()'',​ și să se oprească cu ''​hangUpCall()''​. 
 + 
 +Să se implementeze metodele specifice, asociate claselor ascultător pentru operația de apăsare a butoanelor //Make Call//, respectiv //Hang up Call//. 
 + 
 +<​spoiler|Indicații de Rezolvare>​ 
 +<code java> 
 +private class MakeCallButtonListener implements View.OnClickListener { 
 +  @Override 
 +  public void onClick(View view) { 
 +    String validUri = NgnUriUtils.makeValidSipUri(SIPAddressEditText.getText().toString());​ 
 +    if (validUri == null) { 
 +      Log.e(Constants.TAG,​ "​Invalid SIP address"​);​ 
 +      return; 
 +    } 
 +    if (!ngnEngine.isStarted() || !ngnSipService.isRegistered()) { 
 +      Log.e(Constants.TAG,​ "NGN Engine is not started or NGN Sip Service is not registered!"​);​ 
 +      return; 
 +    } 
 +    ngnAVSession = NgnAVSession.createOutgoingSession( 
 +      NgnEngine.getInstance().getSipService().getSipStack(),​ 
 +      NgnMediaType.Audio 
 +    ); 
 +    if (ngnAVSession.makeCall(validUri)) { 
 +      callStatusTextView.setText(getResources().getString(R.string.calling));​ 
 +      Log.d(Constants.TAG,​ "Call succeeded"​);​ 
 +    } else { 
 +      Log.d(Constants.TAG,​ "Call failed"​);​ 
 +    } 
 +  } 
 +} 
 +</​code>​ 
 + 
 +<code java> 
 +private class HangupCallButtonListener implements View.OnClickListener { 
 +  @Override 
 +  public void onClick(View view) { 
 +    if (ngnAVSession != null) { 
 +      ngnAVSession.hangUpCall();​ 
 +      Log.d(Constants.TAG,​ "Hang Up"​);​ 
 +    } 
 +  } 
 +} 
 +</​code>​ 
 +</​spoiler>​ 
 + 
 +<note tip>​Sesiunea trebuie menținută ca membru al activității, deoarece ​este necesară ​și pentru alte operații.</​note>​  
 + 
 +**8.** ​ Să se activeze / dezactiveze ascultătorul pentru mesaje cu difuzare ''​CallStateBroadcastReceiver'',​ folosind filtrul ''​NgnInviteEventArgs.ACTION_INVITE_EVENT''​.  
 + 
 +Acesta prelucrează mesajele legate de operațiile legate de apelurile de voce, pe care le jurnalizează în Logcat, utilizatorul putând să le vizualizeze și în interfața grafică prin intermediul unor ferestre de tip ''​Toast''​ precum și într-un câmp text care conține starea curentă (//Incoming call//, //Call started//, //Call ended//, //Call state//). 
 + 
 +<​spoiler|Indicații de Rezolvare>​ 
 +Operațiile de activare / dezactivare vor fi realizate pe metodele ''​onCreate()''​ respectiv ''​onDestroy()''​. 
 + 
 +<code java> 
 +public void enableCallStateBroadcastReceiver() { 
 +  ​callStateBroadcastReceiver = new CallStateBroadcastReceiver(SIPAddressEditText,​ callStatusTextView);​ 
 +  callIntentFilter = new IntentFilter();​ 
 +  callIntentFilter.addAction(NgnInviteEventArgs.ACTION_INVITE_EVENT);​ 
 +  registerReceiver(callStateBroadcastReceiver,​ callIntentFilter);​  
 +} 
 +</​code>​ 
 + 
 +<code java> 
 +public void disableCallStateBroadcastReceiver() { 
 +  if (callStateBroadcastReceiver != null) { 
 +    unregisterReceiver(callStateBroadcastReceiver);​ 
 +    callStateBroadcastReceiver = null; 
 +  } 
 +} 
 +</​code>​ 
 +</​spoiler>​ 
 + 
 +**9.** Să se testeze un apel de voce către o adresă SIP de test (''​thetestcall@getonsip.com''​). 
 + 
 +Să se analizeze conversația SIP la nivel pachet: 
 + 
 +<​code>​ 
 +student@eim2016:/​opt/​android-sdk-linux/​platform-tools$ ./adb -s 192.168.56.101:​5555 shell 
 +</​code>​ 
 + 
 +În consola sistemului de operare Android, se folosește utilitarul ​[[http://www.androidtcpdump.com/download/4.7.4/​tcpdump|tcpdump]]:  
 + 
 +<​code>​ 
 +root@android:/#​ ./​tcpdump ​-s0 -ni eth1 -w /​sdcard/​DCIM/​sip.pcap '​udp'​ 
 +</​code>​ 
 + 
 +<note tip> 
 +Utilitarul ''​tcpdump''​ se instalează ​în ''/​data/​bin'',​ apoi se conferă drepturi de execuție ​pentru ​binar: 
 +<​code>​ 
 +root@android:/​data/​bin#​ chmod 777 tcpdump 
 +</​code>​ 
 +</​note>​ 
 + 
 +Se pornește apelul audio și după ce se termină mesajul, se oprește.  
 + 
 +Programul ''​tcpdump''​ este terminat prin Ctrl-C. 
 + 
 +Se obține dump-ul și se analizează folosind ''​wireshark''​. 
 + 
 +<​code>​ 
 +student@eim2016:/​opt/​android-sdk-linux/​platform-tools$ ./adb -s 192.168.56.3:​5555 pull /​sdcard/​DCIM/​sip.pcap 
 +student@eim2016:/​opt/​android-sdk-linux/​platform-tools$ wireshark sip.pcap 
 +</​code>​ 
 + 
 +  * Să se identifice operația ''​REGISTER''​. Ce port se utilizează?​ Care este adresa serverului?​ 
 + 
 +{{ :​laboratoare:​laborator09:​wireshark01.png?​nolink&​800 }} 
 + 
 +  * Să se găsească, în răspunsul de confirmare, adresele NAT prin care trece conversația,​ odată ce a fost acceptată cererea. 
 + 
 +{{ :​laboratoare:​laborator09:​wireshark02.png?​nolink&​800 }} 
 + 
 +  * Să se identifice operația ''​INVITE''​. Apar retransmisii?​ 
 + 
 +{{ :​laboratoare:​laborator09:​wireshark03.png?​nolink&​800 }} 
 + 
 +  * Ce fel de codificare este utilizată pentru semnalul audio? 
 + 
 +{{ :​laboratoare:​laborator09:​wireshark04.png?​nolink&​800 }} 
 + 
 +  * Ce parametri are fluxul de voce (protocol, dimensiune pachet, rata pachetelor)?​ 
 + 
 +{{ :​laboratoare:​laborator09:​wireshark05.png?​nolink }} 
 + 
 +  * Ce adrese sunt folosite pentru traficul de voce și cum au fost negociate?​ 
 + 
 +{{ :​laboratoare:​laborator09:​wireshark06.png?​nolink&​800 }}
  
-** 1. ** Se clonează stiva SIP [[https://​github.com/​dragos-niculescu/​android-ngn-stack|Android NGN stack]], și se importă în Eclipse. Se compilează și se obține bin/​android-ngn-stack.jar. Se adaugă acest jar la scheletul ngnsip la Project Properties/Java Build Path/​Libraries/​Add JARs din proiectul deschis în eclipse (android-ngn-stack).  ​+<note tip>​Pornirea monitorizării (pornirea utilitarului ''​tcpdump''​) trebuie realizată anterior operației de înregistrare. Similar, oprirea monitorizării trebuie realizată ulterior operației de deînregistrare. În acest fel, pot fi surprinse toate operațiile.</note>
  
-    +**10.** (opțional) Pentru a trimite coduri numerice DTMF (Dual Tone Multi Frequency) ​se creează un buton și un câmp text editabil asociat. Transmiterea unui astfel ​de caracter se realizează prin intermediul metodei ''​sendDTMF()''​ a obiectului sesiune ''​NgnAVSession''​ cu valorile întregi 0-9, sau 10 pentru * și 11 pentru #. Folosind o adresa de test (''​thetestcall@getonsip.com''​ sau ''​904@mouselike.org''​) să se testeze codurile ​și navigarea prin meniuri.
-** 2. ** În proiectul schelet, ​se actualizează datele contului SIP din Constants.java. Se configurează butoanele register ​și unregister din activitatea principală ​astfel: register va demara initializarea stivei SIP cu configure_stack() și sign-in cu initalizeManager(). Acestea inițializează și membrii mEngine și mSipService ai activitătii principale. +
  
-** 3. ** Se definește ​ RegistrationBroadcastReceiver cu filtrul NgnRegistrationEventArgs.ACTION_REGISTRATION_EVENT pentru a prinde evenimentele legate ​de înregistrare (signin). Acestea sunt monitorizate în Log, cu Toasts, și într-un câmp din GUI care indică starea curenta (Registered/​In Progress.../​Unregistered). +Să se implementeze metoda asociată clasei ascultător corespunzătoare operației ​de apăsare a butonului respectiv.
  
-** 4. ** Se adaugă un câmp EditText care va primi adresa SIP destinație, și două butoane care initiază/​opresc apelul. Se crează o sesiune către un număr ​de test folosind NgnAVSession.createOutgoingSession( +<​spoiler|Indicații de Rezolvare>​ 
-NgnEngine.getInstance().getSipService().getSipStack(), NgnMediaType.Audio); Se inițiază apelul cu makeCall, și se oprește cu  +<code java> 
-hangUpCall. Sesiunea este menținuta ca membru al activitătii, deoarece este necesară și pe butoanele de hangUp sau DTMF. +private class DTMFButtonClickListener implements View.OnClickListener { 
 +  @Override 
 +  public void onClick(View view) { 
 +    ​if ​(ngnAVSession != null) { 
 +      int character = dtmfEditText.getText().toString().charAt(0); 
 +      ​switch(character) { 
 +        case '​*':​ 
 +          character = 10; 
 +          break; 
 + case '#':​ 
 +   character = 11; 
 +          break; 
 +        default: 
 +   if (character >= '​0'​ && character <= '​9'​) { 
 +            character -= '​0';​ 
 +          } 
 +      } 
 +      if (!ngnAVSession.sendDTMF(character)) { 
 + Log.e(Constants.TAG, "​Failed to send DTMF " + character);​ 
 +      } else { 
 + Log.d(Constants.TAG,​ "​Succeeded to send DTMF " + character);​ 
 +      } 
 +    }  
 +  } 
 +} 
 +</​code>​ 
 +</​spoiler>​
  
-** 5. ** Se definește un CallStateReceiver, si filtrul asociat pentru a monitoriza evenimentele legate ​de apeluri audio NgnInviteEventArgs.ACTION_INVITE_EVENT. Acest receiver monitorizează stările sesiunii audio: ​ INCOMING, INCALL, TERMINATED. +**11.** Activitatea ''​InstantMessagingActivity''​ poate fi lansată din activitatea principală,​ doar ulterior operației de înregistrare. Aceasta primește ca argument, în intenția cu care este lansată în execuție, adresa SIP cu care se va desfașura sesiunea ​de mesagerie instantanee. Funcționalitatea este împărțită între activitate și ascultătorul pentru mesaje cu difuzare ''​MessageBroadcastReceiver''​ care trebuie să gestioneze evenimentele de tipul ''​NgnMessagingEventArgs.ACTION_MESSAGING_EVENT''​. 
  
-** 6. ** Se testează un apel audio către o adresă ​de test (thetestcall@getonsip.com). Inspecție conversație SIP la nivel pachet: +<​spoiler|Indicații ​de Rezolvare>​ 
-  * adb -s 192.168.56.101:​5555 +În activitate, se creează o sesiune pentru fiecare mesaj, folosind ​ 
-  * În Android: tcpdump -s0 -ni eth1 -w /​sdcard/​DCIM/​sip.pcap '​udp'​ +<code java> 
-    * binar pentru arm: [[http://​www.androidtcpdump.com/​download/​4.7.4/​tcpdump | tcpdump]]. Se instalează în /data/bin, apoi se activează execuția chmod 777 /​databin/​tcpdump  +NgnMessagingSession instantMessagingSession = NgnMessagingSession.createOutgoingSession( 
-  * se inițiază apelul, se ascultă greeting, apoi se închide +  ​ngnSipService.getSipStack(), 
-  * se oprește tcpdump cu Ctrl-C +  ​remotePartyUri 
-  * Pe host: adb -s 192.168.56.3:​5555 pull /​sdcard/​DCIM/​sip.pcap ​. +); 
-  ​* wireshark sip.pcap  +</​code>​
-    * identificați operația REGISTER. Ce port se folosește pentru cerere? Care este adresa serverului?​ +
-    * în răspunsul pozitiv la REGISTER, identificați adresele NAT prin care trece conversația +
-    * identificați invitația. Apar retransmisii? ​   +
-    * ce fel de voice codec este folosit? +
-    * ce parametri are fluxul de voce? protocol, dimensiune pachet, rata pachetelor  +
-    * ce adrese se folosesc pentru traficul de voce?  +
-    * cum au fost negociate? ​+
  
 +Textul preluat din activitate este apoi transmis cu metoda ''​sendTextMessage()''​. Nu uitați să eliberați resursele folosite de sesiune atunci când toate informațiile pe care aceasta le deține au fost preluate.
  
-** 7. (Opțional) ** Pentru a trimite coduri numerice DTMF se crează un buton și edittext-ul asociat pentru a apela funcția sendDTMF cu valorile întregi 0-9, sau 10 pentru * si 11 pentru #. Folosind o adresa de test (thetestcall@getonsip.com sau 904@mouselike.org) se pot testa codurile și navigarea prin menuiuri+<code java> 
 +if(!instantMessagingSession.sendTextMessage(messageEditText.getText().toString())) { 
 +  Log.e(Constants.TAG, "​Failed to send message"​);​ 
 +} else { 
 +  String conversation = conversationTextView.getText().toString();​ 
 +  conversationTextView.setText(conversation + "Me: " + messageEditText.getText().toString() + "​\n"​);​ 
 +  messageEditText.setText(""​);​ 
 +  Log.d(Constants.TAG,​ "​Succeeded to send message"​);​  
 +} 
 +NgnMessagingSession.releaseSession(instantMessagingSession); 
 +</​code>​
  
-** 8. ** Se creează o nouă activitate ChatActivity care poate fi lansată din activitatea principală, doar după ce s-a făcut signin.    +În ascultătorul de mesaje cu difuzare, se tratează doar acțiunea ''​NgnMessagingEventArgs.ACTION_MESSAGING_EVENT''​, tipul evenimentului ''​INCOMING'',​ pentru ​a extrage octeții mesajului folosind metoda ''​getPayload()''​. Aceștia se convertesc la șir de caractere și se afișează în fereastra care conține conversația.
-Activitatea primește ca parametru în Intent adresa cu care se va desfașura sesiunea ​de chat. Funcționalitatea este împărțită între Activitate si un BroadcastReceiver care trebuie să primească evenimentele NgnMessagingEventArgs.ACTION_MESSAGING_EVENT. +
  
-În activitate, se creează o sesiune pentru fiecare mesaj, folosind NgnMessagingSession.createOutgoingSession(mSipService.getSipStack(), +<code java> 
-remotePartyUri); Textul preluat din activitate este apoi emis cu sendTextMessage. +if(!NgnStringUtils.equals(arguments.getContentType(), NgnContentType.T140COMMAND, true)) { 
 +  byte[] contentBytes = arguments.getPayload(); 
 +  if(contentBytes != null && contentBytes.length > 0) { 
 +    try { 
 +      String content = new String(contentBytes, "​UTF-8"​);​ 
 +      ​String conversation = conversationTextView.getText().toString(); 
 +      conversationTextView.setText(conversation + "​Others:​ " + content + "​\n"​);​ 
 +    } catch (UnsupportedEncodingException unsupportedEncodingException) { 
 +      Log.i(Constants.TAG,​ unsupportedEncodingException.toString());​ 
 +      if (Constants.DEBUG) { 
 + unsupportedEncodingException.printStackTrace();​ 
 +      } 
 +    } 
 +  } 
 +} 
 +</​code>​ 
 +</​spoiler>​
  
-În receiver, ​se tratează doar acțiunea NgnMessagingEventArgs.ACTION_MESSAGING_EVENT, tipul evenimentului INCOMING, pentru a extrage octeții mesajului ​folosind ​getPayload. Aceștia se convertesc la String și se appendează la fereastra de chat. +**12.** ​ Să se încarce modificările realizate în cadrul depozitului '​Laborator09'​ de pe contul Github personal, folosind ​un mesaj sugestiv. <​code>​ 
 +student@eim2016:​~/​Laborator09$ git add * 
 +student@eim2016:​~/​Laborator09$ git commit -m "​implemented taks for laboratory 08" 
 +student@eim2016:​~/​Laborator09$ git push Laborator09_perfectstudent master 
 +</​code>​
  
 ===== Resurse Utile ===== ===== Resurse Utile =====
laboratoare/laborator09.1462468981.txt.gz · Last modified: 2017/02/20 20:44 (external edit)
CC Attribution-Share Alike 4.0 International
Driven by DokuWiki Recent changes RSS feed Valid CSS Valid XHTML 1.0