Visão geral do Session Initiation Protocol (SIP)

Detectar eSIMs e chips

Como detectar cards

Dispositivos Android com chips e eSIMs usam os seguintes IDs nas APIs de telefonia, incluindo ["TelephonyManager"](/reference/android/telephony/TelephonyManager) e ["SubscriptionManager"](/reference/android/telephony/SubscriptionManager): * ID de assinatura: ID exclusivo de uma assinatura móvel. * Índice ou ID de slot lógico: índice exclusivo que se refere a um slot de chip lógico. Os IDs de slot lógicos começam em 0 e aumentam de acordo com o número de slots ativos com suporte em um dispositivo. Por exemplo, um dispositivo com dois chips normalmente tem os slots 0 e 1. Se um dispositivo tiver vários slots físicos, mas aceitar apenas um slot ativo, ele terá apenas o ID de slot lógico 0. * Índice ou ID do slot físico: índice exclusivo que se refere a um slot físico de chip. Os IDs de slot físico começam em 0 e aumentam de acordo com o número de slots físicos no dispositivo. Isso é diferente do número de slots lógicos que um dispositivo tem, que corresponde ao número de slots ativos que um dispositivo pode usar. Por exemplo, um dispositivo que alterna entre os modos dual chip e único chip pode sempre ter dois slots físicos, mas no modo de chip único terá apenas um slot lógico. * ID do cartão: ID exclusivo usado para identificar um UiccCard. ![Um diagrama de como os IDs são usados em um caso com dois slots lógicos e três slots físicos](/images/guide/topics/connectivity/tel-ids.png) No diagrama acima: * O dispositivo tem dois slots lógicos. * No slot físico 0, há um cartão UICC físico com um perfil ativo. * No slot físico 2, há um eUICC com um perfil ativo. * O slot físico 1 não está em uso no momento. ![Um diagrama de como os IDs são usados em um caso com três slots lógicos e dois slots físicos](/images/guide/topics/connectivity/tel-ids-2.png) No diagrama acima: * O dispositivo tem três slots lógicos. * No slot físico 0, há um cartão UICC físico com um perfil ativo. * No slot físico 1, há um eUICC com dois perfis transferidos por download, ambos ativos usando o MEP (Vários perfis ativados).

Visão geral do protocolo de início de sessão

O Android oferece uma API compatível com o Protocolo de início de sessão (SIP, na sigla em inglês). Isso permite que você adicione recursos de telefonia via Internet baseados em SIP aos seus aplicativos. O Android inclui uma pilha completa de protocolos SIP e serviços integrados de gerenciamento de chamadas que permitem que os aplicativos configurem facilmente chamadas de voz realizadas e recebidas, sem precisar gerenciar sessões, comunicação no nível de transporte ou gravação ou reprodução de áudio diretamente.

Veja alguns exemplos dos tipos de aplicativos que podem usar a API SIP:

  • Videoconferência
  • Mensagem instantânea

Requisitos e limitações

Veja os requisitos para desenvolver um aplicativo com SIP:

  • Você precisa ter um dispositivo móvel com o Android 2.3 ou superior.
  • O SIP é executado em uma conexão de dados sem fio. Portanto, seu dispositivo precisa ter uma conexão de dados (com um serviço de dados móveis ou Wi-Fi). Isso significa que não é possível testar no AVD. Só é possível testar em um dispositivo físico. Para ver detalhes, consulte Testar aplicativos com SIP.
  • Cada participante da sessão de comunicação do aplicativo precisa ter uma conta SIP. Há muitos provedores SIP diferentes que oferecem contas SIP.

Observação:a biblioteca android.net.sip não é compatível com videochamadas. Se você quiser implementar chamadas VoIP usando uma pilha SIP, como android.net.sip, considere uma das diversas alternativas modernas de código aberto como base para qualquer implementação de chamada VOIP. Como alternativa, você pode implementar a API ConnectionService para fornecer uma integração sólida dessas chamadas no app Telefone do dispositivo.

Classes e interfaces da API SIP

Veja um resumo das classes e uma interface (SipRegistrationListener) incluídas na API SIP do Android:

Classe/interface Descrição
SipAudioCall Processa uma chamada de áudio de Internet por meio do SIP.
SipAudioCall.Listener Listener para eventos relacionados a uma chamada SIP, como quando uma chamada é recebida ("tocando") ou realizada ("na chamada").
SipErrorCode Define os códigos de erro retornados durante ações SIP.
SipManager Fornece APIs para tarefas SIP, como iniciar conexões SIP, e fornece acesso a serviços SIP relacionados.
SipProfile Define um perfil SIP, incluindo uma conta SIP, informações de domínio e de servidor.
SipProfile.Builder Classe auxiliar para a criação de um SipProfile.
SipSession Representa uma sessão SIP associada a uma caixa de diálogo do SIP ou uma transação independente que não está em uma caixa de diálogo.
SipSession.Listener Listener para eventos relacionados a uma sessão SIP, como quando uma sessão está sendo registrada ("no registro") ou quando uma chamada é realizada ("na chamada").
SipSession.State Define os estados de sessões SIP, como "registrando", "chamada realizada" e "em chamada".
SipRegistrationListener Uma interface que é um listener para eventos de registro SIP.

Criar um manifesto

Se você estiver desenvolvendo um aplicativo que usa a API SIP, lembre-se de que o recurso oferece suporte apenas ao Android 2.3 (nível 9 da API) e versões mais recentes da plataforma. Além disso, nem todos os dispositivos que executam o Android 2.3 (nível 9 da API) ou versões mais recentes oferecem suporte ao SIP.

Para usar o SIP, adicione as seguintes permissões ao manifesto do seu aplicativo:

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

Para garantir que seu aplicativo só possa ser instalado em dispositivos compatíveis com o SIP, adicione o seguinte ao manifesto do aplicativo:

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

Isso indica que o aplicativo requer o Android 2.3 ou posterior. Para mais informações, consulte Níveis de API e a documentação do elemento <uses-sdk>.

Para controlar como o aplicativo é filtrado de dispositivos não compatíveis com SIP (por exemplo, no Google Play), adicione o seguinte ao manifesto do aplicativo:

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

Isso declara que seu aplicativo usa a API SIP. A declaração precisa incluir um atributo android:required que indica se você quer que o aplicativo seja filtrado de dispositivos que não oferecem suporte ao SIP. Outras declarações <uses-feature> também podem ser necessárias, dependendo da implementação. Para mais informações, consulte a documentação do elemento <uses-feature>.

Se o aplicativo for projetado para receber chamadas, também será necessário definir um destinatário (subclasse BroadcastReceiver) no manifesto do aplicativo:

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

Veja trechos do manifesto 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>

Criar o SipManager

Para usar a API SIP, seu aplicativo precisa criar um objeto SipManager. O SipManager cuida do seguinte no seu aplicativo:

  • Iniciar sessões SIP.
  • Iniciar e receber chamadas.
  • Registrar e cancelar o registro com um provedor SIP.
  • Verificar a conectividade da sessão.

Instancie um novo SipManager da seguinte forma:

Kotlin

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

Java

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

Como registrar-se com um servidor SIP

Um aplicativo SIP típico do Android envolve um ou mais usuários, cada um com uma conta SIP. Em um aplicativo SIP para Android, cada conta SIP é representada por um objeto SipProfile.

Um SipProfile define um perfil SIP, incluindo uma conta SIP e informações de domínio e servidor. O perfil associado à conta SIP no dispositivo que executa o aplicativo é chamado de perfil local. O perfil ao qual a sessão é conectada é chamado de perfil de apps semelhantes. Quando o aplicativo SIP faz login no servidor SIP com o SipProfile local, isso registra o dispositivo como o local para onde enviar chamadas SIP para o endereço SIP.

Esta seção mostra como criar um SipProfile, registrá-lo com um servidor SIP e acompanhar eventos de registro.

Crie um objeto SipProfile da seguinte forma:

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

O trecho de código a seguir abre o perfil local para fazer chamadas e/ou receber chamadas SIP genéricas. O autor da chamada pode fazer chamadas subsequentes usando mSipManager.makeAudioCall. Esse trecho também define a ação android.SipDemo.INCOMING_CALL, que será usada por um filtro de intent quando o dispositivo receber uma chamada. Consulte Como configurar um filtro de intent para receber chamadas. Esta é a etapa de registro:

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

Por fim, este código define um SipRegistrationListener no SipManager. Isso rastreia se o SipProfile foi registrado no provedor de serviços SIP:

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 o aplicativo terminar de usar um perfil, ele será fechado para liberar objetos associados na memória e cancelar o registro do dispositivo no servidor. Por exemplo:

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

Fazer uma chamada de áudio

