Session Initiation Protocol – Übersicht

eSIMs und SIM-Karten erkennen

Karten erkennen

Android-Geräte mit SIM-Karten und eSIMs verwenden bei der Telefonie die folgenden IDs APIs, einschließlich [`TelephonyManager`](/reference/android/telephony/TelephonyManager) und [AboManager](/reference/android/telephony/SubscriptionManager): * Subscription ID: eindeutige ID für ein Mobilfunkabo * Logischer Slotindex oder ID: eindeutiger Index, der auf einen logischen SIM-Steckplatz verweist. Logische Slot-IDs beginnen bei 0 und steigen abhängig von der Anzahl der unterstützten aktiven Slots auf einem Gerät. Ein Dual-SIM-Gerät kann beispielsweise Slot 0 und Slot 1. Wenn ein Gerät über mehrere physische Steckplätze verfügt, einen aktiven Slot unterstützt, hat er nur die logische Slot-ID 0. * Index oder ID des physischen Slots: eindeutiger Index, der sich auf einen physischen SIM-Steckplatz bezieht. Physische Slot-IDs beginnen bei 0 und steigen je nach Anzahl der physischen am Gerät befinden. Sie unterscheidet sich von der Anzahl der logischen Slots auf einem Gerät. was der Anzahl der aktiven Slots entspricht, die ein Gerät haben kann. verwenden. Beispiel: Ein Gerät, das zwischen Dual-SIM und Single-SIM wechselt. hat der Modus immer zwei physische Steckplätze. Im Einzel-SIM-Modus hat er nur einen logischen Slot. * Card ID: eindeutige ID zur Identifizierung einer UiccCard ![Diagramm zur Verwendung von IDs in einem Fall mit zwei logischen und drei physischen Slots](/images/guide/topics/connectivity/tel-ids.png) Im obigen Diagramm gilt Folgendes: * Das Gerät hat zwei logische Steckplätze. * Im physischen Slot 0 befindet sich eine physische UICC-Karte mit einem aktiven Profil. * Im physischen Slot 2 ist eine eUICC mit einem aktiven Profil. * Der physische Slot 1 wird derzeit nicht verwendet. ![Diagramm zur Verwendung von IDs in einem Fall mit drei logischen und zwei physischen Slots](/images/guide/topics/connectivity/tel-ids-2.png) Im obigen Diagramm gilt Folgendes: * Das Gerät hat drei logische Slots. * Im physischen Slot 0 befindet sich eine physische UICC-Karte mit einem aktiven Profil. * Im physischen Slot 1 ist eine eUICC mit zwei heruntergeladenen Profilen vorhanden, die beide mit MEP (Multiple Enabled Profiles) aktiv sind.

Session Initiation Protocol – Übersicht

Android bietet eine API, die das Session Initiation Protocol (SIP) unterstützt. So können Sie Ihren Anwendungen SIP-basierte Internettelefoniefunktionen hinzufügen. Android umfasst einen vollständigen SIP-Protokollstack und integrierte Anrufverwaltung mit denen Anwendungen ganz einfach ausgehende und eingehende Sprachanrufe einrichten können, ohne sich um Sitzungen, die Kommunikation auf Transportebene oder können Sie sie direkt aufzeichnen oder wiedergeben.

Hier sind Beispiele für die Arten von Anwendungen, die die SIP API verwenden können:

  • Videokonferenz
  • Chat

Anforderungen und Einschränkungen

Folgende Anforderungen gelten für die Entwicklung einer SIP-Anwendung:

  • Sie benötigen ein Mobilgerät mit Android 2.3 oder höher.
  • SIP läuft über eine drahtlose Datenverbindung, daher muss Ihr Gerät über -Verbindung (über einen mobilen Datendienst oder WLAN) Das bedeutet, dass Sie Sie können keine AVD-Tests durchführen, sondern nur ein physisches Gerät. Weitere Informationen finden Sie unter SIP-Anwendungen testen
  • Jeder Teilnehmer in der Kommunikationssitzung der Anwendung muss eine SIP-Konto. Es gibt viele verschiedene SIP-Anbieter, die SIP-Konten anbieten.

