A high performance RTMP live streaming application framework
Program.cs
using Harmonic.Hosting;
using System;
using System.Net;
namespace demo
{
class Program
{
static void Main(string[] args)
{
RtmpServer server = new RtmpServerBuilder()
.UseStartup<Startup>()
.Build();
var tsk = server.StartAsync();
tsk.Wait();
}
}
}StartUp.cs
using Autofac;
using Harmonic.Hosting;
namespace demo
{
class Startup : IStartup
{
public void ConfigureServices(ContainerBuilder builder)
{
}
}
}Build a server like this to support websocket-flv transmission
RtmpServer server = new RtmpServerBuilder()
.UseStartup<Startup>()
.UseWebSocket(c =>
{
c.BindEndPoint = new IPEndPoint(IPAddress.Parse("0.0.0.0"), 8080);
})
.Build();Harmonic will scan your assembly and try to find classes that inherit from RtmpController or WebSocketController then register them into Harmonic, and map controller by url rtmp://<address>/<controller_name>/<streamName> for rtmp and ws://<address>/<controller_name>/<streamName>. the controller_name is controller class's name then remove the Controller suffix, for example Living is controller_name of LivingController. once Harmonic found any class that inherts from RtmpController or WebSocketController, it will never register RtmpController and WebSocketController.
You can also inherit builtin classes LivingController or WebSocketPlayController, when Harmonic found a class that inherit from them, it will not register LivingController and WebSocketPlayController. When you want to custom streaming logic, you can create a class that inherits from LivingController or WebSocketPlayController.
public class MyLivingController : LivingController
{
[RpcMethod("createStream")]
public new uint CreateStream()
{
var stream = RtmpSession.CreateNetStream<MyLivingStream>();
return stream.MessageStream.MessageStreamId;
}
}
public class MyLivingStream : LivingStream
{
[RpcMethod(Name = "publish")]
public void Publish([FromOptionalArgument] string publishingName, [FromOptionalArgument] string publishingType)
{
if (...)
{
}
// your logic
base.Publish(publishingName, publishingType);
}
}RtmpController and WebSocketController are two abstract basic controller, they are intended for serving video on rtmp protocol and websocket protocol. When a controller class inherit from RtmpController, it will become an rtmp controller, it will working on rtmp protocol, and supports every rtmp features. When a controller class inherit from WebSocketController, it will become a websocket controller, it can only send flv header and tags.
The RecordController can record video, by default, it will save flv files into working_dir/Record.
You can overrite the recording configuration by register you own configure class in StartUp class
class MyRecordConfiguration: RecordServiceConfiguration
{
public override string RecordPath { get; set; } = @"MyRecordPath";
public override string FilenameFormat { get; set; } = @"recorded-{streamName}";
};
class Startup : IStartup
{
public void ConfigureServices(ContainerBuilder builder)
{
builder.Register(c => new MyRecordConfiguration()).As<RecordServiceConfiguration>();
}
}websocket protocol and rtmp protocol are running on two different controllers, so when you push vide to url: rtmp://127.0.0.1/living/a, the corresponding playing url for websocket is ws://127.0.0.1/websocketplay/a
LivingController provides a simple living service, it recieves video or audio data and broadcast data to other plays.
RecordController supports video recording, and can be configured.
WebsocketPlayController supports two modes: lving mode and vod mode. when stream name in url is not in living, this controller will try to find a stream in recording folder, then play it.
NetConnection is responsible for managing all NetStreams, process some control messages, rpc support, handle connect, createStream and another command messages.
NetStream is created by NetConnection, it reperents a logic stream, all of RtmpController is NetStream.
MessageStream repersents a logic rtmp stream. Every message must be sent on a specific MessageStream.
Message will be break into chunks before sending to peer. chunks must be send on a ChunkStream, in a ChunkStream, every chunk must be sent one by one. that means you can't send a message concurrently on one ChunkStream, but message can be sent concurrently on some different ChunkStream.
RtmpSession is a bridge from NetStream to RtmpServer, controllers can access to it's own RtmpSession property to send message, or close connection or something else.
See rpc-docs
See api-docs
Harmonic uses autofac as the DI framework, you can register you own service in StartUp, and use it in your controller
class Startup : IStartup
{
public void ConfigureServices(ContainerBuilder builder)
{
builder.Register(c => new MyService()).AsSelf();
}
}
class MyController: LivingController
{
public MyController(MyService service)
{
//...
}
}To add your own custom message, you need to write a message class, then rengister the message class when you call UseHarmonic
for example:
static void Main(string[] args)
{
RtmpServer server = new RtmpServerBuilder()
.UseStartup<Startup>()
.UseWebSocket(c =>
{
c.BindEndPoint = new IPEndPoint(IPAddress.Parse("0.0.0.0"), 8080);
})
.UseHarmonic(c => {
c.RegisterMessage<MyMessage>();
})
.Build();
var tsk = server.StartAsync();
tsk.Wait();
}ffmpeg -i test.mp4 -f flv -vcodec h264 -acodec aac "rtmp://127.0.0.1/living/streamName"ffplay "rtmp://127.0.0.1/living/streamName"play flv stream using flv.js by websocket
<video id="player"></video>
<script>
if (flvjs.isSupported()) {
var player = document.getElementById('player');
var flvPlayer = flvjs.createPlayer({
type: 'flv',
url: "ws://127.0.0.1/websocketplay/streamName"
});
flvPlayer.attachMediaElement(player);
flvPlayer.load();
flvPlayer.play();
}
</script>