Agoraの基本概念：RTC、RTM、チャンネル、そしてチャンネルIDの活用法


本記事では、Agoraの基本的な概念であるRTC、RTM、各種チャンネル、チャンネルIDの役割について解説します。また、簡単な実装の流れと、RTCとRTMの関係性についても詳しく説明します。

## Agoraとは
Agoraは、開発者が自分のアプリケーションにリアルタイムの音声、ビデオ、メッセージング機能を統合できるようにするクラウドプラットフォームです。高品質で低遅延な通信を可能にし、グローバルなスケールでのサービス提供をサポートします。

# RTC（リアルタイムコミュニケーション）
### 概要
RTCは、リアルタイムで音声やビデオのデータを送受信する技術です。AgoraのRTC SDKを使用することで、以下のような機能を実装できます。

音声通話：クリアな音質での音声通信
ビデオ通話：高解像度のビデオ通信
ライブストリーミング：多人数へのリアルタイム配信

### 特徴
低遅延：リアルタイム性を重視した通信プロトコル
高品質：ネットワーク状況に応じた動的な品質調整
クロスプラットフォーム：iOS、Android、Webなど多様なプラットフォームに対応
# RTM（リアルタイムメッセージング）
### 概要
RTMは、リアルタイムでテキストメッセージや信号データを送受信するためのサービスです。RTCと組み合わせることで、より豊富なコミュニケーション体験を提供できます。

### 機能
チャット：1対1またはグループでのテキストメッセージング
チャンネルメッセージ：特定のチャンネル内でのメッセージブロードキャスト
状態管理：ユーザーのオンライン状態やトピックのサブスクリプション管理
# RTMとRTCの関係性
RTMとRTCは、それぞれ異なるデータタイプを扱いますが、組み合わせることでアプリケーションの機能性とユーザー体験を大幅に向上させることができます。

:point_up:補完的な機能：RTCは音声・ビデオデータのリアルタイム通信を扱い、RTMはテキストやシグナリングデータを扱います。

:point_up:シグナリングと制御：RTMを使用して、RTCセッション中のユーザー間で制御メッセージやステータス更新を行うことができます。

:point_up:ユーザーエクスペリエンスの向上：チャット機能、ファイル送信、リアクションなど、RTCだけでは実現しにくい機能をRTMで補完できます。
例えば、オンライン会議アプリでは、RTCでビデオ通話を行いながら、RTMでチャットやファイル共有、投票機能などを実装することで、より充実したコミュニケーションが可能になります。

# チャンネルの説明
チャンネルとは
チャンネルは、ユーザー同士が接続し合うための仮想的な空間です。同じチャンネルに参加しているユーザーは、お互いに音声やビデオ、メッセージをリアルタイムでやり取りできます。

### 種類
:point_up:RTCチャンネル：音声やビデオのデータを共有するためのチャンネル

:point_up:RTMチャンネル：テキストメッセージや信号データを共有するためのチャンネル

### チャンネルIDの活用法
チャンネルIDとは
チャンネルIDは、各チャンネルを一意に識別するための識別子です。ユーザーはこのIDを使用してチャンネルに参加します。

# 使用例
:point_up:セッション管理：特定のチャンネルIDを共有することで、同じセッションにユーザーを集める

:point_up:アクセス制御：トークンと組み合わせて、チャンネルへのアクセス権限を管理

:point_up:データ分離：異なるチャンネルIDを使用することで、データの混在を防ぐ

### 注意点
一意性の確保：チャンネルIDは重複しないように設計する
セキュリティ：予測困難なIDを使用し、不正アクセスを防止

# 簡単な実装の流れ
Agoraをアプリケーションに組み込むための基本的な手順を以下に示します。

### 1. Agoraアカウントの作成とプロジェクト設定
アカウント作成：Agoraの公式サイトで無料アカウントを作成します。
プロジェクト作成：ダッシュボードから新しいプロジェクトを作成し、App IDを取得します。
認証方式の設定：トークン認証を使用する場合は、プロジェクト設定で有効にします。

### 2. SDKのインストール
プラットフォームの選択：iOSアプリケーションを開発するために、AgoraのiOS SDKを使用します。

SDKの導入:point_down:
CocoaPodsを使用：Podfileに以下を追加します。

```ruby
pod 'AgoraRtcEngine_iOS'
pod 'AgoraRtm_iOS'
```

Agoraエンジンの初期化:point_down:

```swift
import AgoraRtcKit

class ViewController: UIViewController {
    var agoraEngine: AgoraRtcEngineKit!
    let appID = "YOUR_APP_ID"
    
    override func viewDidLoad() {
        super.viewDidLoad()
        initializeAgoraEngine()
    }
    
    func initializeAgoraEngine() {
        agoraEngine = AgoraRtcEngineKit.sharedEngine(withAppId: appID, delegate: self)
    }
}
```

チャンネルへの参加:point_down:

```swift
extension ViewController {
    func joinChannel() {
        let token = "YOUR_TOKEN" // トークン認証を使用する場合
        let channelId = "YOUR_CHANNEL_ID"
        
        agoraEngine.joinChannel(byToken: token, channelId: channelId, info: nil, uid: 0) { (channel, uid, elapsed) in
            print("Successfully joined channel: \(channel) with uid: \(uid)")
        }
    }
}
```

ローカルビデオの設定と開始:point_down:

```swift
extension ViewController {
    func setupLocalVideo() {
        let videoCanvas = AgoraRtcVideoCanvas()
        videoCanvas.uid = 0
        videoCanvas.view = localVideoView // あなたのUIView
        videoCanvas.renderMode = .hidden
        agoraEngine.setupLocalVideo(videoCanvas)
    }
    
    func startLocalVideo() {
        agoraEngine.enableVideo()
        setupLocalVideo()
    }
}
```

