< Summary

Class:DCL.Components.DCLVideoTexture
Assembly:DCL.Components.Video
File(s):/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/Components/Video/DCLVideoTexture.cs
Covered lines:166
Uncovered lines:17
Coverable lines:183
Total lines:391
Line coverage:90.7% (166 of 183)
Covered branches:0
Total branches:0

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity NPath complexity Sequence coverage
DCLVideoTexture()0%110100%
Model()0%110100%
GetDataFromJSON(...)0%110100%
DCLVideoTexture()0%110100%
ApplyChanges()0%23.5419076.74%
Initialize(...)0%220100%
GetVolume()0%2100%
OnUpdate()0%330100%
UpdateDirtyState()0%220100%
UpdateVideoTexture()0%440100%
UpdateProgressReport()0%440100%
ReportVideoProgress()0%110100%
IsTimeToReportVideoProgress()0%110100%
CalculateVideoVolumeAndPlayStatus()0%880100%
OnVirtualAudioMixerChangedValue(...)0%2100%
UpdateVolume()0%4.014090.91%
IsPlayerInSameSceneAsComponent(...)0%5.024060%
OnPlayerCoordsChanged(...)0%110100%
OnSceneIDChanged(...)0%110100%
AttachTo(...)0%22090%
DetachFrom(...)0%3.013091.67%
SetPlayStateDirty(...)0%110100%
OnAudioSettingsChanged(...)0%110100%
Dispose()0%440100%

File(s)

/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/Components/Video/DCLVideoTexture.cs