Hinweis:Videos werden von der Bibliothek android.net.sip nicht unterstützt. Anrufe. Wenn Sie VoIP-Anrufe mit einem SIP-Stack wie android.net.sip, sehen Sie sich eine der vielen modernen Open-Source- als Basis für VoIP-Anrufe. Alternativ können Sie können Sie die ConnectionService API für eine enge Integration dieser Aufrufe in die Telefonfunktion des Geräts

SIP API-Klassen und -Schnittstellen

Hier ist eine Zusammenfassung der Klassen und einer Benutzeroberfläche (SipRegistrationListener), die im Android SIP enthalten sind API:

Klasse/Schnittstelle Beschreibung
SipAudioCall Verarbeitet Audioanrufe über das Internet über SIP.
SipAudioCall.Listener Listener für Ereignisse in Verbindung mit einem SIP-Anruf, z. B. wenn ein Anruf empfangen („beim Klingeln“) oder ein Anruf ausgehend („bei Anrufen“) ist.
SipErrorCode Definiert Fehlercodes, die während SIP-Aktionen zurückgegeben werden.
SipManager Stellt APIs für SIP-Aufgaben wie das Initiieren von SIP-Verbindungen und den Zugriff bereit zu zugehörigen SIP-Diensten.
SipProfile Definiert ein SIP-Profil, einschließlich SIP-Konto, Domain und Serverinformationen.
SipProfile.Builder Hilfsklasse zum Erstellen eines SipProfile
SipSession Stellt eine SIP-Sitzung dar, die einem SIP-Dialog oder einer eigenständigen Transaktion zugeordnet ist nicht innerhalb eines Dialogfelds.
SipSession.Listener Listener für Ereignisse im Zusammenhang mit einer SIP-Sitzung, z. B. wenn eine Sitzung registriert wird („bei der Registrierung“) oder ein Anruf ist ausgehend („bei Anrufen“).
SipSession.State Definiert den SIP-Sitzungsstatus, z. B. „Registrierung“, „Ausgehender Anruf“ und „Im Anruf“.
SipRegistrationListener Eine Schnittstelle, die ein Listener für SIP-Registrierungsereignisse ist.

Manifest wird erstellt

Wenn Sie eine Anwendung entwickeln, die die SIP API verwendet, denken Sie daran, dass das wird nur unter Android 2.3 (API Level 9) und höheren Versionen der auf der Plattform. Bei Geräten mit Android 2.3 (API-Level 9) oder höher nicht alle Geräte SIP-Unterstützung bieten.

Fügen Sie dem Manifest Ihrer Anwendung die folgenden Berechtigungen hinzu, um SIP zu verwenden:

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

Damit Ihre App nur auf Geräten installiert werden kann, die SIP unterstützen, fügen Sie Folgendes in die Manifest:

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

Dies bedeutet, dass Ihre Anwendung Android 2.3 oder höher erfordert. Für finden Sie unter API-Ebenen und die Dokumentation für die <uses-sdk> -Elements.

Um zu steuern, wie Ihre App von nicht unterstützten Geräten gefiltert wird SIP (z. B. bei Google Play) im Abschnitt Manifest:

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

Damit wird angegeben, dass Ihre Anwendung die SIP API verwendet. Die Erklärung sollte fügen Sie ein android:required-Attribut hinzu, das angibt, möchten, dass die Anwendung nach Geräten gefiltert wird, die keine SIP-Unterstützung bieten. Möglicherweise sind auch andere <uses-feature>-Deklarationen erforderlich. abhängig von Ihrer Implementierung. Weitere Informationen finden Sie in der Dokumentation für die <uses-feature> -Elements.

Wenn deine App darauf ausgelegt ist, Anrufe zu empfangen, musst du im Manifest der App auch einen Empfänger (Unterklasse BroadcastReceiver) definieren:

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

Hier sind Auszüge aus dem SipDemo-Manifest:

<?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>

SipManager wird erstellt

Damit Sie die SIP API verwenden können, muss Ihre Anwendung ein SipManager-Objekt erstellen. Die SipManager nimmt auf Folgendes achten:

  • SIP-Sitzungen werden gestartet.
  • Anrufe starten und empfangen
  • Registrieren und Aufheben der Registrierung bei einem SIP-Anbieter
  • Die Sitzungsverbindung wird geprüft.

