1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Discord】Discord Social SDK のボイチャ機能が正式版になったのでUnityで動かしてみた【Unity】

Last updated at Posted at 2025-08-17

ボイスチャット系SDK組み込みを調べがちなUnityエンジニアのCova です。

以前は Vivoxの導入について調べました。
(Vivox についてはQiitaでは最古の記事みたいです)

そして今回は Automatonさんの記事でも紹介があった通り、ついにDiscordSocialSDKでボイスチャット機能が正式にリリースされたとのことです。

Discord といえばゲーマーやストリーマの方々ではなくてはならないほど浸透しているボイスチャット・テキストチャット・映像共有ツールです。

様々なゲームでもDiscord を内部に取り入れてボイスチャット機能を実装しているマルチプレイゲームも存在します。

そこで今回はインディーズから大手まで、おそらく今後需要が高まるであろう、Discord のボイチャ機能をUnity のアプリに組み込む方法を実際に行ってみました。

STEP1. SDK取得までのフロー

具体的な手順は公式がわかりやすく記事を用意してくれているので、基本的にはこの手順に従ってください。

ざっくり説明すると

  1. アカウント作る
  2. チームアカウント作る
  3. DiscordSDKを適応するDiscordApplication (いわゆるProject)を作成
  4. SDKの有効化
  5. SDK配布ページにアクセスする
  6. SDKをDL

という流れになります。

1. アカウントを作る

Discord 公式にアクセスしてアカウントを作ってください。

(流石に今回はアカウント作成前提で話を進めます)

2. チームアカウントを作る

1−2−1.png

とあるので、とりあえずチームアカウントを作るページに移動しましょう。

そうするとTopページに New Team ボタンが表示されているので押します。
1-2-2.png

そうするとチーム名入力画面が表示されるので入力します
1-2-3.png

入力完了するとTeamInformation の画面に切り替わってチームが作成されます
1-2-4.png

3. DiscordSDKを適応するDiscordApplication (いわゆるProject)を作成

1-3-1.png

ということでApplication作成ページにアクセスします

そうするとTeamと似たUIで Applications ページに New Application ボタンがあるので押します
1-3-2.png

Application 作成ポップアップが表示されるので

  1. Name にApp名を入力する
  2. TEAM に先ほど作成したTEAMを設定する
  3. Create ボタンを押す
    1-3-3.png

そうすると人間かどうかを確認されるので人間アピールしましょう
1-3-4.png

無事作成できるとこんな感じの画面に遷移します。
ここまできたらapp作成は終了です。
1-3-5.png

4. SDKの有効化

1-4-1.png

ということでSDKを有効化しましょう。

さきほどのApplication のページの左側のTab に OAuth2 というタブがあるのでそれを選択します

1-4-2_mosaic.png

そうすると Public Client という項目があるのでそこのToggle をONにしましょう。

このとき、ページ下に設定を保存するかどうかのポップアップがしれっと出現するので、Save Changes ボタンを必ず押しましょう。

1-4-3.png

その後、左側のTab にある Getting Started というタブがあるのでそれを選択してください。

1-4-4.png

開発者名や連絡先などを入力して Submit ボタンを押します
1-4-5.png

成功するとこのような画面が現れます。
1-4-6.png

Let's GO!!

5. SDK配布ページにアクセスする

1-5-1.png

無事Let's goボタンを押すとGetting Started のページが変わり、APIDocument 等のリンクが表示されたページにいくので、一番下のDownloadsを選択します

6. SDKをDL

1-6-1.png

DLページにくるとバージョンと各種SDKが表示されるので、Unity開発者はUnityアイコンのPluginとSampleを、UE開発者はUEのアイコンのPluginとSampleをDLしましょう

STEP.2 公式のSample を確認しよう

公式のSampleは先ほどDLした DiscordSocialSdk-Unity Sample -xxxx.zip です。

zipを解凍するとUnityProject が丸っと入っているのでUnityHub から立ち上げます。

検証環境

項目 version
MacOS Tahoe 26.0
※VisionOS26の検証も並行でやってるのでベータ版を使ってます
Android 15.0
Unity 6000.0.54f1
Discord 1.4.9649

