Live Streaming from Unity - Integrated Chat (Part 4)
In this post, we'll integrate live chat directly into a game!




/chat-token
which will utilize the @aws-sdk/client-ivschat
module to get the tokens.1
npm i @aws-sdk/client-ivschat
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import { CreateChatTokenCommand, IvschatClient } from "@aws-sdk/client-ivschat";
const ivsChatClient = new IvschatClient();
const createChatToken = async (chatArn, userId, username) => {
const chatTokenInput = {
roomIdentifier: chatArn,
userId: userId,
attributes: { username },
capabilities: ['SEND_MESSAGE'],
sessionDurationInMinutes: 180,
};
const createChatTokenRequest = new CreateChatTokenCommand(chatTokenInput);
return await ivsChatClient.send(createChatTokenRequest);
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
else if (parsedUrl.pathname === '/chat-token') {
let body = '';
req.on('data', chunk => {
body += chunk.toString();
});
req.on('end', async () => {
const params = JSON.parse(body);
res.writeHead(200, { 'Content-type': 'application/json' });
const tokenResponse = await createChatToken(
params.chatArn,
params.username,
params.userId,
);
res.write(JSON.stringify(tokenResponse));
res.end();
});
}
1
2
3
4
curl -X POST \
-H "Content-Type: application/json" \
-d '{"chatArn": "[YOUR CHAT ARN]", "username": "todd", "userId": "123"}' \
http://localhost:3000/chat-token | jq
1
2
3
4
5
6
7
8
9
10
11
12
{
"$metadata": {
"httpStatusCode": 200,
"requestId": "...",
"cfId": "...",
"attempts": 1,
"totalRetryDelay": 0
},
"sessionExpirationTime": "2024-01-19T18:22:35.000Z",
"token": "AQICAHgm5DC1V25pBVEhXdu--...",
"tokenExpirationTime": "2024-01-19T16:22:35.000Z"
}


NativeWebSocket
(repo) GitHub URL https://github.com/endel/NativeWebSocket.git#upm
.

1
2
3
4
5
6
7
8
9
using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Networking;
using NativeWebSocket;
using TMPro;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
[
public class ChatAttributes
{
public string username;
public static ChatAttributes CreateFromJSON(string jsonString)
{
return JsonUtility.FromJson<ChatAttributes>(jsonString);
}
}
[ ]
public class ChatSender
{
public string UserId;
public ChatAttributes Attributes;
public static ChatSender CreateFromJSON(string jsonString)
{
return JsonUtility.FromJson<ChatSender>(jsonString);
}
}
[ ]
public class ChatMessage
{
public string Type;
public string Id;
public string RequestId;
public string Content;
public ChatSender Sender;
public static ChatMessage CreateFromJSON(string jsonString)
{
return JsonUtility.FromJson<ChatMessage>(jsonString);
}
}
[ ]
public class ChatToken
{
public System.DateTime sessionExpirationTime;
public string token;
public System.DateTime tokenExpirationTime;
public static ChatToken CreateFromJSON(string jsonString)
{
return JsonUtility.FromJson<ChatToken>(jsonString);
}
}
[ ]
public class ChatTokenRequest
{
public string chatArn;
public string username;
public string userId;
public ChatTokenRequest(string chatArn, string username, string userId)
{
this.chatArn = chatArn;
this.username = username;
this.userId = userId;
}
}
]
IVSChat
class.1
2
3
4
5
6
public class IVSChat : MonoBehaviour
{
TMP_Text chatContainer;
ScrollRect scrollRect;
WebSocket websocket;
}
GetChatToken()
to make a request to our chat token service and retrieve a token. Make sure to pass your chat ARN that we collected above.1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
async Task<ChatToken> GetChatToken()
{
using UnityWebRequest www = new UnityWebRequest("http://localhost:3000/chat-token");
ChatTokenRequest tokenRequest = new ChatTokenRequest(
"[YOUR CHAT ARN]",
"IVS HUD Chat Demo User",
System.Guid.NewGuid().ToString()
);
www.uploadHandler = new UploadHandlerRaw(System.Text.Encoding.ASCII.GetBytes(JsonUtility.ToJson(tokenRequest)));
www.downloadHandler = new DownloadHandlerBuffer();
www.method = UnityWebRequest.kHttpVerbPOST;
www.SetRequestHeader("Content-Type", "application/json");
var request = www.SendWebRequest();
while (!request.isDone)
{
await Task.Yield();
};
var response = www.downloadHandler.text;
if (www.result != UnityWebRequest.Result.Success)
{
Debug.Log(www.error);
return default;
}
else
{
return ChatToken.CreateFromJSON(www.downloadHandler.text);
}
}
ConnectChat()
function that will handle establishing the WebSocket, and set up some connection listeners that will handle parsing and rendering the incoming chat messages. Update [YOUR CHAT ENDPOINT]
with the value we saved above.1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
async Task<WebSocket> ConnectChat()
{
var chatToken = await GetChatToken();
websocket = new WebSocket("[YOUR CHAT ENDPOINT]", chatToken.token);
websocket.OnOpen += () =>
{
Debug.Log("Chat Connection: Open");
};
websocket.OnError += (e) =>
{
Debug.Log("Chat Connection: Error " + e);
};
websocket.OnClose += (e) =>
{
Debug.Log("Chat Connection: Closed");
};
websocket.OnMessage += (bytes) =>
{
var msgString = System.Text.Encoding.UTF8.GetString(bytes);
Debug.Log("Chat Message Received! " + msgString);
ChatMessage chatMsg = ChatMessage.CreateFromJSON(msgString);
Debug.Log(chatMsg);
if (chatMsg.Type == "MESSAGE")
{
chatContainer.text += "<b>" + chatMsg.Sender.Attributes?.username + "</b>: " + chatMsg.Content + "\n";
scrollRect.verticalNormalizedPosition = 0;
}
};
return websocket;
}
Start()
method to call the ConnectChat()
function and the Update()
method to dispatch the message queue. Also, some clean-up is added to Destroy()
.1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
async void Start()
{
chatContainer = GetComponent<TMP_Text>();
scrollRect = chatContainer.transform.parent.parent.parent.GetComponent<ScrollRect>();
await ConnectChat();
await websocket.Connect();
}
void Update()
{
websocket?.DispatchMessageQueue();
}
async void OnDestroy()
{
Debug.Log("OnDestroy");
if (websocket != null) await websocket.Close();
}
NativeWebSocket
has full support if you want to add that.1
2
3
4
5
6
7
8
9
10
11
async void SendWebSocketMessage()
{
if (websocket.State == WebSocketState.Open)
{
// Sending bytes
await websocket.Send(new byte[] { 10, 20, 30 });
// Sending plain text
await websocket.SendText("plain text message");
}
}
Any opinions in this post are those of the individual author and may not reflect the opinions of AWS.