public ConnectionConsumer(RtmpConnection connection, int videoChannel, int audioChannel, int dataChannel) { #if !SILVERLIGHT if (log.IsDebugEnabled) log.Debug(string.Format("Channel ids - video: {0} audio: {1} data: {2}", videoChannel, audioChannel, dataChannel)); #endif _connection = connection; _video = connection.GetChannel(videoChannel); _audio = connection.GetChannel(audioChannel); _data = connection.GetChannel(dataChannel); _timeStamper = new TimeStamper(); }
/// <summary> /// Creates output stream from channels. /// </summary> /// <param name="video">Video channel.</param> /// <param name="audio">Audio channel.</param> /// <param name="data">Data channel.</param> internal OutputStream(RtmpChannel video, RtmpChannel audio, RtmpChannel data) { _video = video; _audio = audio; _data = data; }
internal void OnSharedObject(RtmpConnection connection, RtmpChannel channel, RtmpHeader header, SharedObjectMessage message) { RemoteSharedObject.Dispatch(message); }
public void publish(string name, string mode) { IConnection connection = FluorineContext.Current.Connection; if (!(connection is IStreamCapableConnection)) { return; } IStreamCapableConnection streamConnection = connection as IStreamCapableConnection; IScope scope = connection.Scope; int streamId = GetCurrentStreamId(); if (name == null || string.Empty.Equals(name)) { SendNSFailed(streamConnection as RtmpConnection, "The stream name may not be empty.", name, streamId); return; } IStreamSecurityService security = ScopeUtils.GetScopeService(scope, typeof(IStreamSecurityService)) as IStreamSecurityService; if (security != null) { IEnumerator handlers = security.GetStreamPublishSecurity(); while (handlers.MoveNext()) { IStreamPublishSecurity handler = handlers.Current as IStreamPublishSecurity; if (!handler.IsPublishAllowed(scope, name, mode)) { SendNSFailed(streamConnection as RtmpConnection, "You are not allowed to publish the stream.", name, streamId); return; } } } IBroadcastScope bsScope = GetBroadcastScope(scope, name); if (bsScope != null && bsScope.GetProviders().Count > 0) { // Another stream with that name is already published. StatusASO badName = new StatusASO(StatusASO.NS_PUBLISH_BADNAME); badName.clientid = streamId; badName.details = name; badName.level = "error"; // FIXME: there should be a direct way to send the status RtmpChannel channel = (streamConnection as RtmpConnection).GetChannel((byte)(4 + ((streamId - 1) * 5))); channel.SendStatus(badName); return; } IClientStream stream = streamConnection.GetStreamById(streamId); if (stream != null && !(stream is IClientBroadcastStream)) { return; } bool created = false; if (stream == null) { stream = streamConnection.NewBroadcastStream(streamId); created = true; } IClientBroadcastStream bs = stream as IClientBroadcastStream; try { bs.PublishedName = name; IScopeContext context = connection.Scope.Context; //IProviderService providerService = (IProviderService)context.getBean(IProviderService.BEAN_NAME); IProviderService providerService = ScopeUtils.GetScopeService(connection.Scope, typeof(IProviderService)) as IProviderService; // TODO handle registration failure if (providerService.RegisterBroadcastStream(connection.Scope, name, bs)) { bsScope = GetBroadcastScope(connection.Scope, name); bsScope.SetAttribute(Constants.BroadcastScopeStreamAttribute, bs); if (connection is BaseConnection) { (connection as BaseConnection).RegisterBasicScope(bsScope); } } if (Constants.ClientStreamModeRecord.Equals(mode)) { bs.Start(); bs.SaveAs(name, false); } else if (Constants.ClientStreamModeAppend.Equals(mode)) { bs.Start(); bs.SaveAs(name, true); } else if (Constants.ClientStreamModeLive.Equals(mode)) { bs.Start(); } bs.StartPublishing(); } catch (System.IO.IOException ex) { StatusASO accessDenied = new StatusASO(StatusASO.NS_RECORD_NOACCESS); accessDenied.clientid = streamId; accessDenied.description = "The file could not be created/written to." + ex.Message; accessDenied.details = name; accessDenied.level = "error"; // FIXME: there should be a direct way to send the status RtmpChannel channel = (streamConnection as RtmpConnection).GetChannel((byte)(4 + ((streamId - 1) * 5))); channel.SendStatus(accessDenied); bs.Close(); if (created) { streamConnection.DeleteStreamById(streamId); } } catch (Exception ex) { log.Warn("Publish caught exception", ex); } }
protected override void OnPing(RtmpConnection connection, RtmpChannel channel, RtmpHeader source, Ping ping) { switch (ping.PingType) { case Ping.PingClient: case Ping.StreamBegin: case Ping.RecordedStream: case Ping.StreamPlayBufferClear: // The server wants to measure the RTT Ping pong = new Ping(); pong.PingType = Ping.PongServer; // The event data is a 4-byte timestamp, which was received with the in the Ping request pong.Value2 = ping.Value2; connection.Ping(pong); break; case Ping.StreamDry: #if !SILVERLIGHT if (Log.IsDebugEnabled) { Log.Debug("Stream indicates there is no data available"); } #endif break; case Ping.ClientBuffer: //Set the client buffer IClientStream stream = null; //Get the stream id int streamId = ping.Value2; //Get requested buffer size in milliseconds int buffer = ping.Value3; #if !SILVERLIGHT if (Log.IsDebugEnabled) { Log.Debug(string.Format("Client sent a buffer size: {0} ms for stream id: {1}", buffer, streamId)); } #endif if (streamId != 0) { // The client wants to set the buffer time stream = connection.GetStreamById(streamId); if (stream != null) { stream.SetClientBufferDuration(buffer); #if !SILVERLIGHT if (Log.IsDebugEnabled) { Log.Debug(string.Format("Setting client buffer on stream: {0}", streamId)); } #endif } } //Catch-all to make sure buffer size is set if (stream == null) { // Remember buffer time until stream is created connection.RememberStreamBufferDuration(streamId, buffer); #if !SILVERLIGHT if (Log.IsDebugEnabled) { Log.Debug(string.Format("Remembering client buffer on stream: {0}", streamId)); } #endif } break; default: #if !SILVERLIGHT if (Log.IsDebugEnabled) { Log.Debug(string.Format("Unhandled ping: {0}", ping)); } #endif break; } }
protected override void OnChunkSize(RtmpConnection connection, RtmpChannel channel, RtmpHeader source, ChunkSize chunkSize) { //ChunkSize is not implemented yet }
protected override void OnFlexInvoke(RtmpConnection connection, RtmpChannel channel, RtmpHeader header, FlexInvoke invoke) { OnInvoke(connection, channel, header, invoke); }
protected override void OnSharedObject(RtmpConnection connection, RtmpChannel channel, RtmpHeader header, SharedObjectMessage message) { _netConnection.OnSharedObject(connection, channel, header, message); }
protected override void OnInvoke(RtmpConnection connection, RtmpChannel channel, RtmpHeader header, Notify invoke) { IServiceCall call = invoke.ServiceCall; if (invoke.EventType == EventType.STREAM_DATA) { #if !SILVERLIGHT if (Log.IsDebugEnabled) { Log.Debug(string.Format("Ignoring stream data notify with header {0}", header)); } #endif return; } if (call.ServiceMethodName == "_result" || call.ServiceMethodName == "_error") { if (call.ServiceMethodName == "_error") { call.Status = Messaging.Rtmp.Service.Call.STATUS_INVOCATION_EXCEPTION; } if (call.ServiceMethodName == "_result") { call.Status = Messaging.Rtmp.Service.Call.STATUS_SUCCESS_RESULT; } //Get the panding call, if any, as HandlePendingCallResult will remove it IPendingServiceCall pendingCall = connection.GetPendingCall(invoke.InvokeId); HandlePendingCallResult(connection, invoke); if (call.IsSuccess && invoke.InvokeId == 1) { // Should keep this as an Object to stay compatible with FMS3 etc IDictionary aso = call.Arguments[0] as IDictionary; if (aso != null) { object clientId = null; if (aso.Contains("clientid")) { clientId = aso["clientid"]; } #if !SILVERLIGHT if (Log.IsDebugEnabled) { Log.Debug(string.Format("Client id: {0}", clientId)); } #endif _netConnection.SetClientId(clientId != null ? clientId.ToString() : null); } } //Notify via NetConnection if no IPendingServiceCallback was defined but the call failed if (call.ServiceMethodName == "_error") { object[] args = call.Arguments; ASObject statusAso = null; if ((args != null) && (args.Length > 0)) { statusAso = args[0] as ASObject; } bool raiseError = false; if (pendingCall != null) { IPendingServiceCallback[] callbacks = pendingCall.GetCallbacks(); if (callbacks == null || callbacks.Length == 0) { raiseError = true; } } else { raiseError = true; } if (raiseError) { if (statusAso != null) { _netConnection.RaiseNetStatus(statusAso); } else { string msg = __Res.GetString(__Res.Invocation_Failed, pendingCall != null ? pendingCall.ServiceMethodName : string.Empty, "Invocation failed"); _netConnection.RaiseNetStatus(msg); } } } return; } bool onStatus = call.ServiceMethodName.Equals("onStatus") || call.ServiceMethodName.Equals("onMetaData") || call.ServiceMethodName.Equals("onPlayStatus"); if (onStatus) { /* * IDictionary aso = call.Arguments[0] as IDictionary; * // Should keep this as an Object to stay compatible with FMS3 etc * object clientId = null; * if( aso.Contains("clientid") ) * clientId = aso["clientid"]; * if (clientId == null) * clientId = header.StreamId; #if !SILVERLIGHT * if (log.IsDebugEnabled) * log.Debug(string.Format("Client id: {0}", clientId)); #endif * if (clientId != null) * { * NetStream stream = _connection.GetStreamById((int)clientId) as NetStream; * if (stream != null) * { * stream.OnStreamEvent(invoke); * } * } */ NetStream stream = _connection.GetStreamById(header.StreamId) as NetStream; if (stream != null) { stream.OnStreamEvent(invoke); } return; } if (call is IPendingServiceCall) { IPendingServiceCall psc = call as IPendingServiceCall; /* * object result = psc.Result; * object result = psc.Result; * if (result is DeferredResult) * { * DeferredResult dr = result as DeferredResult; * dr.InvokeId = invoke.InvokeId; * dr.ServiceCall = psc; * dr.Channel = channel; * connection.RegisterDeferredResult(dr); * } * else * { * Invoke reply = new Invoke(); * reply.ServiceCall = call; * reply.InvokeId = invoke.InvokeId; * channel.Write(reply); * } */ MethodInfo mi = MethodHandler.GetMethod(_netConnection.Client.GetType(), call.ServiceMethodName, call.Arguments, false, false); if (mi != null) { ParameterInfo[] parameterInfos = mi.GetParameters(); object[] args = new object[parameterInfos.Length]; call.Arguments.CopyTo(args, 0); TypeHelper.NarrowValues(args, parameterInfos); try { InvocationHandler invocationHandler = new InvocationHandler(mi); object result = invocationHandler.Invoke(_netConnection.Client, args); if (mi.ReturnType == typeof(void)) { call.Status = Messaging.Rtmp.Service.Call.STATUS_SUCCESS_VOID; } else { call.Status = result == null ? Messaging.Rtmp.Service.Call.STATUS_SUCCESS_NULL : Messaging.Rtmp.Service.Call.STATUS_SUCCESS_RESULT; psc.Result = result; } } catch (Exception exception) { call.Exception = exception; call.Status = Messaging.Rtmp.Service.Call.STATUS_INVOCATION_EXCEPTION; //log.Error("Error while invoking method " + call.ServiceMethodName + " on client", exception); } } else // if (!onStatus) { string msg = __Res.GetString(__Res.Invocation_NoSuitableMethod, call.ServiceMethodName); call.Status = Messaging.Rtmp.Service.Call.STATUS_METHOD_NOT_FOUND; call.Exception = new FluorineException(msg); _netConnection.RaiseNetStatus(call.Exception); //log.Error(msg, call.Exception); } if (call.Status == Messaging.Rtmp.Service.Call.STATUS_SUCCESS_VOID || call.Status == Messaging.Rtmp.Service.Call.STATUS_SUCCESS_NULL) { #if !SILVERLIGHT if (Log.IsDebugEnabled) { Log.Debug("Method does not have return value, do not reply"); } #endif return; } Invoke reply = new Invoke(); reply.ServiceCall = call; reply.InvokeId = invoke.InvokeId; channel.Write(reply); } else { IPendingServiceCall pendingCall = connection.RetrievePendingCall(invoke.InvokeId); Unreferenced.Parameter(pendingCall); } }
protected override void OnClientBW(RtmpConnection connection, RtmpChannel channel, RtmpHeader source, ClientBW clientBw) { channel.Write(new ServerBW(clientBw.Bandwidth)); }
protected override void OnServerBW(RtmpConnection connection, RtmpChannel channel, RtmpHeader source, ServerBW serverBw) { }
/// <summary> /// Creates output stream from channels. /// </summary> /// <param name="video">Video channel.</param> /// <param name="audio">Audio channel.</param> /// <param name="data">Data channel.</param> internal OutputStream(RtmpChannel video, RtmpChannel audio, RtmpChannel data) { _video = video; _audio = audio; _data = data; }
protected override void OnInvoke(RtmpConnection connection, RtmpChannel channel, RtmpHeader header, Notify invoke) { IServiceCall serviceCall = invoke.ServiceCall; if ((serviceCall.ServiceMethodName == "_result") || (serviceCall.ServiceMethodName == "_error")) { if (serviceCall.ServiceMethodName == "_error") { serviceCall.Status = 0x13; } if (serviceCall.ServiceMethodName == "_result") { serviceCall.Status = 2; } base.HandlePendingCallResult(connection, invoke); } else if (serviceCall is IPendingServiceCall) { IPendingServiceCall call2 = serviceCall as IPendingServiceCall; MethodInfo methodInfo = MethodHandler.GetMethod(this._netConnection.Client.GetType(), serviceCall.ServiceMethodName, serviceCall.Arguments, false, false); if (methodInfo != null) { ParameterInfo[] parameters = methodInfo.GetParameters(); object[] array = new object[parameters.Length]; serviceCall.Arguments.CopyTo(array, 0); TypeHelper.NarrowValues(array, parameters); try { object obj2 = new InvocationHandler(methodInfo).Invoke(this._netConnection.Client, array); if (methodInfo.ReturnType == typeof(void)) { serviceCall.Status = 4; } else { serviceCall.Status = (obj2 == null) ? ((byte)3) : ((byte)2); call2.Result = obj2; } } catch (Exception exception) { serviceCall.Exception = exception; serviceCall.Status = 0x13; } } else { string message = __Res.GetString("Invocation_NoSuitableMethod", new object[] { serviceCall.ServiceMethodName }); serviceCall.Status = 0x11; serviceCall.Exception = new FluorineException(message); } if ((serviceCall.Status == 4) || (serviceCall.Status == 3)) { if (log.get_IsDebugEnabled()) { log.Debug("Method does not have return value, do not reply"); } } else { FluorineFx.Messaging.Rtmp.Event.Invoke invoke2 = new FluorineFx.Messaging.Rtmp.Event.Invoke { ServiceCall = serviceCall, InvokeId = invoke.InvokeId }; channel.Write(invoke2); } } }
protected override void OnChunkSize(RtmpConnection connection, RtmpChannel channel, RtmpHeader source, ChunkSize chunkSize) { }
/// <summary> /// Send update notification over data channel of RTMP connection /// </summary> private void SendUpdates() { int currentVersion = _version.Value; bool persist = this.IsPersistentObject; //Get read-only version of events ConcurrentLinkedQueue <ISharedObjectEvent> events = new ConcurrentLinkedQueue <ISharedObjectEvent>(_ownerMessage.Events); //clear out previous events _ownerMessage.Events.Clear(); if (events.Count != 0) { //Send update to "owner" of this update request if (_source != null) { RtmpConnection connection = _source as RtmpConnection; // Only send updates when issued through RTMP request RtmpChannel channel = connection.GetChannel((byte)3); // Send update to "owner" of this update request SharedObjectMessage syncOwner; if (connection.ObjectEncoding == ObjectEncoding.AMF0) { syncOwner = new SharedObjectMessage(null, _name, currentVersion, persist); } else { syncOwner = new FlexSharedObjectMessage(null, _name, currentVersion, persist); } syncOwner.AddEvents(events); if (channel != null) { channel.Write(syncOwner); } else { log.Warn(__Res.GetString(__Res.Channel_NotFound)); } } } //Clear owner events events.Clear(); //Get read-only version of sync events events.AddRange(_syncEvents); //Clear out previous events _syncEvents.Clear(); if (events.Count != 0) { // Synchronize updates with all registered clients of this shared foreach (IEventListener listener in _listeners) { if (listener == _source) { // Don't re-send update to active client continue; } if (!(listener is RtmpConnection)) { log.Warn(__Res.GetString(__Res.SharedObject_SyncConnError)); continue; } // Create a new sync message for every client to avoid // concurrent access through multiple threads // TODO: perhaps we could cache the generated message RtmpConnection connection = listener as RtmpConnection; SharedObjectMessage syncMessage; if (connection.ObjectEncoding == ObjectEncoding.AMF0) { syncMessage = new SharedObjectMessage(null, _name, currentVersion, persist); } else { syncMessage = new FlexSharedObjectMessage(null, _name, currentVersion, persist); } syncMessage.AddEvents(events); RtmpChannel channel = connection.GetChannel((byte)3); log.Debug(__Res.GetString(__Res.SharedObject_Sync, channel)); channel.Write(syncMessage); } } }