#LineLine coverage
 1using System.Collections;
 2using System.Collections.Generic;
 3using DCL.Controllers;
 4using DCL.Models;
 5using UnityEngine;
 6using DCL.Components.Video.Plugin;
 7using DCL.Helpers;
 8using DCL.Interface;
 9using DCL.SettingsCommon;
 10using UnityEngine.Assertions;
 11using AudioSettings = DCL.SettingsCommon.AudioSettings;
 12
 13namespace DCL.Components
 14{
 15    public class DCLVideoTexture : DCLTexture
 16    {
 117        public static bool VERBOSE = false;
 118        public static Logger logger = new Logger("DCLVideoTexture") {verboseEnabled = VERBOSE};
 19
 20        private const float OUTOFSCENE_TEX_UPDATE_INTERVAL_IN_SECONDS = 1.5f;
 21        private const float VIDEO_PROGRESS_UPDATE_INTERVAL_IN_SECONDS = 1f;
 22
 123        public static System.Func<IVideoPluginWrapper> videoPluginWrapperBuilder = () => new VideoPluginWrapper_WebGL();
 24
 25        [System.Serializable]
 26        new public class Model : BaseModel
 27        {
 28            public string videoClipId;
 29            public bool playing = false;
 4530            public float volume = 1f;
 4531            public float playbackRate = 1f;
 32            public bool loop = false;
 4533            public float seek = -1;
 34            public BabylonWrapMode wrap = BabylonWrapMode.CLAMP;
 4535            public FilterMode samplingMode = FilterMode.Bilinear;
 36
 1537            public override BaseModel GetDataFromJSON(string json) { return Utils.SafeFromJson<Model>(json); }
 38        }
 39
 40        internal WebVideoPlayer texturePlayer;
 41        private Coroutine texturePlayerUpdateRoutine;
 42        private float baseVolume;
 1543        private float distanceVolumeModifier = 1f;
 44        private bool isPlayStateDirty = false;
 45        internal bool isVisible = false;
 46
 1547        private bool isPlayerInScene = true;
 1548        private float currUpdateIntervalTime = OUTOFSCENE_TEX_UPDATE_INTERVAL_IN_SECONDS;
 49        private float lastVideoProgressReportTime;
 50
 1551        internal Dictionary<string, ISharedComponent> attachedMaterials = new Dictionary<string, ISharedComponent>();
 52        private string lastVideoClipID;
 53        private VideoState previousVideoState;
 54
 1555        public DCLVideoTexture()
 56        {
 1557            model = new Model();
 58
 1559            DataStore.i.virtualAudioMixer.sceneSFXVolume.OnChange += OnVirtualAudioMixerChangedValue;
 1560        }
 61
 62        public override IEnumerator ApplyChanges(BaseModel newModel)
 63        {
 3064            yield return new WaitUntil(() => CommonScriptableObjects.rendererState.Get());
 65
 66            //If the scene creates and destroy the component before our renderer has been turned on bad things happen!
 67            //TODO: Analyze if we can catch this upstream and stop the IEnumerator
 1568            if (isDisposed)
 69            {
 070                yield break;
 71            }
 72
 1573            var model = (Model) newModel;
 74
 1575            unitySamplingMode = model.samplingMode;
 76
 1577            switch (model.wrap)
 78            {
 79                case BabylonWrapMode.CLAMP:
 1580                    unityWrap = TextureWrapMode.Clamp;
 1581                    break;
 82                case BabylonWrapMode.WRAP:
 083                    unityWrap = TextureWrapMode.Repeat;
 084                    break;
 85                case BabylonWrapMode.MIRROR:
 086                    unityWrap = TextureWrapMode.Mirror;
 87                    break;
 88            }
 89
 1590            lastVideoClipID = model.videoClipId;
 91
 1592            if (texturePlayer == null)
 93            {
 1594                DCLVideoClip dclVideoClip = scene.componentsManagerLegacy.GetSceneSharedComponent(lastVideoClipID) as DC
 95
 1596                if (dclVideoClip == null)
 97                {
 098                    logger.Error("Wrong video clip type when playing VideoTexture!!");
 099                    yield break;
 100                }
 101
 15102                Initialize(dclVideoClip);
 103            }
 104
 15105            if (texture == null)
 106            {
 415107                yield return new WaitUntil(() => texturePlayer == null || ((texturePlayer.texture != null && texturePlay
 108
 15109                if (texturePlayer.isError)
 110                {
 0111                    if (texturePlayerUpdateRoutine != null)
 112                    {
 0113                        CoroutineStarter.Stop(texturePlayerUpdateRoutine);
 0114                        texturePlayerUpdateRoutine = null;
 115                    }
 116
 0117                    yield break;
 118                }
 119
 15120                texture = texturePlayer.texture;
 15121                SetPlayStateDirty();
 122            }
 123
 15124            if (texturePlayer != null)
 125            {
 15126                if (model.seek >= 0)
 127                {
 1128                    texturePlayer.SetTime(model.seek);
 1129                    model.seek = -1;
 130
 131                    // Applying seek is not immediate
 1132                    yield return null;
 133                }
 134
 15135                if (model.playing)
 136                {
 3137                    texturePlayer.Play();
 3138                }
 139                else
 140                {
 12141                    texturePlayer.Pause();
 142                }
 143
 15144                ReportVideoProgress();
 145
 15146                if (baseVolume != model.volume)
 147                {
 15148                    baseVolume = model.volume;
 15149                    UpdateVolume();
 150                }
 151
 15152                texturePlayer.SetPlaybackRate(model.playbackRate);
 15153                texturePlayer.SetLoop(model.loop);
 154            }
 15155        }
 156
 157        private void Initialize(DCLVideoClip dclVideoClip)
 158        {
 15159            string videoId = (!string.IsNullOrEmpty(scene.sceneData.id)) ? scene.sceneData.id + id : scene.GetHashCode()
 15160            texturePlayer = new WebVideoPlayer(videoId, dclVideoClip.GetUrl(), dclVideoClip.isStream, videoPluginWrapper
 15161            texturePlayerUpdateRoutine = CoroutineStarter.Start(OnUpdate());
 15162            CommonScriptableObjects.playerCoords.OnChange += OnPlayerCoordsChanged;
 15163            CommonScriptableObjects.sceneID.OnChange += OnSceneIDChanged;
 15164            scene.OnEntityRemoved += SetPlayStateDirty;
 165
 15166            Settings.i.audioSettings.OnChanged += OnAudioSettingsChanged;
 167
 15168            OnSceneIDChanged(CommonScriptableObjects.sceneID.Get(), null);
 15169        }
 170
 0171        public float GetVolume() { return ((Model) model).volume; }
 172
 173        private IEnumerator OnUpdate()
 174        {
 480175            while (true)
 176            {
 495177                UpdateDirtyState();
 495178                UpdateVideoTexture();
 495179                UpdateProgressReport();
 495180                yield return null;
 181            }
 182        }
 183
 184        private void UpdateDirtyState()
 185        {
 495186            if (!isPlayStateDirty)
 453187                return;
 188
 42189            CalculateVideoVolumeAndPlayStatus();
 42190            isPlayStateDirty = false;
 42191        }
 192
 193        private void UpdateVideoTexture()
 194        {
 495195            if (!isPlayerInScene && currUpdateIntervalTime < OUTOFSCENE_TEX_UPDATE_INTERVAL_IN_SECONDS)
 196            {
 340197                currUpdateIntervalTime += Time.unscaledDeltaTime;
 340198            }
 155199            else if (texturePlayer != null)
 200            {
 155201                currUpdateIntervalTime = 0;
 155202                texturePlayer.Update();
 155203                texture = texturePlayer.texture;
 204            }
 155205        }
 206
 207        private void UpdateProgressReport()
 208        {
 495209            var currentState = texturePlayer.GetState();
 210
 495211            if ( currentState == VideoState.PLAYING
 212                 && IsTimeToReportVideoProgress()
 213                 || previousVideoState != currentState)
 214            {
 30215                ReportVideoProgress();
 216            }
 495217        }
 218
 219        private void ReportVideoProgress()
 220        {
 45221            lastVideoProgressReportTime = Time.unscaledTime;
 45222            VideoState videoState = texturePlayer.GetState();
 45223            previousVideoState = videoState;
 45224            var videoStatus = (int)videoState;
 45225            var currentOffset = texturePlayer.GetTime();
 45226            var length = texturePlayer.GetDuration();
 45227            WebInterface.ReportVideoProgressEvent(id, scene.sceneData.id, lastVideoClipID, videoStatus, currentOffset, l
 45228        }
 229
 230        private bool IsTimeToReportVideoProgress()
 231        {
 14232            return Time.unscaledTime - lastVideoProgressReportTime > VIDEO_PROGRESS_UPDATE_INTERVAL_IN_SECONDS;
 233        }
 234
 235        private void CalculateVideoVolumeAndPlayStatus()
 236        {
 42237            isVisible = false;
 42238            float minDistance = float.MaxValue;
 42239            distanceVolumeModifier = 0;
 240
 42241            if (attachedMaterials.Count > 0)
 242            {
 27243                using (var iterator = attachedMaterials.GetEnumerator())
 244                {
 45245                    while (iterator.MoveNext())
 246                    {
 27247                        var materialInfo = iterator.Current;
 27248                        bool isComponentVisible = DCLVideoTextureUtils.IsComponentVisible(materialInfo.Value);
 249
 27250                        if (isComponentVisible)
 251                        {
 9252                            isVisible = true;
 253
 9254                            var entityDist = DCLVideoTextureUtils.GetClosestDistanceSqr(materialInfo.Value,
 255                                CommonScriptableObjects.playerUnityPosition);
 256
 9257                            if (entityDist < minDistance)
 9258                                minDistance = entityDist;
 259
 260                            // NOTE: if current minDistance is enough for full volume then there is no need to keep iter
 9261                            if (minDistance <= DCL.Configuration.ParcelSettings.PARCEL_SIZE * DCL.Configuration.ParcelSe
 9262                                break;
 263                        }
 264                    }
 18265                }
 266            }
 267
 42268            if (isVisible)
 269            {
 270                const float maxDistanceBlockForSound = 12;
 9271                float sqrParcelDistance = DCL.Configuration.ParcelSettings.PARCEL_SIZE * DCL.Configuration.ParcelSetting
 9272                distanceVolumeModifier = 1 - Mathf.Clamp01(Mathf.FloorToInt(minDistance / sqrParcelDistance) / maxDistan
 273            }
 274
 42275            if (texturePlayer != null)
 276            {
 42277                texturePlayer.visible = isVisible;
 278            }
 279
 42280            UpdateVolume();
 42281        }
 282
 0283        private void OnVirtualAudioMixerChangedValue(float currentValue, float previousValue) { UpdateVolume(); }
 284
 285        private void UpdateVolume()
 286        {
 59287            if (texturePlayer == null)
 0288                return;
 289
 59290            float targetVolume = 0f;
 291
 59292            if (CommonScriptableObjects.rendererState.Get() && IsPlayerInSameSceneAsComponent(CommonScriptableObjects.sc
 293            {
 47294                targetVolume = baseVolume * distanceVolumeModifier;
 47295                float virtualMixerVolume = DataStore.i.virtualAudioMixer.sceneSFXVolume.Get();
 47296                float sceneSFXSetting = Settings.i.audioSettings.Data.sceneSFXVolume;
 47297                float masterSetting = Settings.i.audioSettings.Data.masterVolume;
 47298                targetVolume *= Utils.ToVolumeCurve(virtualMixerVolume * sceneSFXSetting * masterSetting);
 299            }
 300
 59301            texturePlayer.SetVolume(targetVolume);
 59302        }
 303
 304        private bool IsPlayerInSameSceneAsComponent(string currentSceneId)
 305        {
 69306            if (scene == null)
 0307                return false;
 69308            if (string.IsNullOrEmpty(currentSceneId))
 0309                return false;
 310
 69311            return (scene.sceneData.id == currentSceneId) || (scene.isPersistent);
 312        }
 313
 314        private void OnPlayerCoordsChanged(Vector2Int coords, Vector2Int prevCoords)
 315        {
 4316            SetPlayStateDirty();
 4317        }
 318
 34319        private void OnSceneIDChanged(string current, string previous) { isPlayerInScene = IsPlayerInSameSceneAsComponen
 320
 321        public override void AttachTo(ISharedComponent component)
 322        {
 10323            Assert.IsTrue(component != null, "Attachment must not be null!");
 324
 10325            if (attachedMaterials.ContainsKey(component.id))
 0326                return;
 327
 10328            AddReference(component);
 329
 10330            SetPlayStateDirty();
 10331            attachedMaterials.Add(component.id, component);
 332
 10333            component.OnAttach += SetPlayStateDirty;
 10334            component.OnDetach += SetPlayStateDirty;
 10335            DCLVideoTextureUtils.SubscribeToEntityUpdates(component, SetPlayStateDirty);
 10336        }
 337
 338        public override void DetachFrom(ISharedComponent component)
 339        {
 1340            Assert.IsTrue(component != null, "Component must not be null!");
 341
 1342            if (!attachedMaterials.ContainsKey(component.id))
 0343                return;
 344
 1345            if (texturePlayer != null)
 1346                texturePlayer.Pause();
 347
 1348            attachedMaterials.Remove(component.id);
 349
 1350            component.OnAttach -= SetPlayStateDirty;
 1351            component.OnDetach -= SetPlayStateDirty;
 1352            DCLVideoTextureUtils.UnsubscribeToEntityShapeUpdate(component, SetPlayStateDirty);
 353
 1354            RemoveReference(component);
 1355            SetPlayStateDirty();
 1356        }
 357
 358        void SetPlayStateDirty(IDCLEntity entity = null)
 359        {
 31360            isPlayStateDirty = true;
 31361        }
 362
 4363        void OnAudioSettingsChanged(AudioSettings settings) { UpdateVolume(); }
 364
 365        public override void Dispose()
 366        {
 1367            DataStore.i.virtualAudioMixer.sceneSFXVolume.OnChange -= OnVirtualAudioMixerChangedValue;
 1368            Settings.i.audioSettings.OnChanged -= OnAudioSettingsChanged;
 1369            CommonScriptableObjects.playerCoords.OnChange -= OnPlayerCoordsChanged;
 1370            CommonScriptableObjects.sceneID.OnChange -= OnSceneIDChanged;
 371
 1372            if (scene != null)
 1373                scene.OnEntityRemoved -= SetPlayStateDirty;
 374
 1375            if (texturePlayerUpdateRoutine != null)
 376            {
 1377                CoroutineStarter.Stop(texturePlayerUpdateRoutine);
 1378                texturePlayerUpdateRoutine = null;
 379            }
 380
 1381            if (texturePlayer != null)
 382            {
 1383                texturePlayer.Dispose();
 1384                texturePlayer = null;
 385            }
 386
 1387            Utils.SafeDestroy(texture);
 1388            base.Dispose();
 1389        }
 390    }
 391}