## RTMの実装
RTMクライアントの初期化:point_down:

```swift
import AgoraRtmKit

class ViewController: UIViewController {
    var rtmKit: AgoraRtmKit!
    let rtmAppID = "YOUR_APP_ID"
    
    override func viewDidLoad() {
        super.viewDidLoad()
        initializeRtmKit()
    }
    
    func initializeRtmKit() {
        rtmKit = AgoraRtmKit(appId: rtmAppID, delegate: self)
    }
}
```

ログイン:point_down:

```swift
extension ViewController {
    func loginRtm() {
        let rtmToken = "YOUR_RTM_TOKEN"
        let userId = "YOUR_USER_ID"
        
        rtmKit.login(byToken: rtmToken, user: userId) { (errorCode) in
            if errorCode == .ok {
                print("RTM login successful")
            } else {
                print("RTM login failed with error: \(errorCode.rawValue)")
            }
        }
    }
}
```

チャンネルへの参加:point_down:

```swift
extension ViewController {
    func joinRtmChannel() {
        let channelId = "YOUR_CHANNEL_ID"
        let rtmChannel = rtmKit.createChannel(withId: channelId, delegate: self)
        
        rtmChannel?.join(completion: { (errorCode) in
            if errorCode == .channelErrorOk {
                print("Joined RTM channel successfully")
            } else {
                print("Failed to join RTM channel with error: \(errorCode.rawValue)")
            }
        })
    }
}
```


メッセージの送受信:point_down:

```swift
extension ViewController: AgoraRtmChannelDelegate {
    func sendMessage(message: String) {
        let rtmMessage = AgoraRtmMessage(text: message)
        rtmChannel?.send(rtmMessage, completion: { (errorCode) in
            if errorCode == .errorOk {
                print("Message sent successfully")
            } else {
                print("Failed to send message with error: \(errorCode.rawValue)")
            }
        })
    }
    
    // メッセージ受信
    func channel(_ channel: AgoraRtmChannel, messageReceived message: AgoraRtmMessage, from member: AgoraRtmMember) {
        print("Received message: \(message.text) from \(member.userId)")
    }
}

```


## イベントの処理
リモートユーザーのビデオストリームの購読:point_down:

```swift
extension ViewController: AgoraRtcEngineDelegate {
    // リモートユーザーがチャンネルに参加したとき
    func rtcEngine(_ engine: AgoraRtcEngineKit, didJoinedOfUid uid: UInt, elapsed: Int) {
        let videoCanvas = AgoraRtcVideoCanvas()
        videoCanvas.uid = uid
        videoCanvas.view = remoteVideoView // あなたのUIView
        videoCanvas.renderMode = .hidden
        agoraEngine.setupRemoteVideo(videoCanvas)
    }
}
```

ユーザーの参加・離脱の検知:point_down:

```swift
extension ViewController: AgoraRtcEngineDelegate {
    func rtcEngine(_ engine: AgoraRtcEngineKit, didJoinedOfUid uid: UInt, elapsed: Int) {
        print("User joined: \(uid)")
    }
    
    func rtcEngine(_ engine: AgoraRtcEngineKit, didOfflineOfUid uid: UInt, reason: AgoraUserOfflineReason) {
        print("User offline: \(uid)")
    }
}
```


## クリーンアップと終了
チャンネルからの離脱:point_down:

```swift
extension ViewController {
    func leaveChannel() {
        agoraEngine.leaveChannel(nil)
        agoraEngine.stopPreview()
        AgoraRtcEngineKit.destroy()
    }
}
```

## リソースの解放

```swift
extension ViewController {
    func cleanup() {
        rtmChannel?.leave(completion: { (errorCode) in
            if errorCode == .errorOk {
                print("Left RTM channel")
            }
        })
        rtmKit.logout(completion: { (errorCode) in
            if errorCode == .ok {
                print("RTM logout successful")
            }
        })
    }
}
```


## エラーハンドリング
エラーイベントの処理:point_down:

```swift
extension ViewController: AgoraRtcEngineDelegate {
    func rtcEngine(_ engine: AgoraRtcEngineKit, didOccurError errorCode: AgoraErrorCode) {
        print("RTC Error occurred: \(errorCode.rawValue)")
    }
}

extension ViewController: AgoraRtmDelegate {
    func rtmKit(_ kit: AgoraRtmKit, connectionStateChanged state: AgoraRtmConnectionState, reason: AgoraRtmConnectionChangeReason) {
        print("RTM connection state changed: \(state.rawValue), reason: \(reason.rawValue)")
    }
}
```


# まとめ
Agoraを利用すれば、リアルタイムの音声・ビデオ通話やメッセージング機能を簡単にアプリケーションに統合できます。RTCとRTM、チャンネル、チャンネルIDの基本概念を理解し、今回ご紹介した実装の流れに沿って開発を進めてみてください。

特に、RTCとRTMを組み合わせることで、音声・ビデオ通話とテキストメッセージングを同時に提供でき、ユーザーエクスペリエンスを大幅に向上させることが可能です。

# 最後に
私の働いている会社で経験の有無を問わず採用を行っています。
興味のある方は是非カジュアル面談から応募してみてください！

https://jambo-support.com/

# 参考リンク

https://docs.agora.io/en/video-calling/get-started/get-started-sdk?platform=ios

https://api-ref.agora.io/en/voice-sdk/ios/4.x/documentation/agorartckit