public void DestroyChannelBucket(ChannelBucket type, ulong channelId) { //Assume this object is locked RequestQueueBucket bucket; _channelBuckets[(int)type].TryRemove(channelId, out bucket); }
/// <summary> /// Picks a random asset from the content exchanger-generated Playlist /// </summary> /// <param name="playlist">The content exchanger-generated Playlist</param> /// <param name="assetScheduler">Asset Scheduler object that determines which assets are temporally capable of being played</param> /// <returns>The information on the content playlist asset, null if no available asset found</returns> private ChannelAssetAssociation PickRandomContentPlaylistAsset() { // this counts the number of buckets we have already tried and have not found any content in. int noConsumedChannelBuckets = _consumedChannelBuckets.Count; _logger.WriteMessage("Attempted Channel Buckets: " + noConsumedChannelBuckets); // if user has not subscribed to any channels or if all channel buckets have been searched, return null // clear consumed buckets to search again on the next run if (_noChannelBuckets == 0 || _noChannelBuckets == noConsumedChannelBuckets) { _consumedChannelBuckets.Clear(); _consumedContentPlaylistAssets.Clear(); if (_noChannelBuckets > 0) { _logger.WriteMessage("All channel buckets searched. No content asset can be played at this time."); } else { _logger.WriteMessage("No channel buckets in playlist. No content asset can be played at this time."); } return(null); } ChannelBucket cb = GetRandomChannelBucket(_playlist); _logger.WriteMessage("channel bucket selected successfully"); ChannelAssetAssociation caa = GetRandomContentPlaylistAsset(cb); if (caa == null) { _consumedChannelBuckets.Add(cb); _logger.WriteMessage("no content in this channel was selected. Channel bucket will not be attempted again in this run. Attempting another channel bucket."); caa = PickRandomContentPlaylistAsset(); } else { _logger.WriteMessage("content asset selected: " + caa.PlaylistAsset.AssetID + " in channel: " + caa.ChannelID); } // at this point the algorithm has succeeded or has processed all buckets and assets and found no content available // clear consumed _consumedChannelBuckets.Clear(); _consumedContentPlaylistAssets.Clear(); // next pick will include content web assets if due to network/website unavailability those were excluded _bIncludeContentWebAssets = true; return(caa); // if this is null, there is no content asset available for playing }
public static void NormalizeChannelBucketPlayingProbabilities(HashSet <ChannelBucket> channelBuckets, Logger logger) { float sumPlayingProbabilities = 0F; float normalisedPlayingProbability = -1F; float previousLowerThresholdNormalised = 0F; foreach (ChannelBucket cb in channelBuckets) { sumPlayingProbabilities += cb.PlayingProbabilityUnnormalized; } // normalize playing probabilities if there is at least a playing probability greater than 0. if (sumPlayingProbabilities <= 0) { return; } int noChannelBuckets = channelBuckets.Count; for (int i = 0; i < noChannelBuckets; i++) { ChannelBucket cb = channelBuckets.ElementAt(i); normalisedPlayingProbability = cb.PlayingProbabilityUnnormalized / sumPlayingProbabilities; cb.PlayingProbabilityNormalised = normalisedPlayingProbability; // calculate lower and upper threshold for random play cb.LowerThresholdNormalised = previousLowerThresholdNormalised; // make last content asset's higher normalized threshold equal to 1, else add the newly calculated normalized weighting. if (i < noChannelBuckets - 1) { cb.HigherThresholdNormalised = previousLowerThresholdNormalised + normalisedPlayingProbability; } else { cb.HigherThresholdNormalised = 1; } // increment lower threshold for next loop run previousLowerThresholdNormalised += normalisedPlayingProbability; } }
// filter non consumed content assets private IEnumerable <ContentPlaylistAsset> GetPlayableContentPlaylistAssetsExcludingConsumed(ChannelBucket cb) { _logger.WriteMessage("shortlisting non attempted content assets that can be displayed and selecting one randomly."); // filter by whether content assets are consumed var channelBucketContentNonConsumedPlayable = from ContentPlaylistAsset contentPlaylistAsset in cb.ContentAssets where !_consumedContentPlaylistAssets.Contains(contentPlaylistAsset) select contentPlaylistAsset; _logger.WriteMessage("successfully selected the non attempted content."); // further filter by date bounds var channelBucketContentDateNonConsumedPlayable = from ContentPlaylistAsset contentPlaylistAsset in channelBucketContentNonConsumedPlayable where contentPlaylistAsset.StartDateTime <= DateTime.Now && contentPlaylistAsset.EndDateTime >= DateTime.Now select contentPlaylistAsset; _logger.WriteMessage("successfully selected the non attempted content whose start and end date/time surround today/now."); // further filter assets that passed date bound filtering by content assets with no scheduling information var channelBucketContentDateNonConsumedNoScheduleInfoPlayable = from ContentPlaylistAsset contentPlaylistAsset in channelBucketContentDateNonConsumedPlayable where contentPlaylistAsset.ScheduleInfo.Length == 0 select contentPlaylistAsset; _logger.WriteMessage("successfully selected the non attempted content with no scheduling info."); // further filter assets that passed date bound filtering by content assets with scheduling information that permits them to be played at this time var channelBucketContentDateNonConsumedWithScheduleInfoPlayable = from ContentPlaylistAsset contentPlaylistAsset in channelBucketContentDateNonConsumedPlayable where _assetScheduler.IsAssetPlayable(contentPlaylistAsset.ScheduleInfo) select contentPlaylistAsset; _logger.WriteMessage("successfully selected the non attempted content with permitted scheduling info."); // union of assets passed scheduling information and assets with no scheduling information var playableContentAssets = channelBucketContentDateNonConsumedNoScheduleInfoPlayable.Union(channelBucketContentDateNonConsumedWithScheduleInfoPlayable); _logger.WriteMessage("successfully combined playable content with permitted scheduling info and without scheduling info."); // of those assets found, which ones are available and can be played due to memory restrictions if any var playableContentAssetsExisting = from ContentPlaylistAsset contentPlaylistAsset in playableContentAssets where ((contentPlaylistAsset.PlayerType == PlayerType.WebSite && AssetWebsiteExists(contentPlaylistAsset.AssetWebSite)) || contentPlaylistAsset.PlayerType != PlayerType.WebSite && AssetFileExists(contentPlaylistAsset.GetAssetFilenameGUIDSuffix(), contentPlaylistAsset.AssetFilename) && (!_bInsufficientMemoryForLargeFiles || IsNonLargeFile(contentPlaylistAsset))) select contentPlaylistAsset; _logger.WriteMessage("successfully selected content that is available locally or online."); return(playableContentAssetsExisting); }
// picks a random content asset from channel bucket private ChannelAssetAssociation GetRandomContentPlaylistAsset(ChannelBucket cb) { // Randomly pick asset from full bucket list // check whether selected asset can be played according to temporal scheduling // if not pick again. This will be repeated 20 times. for (int i = 0; i < 20; i++) { ContentPlaylistAsset contentPlaylistAsset = GetRandomElement(cb.ContentAssets); if (contentPlaylistAsset == null) { _logger.WriteMessage("no asset found in this channel bucket."); return(null); } _logger.WriteMessage("content asset: " + contentPlaylistAsset.AssetID + " selected randomly. Determining if it can be played at this time."); if (_consumedContentPlaylistAssets.Contains(contentPlaylistAsset)) { continue; } _logger.WriteMessage("content asset has not been attempted on this run."); if (!((contentPlaylistAsset.StartDateTime <= DateTime.Now && contentPlaylistAsset.EndDateTime >= DateTime.Now && (contentPlaylistAsset.PlayerType != PlayerType.WebSite || _bIncludeContentWebAssets && contentPlaylistAsset.PlayerType == PlayerType.WebSite))) || (!_assetScheduler.IsAssetPlayable(contentPlaylistAsset.ScheduleInfo))) { _consumedContentPlaylistAssets.Add(contentPlaylistAsset); continue; } _logger.WriteMessage("content asset has no schedule info. Checking if it is available."); if (contentPlaylistAsset.PlayerType == PlayerType.WebSite) { _logger.WriteMessage("content asset is a website. Checking if it is available online."); if (AssetWebsiteExists(contentPlaylistAsset.AssetWebSite)) { _logger.WriteMessage("content asset " + contentPlaylistAsset.AssetWebSite + " is available online and will be selected."); return(new ChannelAssetAssociation(cb.ChannelID, contentPlaylistAsset)); } _logger.WriteMessage("content asset " + contentPlaylistAsset.AssetWebSite + " is not available online. Disabling selection of web content for this run."); _bIncludeContentWebAssets = false; } else { _logger.WriteMessage("content asset is a non-website. Checking if it is available on disk."); if (AssetFileExists(contentPlaylistAsset.GetAssetFilenameGUIDSuffix(), contentPlaylistAsset.AssetFilename)) { _logger.WriteMessage("content asset " + contentPlaylistAsset.AssetFilename + " exists on disk."); if (!_bInsufficientMemoryForLargeFiles || IsNonLargeFile(contentPlaylistAsset)) { _logger.WriteTimestampedMessage("Content asset " + contentPlaylistAsset.AssetFilename + " can be played."); return(new ChannelAssetAssociation(cb.ChannelID, contentPlaylistAsset)); } _logger.WriteTimestampedMessage( "There are physical memory restrictions and content asset " + contentPlaylistAsset.AssetFilename + " cannot be played"); } else { _logger.WriteMessage("content asset " + contentPlaylistAsset.AssetFilename + " does not exist on disk."); } } _consumedContentPlaylistAssets.Add(contentPlaylistAsset); } // if nothing found go through Channel Bucket's entire list (excluding the consumed ones), // checking what CAN be displayed and create a shortlist // then randomly pick one from the shortlist. ContentPlaylistAsset cpa = GetRandomElement(GetPlayableContentPlaylistAssetsExcludingConsumed(cb)); if (cpa == null) { return(null); } return(new ChannelAssetAssociation(cb.ChannelID, cpa)); }
public static Bucket GetBucketInfo(ChannelBucket bucket) => _channelLimits[bucket];
private RequestQueueBucket GetChannelBucket(ChannelBucket type, ulong channelId) { return(_channelBuckets[(int)type].GetOrAdd(channelId, _ => CreateBucket(_channelLimits[type]))); }