Crie aplicações interativas apenas com áudio, como chamadas de voz e salas de bate-papo por voz, integrando o ARTC SDK ao seu projeto iOS.
Conceitos principais
|
Termo |
Definição |
|
ARTC SDK |
SDK do ApsaraVideo Real-time Communication (ARTC). Adiciona recursos de áudio e vídeo em tempo real à sua aplicação. |
|
Canal |
Espaço virtual onde os usuários interagem em tempo real. |
|
Streamer |
Usuário que pode publicar e assinar streams de áudio e vídeo em um canal. Corresponde a |
|
Viewer |
Usuário que pode assinar streams de áudio e vídeo em um canal, mas não pode publicar streams. Corresponde a |
Como canais, streamers e viewers interagem
Todos os usuários devem chamar joinChannel para entrar em um canal antes de publicar ou assinar streams.
|
Cenário |
Funções |
Comportamento |
|
Chamada apenas de áudio |
Todos os usuários são streamers |
Cada usuário pode publicar e assinar streams. |
|
Sala de bate-papo por voz |
Streamers publicam streams; viewers apenas assinam |
Chame |
Após entrar em um canal:
Todos os usuários recebem streams de áudio e vídeo de outros participantes do mesmo canal.
Apenas streamers podem publicar streams de áudio e vídeo no canal.
Para permitir que um viewer publique um stream, chame
setClientRolepara alterar a função do usuário para streamer.
Projeto de exemplo
Baixe ou visualize o source de exemplo no projeto open source do ARTC SDK no GitHub.
Pré-requisitos
Antes de começar, verifique se você tem:
Xcode 14.0 ou posterior instalado. Use a versão oficial mais recente.
CocoaPods 1.9.3 ou posterior instalado.
Dispositivo físico de teste executando iOS 9.0 ou posterior.
Conexão de rede estável.
AppID e AppKey do ARTC. Para mais informações, consulte Criar uma aplicação.
Projeto configurado com o ARTC SDK, incluindo permissões de áudio e rede. Para mais informações, consulte Implementar uma chamada de áudio e vídeo.
Use um dispositivo físico para testes. Simuladores podem não oferecer suporte a determinados recursos.
Implemente a interação apenas com áudio
1. Solicite permissões
Solicite as permissões de câmera e microfone antes de iniciar uma chamada. O SDK verifica as permissões automaticamente, mas solicitá-las antecipadamente proporciona uma experiência mais fluida.
func checkMicrophonePermission(completion: @escaping (Bool) -> Void) {
let status = AVCaptureDevice.authorizationStatus(for: .audio)
switch status {
case .notDetermined:
AVCaptureDevice.requestAccess(for: .audio) { granted in
completion(granted)
}
case .authorized:
completion(true)
default:
completion(false)
}
}
func checkCameraPermission(completion: @escaping (Bool) -> Void) {
let status = AVCaptureDevice.authorizationStatus(for: .video)
switch status {
case .notDetermined:
AVCaptureDevice.requestAccess(for: .video) { granted in
completion(granted)
}
case .authorized:
completion(true)
default:
completion(false)
}
}
// Usage example
checkMicrophonePermission { granted in
if granted {
print("Microphone access granted.")
} else {
print("Microphone access denied.")
}
}
checkCameraPermission { granted in
if granted {
print("Camera access granted.")
} else {
print("Camera access denied.")
}
}
2. Obtenha um token de autenticação
Entrar em um canal ARTC exige um token de autenticação. É possível gerar tokens pelo método de parâmetro único ou multiparâmetro, o que determina qual API joinChannel chamar. Para detalhes, consulte Implementar autenticação baseada em token.
Ambientes de produção
Gere o token no servidor e envie-o ao cliente. Codificar o AppKey diretamente no lado do cliente representa um risco de segurança.
Desenvolvimento e depuração
Se o servidor ainda não gera tokens, use temporariamente a lógica de geração de tokens do APIExample:
class ARTCTokenHelper: NSObject {
/**
* RTC AppId
*/
public static let AppId = "<RTC AppId>"
/**
* RTC AppKey
*/
public static let AppKey = "<RTC AppKey>"
/**
* Generate a multi-parameter token for joining a channel based on channelId, userId, and timestamp.
*/
public func generateAuthInfoToken(appId: String = ARTCTokenHelper.AppId, appKey: String = ARTCTokenHelper.AppKey, channelId: String, userId: String, timestamp: Int64) -> String {
let stringBuilder = appId + appKey + channelId + userId + "\(timestamp)"
let token = ARTCTokenHelper.GetSHA256(stringBuilder)
return token
}
/**
* Generate a single-parameter token for joining a channel based on channelId, userId, and nonce.
*/
public func generateJoinToken(appId: String = ARTCTokenHelper.AppId, appKey: String = ARTCTokenHelper.AppKey, channelId: String, userId: String, timestamp: Int64, nonce: String = "") -> String {
let token = self.generateAuthInfoToken(appId: appId, appKey: appKey, channelId: channelId, userId: userId, timestamp: timestamp)
let tokenJson: [String: Any] = [
"appid": appId,
"channelid": channelId,
"userid": userId,
"nonce": nonce,
"timestamp": timestamp,
"token": token
]
if let jsonData = try? JSONSerialization.data(withJSONObject: tokenJson, options: []),
let base64Token = jsonData.base64EncodedString() as String? {
return base64Token
}
return ""
}
/**
* Sign a string using SHA256.
* String signing (SHA256)
*/
private static func GetSHA256(_ input: String) -> String {
// Convert input string to data.
let data = Data(input.utf8)
// Create a buffer to store the hash result.
var hash = [UInt8](repeating: 0, count: Int(CC_SHA256_DIGEST_LENGTH))
// Calculate the SHA-256 hash.
data.withUnsafeBytes {
_ = CC_SHA256($0.baseAddress, CC_LONG(data.count), &hash)
}
// Convert the hash to a hexadecimal string.
return hash.map { String(format: "%02hhx", $0) }.joined()
}
}
3. Crie e inicialize o mecanismo
Crie o mecanismo RTC
Chame sharedInstance para criar um objeto de mecanismo RTC.
private var rtcEngine: AliRtcEngine? = nil
// Create the engine and set the callback.
let engine = AliRtcEngine.sharedInstance(self, extras:nil)
self.rtcEngine = engine
Inicialize o mecanismo
Configure o perfil do canal, a função do usuário e as definições de áudio:
|
Método |
Finalidade |
Valor |
|
|
Defina o perfil do canal como transmissão ao vivo interativa |
|
|
|
Atribui a função do usuário |
Streamer: |
|
|
Defina a qualidade de áudio e o modo de cenário |
|
// Set the channel profile to interactive live streaming. AliRtcInteractivelive is used for all RTC scenarios.
engine.setChannelProfile(AliRtcChannelProfile.interactivelive)
// Set the role.
if self.isAnchor {
// For streamer mode, which requires publishing audio and video streams, set the role to AliRtcClientRoleInteractive.
engine.setClientRole(AliRtcClientRole.roleInteractive)
}
else {
// For viewer mode, which does not require publishing audio and video streams, set the role to AliRtcClientRolelive.
engine.setClientRole(AliRtcClientRole.rolelive)
}
// Set the audio profile. By default, high-quality mode (AliRtcEngineHighQualityMode) and music mode (AliRtcSceneMusicMode) are used.
engine.setAudioProfile(AliRtcAudioProfile.engineHighQualityMode, audio_scene: AliRtcAudioScenario.sceneMusicMode)
4. Configure a publicação e a assinatura
Por padrão, o SDK publica e assina automaticamente streams de áudio e vídeo no canal.
Depois que a função é definida como viewer, o método
publishLocalAudioStreamtorna-se inválido.A configuração a seguir aplica-se tanto a streamers quanto a viewers.
// Set the audio profile. By default, high-quality mode (AliRtcEngineHighQualityMode) and music mode (AliRtcAudioScenario.sceneMusicMode) are used.
engine.setAudioProfile(AliRtcAudioProfile.engineHighQualityMode, audio_scene: AliRtcAudioScenario.sceneMusicMode)
// For a voice chat scenario, you do not need to publish a video stream.
engine.publishLocalVideoStream(false)
// Set the default subscription to remote audio streams.
engine.setDefaultSubscribeAllRemoteAudioStreams(true)
engine.subscribeAllRemoteAudioStreams(true)
5. Entre em um canal
Chame joinChannel para entrar em um canal e iniciar a interação apenas com áudio.
Se o token foi gerado pelo método de parâmetro único, chame o método [joinChannel[1/3]](t2309760.xdita#758b964acc7jd) de parâmetro único. Se o token foi gerado pelo método multiparâmetro, chame o método [joinChannel[2/3]](t2309760.xdita#766e40a1cfk4p) multiparâmetro. O callback onJoinChannelResult retorna o resultado. Um resultado igual a 0 indica sucesso. Qualquer outro valor indica falha — verifique se o token é válido.
self.rtcEngine?.joinChannel(joinToken, channelId: nil, userId: nil, name: nil)
6. Encerre a interação
Saia do canal e destrua o mecanismo para liberar recursos:
Chame
leaveChannelpara sair do canal.Chame
destroypara destruir o mecanismo e liberar recursos.
self.rtcEngine?.leaveChannel()
AliRtcEngine.destroy()
self.rtcEngine = nil
7. (Opcional) Alterne entre as funções de viewer e streamer
Chame setClientRole para alternar um viewer para streamer (para publicar streams) ou um streamer de volta para viewer (para parar de publicar).
// Switch to the streamer role.
self.rtcEngine?.setClientRole(AliRtcClientRole.roleInteractive)
// Switch to the viewer role.
self.rtcEngine?.setClientRole(AliRtcClientRole.rolelive)
Trate os callbacks do mecanismo
O SDK se recupera da maioria das exceções automaticamente. Para erros que não consegue resolver, o SDK notifica sua aplicação por meio de callbacks.
|
Causa |
Callback e parâmetros |
Solução |
|
Falha na autenticação |
|
Verifique se o token está correto. |
|
Token prestes a expirar |
|
Obtenha as informações de autenticação mais recentes e chame |
|
Token expirado |
|
Faça o usuário entrar novamente no canal. |
|
Erro de conectividade de rede |
|
O SDK se recupera automaticamente de breves desconexões de rede. Se a desconexão exceder o limiar de tempo limite, verifique o status da rede e faça o usuário entrar novamente no canal. |
|
Desconectado forçadamente |
|
|
|
Exceção no dispositivo local |
|
Verifique as permissões e o status do hardware do dispositivo. |
extension VideoCallMainVC: AliRtcEngineDelegate {
func onJoinChannelResult(_ result: Int32, channel: String, elapsed: Int32) {
"onJoinChannelResult1 result: \(result)".printLog()
}
func onJoinChannelResult(_ result: Int32, channel: String, userId: String, elapsed: Int32) {
"onJoinChannelResult2 result: \(result)".printLog()
}
func onRemoteUser(onLineNotify uid: String, elapsed: Int32) {
// A remote user comes online.
"onRemoteUserOlineNotify uid: \(uid)".printLog()
}
func onRemoteUserOffLineNotify(_ uid: String, offlineReason reason: AliRtcUserOfflineReason) {
// A remote user goes offline.
"onRemoteUserOffLineNotify uid: \(uid) reason: \(reason)".printLog()
}
func onRemoteTrackAvailableNotify(_ uid: String, audioTrack: AliRtcAudioTrack, videoTrack: AliRtcVideoTrack) {
"onRemoteTrackAvailableNotify uid: \(uid) audioTrack: \(audioTrack) videoTrack: \(videoTrack)".printLog()
}
func onAuthInfoWillExpire() {
"onAuthInfoWillExpire".printLog()
/* TODO: You must handle this callback. The token is about to expire. Your application must get a new token for the current channel and user, and then call refreshAuthInfo. */
}
func onAuthInfoExpired() {
"onAuthInfoExpired".printLog()
/* TODO: You must handle this callback. Prompt the user that the token has expired, and then leave the channel and release the engine. */
}
func onBye(_ code: Int32) {
"onBye code: \(code)".printLog()
/* TODO: You must handle this callback. Your business may trigger a scenario where different devices with the same user ID compete for access. */
}
func onLocalDeviceException(_ deviceType: AliRtcLocalDeviceType, exceptionType: AliRtcLocalDeviceExceptionType, message msg: String?) {
"onLocalDeviceException deviceType: \(deviceType) exceptionType: \(exceptionType)".printLog()
/* TODO: You must handle this callback. We recommend that your application prompts the user about the device error. This callback is triggered only after the SDK has tried all recovery policies and still cannot continue. */
}
func onConnectionStatusChange(_ status: AliRtcConnectionStatus, reason: AliRtcConnectionStatusChangeReason) {
"onConnectionStatusChange status: \(status) reason: \(reason)".printLog()
if status == .failed {
/* TODO: You must handle this callback. We recommend that your application prompts the user. This callback is triggered only after the SDK has tried all recovery policies and still cannot continue. */
}
else {
/* TODO: Optional. Add business logic, usually for data statistics or UI changes. */
}
}
}
Operações relacionadas
Operações e configurações comuns de áudio — monitoramento intra-auricular, controle de volume e callbacks de alto-falante.
Configurar modificadores de voz, reverberação e embelezamento — efeitos vocais como modificadores de voz e reverberação.
Reproduzir e ingerir entrada de áudio externa (incluindo efeitos sonoros e acompanhamento) — música de fundo e arquivos de áudio de acompanhamento.