/// <summary>
        /// Creates an HLS master manifest<para />
        ///
        /// API endpoint:
        /// https://bitmovin.com/docs/encoding/api-reference/sections/manifests#/Encoding/PostEncodingManifestsHls
        /// </summary>
        /// <param name="output">The output resource to which the manifest will be written to</param>
        /// <param name="outputPath">The path where the manifest will be written to</param>
        private Task <HlsManifest> CreateHlsMasterManifest(Output output, string outputPath)
        {
            var hlsManifest = new HlsManifest()
            {
                Name    = "master.m3u8",
                Outputs = new List <EncodingOutput>()
                {
                    BuildEncodingOutput(output, outputPath)
                }
            };

            return(_bitmovinApi.Encoding.Manifests.Hls.CreateAsync(hlsManifest));
        }
        /// <summary>
        /// Adds custom tags for ad-placement to an HLS video stream playlist at given keyframe positions<para />
        ///
        /// API endpoint:
        /// https://bitmovin.com/docs/encoding/api-reference/sections/manifests#/Encoding/PostEncodingManifestsHlsStreamsCustomTagByManifestIdAndStreamId
        /// </summary>
        /// <param name="hlsManifest">The master manifest to which the playlist belongs to</param>
        /// <param name="streamInfo">The video stream playlist to which the tags should be added</param>
        /// <param name="keyframes">A list of keyframes specifying the positions where tags will be inserted</param>
        private async Task PlaceVideoAdvertisementTags(HlsManifest hlsManifest, StreamInfo streamInfo,
                                                       List <Keyframe> keyframes)
        {
            foreach (var keyframe in keyframes)
            {
                var customTag = new CustomTag()
                {
                    KeyframeId   = keyframe.Id,
                    PositionMode = PositionMode.KEYFRAME,
                    Data         = "#AD-PLACEMENT-OPPORTUNITY"
                };

                await _bitmovinApi.Encoding.Manifests.Hls.Streams.CustomTags.CreateAsync(hlsManifest.Id, streamInfo.Id,
                                                                                         customTag);
            }
        }
        /// <summary>
        /// <para>
        /// Starts the HLS manifest creation and periodically polls its status until it reaches a final state
        /// </para>
        /// <para>API endpoints:
        /// https://bitmovin.com/docs/encoding/api-reference/sections/manifests#/Encoding/PostEncodingManifestsHlsStartByManifestId
        /// <br />
        /// https://bitmovin.com/docs/encoding/api-reference/sections/manifests#/Encoding/GetEncodingManifestsHlsStatusByManifestId
        /// </para>
        /// </summary>
        /// <param name="hlsManifest">The HLS manifest to be created</param>
        /// <exception cref="SystemException"></exception>
        private async Task ExecuteHlsManifestCreation(HlsManifest hlsManifest)
        {
            await _bitmovinApi.Encoding.Manifests.Hls.StartAsync(hlsManifest.Id);

            ServiceTaskStatus task;

            do
            {
                await Task.Delay(1000);

                task = await _bitmovinApi.Encoding.Manifests.Hls.StatusAsync(hlsManifest.Id);
            } while (task.Status != Status.FINISHED && task.Status != Status.ERROR);

            if (task.Status == Status.ERROR)
            {
                LogTaskErrors(task);
                throw new SystemException("HLS manifest creation failed");
            }

            Console.WriteLine("HLS manifest creation finished successfully");
        }
        /// <summary>
        /// Creates an HLS video playlist<para />
        ///
        /// API endpoint:
        /// https://bitmovin.com/docs/encoding/api-reference/sections/manifests#/Encoding/PostEncodingManifestsHlsStreamsByManifestId
        /// </summary>
        /// <param name="encoding">The encoding to which the manifest belongs to</param>
        /// <param name="hlsManifest">The manifest to which the playlist should be added</param>
        /// <param name="filename">The filename to be used for the playlist file</param>
        /// <param name="videoMuxing">The video muxing for which the playlist should be generated</param>
        /// <param name="segmentPath">The path containing the video segments to be referenced</param>
        /// <param name="audioMediaInfo">The audio media playlist containing the associated audio group id</param>
        private Task <StreamInfo> CreateVideoStreamPlaylist(Models.Encoding encoding, HlsManifest hlsManifest,
                                                            string filename, Fmp4Muxing videoMuxing, string segmentPath, AudioMediaInfo audioMediaInfo)
        {
            var streamInfo = new StreamInfo()
            {
                Uri         = filename,
                EncodingId  = encoding.Id,
                StreamId    = videoMuxing.Streams.ElementAt(0).StreamId,
                MuxingId    = videoMuxing.Id,
                Audio       = audioMediaInfo.GroupId,
                SegmentPath = segmentPath
            };

            return(_bitmovinApi.Encoding.Manifests.Hls.Streams.CreateAsync(hlsManifest.Id, streamInfo));
        }
        /// <summary>
        /// Creates an HLS audio media playlist<para />
        ///
        /// API endpoint:
        /// https://bitmovin.com/docs/encoding/api-reference/sections/manifests#/Encoding/PostEncodingManifestsHlsMediaAudioByManifestId
        /// </summary>
        /// <param name="encoding">The encoding to which the manifest belongs to</param>
        /// <param name="hlsManifest">The manifest to which the playlist should be added</param>
        /// <param name="audioMuxing">The audio muxing for which the playlist should be generated</param>
        /// <param name="segmentPath">The path containing the audio segments to be referenced by the playlist</param>
        private Task <AudioMediaInfo> CreateAudioMediaPlaylist(Models.Encoding encoding, HlsManifest hlsManifest,
                                                               Fmp4Muxing audioMuxing, string segmentPath)
        {
            var audioMediaInfo = new AudioMediaInfo()
            {
                Name          = "audio.m3u8",
                Uri           = "audio.m3u8",
                GroupId       = "audio",
                EncodingId    = encoding.Id,
                StreamId      = audioMuxing.Streams[0].StreamId,
                MuxingId      = audioMuxing.Id,
                Language      = "en",
                AssocLanguage = "en",
                Autoselect    = false,
                IsDefault     = false,
                Forced        = false,
                SegmentPath   = segmentPath
            };

            return(_bitmovinApi.Encoding.Manifests.Hls.Media.Audio.CreateAsync(hlsManifest.Id, audioMediaInfo));
        }