Проигрывание списка воспроизведения HLS

266
08 апреля 2019, 10:20

Я пытаюсь написать программу, которая будет играть список воспроизведения HLS. Для примера, имеется ссылка на интернет радио: https://digitacdn.akamaized.net/hls/live/629243/radiosuomipop/master-128000.m3u8. Я использую библиотеку NAudio. До сих пор я написала следующий код:

using System;
using System.Collections.Concurrent;
using System.Globalization;
using System.IO;
using System.Net;
using System.Text;
using System.Threading;
using NAudio.Wave;
using NAudioWpfDemo.ViewModel;
namespace NAudioWpfDemo.MediaFoundationPlayback
{
    internal class MediaFoundationPlaybackViewModel : ViewModelBase, IDisposable
    {
        enum ShoutCastPlaybackState
        {
            Stopped,
            Playing,
            Buffering
        }
        private const string SegmentTargetDuration = "EXT-X-TARGETDURATION";
        private const string SegmentInfo = "#EXTINF";
        private bool isBuffering;
        private string inputPath;
        public RelayCommand PlayCommand { get; }
        public RelayCommand StopCommand { get; }

        private IWavePlayer waveOut;
        private BufferedWaveProvider bufferedWaveProvider;
        private volatile ShoutCastPlaybackState playbackState;
        private readonly ConcurrentQueue<string> foundLinks = new ConcurrentQueue<string>();
        private string previousLink;
        private int segmentDuration;
        private HttpWebRequest webRequest;
        public MediaFoundationPlaybackViewModel()
        {
            PlayCommand = new RelayCommand(() =>
                {
                    playbackState = ShoutCastPlaybackState.Buffering;
                    bufferedWaveProvider = null;
                    Thread webRequestThread = new Thread(GetSegmentLinks);
                    webRequestThread.Start();
                    Thread bufferFillerThread = new Thread(FillBuffer);
                    bufferFillerThread.Start();
                    Thread playerThread = new Thread(Play);
                    playerThread.Start();
                },
                () =>
                    IsStopped
            );
            StopCommand = new RelayCommand(Stop, () => !IsStopped);
        }
        private void Play()
        {
            while (!IsStopped)
            {
                if (waveOut != null || bufferedWaveProvider == null) continue;
                waveOut = new WaveOut();
                waveOut.Init(bufferedWaveProvider);
                waveOut.Play();
                playbackState = ShoutCastPlaybackState.Playing;
                OnPropertyChanged(nameof(IsStopped));
                while (waveOut!= null && waveOut.PlaybackState == PlaybackState.Playing)
                {
                    Thread.Sleep(1000);
                }
            }
        }
        public bool IsStopped => playbackState == ShoutCastPlaybackState.Stopped;
        public bool IsBuffering
        {
            get => isBuffering;
            set
            {
                if (isBuffering == value) return;
                isBuffering = value;
                OnPropertyChanged(nameof(IsBuffering));
                OnPropertyChanged(nameof(IsStopped));
            }
        }
        public string InputPath
        {
            get => inputPath;
            set
            {
                if (inputPath != value)
                {
                    inputPath = value;
                    OnPropertyChanged("InputPath");
                }
            }
        }
        private void Stop()
        {
            if (waveOut == null) return;
            waveOut.Stop();
            waveOut.Dispose();
            waveOut = null;
            playbackState = ShoutCastPlaybackState.Stopped;
        }
        private void FillBuffer()
        {
            Uri baseUri = new Uri(InputPath);
            while (!IsStopped)
            {
                if (IsBufferNearlyFull)
                {
                    Thread.Sleep(500);
                }
                else
                {
                    foundLinks.TryPeek(out string link);
                    if (link == null) continue;
                    foundLinks.TryDequeue(out link);
                    Uri resourceUri = new Uri(baseUri, link);
                    MediaFoundationReader mediaFoundationReader;
                    try
                    {
                        mediaFoundationReader =
                            new MediaFoundationReader(resourceUri.AbsoluteUri);
                    }
                    catch(Exception e)
                    {
                        continue;
                    }
                    byte[] buffer = new byte [mediaFoundationReader.WaveFormat.AverageBytesPerSecond * segmentDuration *2];
                    int readBytes = mediaFoundationReader.Read(buffer, 0,
                        mediaFoundationReader.WaveFormat.AverageBytesPerSecond * segmentDuration * 2);
                    if (bufferedWaveProvider == null)
                    {
                        bufferedWaveProvider = new BufferedWaveProvider(mediaFoundationReader.WaveFormat)
                        {
                            BufferDuration = TimeSpan.FromSeconds(segmentDuration * 5)
                        };
                    }
                    bufferedWaveProvider.AddSamples(buffer, 0, readBytes);
                    mediaFoundationReader.Dispose();
                }
            }
        }
        private void GetSegmentLinks()
        {
            while (!IsStopped)
                try
                {
                    webRequest = (HttpWebRequest) WebRequest.Create(InputPath);
                    HttpWebResponse response = (HttpWebResponse) webRequest.GetResponse();
                    Encoding encoding = Encoding.UTF8;
                    Stream responseStream = response.GetResponseStream();
                    if (responseStream == null) continue;
                    using (StreamReader streamReader = new StreamReader(responseStream, encoding))
                    {
                        string line;
                        while ((line = streamReader.ReadLine()) != null)
                        {
                            if (line.Contains(SegmentTargetDuration))
                            {
                                segmentDuration = Convert.ToInt32(line.Split(':')[1]);
                            }
                            else if (line.Contains(SegmentInfo))
                            {
                                line = streamReader.ReadLine();
                                if (line != null && string.Compare(line, previousLink, true, CultureInfo.InvariantCulture) > 0)
                                {
                                    foundLinks.Enqueue(line);
                                    previousLink = line;
                                }
                            }
                        }
                    }
                }
                catch (Exception)
                {
                    // ignored
                }
        }
        private bool IsBufferNearlyFull => bufferedWaveProvider != null &&
                                           bufferedWaveProvider.BufferLength - bufferedWaveProvider.BufferedBytes
                                           < bufferedWaveProvider.WaveFormat.AverageBytesPerSecond * segmentDuration;
        public void Dispose()
        {
            waveOut?.Dispose();
        }
    }
}