Sample の中身

Assets/Scenes/SampleScene.unity を開くと以下のようなUIが出てきます。

2-2-1.png

左側のHierarchyビューを見て分かる通り、GameObjectが2つしか存在しません。
それなのにUIは色々組まれています。

そうです。 Unity の UIToolKit を用いてDiscord のSampleScene のUIは組まれております。
Discord 社のエンジニアの方々のSkill が非常に高いことをここからも伺えます。(2025年現在でUIToolKit を用いてバリバリ開発している企業の方が少ない。まだuGUI メインの時代なので)

1. アカウントの認証

Token が空の場合はまず Get Token with OAuth ボタンを押します。
2-3-1-1.png

そうするとブラウザに切り替わる (スマホだとブラウザが立ち上がる) のでDiscordアカウントにログインします。
2-3-1-2.png

そうすると、このSampleアプリと連携するかのモーダルが出現するので一番したまでスクロールして認証を押すとOAuth認証による認証が行われてゲームないでアカウント情報を利用できます。
2-3-1-3_mosaic.png

2. Social 機能

OAuth認証が通った後、画面左側に色々機能が開放されます。
ここでFriend ボタンを押すとFriend 一覧を取得できます。
2-3-2-1.png

2-3-2-2.png

ちなみにアカウントを選択すると普通にFriend の削除やBlock なども行えてしまうので扱いには注意してください。

3. テキストチャット

画面左側のLobbies 横の +ボタン を押すと新規にLobby を作成します。
この Lobby は テキストチャットチャンネルボイスチャットチャンネル を統合したチャンネルのことです。

2-4-1.png

Lobby 作成には The void と書かれている部分に任意の名前を入れることでLobbyが作成されます。
Lobby名は被ると厄介なのでなるべくUnique になるように命名するとよさそうです
2-4-2.png

現在Lobby の削除APIはありません。

https://discord.com/developers/docs/discord-social-sdk/development-guides/managing-lobbies#lobby-lifecycle

公式Documentによるとデフォルトは5分のTimerが設定されていて、無人状態からTimerが作動して一定時間経つと自動でLobby が削除される仕組みになっています

Lobby に無事入るとメンバーリストが表示されると共にテキスト入力エリアも下部に表示されます。
2-4-3.png

2-4-4.png

テキスト入力すると上記のような形でメッセージログが表示されます。

4. ボイスチャット

ボイスチャットはLobby 入室後でしか機能しないため、まずはLobbyに参加してください

ボイスチャットは先ほどのLobby の右側にある Join Voice ボタンを押すとそのLobby のボイスチャンネルに参加できます。
2-5-1.png

参加すると画面左下のUIに接続Status 表示が追加されます。
2-5-2.png

Mute/Speaker Mute はそのまま使えます。

歯車アイコンを押すと音声デバイスの設定画面が表示されるのでDiscordアプリ の音声設定同様のことが可能です
2-5-3.png

STEP.3 Unity にSDKを組み込む

DLしたSDKですが、一応UnityPackage 対応されています。

ここの公式に紹介されている通り

  1. 導入したいUnityProjectを作る
  2. Packages/ 以下にDLしたSDKを解凍する
  3. UnityPackageManager のWindowを開く
  4. 左上の+ボタンから Install Package from Disk... を選ぶ
    3-2-1.png
  5. Packages->com.discord.partnersdk->package.json を選ぶ
    3-2-2.png
  6. 無事画像のように追加されてれば導入完了
    3-2-3.png

接続用のC#コードであるDiscordManager.cs は公式に記載されているものを引っ張ってくるのが手っ取り早いです。

DiscordManager.cs
using UnityEngine;
using UnityEngine.UI;
using Discord.Sdk;
using System.Linq;

public class DiscordManager : MonoBehaviour
{
    [SerializeField] 
    private ulong clientId; // Set this in the Unity Inspector from the dev portal
    
    [SerializeField]
    private Button loginButton; 
    
    [SerializeField] 
    private Text statusText;

    private Client client;
    private string codeVerifier;

