// %BANNER_BEGIN% // --------------------------------------------------------------------- // %COPYRIGHT_BEGIN% // Copyright (c) (2018-2022) Magic Leap, Inc. All Rights Reserved. // Use of this file is governed by the Software License Agreement, located here: https://www.magicleap.com/software-license-agreement-ml2 // Terms and conditions applicable to third-party materials accompanying this distribution may also be found in the top-level NOTICE file appearing herein. // %COPYRIGHT_END% // --------------------------------------------------------------------- // %BANNER_END% namespace UnityEngine.XR.MagicLeap { using System; using System.Collections.Generic; /// /// MLWebRTC class contains the API to interface with the /// WebRTC C API. /// public partial class MLWebRTC { /// /// Class that represents a media stream object. /// public partial class MediaStream { /// /// The active tracks mapped by MLWebRTC.MediaStream.Track.Type. /// private Dictionary activeTracks = new Dictionary { { Track.Type.Audio, null}, { Track.Type.Video, null} }; /// /// Initializes a new instance of the class. /// private MediaStream() { } /// /// Gets the list of tracks associated with this media stream. /// public List Tracks { get; private set; } /// /// Gets all video tracks. /// public List VideoTracks { get => Tracks.FindAll(track => track.TrackType == Track.Type.Video); } /// /// Gets all audio tracks. /// public List AudioTracks { get => Tracks.FindAll(track => track.TrackType == Track.Type.Audio); } /// /// Gets the active video track. /// public MediaStream.Track ActiveVideoTrack { get => activeTracks[Track.Type.Video]; } /// /// Gets the active audio track. /// public MediaStream.Track ActiveAudioTrack { get => activeTracks[Track.Type.Audio]; } /// /// Gets the connections associated with this media stream. /// Remote media streams will have just 1 connection, while local streams can have more than one, /// depending on the app setup. /// public HashSet ParentConnections { get; internal set; } = new HashSet(); /// /// Gets the id of this media stream. /// public string Id { get; private set; } /// /// Gets a value indicating whether the media stream is local or not. /// public bool IsLocal { get; private set; } /// /// Creates an initialized local MediaStream object and it's tracks with the given video type. /// Recommended to use CreateWithAppDefinedVideoTrack() in production, with sample video sources /// provided as MLCameraVideoSource and MLMRCameraVideoSource in the UnityEngine.XR.MagicLeap namespace /// since those sources provide more information about and control over various error cases and /// handle special cases like app pause/resume and device standby/reality/active. /// /// Connection to use. /// The id to give the media stream. /// The type of video to use. /// An initialized MediaStream object. public static MediaStream CreateWithBuiltInTracks(string id, Track.VideoType videoType, Track.AudioType audioType, string videoTrackId = "", string audioTrackId = "") { MediaStream mediaStream = Create(id); if (mediaStream == null) { return null; } MediaStream.Track videoTrack = (videoType != Track.VideoType.None) ? MediaStream.Track.CreateVideoTrack(videoType, out MLResult result, trackId: videoTrackId) : null; MediaStream.Track audioTrack = (audioType != Track.AudioType.None) ? MediaStream.Track.CreateAudioTrackFromMicrophone(out result, audioTrackId) : null; if (videoTrack != null) { mediaStream.AddLocalTrack(videoTrack); mediaStream.SelectTrack(videoTrack); } if (audioTrack != null) { mediaStream.AddLocalTrack(audioTrack); mediaStream.SelectTrack(audioTrack); } return mediaStream; } /// /// Creates an initialized local MediaStream object and it's tracks with the given video source. /// /// Connection to use. /// The id to give the media stream. /// The defined video source to use. /// An initialized MediaStream object. public static MediaStream CreateWithAppDefinedVideoTrack(string id, MLWebRTC.AppDefinedVideoSource appDefinedVideoSource, Track.AudioType audioType, string audioTrackId = "", MLWebRTC.AppDefinedAudioSource localDefinedAudioSource = null) { MediaStream mediaStream = Create(id); if (mediaStream == null) { return null; } mediaStream.AddLocalTrack(appDefinedVideoSource); mediaStream.SelectTrack(appDefinedVideoSource); if (audioType != Track.AudioType.None) { MediaStream.Track audioTrack = null; switch (audioType) { case Track.AudioType.Microphone: audioTrack = MediaStream.Track.CreateAudioTrackFromMicrophone(out MLResult micResult, audioTrackId); break; case Track.AudioType.Defined: MLWebRTC.AppDefinedAudioSource.InitializeLocal(localDefinedAudioSource); audioTrack = localDefinedAudioSource; break; } mediaStream.AddLocalTrack(audioTrack); mediaStream.SelectTrack(audioTrack); } return mediaStream; } /// /// Creates an initialized local MediaStream object. /// /// The id to give the media stream. /// An initialized MediaStream object. public static MediaStream Create(string id) { if (MLWebRTC.Instance.uniqueMediaStreamIds.Contains(id)) { MLPluginLog.ErrorFormat("Media stream id '{0}' already exists.", id); return null; } MediaStream mediaStream = Create(null, id); mediaStream.IsLocal = true; MLWebRTC.Instance.uniqueMediaStreamIds.Add(id); return mediaStream; } /// /// Creates an initialized MediaStream object. /// /// The connection to associate the media stream with. /// The id to give the media stream. /// An initialized MediaStream object. internal static MediaStream Create(MLWebRTC.PeerConnection connection, string id) { MediaStream mediaStream = new MediaStream(); mediaStream.Tracks = new List(); mediaStream.Id = id; mediaStream.ParentConnections.Add(connection); return mediaStream; } /// /// Adds a local track to the media stream. /// /// The connection to use. /// The local track to add. /// public MLResult AddLocalTrack(MLWebRTC.MediaStream.Track track) { MLResult result = MLResult.Create(MLResult.Code.Ok); if (this.Tracks.Contains(track)) { return result; } if (track.IsLocal) { this.Tracks.Add(track); track.Streams.Add(this); } return result; } /// /// Removes a local track from the media stream. /// /// The connection to use. /// The local track to add. /// public MLResult RemoveLocalTrack(MLWebRTC.MediaStream.Track track) { MLResult result = MLResult.Create(MLResult.Code.Ok); if (!this.Tracks.Contains(track)) { return result; } if (track.IsLocal) { this.Tracks.Remove(track); track.Streams.Remove(this); } return result; } /// /// Sets the given track as the active track of it's kind and enables it. /// /// The track to make active. public MLResult SelectTrack(MediaStream.Track track) { if (track == null) { return MLResult.Create(MLResult.Code.InvalidParam, "Track is null."); } MediaStream.Track currentActiveTrack = activeTracks[track.TrackType]; if (currentActiveTrack != null) { UnSelectTrack(currentActiveTrack); } activeTracks[track.TrackType] = track; MLResult result = track.SetEnabled(true); return result; } /// /// Sets the given track to longer be the active track of it's kind and disables. /// /// The track to make inactive. public MLResult UnSelectTrack(MediaStream.Track track) { if (track == null) { return MLResult.Create(MLResult.Code.InvalidParam, "Track is null."); } MLResult result = MLResult.Create(MLResult.Code.Ok); MediaStream.Track currentActiveTrack = activeTracks[track.TrackType]; if (currentActiveTrack == track) { if (IsLocal) result = currentActiveTrack.SetEnabled(false); activeTracks[track.TrackType] = null; } return result; } /// /// Destroys this stream and it's associated tracks. /// public void DestroyLocal() { if (!IsLocal) { return; } foreach (Track track in this.Tracks) { track.DestroyLocal(); } MLWebRTC.Instance.uniqueMediaStreamIds.Remove(this.Id); } } } }