Я понимаю, что код не идеален.

Я делаю HTTP запрос и частично обрабатываю полученный ответ. Получаемый файл выглядит приблизительно так:

#EXTM3U
#EXT-X-VERSION:3
## Created with Z/IPStream R/2 v1.03.23
#EXT-X-MEDIA-SEQUENCE:3230447
#EXT-X-TARGETDURATION:6
#EXT-X-PROGRAM-DATE-TIME:2018-11-09T12:57:20Z
#EXTINF:5.99, no desc
01616/seg128000-03230447.aac
#EXTINF:5.99, no desc
01616/seg128000-03230448.aac
#EXTINF:5.99, no desc
01616/seg128000-03230449.aac
#EXTINF:5.99, no desc
01616/seg128000-03230450.aac
#EXTINF:5.99, no desc
01616/seg128000-03230451.aac
#EXTINF:5.99, no desc
01616/seg128000-03230452.aac

Ссылки на сегменты аудиофайла добавляются в очередь. Чтобы один и тот же сегмент не добавлялся в очередь несколько раз, я сравниваю название нового сегмента с названием сегмента, добавленного в очередь последним. Если название нового сегмента следует по порядку после предыдущего, сегмент добавляется в очередь. Меня интересует, что произойдет, когда путь до сегмента станет следующим: 99999/seg128000-99999999.aac? Каким будет путь до следующего семента? 00001/seg128000-00000001.aac? Если да, то в какой-то момент пути до сегментов перестанут добавлятся в очередь, программа не будет работать. Как тогда написать код так, чтобы сегменты не проигрывались повторно? Одной возможностью является использование HashSet, но тогда в какой-то момент ссылки должны быть удалены из него, и я не могу сообразить, когда именно. Кто-нибудь может подсказать, как можно решить данную проблему?

Answer 1

получаем все пути. Тут я скачал файл и читаю из файла потом убираем повторение и сортируем по возрастанию Мы перезаписываем файл

List<string> allSegments = new List<string>();
        void ReadFile(string name)
        {
            using (var client = new WebClient())
            {
                while (true) // тут ваше условие выходи из цикла
                {
                    client.DownloadFile(name, "file.txt");
                    var rt = System.IO.File.ReadAllLines("file.txt")
                        .Where(s => s.EndsWith(".acc")); // тут какое-то ваше условие отбора строк хотя текущее должно в 100 проц прокатить
                    allSegments.AddRange(rt);
                    allSegments = allSegments
                        .OrderBy(g => g)
                        .Distinct()
                        .ToList();
                }
            }

}

А что бы получить последне добавленый

string last = allSegments.Last();
READ ALSO
Проблема с Dictionary

Проблема с Dictionary

Всем привет! При добавлении в Dictionary, некоторых данных p

175
Как автоматически подключать flash player в Chrome 71

Как автоматически подключать flash player в Chrome 71

Данный код не работает, может кто нибуть подскажет куда копать

173
Перемножение факториалов

Перемножение факториалов

Сейчас задачка попалась, не могу сообразить, как ее решить:

188