# 实现语聊房 (/zh-CN/solutions/chatroom/sdk/build/quick-integration)

> For AI agents: see the complete documentation index at [llms.txt](/llms.txt).

<_PlatformTabsGroup>
<_PlatformProcessedMarker groupMode="structured" canonicalPlatform="android" platform="android" />
## 示例项目 [#示例项目]

本文介绍如何实现语聊房，包含登录系统、初始化引擎、创建房间、麦位管理、退出房间。声网在 `agora-ent-scenarios` 仓库中提供实现语聊房的源代码供你参考。

<Cards>
  <Card title="agora-ent-scenarios" href="https://github.com/AgoraIO-Usecase/agora-ent-scenarios/tree/main/Android/scenes/voice" />
</Cards>

## 业务流程 [#业务流程]

本节展示语聊房中常见的业务流程。

### 进出房间 [#进出房间]

下图展示创建、进入、退出房间的流程。

<DocsImage alt="进出房间流程" src="https://web-cdn.agora.io/docs-portal/img/chatroom/flow1-enter-room.svg" displayWidth="40%" />

### 房主邀请听众上麦 [#房主邀请听众上麦]

下图展示房主邀请听众上麦的流程。在这个流程中，房主发起上麦邀请。如果听众接受邀请，房主会收到通知并修改麦位信息，让听众上麦。听众随后发布自己的音频流。

<DocsImage alt="房主邀请听众上麦流程" src="https://web-cdn.agora.io/docs-portal/img/chatroom/flow2-host-invite.svg" displayWidth="70%" />

### 听众申请上麦 [#听众申请上麦]

下图展示听众向房主申请上麦的流程。在这个流程中，听众主动发起上麦申请，如果房主接受申请，房主修改麦位信息以让听众上麦。听众收到上麦消息后，发布自己的音频流。

<DocsImage alt="听众申请上麦流程" src="https://web-cdn.agora.io/docs-portal/img/chatroom/flow3-audience-request.svg" displayWidth="75%" />

## 准备开发环境 [#准备开发环境]

### 前提条件 [#前提条件]

开始前，请确保你的开发环境满足如下要求：

- [Android Studio](https://developer.android.com/studio/) 3.5 及以上。
- Android 手机，版本 Android 5.0（API Level 21）及以上。
- 可以访问互联网的计算机。确保你的网络环境没有部署防火墙，否则无法正常使用声网服务。
- 参考[开通语聊房 SDK 相关服务](/zh-CN/solutions/chatroom/sdk/build/enable-service)创建声网开发者账号和声网项目，并获取项目的 App ID 和临时 Token，以及登录即时通讯系统所需的用户名 (ID) 和 Token。

### 集成 SDK [#集成-sdk]

声动语聊用到声网实时互动 (RTC) SDK 和即时通讯 (IM) SDK。本节介绍如何在 Android Studio 创建项目并集成这两个 SDK：

1. 如需创建新项目，在 **Android Studio** 里，依次选择 **Phone and Tablet > Empty Activity**，创建 [Android 项目](https://developer.android.com/studio/projects/create-project)。

   :::info[信息]
   创建项目后，**Android Studio** 会自动开始同步 Gradle，稍等片刻至同步成功后再进行下一步操作。
   :::

2. 使用 Maven Central 将声网 RTC SDK 和 IM SDK 集成到你的项目中。

   1. 在 `/Gradle Scripts/build.gradle(Project: <projectname>)` 文件中添加如下代码，添加 Maven Central 依赖：

        ```groovy
        buildscript {
            repositories {
                ...
                mavenCentral()
            }
            ...
        }
        allprojects {
            repositories {
                ...
                mavenCentral()
            }
        }
        ```

        :::info[信息]
        如果你的 Android 项目设置了 [dependencyResolutionManagement](https://docs.gradle.org/current/userguide/centralizing_repositories.html)，添加 Maven Central 依赖的方式可能存在差异。
        :::

   2. 在 `/Gradle Scripts/build.gradle(Module: <projectname>.app)` 文件中添加如下代码，将声网 RTC SDK 和 IM SDK 集成到你的 Android 项目中：

      ```groovy
      ...
      dependencies {
          ...
          // x.y.z，请填写具体的 SDK 版本号，如：4.0.0 或 4.1.0-1
          // 通过实时互动产品发版说明获取最新版本号
          implementation 'io.agora.rtc:full-sdk:x.y.z'
          // 指定 IM SDK 1.1.0 版
          implementation 'io.agora.rtc:chat-sdk:1.1.0'
      }
      ```

3. 添加网络及设备权限。

   在 `/app/Manifests/AndroidManifest.xml` 文件中，在 `</application>` 后面添加如下权限：

   ```xml
   <uses-permission android:name="android.permission.INTERNET"/>
   <uses-permission android:name="android.permission.CAMERA"/>
   <uses-permission android:name="android.permission.RECORD_AUDIO"/>
   <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
   <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
   <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
   <uses-permission android:name="android.permission.BLUETOOTH"/>
   <!-- 对于 Android 12.0 及以上且集成 v4.1.0 以下声网 RTC SDK 的设备，还需要添加以下权限 -->
   <uses-permission android:name="android.permission.BLUETOOTH_CONNECT"/>
   <!-- 对于 Android 12.0 及以上设备，还需要添加以下权限 -->
   <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
   <uses-permission android:name="android.permission.BLUETOOTH_SCAN"/>
   ```

4. 在 `/Gradle Scripts/proguard-rules.pro` 文件中添加如下行，以防止声网 SDK 的代码被混淆：

   ```kotlin
   -keep class io.agora.**{*;}
   -dontwarn javax.**
   -dontwarn com.google.devtools.build.android.**
   ```

## 实现语聊房 [#实现语聊房]

你需要声网 RTC SDK、IM SDK 和云服务 (Service) 共同搭建语聊房场景。其中：

- 实时互动 RTC SDK 承担实时音频的业务。
- 即时通讯 IM SDK 实现房间内的信令通信。
- 云服务 (Service) 实现了房间列表的存储和房间生命周期的管理。

本节会详细介绍如何调用声网云服务（`voiceServiceProtocol`）、IM SDK 和 RTC SDK 的 API 完成登录即时通讯系统、获取房间列表、创建房间、进入房间、加入 RTC 房间、离开 RTC 房间等关键逻辑。完整的调用时序可以参考 [API 时序图](#api-时序图)。

:::warning[注意]
声网云服务为内部自研服务，暂不对外提供。你可以调用声网云服务的 API 用于测试，但是对于正式环境，声网建议你参考文档自行实现相似的一套服务。如需协助，请[联系技术支持](https://ticket.shengwang.cn/)。
:::

### 1. 获取房间列表 [#1-获取房间列表]

调用声网云服务中 `voiceServiceProtocol` 类的 `fetchRoomList` 方法获取房间列表。获取到房间列表后刷新 UI 并将房间列表展示在界面上。

```kotlin
voiceServiceProtocol.fetchRoomList(page, completion = { error, result ->
    ...
})
```

### 2. 登录即时通讯系统 [#2-登录即时通讯系统]

参考如下步骤登录即时通讯 (IM) 系统：

1. 根据[前提条件](#前提条件)开启声网即时通讯服务，并获取登录即时通讯系统所需的用户名 (ID) 和 Token。
2. 调用声网即时通讯 (IM) SDK 中 `ChatClient` 类的 [`loginWithToken`](https://docs-preprod.agora.io/cn/agora-chat/API%20Reference/im_java/v1.1.0/classio_1_1agora_1_1chat_1_1_chat_client.html#ac2b19ffdcd879b5f239baacbaa09423b) 方法并传入即时通讯服务的用户名和 Token 以登录即时通讯系统。

```kotlin
public void login(String uid,String token,CallBack callBack){
    ChatClient.getInstance().loginWithToken(uid, token, new CallBack() {
        @Override
        public void onSuccess() {
            ThreadManager.getInstance().runOnMainThread(new Runnable() {
                @Override
                public void run() {
                    callBack.onSuccess();
                }
            });
            LogTools.d("ChatroomConfigManager","Login success");
        }

        @Override
        public void onError(int code, String msg) {
            ThreadManager.getInstance().runOnMainThread(new Runnable() {
                @Override
                public void run() {
                    callBack.onError(code,msg);
                }
            });
            LogTools.e("ChatroomConfigManager", "Login onError code:" + code + " desc: " + msg);
        }
    });
}
```

### 3. 初始化 `RtcEngine` [#3-初始化-rtcengine]

参考如下步骤初始化 `RtcEngine`：

1. 根据[开通语聊房 SDK 相关服务](/zh-CN/solutions/chatroom/sdk/build/enable-service)在声网控制台创建声网项目后，复制界面的 App ID。
2. 调用声网 RTC SDK 中的 [`create`](/zh-CN/api-reference/rtc/android/initialize#api_irtcengine_initialize) 方法创建并初始化 `RtcEngine`。

```kotlin
// 初始化配置
val config = RtcEngineConfig()
// 设置 App ID
config.mAppId = "YourAppId"
// 创建 RtcEngine 实例
val rtcEngine = RtcEngineEx.create(config) as RtcEngineEx
```

### 4. 创建并进入房间 [#4-创建并进入房间]

参考如下步骤创建并进入房间：

1. 调用 `voiceServiceProtocol` 对象中的 `createRoom` 方法创建一个房间。

    ```kotlin
    val voiceCreateRoomModel = VoiceCreateRoomModel(
        roomName = roomName,
        soundEffect = soundEffect,
        isPrivate = !TextUtils.isEmpty(password),
        password = password ?: "",
        roomType = roomType
    )
    voiceServiceProtocol.createRoom(voiceCreateRoomModel, completion = { error, result ->
        when (error) {
            VoiceServiceProtocol.ERR_OK -> {
                callBack.onSuccess(createLiveData(result))
            }
            VoiceServiceProtocol.ERR_ROOM_NAME_INCORRECT -> {
                callBack.onError(error, "")
            }
            else -> {
                callBack.onError(error, "")
            }
        }
    })
    ```

2. 调用 `voiceServiceProtocol` 对象的 `joinRoom` 方法进入房间。

    ```kotlin
    voiceServiceProtocol.joinRoom(roomId, completion = { error, result ->
        when (error) {
            VoiceServiceProtocol.ERR_OK -> {
                callBack.onSuccess(createLiveData(result))
            }
            VoiceServiceProtocol.ERR_ROOM_UNAVAILABLE -> {
                callBack.onError(error, "room is not existent")
            }
            else -> {
                callBack.onError(error, "")
            }
        }
    })
    ```

3. 语聊房里需要有消息聊天和语音聊天，因此你还需进行如下操作：

    - 调用声网 IM SDK 中 `joinChatRoom` 实现房间内的消息互动。方法中的参数含义和取值请参考 [`joinChatRoom`](https://docs-preprod.agora.io/cn/agora-chat/API%20Reference/im_java/v1.1.0/classio_1_1agora_1_1chat_1_1_chat_room_manager.html#a895dbd6d0217ba08bcf2dbb6cf441591)。

        ```kotlin
        // 实现房间内的消息互动
        public void joinRoom(String chatroomId, ValueCallBack<ChatRoom> callBack){
            ChatClient.getInstance().chatroomManager()
                    .joinChatRoom(chatroomId, new ValueCallBack<ChatRoom>() {
                        @Override
                        public void onSuccess(ChatRoom value) {
                            ThreadManager.getInstance().runOnMainThreadDelay(new Runnable() {
                                @Override
                                public void run() {
                                    callBack.onSuccess(value);
                                }
                            },200);
                        }

                        @Override
                        public void onError(int error, String errorMsg) {
                            ThreadManager.getInstance().runOnMainThread(new Runnable() {
                                @Override
                                public void run() {
                                    callBack.onError(error,errorMsg);
                                }
                            });
                        }
                    });
        }
        ```

    - 调用声网 RTC SDK 中 `RtcEngine` 类的 `joinChannel` 加入 RTC 频道以实现房间内的实时音频通话。方法中的参数含义和支持取值请参考 [`joinChannel`](/zh-CN/api-reference/rtc/android/channel#api_irtcengine_joinchannel2)。在这一步里需要填写声网 RTC Token。你可以使用[开通语聊房 SDK 相关服务](/zh-CN/solutions/chatroom/sdk/build/enable-service)中获取的临时 Token，也可以参考[使用 Token 鉴权](/zh-CN/realtime-media/rtc/build/setup-and-access/token-authentication)获取正式用途的声网 RTC Token。临时 Token 的有效期为 24 小时，建议你仅在测试用途下使用。

      你还可以调用 [`setChannelProfile`](/zh-CN/api-reference/rtc/android/channel#api_irtcengine_setchannelprofile)、[`setAudioProfile`](/zh-CN/api-reference/rtc/android/audio/audio-basic#api_irtcengine_setaudioprofile2)、[`setAudioScenario`](/zh-CN/api-reference/rtc/android/audio/audio-basic#api_irtcengine_setaudioscenario)、[`setParameters`](/zh-CN/api-reference/rtc/android/network#api_irtcengine_setparameters) 为不同业务场景（语聊社交、KTV、游戏陪玩、专业音频直播场景）配置语聊房的推荐音效参数。

        ```kotlin
        // 实现房间内的语音互动
        rtcEngine?.apply {
            when (soundEffect) {
                // 在线 K 歌房和泛娱乐社交场景下推荐设置
                ConfigConstants.SoundSelection.Social_Chat,
                ConfigConstants.SoundSelection.Karaoke -> {
                    // 设置频道属性为直播
                    setChannelProfile(Constants.CHANNEL_PROFILE_LIVE_BROADCASTING)
                    // 设置 48 kHz 采样率，音乐编码，单声道，编码码率最大值为 96 Kbps
                    setAudioProfile(Constants.AUDIO_PROFILE_MUSIC_HIGH_QUALITY)
                    // 设置为高音质场景
                    setAudioScenario(Constants.AUDIO_SCENARIO_GAME_STREAMING)
                }
                // 1 对 1 游戏陪玩通话场景下推荐
                ConfigConstants.SoundSelection.Gaming_Buddy -> {
                    // 设置频道属性为通信
                    setChannelProfile(Constants.CHANNEL_PROFILE_COMMUNICATION)
                }
                else -> {
                    // 专业音频直播场景下推荐设置
                    // 设置频道属性为直播
                    setChannelProfile(Constants.CHANNEL_PROFILE_LIVE_BROADCASTING)
                    // 指定 48 kHz 采样率，音乐编码，双声道，编码码率最大值为 128 Kbps
                    setAudioProfile(Constants.AUDIO_PROFILE_MUSIC_HIGH_QUALITY)
                    // 设置为高音质场景
                    setAudioScenario(Constants.AUDIO_SCENARIO_GAME_STREAMING)
                    // 设置私有参数以获得好的实时音频互动体验
                    setParameters("{\"che.audio.custom_payload_type\":73}")
                    setParameters("{\"che.audio.custom_bitrate\":128000}")
                    setParameters("{\"che.audio.input_channels\":2}")
                }
            }
        }
        // 加入 RTC 频道
        // 此处的 Token 为声网 RTC Token
        val status = rtcEngine?.joinChannel(VoiceBuddyFactory.get().getVoiceBuddy().rtcToken(), channelId, "", rtcUid)
        ```

### 5. 麦位管理 [#5-麦位管理]

具体步骤详见[麦位管理](/zh-CN/solutions/chatroom/sdk/build/mic-seat-management)。

### 6. 退出房间 [#6-退出房间]

参考如下步骤退出并销毁语聊房。

1. 调用 `voiceServiceProtocol` 对象的 `leaveRoom` 方法离开房间。

    ```kotlin
    voiceServiceProtocol.leaveRoom(roomId, isRoomOwnerLeave, completion = { error, result ->
        ...
    })
    ```

2. 调用 `RtcEngine` 类的 [`leaveChannel`](/zh-CN/api-reference/rtc/android/channel#api_irtcengine_leavechannel) 方法离开 RTC 频道。

    ```kotlin
    rtcEngine?.leaveChannel()
    ```

3. 调用 [`leaveChatRoom`](https://docs-preprod.agora.io/cn/agora-chat/API%20Reference/im_java/v1.1.0/classio_1_1agora_1_1chat_1_1_chat_room_manager.html#a4f2c430782206971480c73a49311b1437) 离开聊天室，调用 [`asyncDestroyChatRoom`](https://docs-preprod.agora.io/cn/agora-chat/API%20Reference/im_java/v1.1.0/classio_1_1agora_1_1chat_1_1_chat_room_manager.html?transId=194274c0-bee4-11ed-b167-a39cc89dc96e#a0d50d2e34d9992fc3f8ea1c82e2db1a) 销毁聊天室。调用 [`destroy`](/zh-CN/api-reference/rtc/android/initialize#api_irtcengine_release) 销毁 RTC 引擎。

    ```kotlin
    ChatroomIMManager.getInstance().leaveChatRoom(roomKitBean.chatroomId)
    ChatroomIMManager.getInstance().asyncDestroyChatRoom(roomKitBean.chatroomId, object :
        CallBack {
        override fun onSuccess() {}
        override fun onError(code: Int, error: String?) {}
    })
    RtcEngineEx.destroy()
    rtcEngine = null
    ```

### API 时序图 [#api-时序图]

如下时序图展示了如何登录即时通讯系统、获取房间列表、创建房间、进入房间、加入 RTC 频道、麦位管理、退出房间、离开 RTC 频道。

<DocsImage alt="API 时序" src="https://web-cdn.agora.io/docs-portal/img/chatroom/integ-and.svg" displayWidth="80%" />
<_PlatformProcessedMarker close="true" />

<_PlatformProcessedMarker groupMode="structured" canonicalPlatform="android" platform="ios" />
本文介绍如何实现语聊房，包含登录系统、初始化引擎、创建房间、麦位管理、退出房间。
## 示例项目 [#示例项目-1]

声网在 `agora-ent-scenarios` 仓库中提供实现语聊房的源代码供你参考。

<Cards>
  <Card title="agora-ent-scenarios" href="https://github.com/AgoraIO-Usecase/agora-ent-scenarios/tree/main/iOS/AgoraEntScenarios/Scenes/VoiceChatRoom" />
</Cards>

## 业务流程 [#业务流程-1]

本节展示语聊房中常见的业务流程。

### 进出房间 [#进出房间-1]

下图展示创建、进入、退出房间的流程。

<DocsImage alt="进出房间流程" src="https://web-cdn.agora.io/docs-portal/img/chatroom/flow1-enter-room.svg" displayWidth="40%" />

### 房主邀请听众上麦 [#房主邀请听众上麦-1]

下图展示房主邀请听众上麦的流程。在这个流程中，房主发起上麦邀请。如果听众接受邀请，房主会收到通知并修改麦位信息，让听众上麦。听众随后发布自己的音频流。

<DocsImage alt="房主邀请听众上麦流程" src="https://web-cdn.agora.io/docs-portal/img/chatroom/flow2-host-invite.svg" displayWidth="70%" />

### 听众申请上麦 [#听众申请上麦-1]

下图展示听众向房主申请上麦的流程。在这个流程中，听众主动发起上麦申请，如果房主接受申请，房主修改麦位信息以让听众上麦。听众收到上麦消息后，发布自己的音频流。

<DocsImage alt="听众申请上麦流程" src="https://web-cdn.agora.io/docs-portal/img/chatroom/flow3-audience-request.svg" displayWidth="75%" />

## 准备开发环境 [#准备开发环境-1]

### 前提条件 [#前提条件-1]

开始前，请确保你的开发环境满足如下要求：

- [Xcode](https://apps.apple.com/cn/app/xcode/id497799835?mt=12) 13.0 及以上。
- iOS 设备，版本 13.0 及以上。
- 有效的苹果开发者账号。
- 可以访问互联网的计算机。确保你的网络环境没有部署防火墙，否则无法正常使用声网服务。
- 参考[开通语聊房 SDK 相关服务](/zh-CN/solutions/chatroom/sdk/build/enable-service)创建声网开发者账号和声网项目，并获取项目的 App ID 和临时 Token。

### 集成 SDK [#集成-sdk-1]

语聊房用到声网实时互动 (RTC) SDK 和即时通讯 (IM) SDK。本节介绍如何在 Xcode 创建项目并集成这两个 SDK：

1. 参考 [Create a project](https://help.apple.com/xcode/mac/current/#/dev07db0e578) 创建一个新的项目，**Application** 选择 **App**，**Interface** 选择 **Storyboard**，**Language** 选择 **Swift**。

   :::info[信息]
   如果你没有添加过开发团队信息，会看到 **Add account...** 按钮。点击该按钮并按照屏幕提示登入 Apple ID，点击 **Next**，完成后即可选择你的 Apple 账户作为开发团队。
   :::

2. 为你的项目设置[自动签名](https://help.apple.com/xcode/mac/current/#/dev23aab79b4)。

3. 设置部署你的 App 的[目标设备](https://help.apple.com/xcode/mac/current/#/deve69552ee5)。

4. 添加项目的设备权限。在项目导航栏中打开 `info.plist` 文件，编辑[属性列表](https://help.apple.com/xcode/mac/current/#/dev3f399a2a6)，添加以下属性：

    | key                                    | type   | value                                                        |
    | -------------------------------------- | ------ | ------------------------------------------------------------ |
    | Privacy - Microphone Usage Description | String | 使用麦克风的目的，例如 for a live interactive streaming |
    | Privacy - Camera Usage Description       | String | 使用摄像头的目的，例如 for a live interactive streaming |

    :::info[信息]
    - 如果你的项目中需要添加第三方插件或库（例如第三方摄像头），且该插件或库的签名与项目的签名不一致，你还需勾选 **Hardened Runtime** > **Runtime Exceptions** 中的 **Disable Library Validation**。
        - 更多注意事项，可以参考 [Preparing Your App for Distribution](https://developer.apple.com/documentation/xcode/preparing_your_app_for_distribution)。
    :::

5. 将声网实时互动和即时通讯 SDK 集成到你的项目。开始前请确保你已安装 CocoaPods，如尚未安装 CocoaPods，参考 [Getting Started with CocoaPods](https://guides.cocoapods.org/using/getting-started.html#getting-started) 安装说明。

    1. 在终端里进入项目根目录，并运行 `pod init` 命令。项目文件夹下会生成一个 `Podfile` 文本文件。
    2. 打开 `Podfile` 文件，修改文件为如下内容。注意将 `Your App` 替换为你的 Target 名称。

        ```ruby
        platform :ios, '11.0'
        target 'Your App' do
            # 集成 RTC SDK
            # x.y.z 请填写具体的 SDK 版本号，如 4.4.1
            # 可通过实时互动发版说明获取最新版本号
            pod 'AgoraRtcEngine_iOS', 'x.y.z'
            # 集成即时通讯 SDK
            pod 'Agora_Chat_iOS'
        end
        ```

6. 在终端内运行 `pod install` 命令安装 SDK。成功安装后，Terminal 中会显示 `Pod installation complete!`。

## 实现语聊房 [#实现语聊房-1]

你需要声网实时互动 (RTC) SDK、即时通讯 (IM) SDK 和云服务 (Service) 共同搭建语聊房场景。其中：

- 实时互动 SDK 承担实时音频的业务。
- 即时通讯 SDK 实现房间内的信令通信。
- 云服务 (Service) 实现了房间列表的存储和房间生命周期的管理。

本节会详细介绍如何调用声网云服务（`voiceServiceProtocol`）、IM SDK 和 RTC SDK 的 API 完成登录即时通讯系统、获取房间列表、创建房间、进入房间、加入 RTC 房间、离开 RTC 房间等关键逻辑。完整的调用时序可以参考 [API 时序图](#api-时序图-1)。

:::warning[注意]
声网云服务为内部自研服务，暂不对外提供。你可以调用声网云服务的 API 用于测试，但是对于正式环境，声网建议你参考文档自行实现相似的一套服务。如需协助，请[联系技术支持](https://ticket.shengwang.cn/)。
:::

### 1. 获取房间列表 [#1-获取房间列表-1]

调用声网云服务中 `voiceServiceProtocol` 类的 `fetchRoomList` 方法获取房间列表。获取到房间列表后刷新 UI 并将房间列表展示在界面上。

```swift
ChatRoomServiceImp.getSharedInstance().fetchRoomList(page: 0) { error, rooms in
    self.roomList.refreshControl?.endRefreshing()
    if error == nil {
        guard let rooms = rooms else {return}
        let roomsEntity: VRRoomsEntity = VRRoomsEntity()
        roomsEntity.rooms = rooms
        roomsEntity.total = rooms.count
        self.fillDataSource(rooms: roomsEntity)
        self.roomList.reloadData()
        self.empty.isHidden = (rooms.count > 0)
    } else {
        self.view.makeToast("\(error?.localizedDescription ?? "")")
    }
}
```

### 2. 登录即时通讯系统 [#2-登录即时通讯系统-1]

参考如下步骤登录即时通讯 (IM) 系统：

1. 根据[前提条件](#前提条件-1)开启声网即时通讯服务，并获取登录即时通讯系统所需的用户名 (ID) 和 Token。
2. 调用声网即时通讯（IM）SDK 中 `AgoraChatClient` 类的 [`loginWithUsername:token:completion:`](https://docs-preprod.agora.io/cn/agora-chat/API%20Reference/im_oc/v1.1.0/interface_agora_chat_client.html#ad1f4dbc685867ed236fcb57c2d29c2b0) 方法并传入即时通讯服务的用户名和 Token 以登录即时通讯系统。

```swift
@objc public func loginIM(userName: String, token: String, completion: @escaping (String, AgoraChatError?) -> Void) {
    if AgoraChatClient.shared().isLoggedIn {
        completion(AgoraChatClient.shared().currentUsername ?? "", nil)
    } else {
        // 登录即时通讯系统
        // 此处的 Token 为声网 Chat Token
        // 不要和声网 RTC Token 混淆
        AgoraChatClient.shared().login(withUsername: userName, token: token, completion: completion)
    }
}
```

### 3. 初始化 RTC 引擎 [#3-初始化-rtc-引擎]

参考如下步骤初始化 `AgoraRtcEngineKit`：

1. 根据[开通语聊房 SDK 相关服务](/zh-CN/solutions/chatroom/sdk/build/enable-service)在声网控制台创建声网项目后，复制界面的 App ID。
2. 调用声网 RTC SDK 中的 [`sharedEngineWithAppId`](/zh-CN/api-reference/rtc/ios/initialize#api_irtcengine_create) 方法创建并初始化 `AgoraRtcEngineKit`。

```swift
let rtcKit: AgoraRtcEngineKit = AgoraRtcEngineKit.sharedEngine(withAppId: KeyCenter.AppId, delegate: nil)
```

### 4. 创建并进入房间 [#4-创建并进入房间-1]

参考如下步骤创建并进入房间：

1. 调用 `ChatRoomServiceImp` 类中的 `createRoom` 方法创建一个房间。

    ```swift
    ChatRoomServiceImp.getSharedInstance().createRoom(room: entity) { error, room in
        SVProgressHUD.dismiss()
        self.view.window?.isUserInteractionEnabled = true
        if let room = room,error == nil {
            self.entryRoom(room: room)
        } else {
            SVProgressHUD.showError(withStatus: "Create failed!".localized())
        }
    }
    ```

2. 调用 `ChatRoomServiceImp` 类的 `joinRoom` 方法进入房间。

    ```swift
    // 显示加载提示
    SVProgressHUD.show(withStatus: "Loading".localized())
    // 生成声网 RTC Token
    // 不要和声网 Chat Token 搞混淆
    NetworkManager.shared.generateToken(channelName: room.channel_id ?? "", uid: VLUserCenter.user.id, tokenType: .token007, type: .rtc) { token in
        VLUserCenter.user.agoraRTCToken = token ?? ""
        // 进入房间
        ChatRoomServiceImp.getSharedInstance().joinRoom(room.room_id ?? "") { error, room_entity in
            SVProgressHUD.dismiss()
            if VLUserCenter.user.chat_uid.isEmpty || VLUserCenter.user.im_token.isEmpty || self.initialError != nil {
                SVProgressHUD.showError(withStatus: "Fetch IMconfig failed!")
                return
            }
            self.mapUser(user: VLUserCenter.user)
            let info: VRRoomInfo = VRRoomInfo()
            info.room = room
            info.mic_info = nil
            self.isDestory = false
            let vc = VoiceRoomViewController(info: info)
            self.navigationController?.pushViewController(vc, animated: true)
            self.normal.roomList.isUserInteractionEnabled = true
        }
    }
    ```

3. 语聊房里需要有消息聊天和语音聊天，因此你还需进行如下操作：

    - 调用声网 IM SDK 中 `joinChatRoom` 实现房间内的消息互动。方法中的参数含义和支持取值请参考 [`joinChatRoom`](https://docs-preprod.agora.io/cn/agora-chat/API%20Reference/im_oc/v1.1.0/protocol_i_agora_chatroom_manager-p.html#ad8d19bd36e60c8af8d04c1f8b4daa2f0)。

        ```swift
        // 实现房间内的消息互动
        @objc func joinedChatRoom(roomId: String, completion: @escaping ((AgoraChatroom?, AgoraChatError?) -> Void)) {
            AgoraChatClient.shared().roomManager?.joinChatroom(roomId, completion: { room, error in
                if error == nil, let id = room?.chatroomId {
                    self.currentRoomId = id
                }
                completion(room, error)
            })
        }
        ```

    - 调用声网 RTC SDK 中 `AgoraRtcEngineKit` 类的 `joinChannelByToken` 加入 RTC 频道以实现房间内的实时音频通话。方法中的参数含义和支持取值请参考 [`joinChannelByToken`](/zh-CN/api-reference/rtc/ios/channel#api_irtcengine_joinchannel1)。在这一步里需要填写声网 RTC Token。你可以使用[开通语聊房 SDK 相关服务](/zh-CN/solutions/chatroom/sdk/build/enable-service)中获取的临时 Token，也可以参考[使用 Token 鉴权](/zh-CN/realtime-media/rtc/build/setup-and-access/token-authentication)获取正式用途的声网 RTC Token。临时 Token 的有效期为 24 小时，建议你仅在测试用途下使用。

      你还可以调用 [`setChannelProfile`](/zh-CN/api-reference/rtc/ios/channel#api_irtcengine_setchannelprofile)、[`setAudioProfile`](/zh-CN/api-reference/rtc/ios/audio/audio-basic#api_irtcengine_setaudioprofile2)、[`setAudioScenario`](/zh-CN/api-reference/rtc/ios/audio/audio-basic#api_irtcengine_setaudioscenario)、[`setParameters`](/zh-CN/api-reference/rtc/ios/network#api_irtcengine_setparameters) 来为不同业务场景（语聊社交、KTV、游戏陪玩、专业音频直播场景）设置语聊房的最佳音效。

        ```swift
        // 实现房间内的语音互动
        rtcKit.delegate = self
        rtcKit.enableAudioVolumeIndication(200, smooth: 3, reportVad: true)
        self .setParametersWithMD()
        // 在线 K 歌房和泛娱乐社交场景下推荐设置
        if type == .ktv || type == .social {
            // 设置频道属性为直播
            rtcKit.setChannelProfile(.liveBroadcasting)
            // 设置 48 kHz 采样率，音乐编码，单声道，编码码率最大值为 96 Kbps
            rtcKit.setAudioProfile(.musicHighQuality)
            // 设置为高音质场景
            rtcKit.setAudioScenario(.gameStreaming)
        } else if type == .game {
            // 1 对 1 游戏陪玩通话场景下推荐
            // 设置频道属性为通信
            rtcKit.setChannelProfile(.communication)
        } else if type == .anchor {
            // 专业音频直播场景下推荐设置
            // 设置频道属性为直播
            rtcKit.setChannelProfile(.liveBroadcasting)
            // 指定 48 kHz 采样率，音乐编码，双声道，编码码率最大值为 128 Kbps
            rtcKit.setAudioProfile(.musicHighQualityStereo)
            // 设置为高音质场景
            rtcKit.setAudioScenario(.gameStreaming)
            // 设置私有参数以获得好的实时音频互动体验
            rtcKit.setParameters("{\"che.audio.custom_payload_type\":73}")
            rtcKit.setParameters("{\"che.audio.custom_bitrate\":128000}")
            rtcKit.setParameters("{\"che.audio.input_channels\":2}")
        }
        setAINS(with: .mid)
        rtcKit.setParameters("{\"che.audio.start_debug_recording\":\"all\"}")
        rtcKit.setEnableSpeakerphone(true)
        rtcKit.setDefaultAudioRouteToSpeakerphone(true)
        // 加入 RTC 频道
        // 此处的 Token 为声网 RTC Token
        let code: Int32 = rtcKit.joinChannel(byToken: token, channelId: channelName, info: nil, uid: UInt(rtcUid ?? 0))
        ```

### 5. 麦位管理 [#5-麦位管理-1]

具体步骤详见[麦位管理](/zh-CN/solutions/chatroom/sdk/build/mic-seat-management)。

### 6. 退出房间 [#6-退出房间-1]

参考如下步骤退出并销毁语聊房。

1. 调用 `ChatRoomServiceImp` 类的 `leaveRoom` 方法离开房间。

    ```swift
    ChatRoomServiceImp.getSharedInstance().leaveRoom(self.roomInfo?.room?.room_id ?? "") { _, _ in
    }
    ```

2. 调用 `AgoraRtcEngineKit` 类的 [`leaveChannel`](/zh-CN/api-reference/rtc/ios/channel#api_irtcengine_leavechannel) 方法离开 RTC 频道。

    ```swift
    rtcKit.leaveChannel(nil)
    ```

3. 调用 [`leaveChatroom:completion:`](https://docs-preprod.agora.io/cn/agora-chat/API%20Reference/im_oc/v1.1.0/protocol_i_agora_chatroom_manager-p.html#ae9b671ece1a36ad8ac26375d91755467) 离开聊天室，调用 [`destroyChatroom:`](https://docs-preprod.agora.io/cn/agora-chat/API%20Reference/im_oc/v1.1.0/protocol_i_agora_chatroom_manager-p.html#a1e3a6bacf44a96ff37b34d2068c84386) 销毁聊天室。调用 [`destroy`](/zh-CN/api-reference/rtc/ios/initialize#api_irtcengine_release) 销毁 RTC 引擎。

    ```swift
    AgoraChatClient.shared().roomManager?.leaveChatroom(currentRoomId, completion: { error in
    })
    AgoraChatClient.shared().roomManager?.destroyChatroom(currentRoomId)
    AgoraRtcEngineKit.destroy()
    rtcKit.delegate = nil
    ```

### API 时序图 [#api-时序图-1]

如下时序图展示了如何登录即时通讯系统、获取房间列表、创建房间、进入房间、加入 RTC 频道、麦位管理、退出房间、离开 RTC 频道。

<DocsImage alt="API 时序" src="https://web-cdn.agora.io/docs-portal/img/chatroom/integ-ios.svg" displayWidth="80%" />
<_PlatformProcessedMarker close="true" />
</_PlatformTabsGroup>
