Panoramica del protocollo di avvio delle sessioni

Rileva eSIM e schede SIM

Rilevamento delle schede

I dispositivi Android con schede SIM e eSIM utilizzano i seguenti ID nel servizio di telefonia API, tra cui ["TelephonyManager"](/reference/android/telephony/TelephonyManager) e ["SubscriptionManager"](/reference/android/telephony/SubscriptionManager): * ID abbonamento: ID univoco di un abbonamento mobile. * Indice o ID dello slot logico: indice univoco che fa riferimento a uno slot della SIM logica. Gli ID slot logici iniziano da 0 e aumentano in base al numero di slot attivi supportati su un dispositivo. Ad esempio, un dispositivo dual SIM in genere ha gli slot 0 e 1. Se un dispositivo ha più slot fisici, ma solo supporta uno slot attivo, avrà solo l'ID slot logico 0. * Indice o ID dello slot fisico: indice univoco che fa riferimento a uno slot fisico della SIM. Gli ID degli slot fisici iniziano da 0 e aumentano in base al numero di slot fisici slot sul dispositivo. È diverso dal numero di slot logici su un dispositivo che corrisponde al numero di slot attivi di cui può disporre un dispositivo che utilizzano. Ad esempio, un dispositivo che passa dalla modalità dual SIM a quella singola SIM e viceversa può avere sempre due slot fisici, mentre in modalità SIM singola avrà uno slot logico. * ID carta: ID univoco utilizzato per identificare una UiccCard. ![Un diagramma di come gli ID vengono utilizzati in una richiesta con due slot logici e tre slot fisici](/images/guide/topics/connectivity/tel-ids.png) Nel diagramma riportato sopra: * Il dispositivo ha due slot logici. * Nello slot fisico 0 è presente una scheda UICC fisica con un profilo attivo. * Nello slot fisico 2 è presente una eUICC con un profilo attivo. * Lo slot fisico 1 non è attualmente in uso. ![Un diagramma di come gli ID vengono utilizzati in un caso con tre slot logici e due slot fisici](/images/guide/topics/connectivity/tel-ids-2.png) Nel diagramma riportato sopra: * Il dispositivo ha tre slot logici. * Nello slot fisico 0 è presente una scheda UICC fisica con un profilo attivo. * Nello slot fisico 1 c'è una eUICC che ha due profili scaricati, entrambi attivi mediante MEP (Multiple Enabled Profiles).

Panoramica del protocollo di avvio della sessione

Android mette a disposizione un'API che supporta il protocollo SIP (Session Initiation Protocol). Ciò ti consente di aggiungere alle tue applicazioni funzionalità di telefonia internet basate su SIP. Android include uno stack di protocollo SIP completo e una gestione delle chiamate integrata che permettono alle applicazioni di configurare facilmente le chiamate vocali in entrata e in uscita, senza dover gestire sessioni, comunicazioni a livello di trasporto o audio registrare o riprodurre direttamente i contenuti.

Ecco alcuni esempi dei tipi di applicazioni che potrebbero utilizzare l'API SIP:

  • Videoconferenze
  • Messaggistica immediata

Requisiti e limitazioni

Di seguito sono riportati i requisiti per lo sviluppo di un'applicazione SIP:

  • Devi avere un dispositivo mobile con Android 2.3 o versioni successive.
  • Il protocollo SIP viene eseguito tramite una connessione dati wireless, quindi il dispositivo deve disporre di una connessione dati (con un servizio dati mobile o Wi-Fi). Ciò significa che non possono eseguire test sulla durata di visualizzazione media: il test può essere eseguito solo su un dispositivo fisico. Per maggiori dettagli, vedi Test delle applicazioni SIP.
  • Ciascun partecipante alla sessione di comunicazione dell'applicazione deve avere un Account SIP. Esistono diversi fornitori SIP che offrono account SIP.

Nota: la raccolta android.net.sip non supporta i video. chiamate. Se vuoi implementare le chiamate VOIP utilizzando uno stack SIP come android.net.sip, dai un'occhiata a una delle tante moderne applicazioni alternative come base per qualsiasi implementazione di chiamate VoIP. In alternativa, puoi implementare ConnectionService API per fornire una stretta integrazione di queste chiamate nel Telefono del dispositivo dell'app.

Classi e interfacce dell'API SIP

