using System; using System.Collections.Generic; using System.Linq; using Unity.WebRTC; using UnityEngine; namespace Unity.RenderStreaming { /// /// AudioStreamReceiver is a component that receives audio streams and plays them through a specified AudioSource. /// /// [AddComponentMenu("Render Streaming/Audio Stream Receiver")] public class AudioStreamReceiver : StreamReceiverBase { internal const string CodecPropertyName = nameof(m_Codec); internal const string TargetAudioSourcePropertyName = nameof(m_TargetAudioSource); /// /// Delegate for handling updates to the received audio source. /// /// The updated AudioSource. public delegate void OnUpdateReceiveAudioSourceHandler(AudioSource source); /// /// Event triggered when the received audio source is updated. /// public OnUpdateReceiveAudioSourceHandler OnUpdateReceiveAudioSource; [SerializeField] private AudioSource m_TargetAudioSource; [SerializeField, Codec] private AudioCodecInfo m_Codec; /// /// Gets the codec information for the audio stream. /// public AudioCodecInfo codec { get { return m_Codec; } } /// /// Gets or sets the target AudioSource where the received audio will be played. /// public AudioSource targetAudioSource { get { return m_TargetAudioSource; } set { m_TargetAudioSource = value; } } /// /// Gets the available audio codecs. /// /// /// var codecs = AudioStreamReceiver.GetAvailableCodecs(); /// foreach (var codec in codecs) /// Debug.Log(codec.name); /// /// /// A list of available codecs. static public IEnumerable GetAvailableCodecs() { var excludeCodecMimeType = new[] { "audio/CN", "audio/telephone-event" }; var capabilities = RTCRtpReceiver.GetCapabilities(TrackKind.Audio); return capabilities.codecs.Where(codec => !excludeCodecMimeType.Contains(codec.mimeType)).Select(codec => AudioCodecInfo.Create(codec)); } /// /// Sets the codec for the audio stream. /// /// /// /// x.mimeType.Contains("opus")); /// audioStreamReceiver.SetCodec(codec); /// ]]> /// /// /// The codec information to set. /// Thrown if the transceiver is streaming or the track has ended. public void SetCodec(AudioCodecInfo codec) { m_Codec = codec; if (Transceiver == null) return; if (!string.IsNullOrEmpty(Transceiver.Mid)) throw new InvalidOperationException("Transceiver is streaming. This operation is invalid during the track is in use."); if (Transceiver.Sender.Track.ReadyState == TrackState.Ended) throw new InvalidOperationException("Track has already been ended."); var codecs = new AudioCodecInfo[] { m_Codec }; RTCErrorType error = Transceiver.SetCodecPreferences(SelectCodecCapabilities(codecs).ToArray()); if (error != RTCErrorType.None) throw new InvalidOperationException($"Set codec is failed. errorCode={error}"); } internal IEnumerable SelectCodecCapabilities(IEnumerable codecs) { return RTCRtpReceiver.GetCapabilities(TrackKind.Audio).SelectCodecCapabilities(codecs); } private protected virtual void Start() { OnStartedStream += StartedStream; OnStoppedStream += StoppedStream; } private void StartedStream(string connectionId) { if (Track is AudioStreamTrack audioTrack) { m_TargetAudioSource?.SetTrack(audioTrack); OnUpdateReceiveAudioSource?.Invoke(m_TargetAudioSource); } } private void StoppedStream(string connectionId) { } } }