public void Stop() { Started = false; foreach (var current in connects) { StreamConnectState state = current.Value; ushort client_id = current.Key; IStreamConnect connect = state.Connect; if (connect.IsDisconnected) { continue; } try { Close(client_id); } catch (Exception e) { Console.WriteLine(e.StackTrace); } } connects.Clear(); allocated_client_id.Clear(); allocated_stream_id.Clear(); listener.Close(); }
internal void SendMetadata(string app, string path, IStreamConnect self, bool flvHeader = false) { ushort client_id; StreamConnectState state; IStreamConnect connect; var uri = new Uri("http://127.0.0.1/" + path); var key = new Tuple <string, string>(app, uri.AbsolutePath); if (!clientRoute.TryGetValue(key, out client_id)) { throw new KeyNotFoundException("Request Path Not Found"); } if (!connects.TryGetValue(client_id, out state)) { clientRoute.Remove(key); throw new KeyNotFoundException("Request Client Not Exists"); } connect = state.Connect; if (connect.IsPublishing) { var flv_metadata = (Dictionary <string, object>)connect.FlvMetaData.MethodCall.Parameters[0]; var has_audio = flv_metadata.ContainsKey("audiocodecid"); var has_video = flv_metadata.ContainsKey("videocodecid"); if (flvHeader) { var header_buffer = Enumerable.Repeat <byte>(0x00, 13).ToArray <byte>(); header_buffer[0] = 0x46; header_buffer[1] = 0x4C; header_buffer[2] = 0x56; header_buffer[3] = 0x01; byte has_audio_flag = 0x01 << 2; byte has_video_flag = 0x01; byte type_flag = 0x00; if (has_audio) { type_flag |= has_audio_flag; } if (has_video) { type_flag |= has_video_flag; } header_buffer[4] = type_flag; var data_offset = BitConverter.GetBytes((uint)9); header_buffer[5] = data_offset[3]; header_buffer[6] = data_offset[2]; header_buffer[7] = data_offset[1]; header_buffer[8] = data_offset[0]; self.SendRawData(header_buffer); } self.SendAmf0Data(connect.FlvMetaData); if (has_audio) { self.SendAmf0Data(connect.AACConfigureRecord); } if (has_video) { self.SendAmf0Data(connect.AvCConfigureRecord); } } }
public void Close(ushort client_id) { allocated_client_id.Remove(client_id); allocated_stream_id.Remove(client_id); StreamConnectState state; connects.TryGetValue(client_id, out state); IStreamConnect connect = state.Connect; prepare_to_remove.Add(client_id); if (connect.IsPublishing) { UnRegisterPublish(client_id); } if (connect.IsPlaying) { var client_channels = routedClients.FindAll((t) => (t.Item1 == client_id || t.Item2 == client_id)); routedClients.RemoveAll((t) => (t.Item1 == client_id)); foreach (var i in client_channels) { routedClients.Remove(i); } } connect.OnDisconnected(new ExceptionalEventArgs("disconnected")); }
void DisconnectSession(ushort client_id) { ClientSession clientSession; if (ClientSessions.TryGetValue(client_id, out clientSession)) { if (clientSession != null) { IStreamConnect client = clientSession.Connect; if (client.IsPublishing) { UnRegisterPublish(client_id); } if (client.IsPlaying) { var client_channels = _routedClients.FindAll((t) => (t.Item1 == client_id || t.Item2 == client_id)); _routedClients.RemoveAll((t) => (t.Item1 == client_id)); foreach (var i in client_channels) { _routedClients.Remove(i); } } client.OnDisconnected(new ExceptionalEventArgs("disconnected")); } } ClientSessions.Remove(client_id); }
internal void ConnectToClient(string app, string path, ushort self_id, ChannelType channel_type) { StreamConnectState state; ushort client_id; var uri = new Uri("http://127.0.0.1/" + path); var key = new Tuple <string, string>(app, uri.AbsolutePath); if (!clientRoute.TryGetValue(key, out client_id)) { throw new KeyNotFoundException("Request Path Not Found"); } if (!connects.TryGetValue(client_id, out state)) { IStreamConnect connect = state.Connect; clientRoute.Remove(key); throw new KeyNotFoundException("Request Client Not Exists"); } routedClients.Add(new Tuple <ushort, ushort, ChannelType>(self_id, client_id, channel_type)); }
public void Stop() { try { Started = false; ClientSessionDictionary nClientSessions = null; lock (_locker) { nClientSessions = ClientSessions.Clone() as ClientSessionDictionary; } foreach (var current in nClientSessions) { ClientSession state = current.Value; ushort client_id = current.Key; IStreamConnect connect = state.Connect; if (connect.IsDisconnected) { continue; } try { DisconnectSession(client_id); } catch (Exception e) { Console.WriteLine(e.StackTrace); } } lock (_locker) { ClientSessions.Clear(); } _listener.Close(); } catch { } }
internal bool UnRegisterPublish(ushort clientId) { var key = clientRoute.First(x => x.Value == clientId).Key; StreamConnectState state; if (clientRoute.ContainsKey(key)) { if (connects.TryGetValue(clientId, out state)) { IStreamConnect connect = state.Connect; connect.ChannelDataReceived -= sendDataHandler; var clients = routedClients.FindAll(t => t.Item2 == clientId); foreach (var i in clients) { Close(i.Item1); } routedClients.RemoveAll(t => t.Item2 == clientId); } clientRoute.Remove(key); return(true); } return(false); }
internal void ConnectToClient(string liveChannel, string path, ushort clientID, ChannelType channel_type) { ClientSession clientSession; ushort cachedClientID; var uri = new Uri("http://127.0.0.1/" + path); var key = new Tuple <string, string>(liveChannel, uri.AbsolutePath); if (!_clientRouteTable.TryGetValue(key, out cachedClientID)) { throw new KeyNotFoundException("请求地址不存在~"); } if (!ClientSessions.TryGetValue(cachedClientID, out clientSession)) { IStreamConnect connect = clientSession.Connect; _clientRouteTable.Remove(key); throw new KeyNotFoundException("请求客户端不存在~"); } _routedClients.Add(new Tuple <ushort, ushort, ChannelType>(clientID, cachedClientID, channel_type)); }
public RtmpServer( SerializationContext context, X509Certificate2 cert = null, ObjectEncoding object_encoding = ObjectEncoding.Amf0, ParameterAuthCallback publishParameterAuth = null, ParameterAuthCallback playParameterAuth = null, string bindIp = "0.0.0.0", int bindRtmpPort = 1935, int bindWebsocketPort = -1 ) { this.context = context; objectEncoding = object_encoding; if (bindWebsocketPort != -1) { var server = new WebSocketServer("ws://" + bindIp.ToString() + ":" + bindWebsocketPort.ToString()); if (cert != null) { this.cert = cert; server.Certificate = cert; server.EnabledSslProtocols = SslProtocols.Default; } server.ListenerSocket.NoDelay = true; server.Start(socket => { socket.OnOpen = () => { var path = socket.ConnectionInfo.Path.Split('/'); if (path.Length != 3) { socket.Close(); } ushort client_id = GetNewClientId(); IStreamConnect connect = new WebsocketConnect(socket, context, object_encoding); lock (connects) { connects.Add(client_id, new StreamConnectState() { Connect = connect, LastPing = DateTime.UtcNow, ReaderTask = null, WriterTask = null }); } try { SendMetadata(path[1], path[2], connect, flvHeader: true); ConnectToClient(path[1], path[2], client_id, ChannelType.Audio); ConnectToClient(path[1], path[2], client_id, ChannelType.Video); } catch { Close(client_id); } }; socket.OnPing = b => socket.SendPong(b); }); } if (publishParameterAuth != null) { this.publishParameterAuth = publishParameterAuth; } if (playParameterAuth != null) { this.playParameterAuth = playParameterAuth; } ioThread = new Thread(() => { while (true) { foreach (var current in connects) { StreamConnectState state = current.Value; ushort client_id = current.Key; IStreamConnect connect = state.Connect; if (connect.IsDisconnected) { Close(client_id); continue; } try { if (state.WriterTask == null || state.WriterTask.IsCompleted) { state.WriterTask = connect.WriteOnceAsync(); } if (state.WriterTask.IsCanceled || state.WriterTask.IsFaulted) { throw state.WriterTask.Exception; } if (state.LastPing == null || DateTime.UtcNow - state.LastPing >= new TimeSpan(0, 0, PingPeriod)) { connect.PingAsync(PingTimeout); state.LastPing = DateTime.UtcNow; } if (state.ReaderTask == null || state.ReaderTask.IsCompleted) { state.ReaderTask = connect.ReadOnceAsync(); } if (state.ReaderTask.IsCanceled || state.ReaderTask.IsFaulted) { throw state.ReaderTask.Exception; } } catch { Close(client_id); continue; } } var prepare_add_length = prepare_to_add.Count; if (prepare_add_length != 0) { for (int i = 0; i < prepare_add_length; i++) { var current = prepare_to_add[0]; connects.Add(current.Key, current.Value); prepare_to_add.RemoveAt(0); } } var prepare_remove_length = prepare_to_remove.Count; if (prepare_remove_length != 0) { for (int i = 0; i < prepare_remove_length; i++) { var current = prepare_to_remove[0]; connects.Remove(current); prepare_to_remove.RemoveAt(0); } } } }) { IsBackground = true }; ioThread.Start(); listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); listener.NoDelay = true; IPEndPoint localEndPoint = new IPEndPoint(IPAddress.Parse(bindIp), bindRtmpPort); listener.Bind(localEndPoint); listener.Listen(10); }
/// <summary> /// 启动连接状态检查线程 /// 执行rtmp的读写异步任务 /// </summary> void ClientWorkHandler() { _clientWorkThread = new Thread(() => { while (true) { try { if (ClientSessions.Count() < 1) { Thread.Sleep(1); continue; } ClientSessionDictionary nclientSessions = null; lock (_locker) { nclientSessions = ClientSessions.Clone() as ClientSessionDictionary; } Parallel.ForEach(nclientSessions, current => { ClientSession state = current.Value; ushort client_id = current.Key; IStreamConnect connect = state.Connect; try { if (connect.IsDisconnected) { DisconnectSession(client_id); } else { if (state.WriterTask == null) { state.WriterTask = connect.WriteOnceAsync(); } else { if (state.WriterTask.IsCompleted) { state.WriterTask = connect.WriteOnceAsync(); } if (state.WriterTask.IsCanceled || state.WriterTask.IsFaulted) { this.DisconnectSession(current.Key); //throw state.WriterTask.Exception; } if (state.LastPing == null || DateTime.UtcNow - state.LastPing >= new TimeSpan(0, 0, _pingPeriod)) { connect.PingAsync(_pingTimeout); state.LastPing = DateTime.UtcNow; } if (state.ReaderTask == null || state.ReaderTask.IsCompleted) { state.ReaderTask = connect.ReadOnceAsync(); } if (state.ReaderTask.IsCanceled || state.ReaderTask.IsFaulted) { this.DisconnectSession(current.Key); //throw state.ReaderTask.Exception; } } } } catch { DisconnectSession(client_id); } }); } catch (Exception ex) { FleckLog.Error("ConnectStateCheckUp.Thread.Error", ex); } } }) { IsBackground = true }; _clientWorkThread.Start(); }
/// <summary> /// 将发布者的媒体的meta发给播放者 /// </summary> /// <param name="liveChannel"></param> /// <param name="path"></param> /// <param name="self"></param> /// <param name="flvHeader"></param> internal void SendMetadataToPlayer(string liveChannel, string path, IStreamConnect self, bool flvHeader = false) { ushort publisherID; IStreamConnect publisher; ClientSession publisherState; var uri = new Uri("http://127.0.0.1/" + path); var key = new Tuple <string, string>(liveChannel, uri.AbsolutePath); if (!_clientRouteTable.TryGetValue(key, out publisherID)) { throw new KeyNotFoundException("请求地址不存在~"); } if (!ClientSessions.TryGetValue(publisherID, out publisherState)) { _clientRouteTable.Remove(key); throw new KeyNotFoundException("请求客户端不存在~"); } publisher = publisherState.Connect; if (publisher.IsPublishing) { var flv_metadata = (Dictionary <string, object>)publisher.FlvMetaData.MethodCall.Parameters[0]; var has_audio = flv_metadata.ContainsKey("audiocodecid"); var has_video = flv_metadata.ContainsKey("videocodecid"); if (flvHeader) { var header_buffer = Enumerable.Repeat <byte>(0x00, 13).ToArray <byte>(); header_buffer[0] = 0x46; header_buffer[1] = 0x4C; header_buffer[2] = 0x56; header_buffer[3] = 0x01; byte has_audio_flag = 0x01 << 2; byte has_video_flag = 0x01; byte type_flag = 0x00; if (has_audio) { type_flag |= has_audio_flag; } if (has_video) { type_flag |= has_video_flag; } header_buffer[4] = type_flag; var data_offset = BitConverter.GetBytes((uint)9); header_buffer[5] = data_offset[3]; header_buffer[6] = data_offset[2]; header_buffer[7] = data_offset[1]; header_buffer[8] = data_offset[0]; self.SendRawData(header_buffer); } self.SendAmf0Data(publisher.FlvMetaData); if (has_audio) { self.SendAmf0Data(publisher.AACConfigureRecord); } if (has_video) { self.SendAmf0Data(publisher.AvCConfigureRecord); } } }