Ecco un riepilogo dei corsi e un'interfaccia (SipRegistrationListener) inclusi nel SIP di Android API:

Classe/interfaccia Descrizione
SipAudioCall Gestisce una chiamata audio internet tramite SIP.
SipAudioCall.Listener Listener di eventi relativi a una chiamata SIP, ad esempio quando è in corso una chiamata ricevuto ("squillo") o una chiamata in uscita ("in chiamata").
SipErrorCode Definisce i codici di errore restituiti durante le azioni SIP.
SipManager Fornisce API per attività SIP, ad esempio l'avvio di connessioni SIP e fornisce l'accesso ai servizi SIP correlati.
SipProfile Definisce un profilo SIP, incluse le informazioni di un account SIP, di dominio e di server.
SipProfile.Builder lezione di supporto per la creazione di un profilo SIP.
SipSession Rappresenta una sessione SIP associata a una finestra di dialogo SIP o a una transazione autonoma non all'interno di una finestra di dialogo.
SipSession.Listener Listener di eventi relativi a una sessione SIP, ad esempio quando una sessione viene registrata ("in registrazione") o in uscita ("in chiamata").
SipSession.State Definisce gli stati della sessione SIP, ad esempio "registrazione", "chiamata in uscita" e "in chiamata".
SipRegistrationListener Un'interfaccia che funge da listener per gli eventi di registrazione SIP.

Creazione del manifest in corso...

Se stai sviluppando un'applicazione che utilizza l'API SIP, ricorda che la classe è supportata soltanto su Android 2.3 (livello API 9) e versioni successive di della piattaforma. Inoltre, tra i dispositivi con Android 2.3 (livello API 9) o versioni successive, non tutti i dispositivi offrono il supporto SIP.

Per utilizzare SIP, aggiungi le seguenti autorizzazioni al file manifest dell'applicazione:

  • android.permission.USE_SIP
  • android.permission.INTERNET

Per assicurarti che l'applicazione possa essere installata solo su dispositivi che in grado di supportare SIP, aggiungi quanto segue all'interfaccia manifest:

<uses-sdk android:minSdkVersion="9" />

Questo indica che la tua applicazione richiede Android 2.3 o versioni successive. Per ulteriori informazioni, vedi Livelli API e la documentazione per gli sviluppatori <uses-sdk> .

Per controllare in che modo la tua applicazione viene filtrata dai dispositivi che non supportano SIP (ad esempio su Google Play), aggiungi quanto segue al manifest:

<uses-feature android:name="android.software.sip.voip" />

Indica che la tua applicazione utilizza l'API SIP. La dichiarazione dovrebbe includi un attributo android:required che indichi se Vuoi che l'applicazione venga filtrata dai dispositivi che non offrono supporto SIP. Potrebbero essere necessarie anche altre dichiarazioni <uses-feature>. a seconda dell'implementazione. Per ulteriori informazioni, consulta la documentazione per <uses-feature> .

Se l'applicazione è progettata per ricevere chiamate, devi anche definire un ricevitore (sottoclasse BroadcastReceiver) nel file manifest dell'applicazione:

<receiver android:name=".IncomingCallReceiver" android:label="Call Receiver" />

Ecco alcuni estratti del manifest SipDemo:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="com.example.android.sip">
  ...
     <receiver android:name=".IncomingCallReceiver" android:label="Call Receiver" />
  ...
  <uses-sdk android:minSdkVersion="9" />
  <uses-permission android:name="android.permission.USE_SIP" />
  <uses-permission android:name="android.permission.INTERNET" />
  ...
  <uses-feature android:name="android.software.sip.voip" android:required="true" />
  <uses-feature android:name="android.hardware.wifi" android:required="true" />
  <uses-feature android:name="android.hardware.microphone" android:required="true" />
</manifest>

Creazione di SipManager

Per utilizzare l'API SIP, l'applicazione deve creare un oggetto SipManager. SipManager richiede nella tua applicazione:

  • Avvio delle sessioni SIP.
  • Avvio e ricezione di chiamate.
  • Registrazione e annullamento della registrazione con un provider SIP.
  • Verifica della connettività della sessione in corso...

Crea un'istanza per un nuovo SipManager nel seguente modo:

Kotlin

val sipManager: SipManager? by lazy(LazyThreadSafetyMode.NONE) {
    SipManager.newInstance(this)
}

