Я пытаюсь написать программу, которая будет играть список воспроизведения 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, но тогда в какой-то момент ссылки должны быть удалены из него, и я не могу сообразить, когда именно. Кто-нибудь может подсказать, как можно решить данную проблему?
получаем все пути. Тут я скачал файл и читаю из файла потом убираем повторение и сортируем по возрастанию Мы перезаписываем файл
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();
Виртуальный выделенный сервер (VDS) становится отличным выбором
Данный код не работает, может кто нибуть подскажет куда копать