        void Start()
    {
        client = new Client();

        // Modifying LoggingSeverity will show you more or less logging information
        client.AddLogCallback(OnLog, LoggingSeverity.Error);
        client.SetStatusChangedCallback(OnStatusChanged);

        // Make sure the button has a listener
        if (loginButton != null)
        {
            loginButton.onClick.AddListener(StartOAuthFlow);
        }
        else
        {
            Debug.LogError("Login button reference is missing, connect it in the inspector!");
        }

        // Set initial status text
        if (statusText != null)
        {
            statusText.text = "Ready to login";
        }
        else
        {
            Debug.LogError("Status text reference is missing, connect it in the inspector!");
        }
    }

    private void OnLog(string message, LoggingSeverity severity)
    {
        Debug.Log($"Log: {severity} - {message}");
    }

    private void OnStatusChanged(Client.Status status, Client.Error error, int errorCode)
    {
        Debug.Log($"Status changed: {status}");
        statusText.text = status.ToString();
        if(error != Client.Error.None)
        {
            Debug.LogError($"Error: {error}, code: {errorCode}");
        }

        if (status == Client.Status.Ready)
        {
            ClientReady();
        }
    }

    private void ClientReady()
    {
            Debug.Log($"Friend Count: {client.GetRelationships().Count()}");

            Activity activity = new Activity();
            activity.SetType(ActivityTypes.Playing);
            activity.SetState("In Competitive Match");
            activity.SetDetails("Rank: Diamond II");
            client.UpdateRichPresence(activity, (ClientResult result) => {
                if (result.Successful()) {
                    Debug.Log("Rich presence updated!");
                } else {
                    Debug.LogError("Failed to update rich presence");
                }
            });
    }

    private void StartOAuthFlow() {
        var authorizationVerifier = client.CreateAuthorizationCodeVerifier();
        codeVerifier = authorizationVerifier.Verifier();
        
        var args = new AuthorizationArgs();
        args.SetClientId(clientId);
        args.SetScopes(Client.GetDefaultPresenceScopes());
        args.SetCodeChallenge(authorizationVerifier.Challenge());
        client.Authorize(args, OnAuthorizeResult);
    }

    private void OnAuthorizeResult(ClientResult result, string code, string redirectUri) {
        Debug.Log($"Authorization result: [{result.Error()}] [{code}] [{redirectUri}]");
        if (!result.Successful()) {
            return;
        }
        GetTokenFromCode(code, redirectUri);
    }

    private void GetTokenFromCode(string code, string redirectUri) {
        client.GetToken(clientId,
                        code,
                        codeVerifier,
                        redirectUri,
                        (result, token, refreshToken, tokenType, expiresIn, scope) => {
                            if (token != "") {
                                OnReceivedToken(token);
                            } else {
                                OnRetrieveTokenFailed();
                            }
                        });
    }

    private void OnReceivedToken(string token) {
        Debug.Log("Token received: " + token);
        client.UpdateToken(AuthorizationTokenType.Bearer, token, (ClientResult result) => { client.Connect(); });
    }

    private void OnRetrieveTokenFailed() { statusText.text = "Failed to retrieve token"; }
}

(公式がStep by Step でこのDiscordManager の差分とそこまでのStepにおけるコードを記載してくれているので初中級者でも導入できるんじゃないかと思います。とても親切)

ApplicationID とClientID

同じです。

Application Topページの ApplicationID をそのまま引っ張ってきてもらってOKです。
3-3-1_mosaic.png

FAQ

Mac で動かないよ

DiscordのSDKがMacOSだとデフォルトでセキュリティチェックに引っかかるため、設定→プライバシーとセキュリティ→セキュリティ の項目にDiscordSDKの項目が表示されているので有効化してあげてください。

まとめ

Discord のSDK導入解説とSample の機能紹介を行いました。
Discordはゲーマーに人気のため今後はどんどんDiscord内蔵ゲームアプリが出てくると思います。

Lobbyを二つ用意しておいて、いわゆる生存者側部屋と天国部屋みたいなボイスチャンネルの自動移動とかはかなり需要がありそうなので、それをゲーム側が自動でとり行ってくれると、ユーザーとしては非常に便利になりそうですね。

謝辞

今回検証にご協力くださった @AzuQiitaFumi411様。
本当にありがとうございます。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?