Java

public SipManager sipManager = null;
...
if (sipManager == null) {
    sipManager = SipManager.newInstance(this);
}

Registrazione con un server SIP

Una tipica applicazione SIP Android coinvolge uno o più utenti, ognuno dei quali ha un account SIP. In un'applicazione SIP Android, ogni account SIP rappresentato da un oggetto SipProfile.

Un SipProfile definisce un profilo SIP, incluso un SIP l'account, il dominio e le informazioni del server. Il profilo associato al SIP l'account di servizio sul dispositivo su cui è in esecuzione l'applicazione è chiamato profilo. Il profilo a cui è connessa la sessione è chiamato profilo peer. Quando l'applicazione SIP accede al server SIP con il SipProfile locale, questo registra in modo efficace dispositivo come posizione a cui inviare le chiamate SIP per il tuo indirizzo SIP.

Questa sezione spiega come creare un SipProfile, registrarlo con un server SIP e monitorare gli eventi di registrazione.

Puoi creare un oggetto SipProfile nel seguente modo:

Kotlin

private var sipProfile: SipProfile? = null
...

val builder = SipProfile.Builder(username, domain)
        .setPassword(password)
sipProfile = builder.build()

Java

public SipProfile sipProfile = null;
...

SipProfile.Builder builder = new SipProfile.Builder(username, domain);
builder.setPassword(password);
sipProfile = builder.build();

Il seguente estratto di codice apre il profilo locale per effettuare chiamate e/o la ricezione di chiamate SIP generiche. Il chiamante può effettuare chiamate successive utilizzando mSipManager.makeAudioCall. Questo estratto definisce anche l'azione android.SipDemo.INCOMING_CALL, che verrà utilizzata da un intent filtra quando il dispositivo riceve una chiamata (vedi Configurazione un filtro per intent per ricevere chiamate). Questo è il passaggio di registrazione:

Kotlin

val intent = Intent("android.SipDemo.INCOMING_CALL")
val pendingIntent: PendingIntent = PendingIntent.getBroadcast(this, 0, intent, Intent.FILL_IN_DATA)
sipManager?.open(sipProfile, pendingIntent, null)

Java

Intent intent = new Intent();
intent.setAction("android.SipDemo.INCOMING_CALL");
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, intent, Intent.FILL_IN_DATA);
sipManager.open(sipProfile, pendingIntent, null);

Infine, questo codice imposta un SipRegistrationListener in SipManager. Monitora se SipProfile è stato registrato correttamente con il tuo servizio SIP fornitore:

Kotlin

sipManager?.setRegistrationListener(sipProfile?.uriString, object : SipRegistrationListener {

    override fun onRegistering(localProfileUri: String) {
        updateStatus("Registering with SIP Server...")
    }

    override fun onRegistrationDone(localProfileUri: String, expiryTime: Long) {
        updateStatus("Ready")
    }

    override fun onRegistrationFailed(
            localProfileUri: String,
            errorCode: Int,
            errorMessage: String
    ) {
        updateStatus("Registration failed. Please check settings.")
    }
})

Java

sipManager.setRegistrationListener(sipProfile.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.");
    }
}

Quando l'applicazione ha finito di utilizzare un profilo, dovrebbe chiuderlo gli oggetti associati in memoria e annullare la registrazione del dispositivo dal server. Per esempio:

Kotlin

fun closeLocalProfile() {
    try {
        sipManager?.close(sipProfile?.uriString)
    } catch (ee: Exception) {
        Log.d("WalkieTalkieActivity/onDestroy", "Failed to close local profile.", ee)
    }
}

Java

public void closeLocalProfile() {
    if (sipManager == null) {
       return;
    }
    try {
       if (sipProfile != null) {
          sipManager.close(sipProfile.getUriString());
       }
     } catch (Exception ee) {
       Log.d("WalkieTalkieActivity/onDestroy", "Failed to close local profile.", ee);
     }
}

Effettuare una chiamata audio

Per effettuare una chiamata audio, devi disporre di quanto segue:

  • Un SipProfile che sta effettuando la chiamata (il "profilo locale") e un indirizzo SIP valido per ricevere la chiamata (il "profilo peer").
  • Un oggetto SipManager.