So instanziieren Sie eine neue SipManager:

Kotlin

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

Java

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

Bei einem SIP-Server registrieren

An einer typischen Android SIP-Anwendung sind ein oder mehrere Nutzende beteiligt, von denen jeder hat ein SIP-Konto. In einer Android SIP-Anwendung ist jedes SIP-Konto dargestellt durch ein SipProfile-Objekt.

Ein SipProfile definiert ein SIP-Profil, einschließlich eines SIP Konto-, Domain- und Serverinformationen. Das mit dem SIP verknüpfte Profil Konto auf dem Gerät, auf dem die Anwendung läuft, heißt lokale Profil. Das Profil, mit dem die Sitzung verbunden ist, Peer-Profil. Wenn sich Ihre SIP-Anwendung beim SIP-Server mit die lokale SipProfile, registriert dies effektiv die Gerät als Standort für SIP-Anrufe für Ihre SIP-Adresse festlegen.

In diesem Abschnitt erfahren Sie, wie Sie eine SipProfile, auf einem SIP-Server registrieren und Registrierungsereignisse erfassen.

So erstellen Sie ein SipProfile-Objekt:

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();

Mit dem folgenden Codeauszug wird das lokale Profil geöffnet, um Anrufe zu tätigen und/oder generische SIP-Anrufe empfangen. Der Anrufer kann weitere Anrufe über mSipManager.makeAudioCall Dieser Auszug legt auch die Handlung android.SipDemo.INCOMING_CALL, die von einem Intent verwendet wird Filter, wenn das Gerät einen Anruf empfängt (siehe Einrichten der Intent-Filter zum Empfangen von Anrufen) verwenden. Dies ist der Registrierungsschritt:

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);

Schließlich wird mit diesem Code ein SipRegistrationListener für den SipManager festgelegt. Hier wird nachverfolgt, ob die SipProfile bei Ihrem SIP-Dienst registriert wurde Anbieter:

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.");
    }
}

Wenn Ihre Anwendung mit der Nutzung eines Profils fertig ist, sollte es geschlossen werden, damit es kostenlos verfügbar ist. zugehörige Objekte im Arbeitsspeicher verschieben und das Gerät vom Server abmelden. Für Beispiel:

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);
     }
}

Tätigen eines Sprachanrufs

Für Sprachanrufe müssen folgende Voraussetzungen erfüllt sein:

  • Ein SipProfile, der den Aufruf tätigt (die „lokales Profil“) und eine gültige SIP-Adresse zum Empfang des Anrufs (die „Peer-Profil“).
  • Ein SipManager-Objekt.

Für Audioanrufe musst du eine SipAudioCall.Listener einrichten. Ein Großteil der Interaktion der Kundschaft mit den SIP-Stack über Hörer. In diesem Snippet sehen Sie, wie SipAudioCall.Listener nach dem Anruf eingerichtet wird. gegründet:

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.
   }
};

Sobald du das Gerät (SipAudioCall.Listener) eingerichtet hast, kannst du Folgendes tun: den Anruf zu starten. Die Methode SipManager makeAudioCall verwendet die folgenden Parameter:

  • Ein lokales SIP-Profil (der Anrufer)
  • Ein Peer-SIP-Profil (der aufgerufene Nutzer)
  • SipAudioCall.Listener, um den Anruf anzuhören Events von SipAudioCall. Das kann null sein, Wie oben gezeigt, wird der Listener jedoch zur Einrichtung verwendet, sobald der Aufruf festgelegt ist.
  • Der Wert für das Zeitlimit in Sekunden.

Beispiel:

Kotlin

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

Java

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

Anrufe erhalten