Para fazer uma chamada de áudio, é preciso ter o seguinte:

  • Um SipProfile que esteja fazendo a chamada (o "perfil local") e um endereço SIP válido para receber a chamada (o "perfil de peering").
  • Um objeto SipManager.

Para fazer uma chamada de áudio, configure um SipAudioCall.Listener. Grande parte da interação do cliente com a pilha do SIP acontece por meio de listeners. Neste snippet, você pode conferir como o SipAudioCall.Listener faz as configurações depois que a chamada é estabelecida:

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

Depois de configurar o SipAudioCall.Listener, é possível fazer a chamada. O método makeAudioCall do SipManager usa estes parâmetros:

  • Um perfil SIP local (o autor da chamada).
  • Um perfil SIP semelhante (o usuário que recebe a chamada).
  • Um SipAudioCall.Listener para detectar os eventos de chamada de SipAudioCall. Pode ser null, mas, como mostrado acima, o listener é usado para definir as configurações depois que a chamada é estabelecida.
  • O valor de tempo limite, em segundos.

Por exemplo:

Kotlin

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

Java

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

Receber chamadas

Para receber chamadas, um aplicativo SIP precisa incluir uma subclasse de BroadcastReceiver, que possa responder a uma intent indicando que há uma chamada recebida. Portanto, faça o seguinte no seu aplicativo:

  • Em AndroidManifest.xml, declare um <receiver>. Em SipDemo, isso é <receiver android:name=".IncomingCallReceiver" android:label="Call Receiver" />.
  • Implemente o destinatário, que é uma subclasse de BroadcastReceiver. Em SipDemo, isso é IncomingCallReceiver.
  • Inicialize o perfil local (SipProfile) com uma intent pendente que dispara seu receptor quando alguém liga para o perfil local.
  • Configure um filtro de intent que filtre pela ação que representa uma chamada recebida. Em SipDemo, essa ação é android.SipDemo.INCOMING_CALL.

Criar uma subclasse de BroadcastReceiver

Para receber chamadas, seu aplicativo SIP precisa ter a subclasse BroadcastReceiver. O sistema Android processa chamadas SIP recebidas e transmite uma intent de "chamada recebida" (conforme definido pelo aplicativo) quando recebe uma chamada. Veja o código BroadcastReceiver com subclasses do exemplo 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();
            }
        }
    }
}

Como configurar um filtro de intent para receber chamadas

Quando o serviço SIP recebe uma nova chamada, ele envia uma intent com a string de ação fornecida pelo aplicativo. No SipDemo, essa string de ação é android.SipDemo.INCOMING_CALL.

Este trecho de código de SipDemo mostra como o objeto SipProfile é criado com uma intent pendente baseada na string de ação android.SipDemo.INCOMING_CALL. O objeto PendingIntent realizará uma transmissão quando o SipProfile receber uma chamada:

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

A transmissão será interceptada pelo filtro de intent, que acionará o receptor (IncomingCallReceiver). É possível especificar um filtro de intent no arquivo de manifesto do app ou fazer isso no código, como no método onCreate() do aplicativo de exemplo SipDemo do 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);
       ...
    }
    ...
}

Testar aplicativos SIP

Para testar aplicativos SIP, você precisa do seguinte:

  • Um dispositivo móvel com o Android 2.3 ou versões posteriores. O SIP é executado por Wi-Fi, portanto, você precisa testar em um dispositivo real. Não é possível realizar os testes no AVD.
  • Uma conta SIP. Há muitos provedores SIP diferentes que oferecem contas SIP.
  • Se você estiver fazendo uma chamada, ela também precisa ser para uma conta SIP válida.

Para testar um aplicativo SIP:

  1. No dispositivo, conecte-se a uma rede sem fio (Configurações > Redes sem fio e outras > Wi-Fi > Configurações de Wi-Fi).
  2. Configure seu dispositivo móvel para testes, conforme descrito em Executar apps em um dispositivo de hardware.
  3. Execute seu aplicativo no dispositivo móvel, conforme descrito em Executar apps em um dispositivo de hardware.
  4. Se você está usando o Android Studio, é possível conferir a saída do registro do aplicativo abrindo o console do log de eventos (View > Tool Windows > Event Log).
  5. Verifique se o aplicativo está configurado para iniciar o Logcat automaticamente quando ele for executado:
    1. Selecione Run > Edit Configurations.
    2. Selecione a guia Miscellaneous na janela Run/Debug Configurations.
    3. Em Logcat, selecione Show logcat automatically e, em seguida, OK.