Per effettuare una chiamata audio, devi configurare un SipAudioCall.Listener. Gran parte dell'interazione del cliente con lo stack SIP avviene tramite listener. In questo snippet puoi vedere come viene configurato SipAudioCall.Listener al termine della chiamata data di creazione:

Kotlin

var listener: SipAudioCall.Listener = object : SipAudioCall.Listener() {

    override fun onCallEstablished(call: SipAudioCall) {
        call.apply {
            startAudio()
            setSpeakerMode(true)
            toggleMute()
        }
    }

    override fun onCallEnded(call: SipAudioCall) {
        // Do something.
    }
}

Java

SipAudioCall.Listener listener = new SipAudioCall.Listener() {

   @Override
   public void onCallEstablished(SipAudioCall call) {
      call.startAudio();
      call.setSpeakerMode(true);
      call.toggleMute();
         ...
   }

   @Override

   public void onCallEnded(SipAudioCall call) {
      // Do something.
   }
};

Dopo aver configurato SipAudioCall.Listener, puoi effettuare la chiamata. Il metodo SipManager makeAudioCall richiede i seguenti parametri:

  • Un profilo SIP locale (il chiamante).
  • Un profilo SIP peer (l'utente chiamato).
  • Un SipAudioCall.Listener per ascoltare la chiamata eventi da SipAudioCall. Può essere null, ma, come mostrato sopra, il listener viene utilizzato per configurare le impostazioni una volta che la chiamata viene la creazione di un progetto.
  • Il valore di timeout, in secondi.

Ad esempio:

Kotlin

val call: SipAudioCall? = sipManager?.makeAudioCall(
        sipProfile?.uriString,
        sipAddress,
        listener,
        30
)

Java

call = sipManager.makeAudioCall(sipProfile.getUriString(), sipAddress, listener, 30);

Ricevere chiamate

Per ricevere chiamate, un'applicazione SIP deve includere una sottoclasse BroadcastReceiver in grado di rispondere a un intent a indicare che c'è una chiamata in arrivo. Pertanto, devi eseguire le seguenti operazioni la tua applicazione:

  • In AndroidManifest.xml, dichiara <receiver>. In SipDemo, <receiver android:name=".IncomingCallReceiver" android:label="Call Receiver" />.
  • Implementa il ricevitore, che è una sottoclasse di BroadcastReceiver. In SipDemo, IncomingCallReceiver.
  • Inizializza il profilo locale (SipProfile) con un intent in attesa che attiva il destinatario quando qualcuno chiama il profilo locale.
  • Configura un filtro per intent che filtri in base all'azione che rappresenta un chiamata in arrivo. In SipDemo, questa azione android.SipDemo.INCOMING_CALL.

BroadcastRicevir per la creazione di sottoclassi

Per ricevere chiamate, l'applicazione SIP deve avere la sottoclasse BroadcastReceiver. La Il sistema Android gestisce le chiamate SIP in arrivo e trasmette il messaggio "In arrivo call" intent (come definito dall'applicazione) quando riceve una chiamata. Ecco la sottoclasse BroadcastReceiver dall'esempio SipDemo.

Kotlin

/**
 * Listens for incoming SIP calls, intercepts and hands them off to WalkieTalkieActivity.
 */
class IncomingCallReceiver : BroadcastReceiver() {

    /**
     * Processes the incoming call, answers it, and hands it over to the
     * WalkieTalkieActivity.
     * @param context The context under which the receiver is running.
     * @param intent The intent being received.
     */
    override fun onReceive(context: Context, intent: Intent) {
        val wtActivity = context as WalkieTalkieActivity

        var incomingCall: SipAudioCall? = null
        try {
            incomingCall = wtActivity.sipManager?.takeAudioCall(intent, listener)
            incomingCall?.apply {
                answerCall(30)
                startAudio()
                setSpeakerMode(true)
                if (isMuted) {
                    toggleMute()
                }
                wtActivity.call = this
                wtActivity.updateStatus(this)
            }
        } catch (e: Exception) {
            incomingCall?.close()
        }
    }

    private val listener = object : SipAudioCall.Listener() {

        override fun onRinging(call: SipAudioCall, caller: SipProfile) {
            try {
                call.answerCall(30)
            } catch (e: Exception) {
                e.printStackTrace()
            }
        }
    }
}

Java

/**
 * Listens for incoming SIP calls, intercepts and hands them off to WalkieTalkieActivity.
 */
