Last active
January 19, 2024 14:30
-
-
Save recursivecodes/e948b81e53bf9259b981c88e9fc216fa to your computer and use it in GitHub Desktop.
This script is a demo of how to broadcast to an Amazon IVS real-time stage from Unity.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Collections; | |
using System.Collections.Generic; | |
using System.Threading.Tasks; | |
using UnityEngine; | |
using Unity.WebRTC; | |
using UnityEngine.Networking; | |
[System.Serializable] | |
public class ParticipantToken | |
{ | |
public string token; | |
public string participantId; | |
public System.DateTime expirationTime; | |
public static ParticipantToken CreateFromJSON(string jsonString) | |
{ | |
return JsonUtility.FromJson<ParticipantToken>(jsonString); | |
} | |
} | |
[System.Serializable] | |
public class StageToken | |
{ | |
public ParticipantToken participantToken; | |
public static StageToken CreateFromJSON(string jsonString) | |
{ | |
return JsonUtility.FromJson<StageToken>(jsonString); | |
} | |
} | |
[System.Serializable] | |
public class StageTokenRequestAttributes | |
{ | |
public string username; | |
public StageTokenRequestAttributes(string username) | |
{ | |
this.username = username; | |
} | |
} | |
[System.Serializable] | |
public class StageTokenRequest | |
{ | |
public string stageArn; | |
public string userId; | |
public int duration; | |
public StageTokenRequestAttributes attributes; | |
public string[] capabilities; | |
public StageTokenRequest(string stageArn, string userId, int duration, string[] capabilities, StageTokenRequestAttributes attributes) | |
{ | |
this.stageArn = stageArn; | |
this.userId = userId; | |
this.duration = duration; | |
this.capabilities = capabilities; | |
this.attributes = attributes; | |
} | |
} | |
[RequireComponent(typeof(AudioListener))] | |
public class WebRTCPublish : MonoBehaviour | |
{ | |
RTCPeerConnection peerConnection; | |
MediaStreamTrack videoTrack; | |
AudioStreamTrack audioTrack; | |
Camera cam; | |
ParticipantToken participantToken; | |
async Task<StageToken> GetStageToken() | |
{ | |
using UnityWebRequest www = new UnityWebRequest("http://localhost:3000/token"); | |
StageTokenRequest tokenRequest = new StageTokenRequest( | |
"[YOUR STAGE ARN]", | |
System.Guid.NewGuid().ToString(), | |
1440, | |
new string[] { "PUBLISH", "SUBSCRIBE" }, | |
new StageTokenRequestAttributes("ivs-rtx-broadcast-demo") | |
); | |
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; | |
Debug.Log(response); | |
if (www.result != UnityWebRequest.Result.Success) | |
{ | |
Debug.Log(www.error); | |
return default; | |
} | |
else | |
{ | |
StageToken stageToken = StageToken.CreateFromJSON(www.downloadHandler.text); | |
Debug.Log(stageToken); | |
participantToken = stageToken.participantToken; | |
return stageToken; | |
} | |
} | |
async void Start() | |
{ | |
StartCoroutine(WebRTC.Update()); | |
peerConnection = new RTCPeerConnection | |
{ | |
OnIceConnectionChange = state => { Debug.Log("Peer Connection: " + state); } | |
}; | |
cam = GetComponent<Camera>(); | |
videoTrack = cam.CaptureStreamTrack(1280, 720); | |
peerConnection.AddTrack(videoTrack); | |
AudioListener audioListener = cam.GetComponent<AudioListener>(); | |
audioTrack = new AudioStreamTrack(audioListener) { Loopback = true }; | |
peerConnection.AddTrack(audioTrack); | |
StartCoroutine(DoWHIP()); | |
} | |
IEnumerator DoWHIP() | |
{ | |
Task getStageTokenTask = GetStageToken(); | |
yield return new WaitUntil(() => getStageTokenTask.IsCompleted); | |
Debug.Log(participantToken.token); | |
Debug.Log(participantToken.participantId); | |
var offer = peerConnection.CreateOffer(); | |
yield return offer; | |
var offerDesc = offer.Desc; | |
var opLocal = peerConnection.SetLocalDescription(ref offerDesc); | |
yield return opLocal; | |
var filteredSdp = ""; | |
foreach (string sdpLine in offer.Desc.sdp.Split("\r\n")) | |
{ | |
if (!sdpLine.StartsWith("a=extmap")) | |
{ | |
filteredSdp += sdpLine + "\r\n"; | |
} | |
} | |
using (UnityWebRequest www = new UnityWebRequest("https://global.whip.live-video.net/")) | |
{ | |
www.uploadHandler = new UploadHandlerRaw(System.Text.Encoding.ASCII.GetBytes(filteredSdp)); | |
www.downloadHandler = new DownloadHandlerBuffer(); | |
www.method = UnityWebRequest.kHttpVerbPOST; | |
www.SetRequestHeader("Content-Type", "application/sdp"); | |
www.SetRequestHeader("Authorization", "Bearer " + participantToken.token); | |
yield return www.SendWebRequest(); | |
if (www.result != UnityWebRequest.Result.Success) | |
{ | |
Debug.Log(www.error); | |
} | |
else | |
{ | |
var answer = new RTCSessionDescription { type = RTCSdpType.Answer, sdp = www.downloadHandler.text }; | |
var opRemote = peerConnection.SetRemoteDescription(ref answer); | |
yield return opRemote; | |
if (opRemote.IsError) | |
{ | |
Debug.Log(opRemote.Error); | |
} | |
} | |
} | |
} | |
async void OnDestroy() | |
{ | |
Debug.Log("OnDestroy"); | |
if (peerConnection != null) | |
{ | |
peerConnection.Close(); | |
peerConnection.Dispose(); | |
} | |
if (videoTrack != null) videoTrack.Dispose(); | |
if (audioTrack != null) audioTrack.Dispose(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment