セッション開始プロトコルの概要

eSIM と SIM カードを検出する

カードの検出

SIM カードと eSIM を搭載した Android デバイスでは、電話通信で次の ID が使用されます Google Cloud などの [`TelephonyManager`](/reference/android/telephony/TelephonyManager) と [`SubscriptionManager`](/reference/android/telephony/SubscriptionManager): * サブスクリプション ID: モバイル サブスクリプションの一意の ID。 * 論理スロット インデックス(ID): 論理 SIM スロットを参照する一意のインデックス。 論理スロット ID は 0 から始まり、論理スロット ID はスロットの数に応じて アクティブなスロットの数を表します。たとえばデュアル SIM デバイスでは通常、 スロット 0 とスロット 1 がありますデバイスに複数の物理スロットがあるが、 1 つのアクティブなスロットをサポートする場合、論理スロット ID は 0 のみになります。 * 物理スロット インデックスまたは ID: 物理的な SIM スロットを参照する一意のインデックス。 物理スロット ID は 0 から始まり、物理スロット ID の数に応じて増加します。 スロットにアタッチできます。デバイスの論理スロット数とは異なります。 (デバイスのアクティブなスロット数に対応) できます。(デュアル SIM とシングル SIM を切り替えるデバイスなど) 物理スロットが 2 つある場合もありますが、シングル SIM モードでは、 スロットは 1 つだけです。 * カード ID: UiccCard の識別に使用される一意の ID ![2 つの論理スロットと 3 つの物理スロットがあるケースで ID がどのように使用されるかを示す図](/images/guide/topics/connectivity/tel-ids.png) 上の図の内容は次のとおりです。 * デバイスには 2 つの論理スロットがあります。 * 物理スロット 0 には、アクティブなプロファイルを持つ物理 UICC カードがあります。 * 物理スロット 2 には、アクティブなプロファイルの eUICC があります。 * 物理スロット 1 は現在使用されていません。 ![3 つの論理スロットと 2 つの物理スロットがあるケースで ID がどのように使用されるかを示す図](/images/guide/topics/connectivity/tel-ids-2.png) 上の図の内容は次のとおりです。 * デバイスには 3 つの論理スロットがある。 * 物理スロット 0 には、アクティブなプロファイルを持つ物理 UICC カードがあります。 * 物理スロット 1 には eUICC があり、ダウンロードしたプロファイルが 2 つあり、どちらも MEP(Multiple Enabled Profiles)を使用してアクティブです。

セッション開始プロトコルの概要

Android には、SIP(セッション開始プロトコル)をサポートする API が用意されています。 これにより、SIP ベースのインターネット電話機能をアプリケーションに追加できます。 Android は完全な SIP プロトコル スタックと統合された通話管理を搭載 アプリが音声通話の発信と着信を簡単に設定できるようにするサービス セッション、トランスポート レベルの通信、音声を管理することなく、 直接録画や再生ができます。

SIP API を使用するアプリケーションの種類の例を次に示します。

  • ビデオ会議
  • インスタント メッセージ

要件と制限事項

SIP アプリケーションを開発するための要件は次のとおりです。

  • Android 2.3 以降を搭載しているモバイル デバイスが必要です。
  • SIP はワイヤレス データ接続で動作するため、デバイスに モバイルデータ通信または Wi-Fi に接続する必要があります。つまり、 AVD ではテストできず、実機でのみテストできます。詳しくは、 SIP アプリケーションをテストする
  • アプリケーションの通信セッションの各参加者は、 SIP アカウント。さまざまな SIP プロバイダが SIP アカウントを提供しています。

注: android.net.sip ライブラリは動画をサポートしていません。 できます。次のような SIP スタックを使用して VoIP 通話を実装するには、 android.net.sip は、数多く存在する最新のオープンソースの一つです。 あらゆる VoIP 通話実装の基盤として利用できます。または kubectl の「get pods」 ConnectionService これらの呼び出しをデバイスの電話アプリと緊密に統合する API 。

SIP API のクラスとインターフェース

これらのクラスとインターフェースの概要は以下のとおりです。 (SipRegistrationListener) API:

クラス / インターフェース 説明
SipAudioCall SIP を介したインターネット音声通話を処理します。
SipAudioCall.Listener SIP 通話に関連するイベントのリスナー(通話中など) 着信(「着信中」)、通話が発信中(「通話中」)などです。
SipErrorCode SIP アクション中に返されるエラーコードを定義します。
SipManager SIP 接続の開始などの SIP タスク用の API を提供し、 関連付けることもできます。
SipProfile SIP アカウント、ドメイン、サーバー情報を含む SIP プロファイルを定義します。
SipProfile.Builder SipProfile を作成するためのヘルパークラス。
SipSession SIP ダイアログまたはスタンドアロン トランザクションに関連付けられている SIP セッションを表します。 必要があります。
SipSession.Listener SIP セッションに関連するイベントのリスナー(セッションの登録時など) (「登録中」)、通話が発信中(「通話中」)などです。
SipSession.State 「登録」、「発信」、「着信」など、SIP セッションの状態を定義します。
SipRegistrationListener SIP 登録イベントのリスナーであるインターフェース。

マニフェストの作成

SIP API を使用するアプリケーションを開発する場合、 この機能は、Android 2.3(API レベル 9)以降の 説明します。また、Android 2.3(API レベル 9)以降を搭載しているデバイスでは、 すべてのデバイスが SIP に対応しているわけではありません。

SIP を使用するには、アプリケーションのマニフェストに次の権限を追加します。

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

次の要件を満たすデバイスにのみアプリをインストールするには、 サポートする必要がある場合は、アプリケーションの manifest:

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

これは、アプリケーションに Android 2.3 以降が必要であることを示しています。対象 詳細については、以下をご覧ください。 API レベル およびドキュメントをご覧ください <uses-sdk> 要素です。

サポートしていないデバイスからのアプリケーションのフィルタリング方法を制御するには SIP(Google Play など)を使用する場合は、アプリの manifest:

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

これは、アプリケーションが SIP API を使用していることを示しています。この宣言では、 android:required 属性を含めて、 SIP に対応していないデバイスからアプリケーションを除外したい。 その他の <uses-feature> 宣言が必要になる場合もあります。 どちらを使用するかは異なります詳細については、このモジュールのコースリソースに の <uses-feature> 要素です。

アプリケーションが通話を受信するように設計されている場合は、アプリケーションのマニフェストで受信側(BroadcastReceiver サブクラス)を定義する必要もあります。

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

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>

SipManager の作成

SIP API を使用するには、アプリケーションで SipManager オブジェクトを作成する必要があります。SipManager は、 アプリケーションで次のことに注意する必要があります。

  • SIP セッションの開始。
  • 通話の開始と受信。
  • SIP プロバイダへの登録と登録解除。
  • セッション接続の確認。

新しい SipManager を次のようにインスタンス化します。

Kotlin

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

Java

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

SIP サーバーへの登録

一般的な Android SIP アプリケーションでは、1 人以上のユーザーが 持っているかどうかを選択します。Android SIP アプリケーションでは、各 SIP アカウントは SipProfile オブジェクトで表されます。

SipProfile は、SIP を含む SIP プロファイルを定義します。 アカウント、ドメイン、サーバーの情報。SIP に関連付けられたプロファイル アプリケーションを実行しているデバイス上のアカウントは、ローカル プロファイルをご覧ください。セッションが接続されているプロファイルは、 ピア プロファイル。SIP アプリケーションが 2 段階認証プロセスを使用して SIP サーバーにログインすると、 これにより、SipProfileローカルの SIP アドレスへの SIP 通話の送信先として指定します。

このセクションでは、SipProfile を作成する方法について説明します。 SIP サーバーに登録し、登録イベントを追跡します。

SipProfile オブジェクトは、次のように作成します。

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

次のコードの抜粋では、通話や通話を行うためのローカル プロファイルを開きます。 一般的な SIP 通話を受信します呼び出し元は、後続の呼び出しを mSipManager.makeAudioCall。この抜粋では android.SipDemo.INCOMING_CALL: インテントで使用されます 受信時にフィルタできます( 通話を受信するインテント フィルタなど)が含まれます。これは登録手順です。

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

最後に、このコードは SipManagerSipRegistrationListener を設定します。SipProfile が SIP サービスに正常に登録されたかどうかを追跡します provider:

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

プロファイルを使用したアプリの処理が完了したら、プロファイルを閉じてから解放する必要があります。 関連付けられたオブジェクトをメモリに書き込み、サーバーからデバイスの登録を解除します。次に例を示します。

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

音声通話を発信する