public class IncomingCallReceiver extends BroadcastReceiver {
    /**
     * Processes the incoming call, answers it, and hands it over to the
     * WalkieTalkieActivity.
     * @param context The context under which the receiver is running.
     * @param intent The intent being received.
     */
    @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.sipManager.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();
            }
        }
    }
}

Configurare un filtro per intent per ricevere chiamate

Quando il servizio SIP riceve una nuova chiamata, invia un intent con stringa di azione fornita dall'applicazione. In SipDemo, questa stringa di azione è android.SipDemo.INCOMING_CALL.

Questo estratto di codice da SipDemo mostra come viene creato l'oggetto SipProfile con un intent in attesa basato su la stringa di azioni android.SipDemo.INCOMING_CALL. La L'oggetto PendingIntent eseguirà una trasmissione quando l'SipProfile riceve una chiamata:

Kotlin

val sipManager: SipManager? by lazy(LazyThreadSafetyMode.NONE) {
    SipManager.newInstance(this)
}

var sipProfile: SipProfile? = null
...

val intent = Intent("android.SipDemo.INCOMING_CALL")
val pendingIntent: PendingIntent = PendingIntent.getBroadcast(this, 0, intent, Intent.FILL_IN_DATA)
sipManager?.open (sipProfile, pendingIntent, null)

Java

public SipManager sipManager = null;
public SipProfile sipProfile = null;
...

Intent intent = new Intent();
intent.setAction("android.SipDemo.INCOMING_CALL");
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, intent, Intent.FILL_IN_DATA);
sipManager.open(sipProfile, pendingIntent, null);

La trasmissione verrà intercettata dal filtro per intent, che verrà quindi attivato il destinatario (IncomingCallReceiver). Puoi specificare un intent filtrare nel file manifest dell'applicazione o farlo nel codice come in SipDemo metodo onCreate() dell'applicazione di esempio dei Activity dell'applicazione:

Kotlin

class WalkieTalkieActivity : Activity(), View.OnTouchListener {
    ...
    lateinit var callReceiver: IncomingCallReceiver
    ...

    override fun onCreate(savedInstanceState: Bundle) {
        val filter = IntentFilter().apply {
            addAction("android.SipDemo.INCOMING_CALL")
        }
        callReceiver = IncomingCallReceiver()
        this.registerReceiver(callReceiver, filter)
        ...
    }
    ...
}

Java

public class WalkieTalkieActivity extends Activity implements View.OnTouchListener {
...
    public IncomingCallReceiver callReceiver;
    ...

    @Override
    public void onCreate(Bundle savedInstanceState) {

       IntentFilter filter = new IntentFilter();
       filter.addAction("android.SipDemo.INCOMING_CALL");
       callReceiver = new IncomingCallReceiver();
       this.registerReceiver(callReceiver, filter);
       ...
    }
    ...
}

Test delle applicazioni SIP

Per testare le applicazioni SIP, occorre quanto segue:

  • Un dispositivo mobile con Android 2.3 o versioni successive. Esecuzioni SIP oltre wireless, quindi devi testarlo su un dispositivo reale. I test sulla durata di visualizzazione media non funzionano.
  • Un account SIP. Esistono diversi fornitori SIP che offrono account SIP.
  • Se stai effettuando una chiamata, deve essere anche a un account SIP valido.

Per testare un'applicazione SIP:

  1. Sul dispositivo, connettiti alla rete wireless (Impostazioni > Wireless e reti) &gt; Wi-Fi > impostazioni Wi-Fi).
  2. Configura il dispositivo mobile per i test, come descritto nella sezione Sviluppare su un dispositivo.
  3. Esegui l'applicazione sul tuo dispositivo mobile, come descritto nella sezione Sviluppo su un dispositivo.
  4. Se utilizzi Android Studio, puoi visualizzare l'output del log dell'applicazione aprendo la console Log eventi (Visualizza > Finestre strumenti > Registro eventi).
  5. Assicurati che l'applicazione sia configurata per avviare automaticamente Logcat durante l'esecuzione:
    1. Seleziona Esegui > Modifica configurazioni.
    2. Seleziona la scheda Varie nella finestra Configurazioni esecuzione/debug.
    3. In Logcat, seleziona Mostra logcat automaticamente, quindi Seleziona OK.