diff --git a/Assets/Samples/Stream Video & Audio Chat SDK/0.8.20.meta b/Assets/Samples/Stream Video & Audio Chat SDK/0.8.21.meta similarity index 77% rename from Assets/Samples/Stream Video & Audio Chat SDK/0.8.20.meta rename to Assets/Samples/Stream Video & Audio Chat SDK/0.8.21.meta index 2b364dff..621a5836 100644 --- a/Assets/Samples/Stream Video & Audio Chat SDK/0.8.20.meta +++ b/Assets/Samples/Stream Video & Audio Chat SDK/0.8.21.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 824737c426eb4344c877fa48581b6894 +guid: 2518f23273a1fba42b81a9225925749f folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/Assets/Samples/Stream Video & Audio Chat SDK/0.8.21/Video & Audio Chat Example Project/Prefabs/UI/Screens/ParticipantView.prefab b/Assets/Samples/Stream Video & Audio Chat SDK/0.8.21/Video & Audio Chat Example Project/Prefabs/UI/Screens/ParticipantView.prefab index 9e1f2672..70859c45 100644 --- a/Assets/Samples/Stream Video & Audio Chat SDK/0.8.21/Video & Audio Chat Example Project/Prefabs/UI/Screens/ParticipantView.prefab +++ b/Assets/Samples/Stream Video & Audio Chat SDK/0.8.21/Video & Audio Chat Example Project/Prefabs/UI/Screens/ParticipantView.prefab @@ -1,5 +1,139 @@ %YAML 1.1 %TAG !u! tag:unity3d.com,2011: +--- !u!1 &1859891430991424952 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6866918036725292465} + - component: {fileID: 926551099080777182} + - component: {fileID: 8686146479983388870} + m_Layer: 5 + m_Name: AudioLevel + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 0 +--- !u!224 &6866918036725292465 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1859891430991424952} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 2006121863080428319} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 112.09, y: 39.4} + m_SizeDelta: {x: 400, y: 50} + m_Pivot: {x: 0, y: 0} +--- !u!222 &926551099080777182 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1859891430991424952} + m_CullTransparentMesh: 1 +--- !u!114 &8686146479983388870 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1859891430991424952} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_text: 23 + m_isRightToLeft: 0 + m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_fontSharedMaterials: [] + m_fontMaterial: {fileID: 0} + m_fontMaterials: [] + m_fontColor32: + serializedVersion: 2 + rgba: 4294967295 + m_fontColor: {r: 1, g: 1, b: 1, a: 1} + m_enableVertexGradient: 0 + m_colorMode: 3 + m_fontColorGradient: + topLeft: {r: 1, g: 1, b: 1, a: 1} + topRight: {r: 1, g: 1, b: 1, a: 1} + bottomLeft: {r: 1, g: 1, b: 1, a: 1} + bottomRight: {r: 1, g: 1, b: 1, a: 1} + m_fontColorGradientPreset: {fileID: 0} + m_spriteAsset: {fileID: 0} + m_tintAllSprites: 0 + m_StyleSheet: {fileID: 0} + m_TextStyleHashCode: -1183493901 + m_overrideHtmlColors: 0 + m_faceColor: + serializedVersion: 2 + rgba: 4294967295 + m_fontSize: 40 + m_fontSizeBase: 40 + m_fontWeight: 400 + m_enableAutoSizing: 0 + m_fontSizeMin: 18 + m_fontSizeMax: 72 + m_fontStyle: 0 + m_HorizontalAlignment: 1 + m_VerticalAlignment: 256 + m_textAlignment: 65535 + m_characterSpacing: 0 + m_wordSpacing: 0 + m_lineSpacing: 0 + m_lineSpacingMax: 0 + m_paragraphSpacing: 0 + m_charWidthMaxAdj: 0 + m_enableWordWrapping: 1 + m_wordWrappingRatios: 0.4 + m_overflowMode: 0 + m_linkedTextComponent: {fileID: 0} + parentLinkedComponent: {fileID: 0} + m_enableKerning: 1 + m_enableExtraPadding: 0 + checkPaddingRequired: 0 + m_isRichText: 1 + m_parseCtrlCharacters: 1 + m_isOrthographic: 1 + m_isCullingEnabled: 0 + m_horizontalMapping: 0 + m_verticalMapping: 0 + m_uvLineOffset: 0 + m_geometrySortingOrder: 0 + m_IsTextObjectScaleStatic: 0 + m_VertexBufferAutoSizeReduction: 0 + m_useMaxVisibleDescender: 1 + m_pageToDisplay: 1 + m_margin: {x: 0, y: 0, z: 0, w: 0} + m_isUsingLegacyAnimationComponent: 0 + m_isVolumetricText: 0 + m_hasFontAssetChanged: 0 + m_baseMaterial: {fileID: 0} + m_maskOffset: {x: 0, y: 0, z: 0, w: 0} --- !u!1 &2006121863080428312 GameObject: m_ObjectHideFlags: 0 @@ -34,6 +168,8 @@ RectTransform: - {fileID: 7252032941131618416} - {fileID: 7637150640667577125} - {fileID: 3604744137779619309} + - {fileID: 1036960430990650392} + - {fileID: 6866918036725292465} m_Father: {fileID: 2006121863544806348} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} @@ -193,6 +329,8 @@ MonoBehaviour: _forceRequestedResolutionHeight: 300 _isMutedIcon: {fileID: 7852245601941594288} _muteLocallyToggleButton: {fileID: 6073022831238027141} + _audioLevel: {fileID: 8686146479983388870} + _isSpeakingIcon: {fileID: 4664516320093859518} --- !u!1 &2006121864280196914 GameObject: m_ObjectHideFlags: 0 @@ -348,6 +486,81 @@ MonoBehaviour: m_FlexibleWidth: -1 m_FlexibleHeight: -1 m_LayoutPriority: 1 +--- !u!1 &4664516320093859518 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1036960430990650392} + - component: {fileID: 8542746723167520707} + - component: {fileID: 5072929113691457332} + m_Layer: 5 + m_Name: IsSpeakingIcon + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1036960430990650392 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4664516320093859518} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 2006121863080428319} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 10, y: 10} + m_SizeDelta: {x: 100, y: 100} + m_Pivot: {x: 0, y: 0} +--- !u!222 &8542746723167520707 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4664516320093859518} + m_CullTransparentMesh: 1 +--- !u!114 &5072929113691457332 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4664516320093859518} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0, g: 1, b: 0.030314207, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10913, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 --- !u!1 &5510979313677697257 GameObject: m_ObjectHideFlags: 0 diff --git a/Assets/Samples/Stream Video & Audio Chat SDK/0.8.21/Video & Audio Chat Example Project/Scripts/UI/ParticipantView.cs b/Assets/Samples/Stream Video & Audio Chat SDK/0.8.21/Video & Audio Chat Example Project/Scripts/UI/ParticipantView.cs index 50462f31..4a7696ac 100644 --- a/Assets/Samples/Stream Video & Audio Chat SDK/0.8.21/Video & Audio Chat Example Project/Scripts/UI/ParticipantView.cs +++ b/Assets/Samples/Stream Video & Audio Chat SDK/0.8.21/Video & Audio Chat Example Project/Scripts/UI/ParticipantView.cs @@ -28,7 +28,12 @@ public void Init(IStreamVideoCallParticipant participant, StreamVideoManager vid OnParticipantTrackAdded(Participant, track); } + OnIsSpeakingChanged(Participant.IsSpeaking); + OnAudioLevelChanged(Participant.AudioLevel); + Participant.TrackAdded += OnParticipantTrackAdded; + Participant.AudioLevelChanged += OnAudioLevelChanged; + Participant.IsSpeakingChanged += OnIsSpeakingChanged; _name.text = Participant.Name; } @@ -107,6 +112,8 @@ protected void OnDestroy() if (Participant != null) { Participant.TrackAdded -= OnParticipantTrackAdded; + Participant.AudioLevelChanged -= OnAudioLevelChanged; + Participant.IsSpeakingChanged -= OnIsSpeakingChanged; } } @@ -140,6 +147,12 @@ protected void OnDestroy() [SerializeField] private Button _muteLocallyToggleButton; + [SerializeField] + private TMP_Text _audioLevel; + + [SerializeField] + private GameObject _isSpeakingIcon; + private AudioSource _audioSource; private RectTransform _videoRectTransform; private Vector2 _lastRequestedResolution; @@ -211,5 +224,15 @@ private void UpdateMuteIcon() var isMuted = _videoManager.IsParticipantMutedLocally(Participant); _isMutedIcon.SetActive(isMuted); } + + private void OnIsSpeakingChanged(bool isSpeaking) + { + _isSpeakingIcon.SetActive(isSpeaking); + } + + private void OnAudioLevelChanged(float audioLevel) + { + _audioLevel.text = audioLevel.ToString(); + } } } \ No newline at end of file diff --git a/Packages/StreamVideo/Runtime/Core/LowLevelClient/RtcSession.cs b/Packages/StreamVideo/Runtime/Core/LowLevelClient/RtcSession.cs index 02663ebe..c10d10da 100644 --- a/Packages/StreamVideo/Runtime/Core/LowLevelClient/RtcSession.cs +++ b/Packages/StreamVideo/Runtime/Core/LowLevelClient/RtcSession.cs @@ -1421,8 +1421,8 @@ private void OnSfuConnectionQualityChanged(ConnectionQualityChanged connectionQu private void OnSfuAudioLevelChanged(AudioLevelChanged audioLevelChanged) { - - // StreamTODO: Implement OnSfuAudioLevelChanged + // Ignore tracing AudioLevelChanged -> not much debug value + creates too much noise in data + ActiveCall?.UpdateFromSfu(audioLevelChanged); } private void OnSfuPublisherAnswer(PublisherAnswer publisherAnswer) diff --git a/Packages/StreamVideo/Runtime/Core/Models/CallSession.cs b/Packages/StreamVideo/Runtime/Core/Models/CallSession.cs index c31480c8..f61d95d1 100644 --- a/Packages/StreamVideo/Runtime/Core/Models/CallSession.cs +++ b/Packages/StreamVideo/Runtime/Core/Models/CallSession.cs @@ -232,5 +232,19 @@ private void UpdateParticipantCountFromSessionInternal(int anonymousParticipantC ((IStateLoadableFrom)ParticipantCount) .LoadFromDto(dto, null); } + + internal void UpdateFromSfu(AudioLevelChanged audioLevelChanged) + { + foreach (var entry in audioLevelChanged.AudioLevels) + { + for (int i = 0; i < _participants.Count; i++) + { + if (_participants[i].SessionId == entry.SessionId) + { + _participants[i].UpdateFromSfu(entry); + } + } + } + } } } \ No newline at end of file diff --git a/Packages/StreamVideo/Runtime/Core/StatefulModels/IStreamVideoCallParticipant.cs b/Packages/StreamVideo/Runtime/Core/StatefulModels/IStreamVideoCallParticipant.cs index a3fb2cbc..7b223863 100644 --- a/Packages/StreamVideo/Runtime/Core/StatefulModels/IStreamVideoCallParticipant.cs +++ b/Packages/StreamVideo/Runtime/Core/StatefulModels/IStreamVideoCallParticipant.cs @@ -22,6 +22,16 @@ public interface IStreamVideoCallParticipant : IStreamStatefulModel, IHasCustomD /// event ParticipantTrackChangedHandler TrackIsEnabledChanged; + /// + /// Event notifying that the value of changed for this participant. The event callback contains the current value of + /// + event Action AudioLevelChanged; + + /// + /// Event notifying that the value of changed for this participant. The event callback contains the current value of + /// + event Action IsSpeakingChanged; + /// /// Is this participant "pinned" in the call meaning it will have precedence in list /// diff --git a/Packages/StreamVideo/Runtime/Core/StatefulModels/StreamCall.cs b/Packages/StreamVideo/Runtime/Core/StatefulModels/StreamCall.cs index 52c750d3..131e3756 100644 --- a/Packages/StreamVideo/Runtime/Core/StatefulModels/StreamCall.cs +++ b/Packages/StreamVideo/Runtime/Core/StatefulModels/StreamCall.cs @@ -720,6 +720,11 @@ internal void UpdateFromSfu(HealthCheckResponse healthCheckResponse, ICache cach { Session?.UpdateFromSfu(healthCheckResponse, cache); } + + internal void UpdateFromSfu(AudioLevelChanged audioLevelChanged) + { + Session?.UpdateFromSfu(audioLevelChanged); + } internal void UpdateFromCoordinator(CallSessionParticipantCountsUpdatedEventInternalDTO eventData) { diff --git a/Packages/StreamVideo/Runtime/Core/StatefulModels/StreamVideoCallParticipant.cs b/Packages/StreamVideo/Runtime/Core/StatefulModels/StreamVideoCallParticipant.cs index 1cd13543..8ff891b8 100644 --- a/Packages/StreamVideo/Runtime/Core/StatefulModels/StreamVideoCallParticipant.cs +++ b/Packages/StreamVideo/Runtime/Core/StatefulModels/StreamVideoCallParticipant.cs @@ -9,6 +9,7 @@ using StreamVideo.Core.StatefulModels.Tracks; using StreamVideo.Core.Utils; using StreamVideo.Libs.Serialization; +using StreamVideo.v1.Sfu.Events; using Unity.WebRTC; using UnityEngine; using Participant = StreamVideo.v1.Sfu.Models.Participant; @@ -22,6 +23,9 @@ internal sealed class StreamVideoCallParticipant : StreamStatefulModelBase AudioLevelChanged; + public event Action IsSpeakingChanged; public bool IsLocalParticipant => SessionId == Client.InternalLowLevelClient.RtcSession.SessionId; @@ -60,9 +64,39 @@ internal sealed class StreamVideoCallParticipant : StreamStatefulModelBase _isSpeaking; + private set + { + if (_isSpeaking == value) + { + return; + } + + _isSpeaking = value; + IsSpeakingChanged?.Invoke(value); + } + } + public bool IsDominantSpeaker { get; private set; } - public float AudioLevel { get; private set; } + + public float AudioLevel + { + get => _audioLevel; + private set + { + if (Math.Abs(_audioLevel - value) < Mathf.Epsilon) + { + return; + } + + _audioLevel = value; + AudioLevelChanged?.Invoke(value); + } + } + public string Name { get; private set; } public string Image { get; private set; } public IEnumerable Roles => _roles; @@ -176,6 +210,12 @@ internal void UpdateFromSfu(Participant dto) { ((IUpdateableFrom)this).UpdateFromDto(dto, Cache); } + + internal void UpdateFromSfu(AudioLevel audioLevel) + { + IsSpeaking = audioLevel.IsSpeaking; + AudioLevel = audioLevel.Level; + } internal void Update() { @@ -280,6 +320,8 @@ protected override Task UploadCustomDataAsync() private readonly List _publishedTracks = new List(); private readonly List _roles = new List(); + private float _audioLevel; + private bool _isSpeaking; #endregion diff --git a/Packages/StreamVideo/Samples~/VideoChat/Prefabs/UI/Screens/ParticipantView.prefab b/Packages/StreamVideo/Samples~/VideoChat/Prefabs/UI/Screens/ParticipantView.prefab index 9e1f2672..70859c45 100644 --- a/Packages/StreamVideo/Samples~/VideoChat/Prefabs/UI/Screens/ParticipantView.prefab +++ b/Packages/StreamVideo/Samples~/VideoChat/Prefabs/UI/Screens/ParticipantView.prefab @@ -1,5 +1,139 @@ %YAML 1.1 %TAG !u! tag:unity3d.com,2011: +--- !u!1 &1859891430991424952 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6866918036725292465} + - component: {fileID: 926551099080777182} + - component: {fileID: 8686146479983388870} + m_Layer: 5 + m_Name: AudioLevel + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 0 +--- !u!224 &6866918036725292465 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1859891430991424952} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 2006121863080428319} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 112.09, y: 39.4} + m_SizeDelta: {x: 400, y: 50} + m_Pivot: {x: 0, y: 0} +--- !u!222 &926551099080777182 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1859891430991424952} + m_CullTransparentMesh: 1 +--- !u!114 &8686146479983388870 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1859891430991424952} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_text: 23 + m_isRightToLeft: 0 + m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_fontSharedMaterials: [] + m_fontMaterial: {fileID: 0} + m_fontMaterials: [] + m_fontColor32: + serializedVersion: 2 + rgba: 4294967295 + m_fontColor: {r: 1, g: 1, b: 1, a: 1} + m_enableVertexGradient: 0 + m_colorMode: 3 + m_fontColorGradient: + topLeft: {r: 1, g: 1, b: 1, a: 1} + topRight: {r: 1, g: 1, b: 1, a: 1} + bottomLeft: {r: 1, g: 1, b: 1, a: 1} + bottomRight: {r: 1, g: 1, b: 1, a: 1} + m_fontColorGradientPreset: {fileID: 0} + m_spriteAsset: {fileID: 0} + m_tintAllSprites: 0 + m_StyleSheet: {fileID: 0} + m_TextStyleHashCode: -1183493901 + m_overrideHtmlColors: 0 + m_faceColor: + serializedVersion: 2 + rgba: 4294967295 + m_fontSize: 40 + m_fontSizeBase: 40 + m_fontWeight: 400 + m_enableAutoSizing: 0 + m_fontSizeMin: 18 + m_fontSizeMax: 72 + m_fontStyle: 0 + m_HorizontalAlignment: 1 + m_VerticalAlignment: 256 + m_textAlignment: 65535 + m_characterSpacing: 0 + m_wordSpacing: 0 + m_lineSpacing: 0 + m_lineSpacingMax: 0 + m_paragraphSpacing: 0 + m_charWidthMaxAdj: 0 + m_enableWordWrapping: 1 + m_wordWrappingRatios: 0.4 + m_overflowMode: 0 + m_linkedTextComponent: {fileID: 0} + parentLinkedComponent: {fileID: 0} + m_enableKerning: 1 + m_enableExtraPadding: 0 + checkPaddingRequired: 0 + m_isRichText: 1 + m_parseCtrlCharacters: 1 + m_isOrthographic: 1 + m_isCullingEnabled: 0 + m_horizontalMapping: 0 + m_verticalMapping: 0 + m_uvLineOffset: 0 + m_geometrySortingOrder: 0 + m_IsTextObjectScaleStatic: 0 + m_VertexBufferAutoSizeReduction: 0 + m_useMaxVisibleDescender: 1 + m_pageToDisplay: 1 + m_margin: {x: 0, y: 0, z: 0, w: 0} + m_isUsingLegacyAnimationComponent: 0 + m_isVolumetricText: 0 + m_hasFontAssetChanged: 0 + m_baseMaterial: {fileID: 0} + m_maskOffset: {x: 0, y: 0, z: 0, w: 0} --- !u!1 &2006121863080428312 GameObject: m_ObjectHideFlags: 0 @@ -34,6 +168,8 @@ RectTransform: - {fileID: 7252032941131618416} - {fileID: 7637150640667577125} - {fileID: 3604744137779619309} + - {fileID: 1036960430990650392} + - {fileID: 6866918036725292465} m_Father: {fileID: 2006121863544806348} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} @@ -193,6 +329,8 @@ MonoBehaviour: _forceRequestedResolutionHeight: 300 _isMutedIcon: {fileID: 7852245601941594288} _muteLocallyToggleButton: {fileID: 6073022831238027141} + _audioLevel: {fileID: 8686146479983388870} + _isSpeakingIcon: {fileID: 4664516320093859518} --- !u!1 &2006121864280196914 GameObject: m_ObjectHideFlags: 0 @@ -348,6 +486,81 @@ MonoBehaviour: m_FlexibleWidth: -1 m_FlexibleHeight: -1 m_LayoutPriority: 1 +--- !u!1 &4664516320093859518 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1036960430990650392} + - component: {fileID: 8542746723167520707} + - component: {fileID: 5072929113691457332} + m_Layer: 5 + m_Name: IsSpeakingIcon + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1036960430990650392 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4664516320093859518} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 2006121863080428319} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 10, y: 10} + m_SizeDelta: {x: 100, y: 100} + m_Pivot: {x: 0, y: 0} +--- !u!222 &8542746723167520707 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4664516320093859518} + m_CullTransparentMesh: 1 +--- !u!114 &5072929113691457332 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4664516320093859518} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0, g: 1, b: 0.030314207, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10913, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 --- !u!1 &5510979313677697257 GameObject: m_ObjectHideFlags: 0 diff --git a/Packages/StreamVideo/Samples~/VideoChat/Scripts/UI/ParticipantView.cs b/Packages/StreamVideo/Samples~/VideoChat/Scripts/UI/ParticipantView.cs index 50462f31..4a7696ac 100644 --- a/Packages/StreamVideo/Samples~/VideoChat/Scripts/UI/ParticipantView.cs +++ b/Packages/StreamVideo/Samples~/VideoChat/Scripts/UI/ParticipantView.cs @@ -28,7 +28,12 @@ public void Init(IStreamVideoCallParticipant participant, StreamVideoManager vid OnParticipantTrackAdded(Participant, track); } + OnIsSpeakingChanged(Participant.IsSpeaking); + OnAudioLevelChanged(Participant.AudioLevel); + Participant.TrackAdded += OnParticipantTrackAdded; + Participant.AudioLevelChanged += OnAudioLevelChanged; + Participant.IsSpeakingChanged += OnIsSpeakingChanged; _name.text = Participant.Name; } @@ -107,6 +112,8 @@ protected void OnDestroy() if (Participant != null) { Participant.TrackAdded -= OnParticipantTrackAdded; + Participant.AudioLevelChanged -= OnAudioLevelChanged; + Participant.IsSpeakingChanged -= OnIsSpeakingChanged; } } @@ -140,6 +147,12 @@ protected void OnDestroy() [SerializeField] private Button _muteLocallyToggleButton; + [SerializeField] + private TMP_Text _audioLevel; + + [SerializeField] + private GameObject _isSpeakingIcon; + private AudioSource _audioSource; private RectTransform _videoRectTransform; private Vector2 _lastRequestedResolution; @@ -211,5 +224,15 @@ private void UpdateMuteIcon() var isMuted = _videoManager.IsParticipantMutedLocally(Participant); _isMutedIcon.SetActive(isMuted); } + + private void OnIsSpeakingChanged(bool isSpeaking) + { + _isSpeakingIcon.SetActive(isSpeaking); + } + + private void OnAudioLevelChanged(float audioLevel) + { + _audioLevel.text = audioLevel.ToString(); + } } } \ No newline at end of file