音声通話を発信するには、次のものが必要です。

  • 呼び出し元の SipProfile( 「ローカル プロファイル」)、通話を受けるための有効な SIP アドレス( 「ピアのプロフィール」)を入力します。
  • SipManager オブジェクト。

音声通話を発信するには、SipAudioCall.Listener を設定する必要があります。クライアントとのやり取りの多くは、 SIP スタックはリスナーを介して発生しますこのスニペットでは、呼び出し後に SipAudioCall.Listener がどのように設定を行うかを示しています。 確立:

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

SipAudioCall.Listener を設定すると、次のことが可能になります。 電話をかけます。SipManager メソッド makeAudioCall は次のパラメータを取ります。

  • ローカル SIP プロファイル(発信側)。
  • ピア SIP プロファイル(通話を受けるユーザー)。
  • 通話を聴くための SipAudioCall.Listener SipAudioCall のイベント。null、 ただし、上に示したように、リスナーを使用して、呼び出しが完了したら、セットアップを行います。 あります。
  • タイムアウト値(秒)。

例:

Kotlin

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

Java

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

通話を受信する

着信を受けるには、インテントに応答できる BroadcastReceiver のサブクラスが SIP アプリケーションに含まれている必要があります。 着信があることを示しています。したがって、次のことを行う必要があります。 説明します。

  • AndroidManifest.xml で、 <receiver>SipDemo では、 <receiver android:name=".IncomingCallReceiver" android:label="Call Receiver" />
  • 受信側(BroadcastReceiver のサブクラス)を実装する。SipDemo では、 IncomingCallReceiver
  • ローカル プロファイル(SipProfile)を 保留中のインテントがあります。
  • アクションでフィルタするインテント フィルタをセットアップします。 着信を通知します。SipDemo では、このアクションは android.SipDemo.INCOMING_CALL

BroadcastReceiver のサブクラス化

通話を受信するには、SIP アプリケーションで BroadcastReceiver をサブクラス化する必要があります。 Android システムが SIP 通話の着信を処理し、 (アプリで定義される) インテントを呼び出すことができます。 通話ができるようになります。サブクラス化された BroadcastReceiver は次のとおりです。 (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();
            }
        }
    }
}

通話を受信するためのインテント フィルタの設定

新しい通話を受信すると、SIP サービスは アクション文字列を返します。SipDemo では、このアクション文字列を android.SipDemo.INCOMING_CALL

SipDemo からのこのコードの抜粋は、SipProfile オブジェクトがどのように作成されたかを示しています。 アクション文字列 android.SipDemo.INCOMING_CALL。「 PendingIntent オブジェクトは、SipProfile が呼び出しを受け取るとブロードキャストを実行します。

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

ブロードキャストがインテント フィルタによってインターセプトされ、 受信側(IncomingCallReceiver)。インテントを指定すると、 フィルタを使用するか、SipDemo サンプル アプリケーションの onCreate() メソッド アプリケーションの Activity:

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 アプリケーションのテスト

SIP アプリケーションをテストするには、次のものが必要です。

  • Android 2.3 以降を搭載しているモバイル デバイス。SIP は 実際のデバイスでテストする必要があります。AVD でのテストは機能しません。
  • SIP アカウント。さまざまな SIP プロバイダが SIP アカウントを提供しています。
  • 通話を発信する場合は、有効な SIP アカウントにも発信する必要があります。

SIP アプリケーションをテストする手順は次のとおりです。

  1. デバイスをワイヤレスに接続します([設定] > [無線とネットワーク] &gt;Wi-Fi >Wi-Fi 設定をご覧ください)。
  2. デバイスでの開発の説明に沿って、モバイル デバイスをテスト用に設定します。
  3. デバイスでの開発の説明に従って、モバイル デバイスでアプリケーションを実行します。
  4. Android Studio を使用している場合は、次のコマンドでアプリケーション ログの出力を表示できます。 イベントログ コンソールを開きます([View] > [Tool Windows] > [Event Log])。
  5. 実行時に Logcat を自動的に起動するようにアプリケーションを構成します。 <ph type="x-smartling-placeholder">
      </ph>
    1. [Run] >構成の編集をご覧ください。
    2. [Run/Debug Configurations] ウィンドウで [Miscellaneous] タブを選択します。
    3. [Logcat] で、[Show logcat で利用可能な] を選択し、 [OK] を選択します。