BililiveRecorder/BililiveRecorder.Core/RecordedRoom.cs

183 lines
5.4 KiB
C#
Raw Normal View History

2018-03-12 18:57:20 +08:00
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
2018-03-13 13:21:01 +08:00
using System.Diagnostics;
2018-03-18 18:55:28 +08:00
using System.IO;
2018-03-13 13:21:01 +08:00
using System.Linq;
2018-03-13 14:23:53 +08:00
using System.Net;
2018-03-12 18:57:20 +08:00
using System.Text;
using BililiveRecorder.FlvProcessor;
namespace BililiveRecorder.Core
{
public class RecordedRoom : INotifyPropertyChanged
{
2018-03-15 21:55:01 +08:00
public int roomID { get; private set; }
public RoomInfo roomInfo { get; private set; }
public RecordStatus Status;
2018-03-12 18:57:20 +08:00
2018-03-13 14:23:53 +08:00
public StreamMonitor streamMonitor;
2018-03-12 18:57:20 +08:00
public FlvStreamProcessor Processor; // FlvProcessor
2018-03-13 13:21:01 +08:00
public readonly ObservableCollection<FlvClipProcessor> Clips = new ObservableCollection<FlvClipProcessor>();
2018-03-13 14:23:53 +08:00
private HttpWebRequest webRequest;
2018-03-13 13:21:01 +08:00
public RecordedRoom()
{
Processor.BlockProcessed += Processor_BlockProcessed;
2018-03-13 14:23:53 +08:00
streamMonitor.StreamStatusChanged += StreamMonitor_StreamStatusChanged;
2018-03-15 21:55:01 +08:00
UpdateRoomInfo();
2018-03-13 14:23:53 +08:00
}
private void StreamMonitor_StreamStatusChanged(object sender, StreamStatusChangedArgs e)
{
if (e.status.isStreaming)
{
// TODO: 失败重试逻辑 & 掉线重连逻辑
_StartRecord();
}
}
2018-03-15 21:55:01 +08:00
public void StartRecord()
2018-03-13 14:23:53 +08:00
{
throw new NotImplementedException();
2018-03-13 13:21:01 +08:00
}
2018-03-15 21:55:01 +08:00
private void _StartRecord()
{
// throw new NotImplementedException();
if (webRequest != null)
{
//TODO: cleanup
webRequest = null;
}
if (Processor != null)
{
//TODO: cleanup
Processor = null;
}
string flv_path = BililiveAPI.GetPlayUrl(roomInfo.RealRoomid);
webRequest = WebRequest.CreateHttp(flv_path);
_SetupFlvRequest(webRequest);
HttpWebResponse response = webRequest.GetResponse() as HttpWebResponse;
if (response.StatusCode != HttpStatusCode.OK)
{
//TODO: Log
response.Close();
webRequest = null;
return;
}
2018-03-18 18:55:28 +08:00
Stream flvStream = response.GetResponseStream();
const int BUF_SIZE = 1024 * 8;// 8 KiB
byte[] buffer = new byte[BUF_SIZE];
2018-03-15 21:55:01 +08:00
2018-03-18 18:55:28 +08:00
AsyncCallback callback = null;
callback = ar =>
{
try
{
int bytesRead = flvStream.EndRead(ar);
if (bytesRead == 0)
{
// TODO: connection closed
}
else
{
if (bytesRead != buffer.Length)
{
Processor.AddBytes(buffer.Take(bytesRead).ToArray());
}
else
{
Processor.AddBytes(buffer);
}
Console.Write('#');
flvStream.BeginRead(buffer, 0, BUF_SIZE, callback, null);
}
}
catch (Exception e)
{
throw; //TODO
}
};
flvStream.BeginRead(buffer, 0, BUF_SIZE, callback, null);
2018-03-15 21:55:01 +08:00
}
private static void _SetupFlvRequest(HttpWebRequest r)
{
r.Accept = "*/*";
r.AllowAutoRedirect = true;
r.Connection = "keep-alive";
r.Referer = "https://live.bilibili.com";
r.Headers["Origin"] = "https://live.bilibili.com";
r.UserAgent = "Mozilla/5.0 BililiveRecorder/0.0.0.0 (+https://github.com/Bililive/BililiveRecorder;bliverec@genteure.com)";
}
void StartWebRequest()
{
webRequest.BeginGetResponse(new AsyncCallback(FinishWebRequest), webRequest);
}
void FinishWebRequest(IAsyncResult result)
{
HttpWebResponse response = (result.AsyncState as HttpWebRequest).EndGetResponse(result) as HttpWebResponse;
}
public bool UpdateRoomInfo()
{
try
{
roomInfo = BililiveAPI.GetRoomInfo(roomID);
return true;
}
catch (Exception ex)
{
Debug.WriteLine(ex.ToString());
return false;
}
}
2018-03-13 13:21:01 +08:00
// Called by API or GUI
public void Clip()
{
var clip = Processor.Clip();
// TODO: 多个线程同时运行,这个位置有可能会导致 Clip 丢数据
// 考虑在此处加锁, Clip 操作时停止向主 Processor 添加数据
clip.ClipFinalized += CallBack_ClipFinalized;
Clips.Add(clip);
}
private void CallBack_ClipFinalized(object sender, ClipFinalizedArgs e)
{
if (Clips.Remove(e.ClipProcessor))
{
Debug.WriteLine("Clip Finalized");
}
else
{
Debug.WriteLine("Warning! Clip Finalized but was not in Collection.");
}
}
private void Processor_BlockProcessed(object sender, BlockProcessedArgs e)
{
Clips.ToList().ForEach((fcp) => fcp.AddBlock(e.DataBlock));
}
2018-03-12 18:57:20 +08:00
public event PropertyChangedEventHandler PropertyChanged;
}
}