Zum Empfangen von Anrufen muss eine SIP-Anwendung eine Unterklasse von BroadcastReceiver enthalten, die in der Lage ist, auf einen Intent zu antworten zeigt an, dass ein Anruf eingeht. Daher müssen Sie Folgendes in Ihre Anwendung:

  • Deklarieren Sie in AndroidManifest.xml Folgendes: <receiver>. In SipDemo ist das <receiver android:name=".IncomingCallReceiver" android:label="Call Receiver" />
  • Implementieren Sie den Empfänger, eine abgeleitete Klasse von BroadcastReceiver. In SipDemo ist das IncomingCallReceiver
  • Initialisieren Sie das lokale Profil (SipProfile) mit einem Pending Intent, der den Empfänger auslöst, wenn jemand das lokale Profil anruft.
  • Richten Sie einen Intent-Filter ein, der nach der Aktion filtert, die ein Eingehender Anruf. In SipDemo ist diese Aktion android.SipDemo.INCOMING_CALL

Abgeleitete Klassen für BroadcastReceiver erstellen

Zum Empfangen von Anrufen muss Ihre SIP-Anwendung eine abgeleitete Klasse von BroadcastReceiver erstellen. Die Das Android-System verarbeitet eingehende SIP-Anrufe und sendet eine Call"-Intent (wie von der Anwendung definiert), wenn er anrufen. Hier ist die abgeleitete Klasse BroadcastReceiver Code aus dem SipDemo-Beispiel.

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();
            }
        }
    }
}

Intent-Filter zum Empfangen von Anrufen einrichten

Wenn der SIP-Dienst einen neuen Anruf empfängt, sendet er einen Intent mit dem Parameter Aktions-String, der von der Anwendung bereitgestellt wird. In SipDemo lautet dieser Aktionsstring android.SipDemo.INCOMING_CALL

Dieser Codeauszug aus SipDemo zeigt, wie das Objekt SipProfile mit einem ausstehenden Intent erstellt wird. Aktionsstring android.SipDemo.INCOMING_CALL Die Das PendingIntent-Objekt führt eine Übertragung aus, wenn SipProfile einen Aufruf empfängt:

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);

Die Übertragung wird vom Intent-Filter abgefangen, der dann Empfänger (IncomingCallReceiver). Sie können einen Intent angeben, in der Manifest-Datei Ihrer App filtern oder dies im Code wie in der SipDemo Methode onCreate() der Beispielanwendung des Activity der Anwendung:

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);
       ...
    }
    ...
}

SIP-Anwendungen testen

Zum Testen von SIP-Anwendungen ist Folgendes erforderlich:

  • Ein Mobilgerät mit Android 2.3 oder höher. SIP-Laufzeiten über die drahtlose Verbindung erfordern, Sie müssen den Test daher auf einem echten Gerät durchführen. Das Testen mit AVD funktioniert nicht.
  • Ein SIP-Konto. Es gibt viele verschiedene SIP-Anbieter, die SIP-Konten anbieten.
  • Wenn du jemanden anrufst, muss es sich auch um ein gültiges SIP-Konto handeln.

So testen Sie eine SIP-Anwendung:

  1. Stellen Sie auf Ihrem Gerät eine Verbindung zu WLAN her (Einstellungen > Drahtlos & Netzwerke). &gt; WLAN > WLAN-Einstellungen).
  2. Richten Sie Ihr Mobilgerät für Tests ein, wie unter Auf einem Gerät entwickeln beschrieben.
  3. Führen Sie Ihre Anwendung auf Ihrem Mobilgerät aus, wie unter Auf einem Gerät entwickeln beschrieben.
  4. Wenn Sie Android Studio verwenden, können Sie die Ausgabe des Anwendungsprotokolls folgendermaßen aufrufen: Öffnen Sie die Konsole des Ereignisprotokolls (Ansicht > Toolfenster > Ereignisprotokoll).
  5. Achten Sie darauf, dass Ihre Anwendung so konfiguriert ist, dass Logcat bei der Ausführung automatisch gestartet wird: <ph type="x-smartling-placeholder">
      </ph>
    1. Wählen Sie Ausführen > Konfigurationen bearbeiten.
    2. Wählen Sie im Fenster Run/Debug Configurations (Ausführungs-/Fehlerbehebungskonfigurationen) den Tab Verschiedenes aus.
    3. Wählen Sie unter Logcat die Option Show logcat automatisch (Logcat automatisch anzeigen) aus. wählen Sie OK aus.