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(); }
public override void ConnectionOpened(RtmpConnection connection) { try { // Send "connect" call to the server RtmpChannel channel = connection.GetChannel(3); PendingCall pendingCall = new PendingCall("connect", _connectArguments); Invoke invoke = new Invoke(pendingCall); invoke.ConnectionParameters = _connectionParameters; invoke.InvokeId = connection.InvokeId; pendingCall.RegisterCallback(this); connection.RegisterPendingCall(invoke.InvokeId, pendingCall); channel.Write(invoke); } catch (Exception ex) { _netConnection.RaiseNetStatus(ex); } }
public override void ConnectionOpened(RtmpConnection connection) { try { RtmpChannel channel = connection.GetChannel(3); PendingCall serviceCall = new PendingCall("connect", this._connectArguments); FluorineFx.Messaging.Rtmp.Event.Invoke message = new FluorineFx.Messaging.Rtmp.Event.Invoke(serviceCall) { ConnectionParameters = this._connectionParameters, InvokeId = connection.InvokeId }; serviceCall.RegisterCallback(this); connection.RegisterPendingCall(message.InvokeId, serviceCall); channel.Write(message); } catch (Exception exception) { this._netConnection.RaiseNetStatus(exception); } }
/// <summary> /// Send update notification over data channel of RTMP connection /// </summary> private void SendUpdates() { if (_ownerMessage.Events.Count != 0) { if (_connection.NetConnectionClient.Connection != null) { RtmpConnection connection = _connection.NetConnectionClient.Connection 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, _version, this.IsPersistentObject); } else { syncOwner = new FlexSharedObjectMessage(null, _name, _version, this.IsPersistentObject); } syncOwner.AddEvents(_ownerMessage.Events); if (channel != null) { channel.Write(syncOwner); } else { #if !SILVERLIGHT log.Warn(__Res.GetString(__Res.Channel_NotFound)); #endif } } _ownerMessage.Events.Clear(); } }
protected override void OnFlexInvoke(RtmpConnection connection, RtmpChannel channel, RtmpHeader header, FlexInvoke invoke) { OnInvoke(connection, channel, header, invoke); }
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 OnServerBW(RtmpConnection connection, RtmpChannel channel, RtmpHeader source, ServerBW serverBw) { }
protected override void OnChunkSize(RtmpConnection connection, RtmpChannel channel, RtmpHeader source, ChunkSize chunkSize) { //ChunkSize is not implemented yet }
/// <summary> /// This method supports the infrastructure and is not intended to be used directly from your code. /// </summary> /// <param name="connection"></param> /// <param name="channel"></param> /// <param name="source"></param> /// <param name="clientBW"></param> protected abstract void OnClientBW(RtmpConnection connection, RtmpChannel channel, RtmpHeader source, ClientBW clientBW);
/// <summary> /// This method supports the infrastructure and is not intended to be used directly from your code. /// </summary> /// <param name="connection"></param> /// <param name="channel"></param> /// <param name="header"></param> /// <param name="invoke"></param> protected abstract void OnFlexInvoke(RtmpConnection connection, RtmpChannel channel, RtmpHeader header, FlexInvoke invoke);
/// <summary> /// This method supports the infrastructure and is not intended to be used directly from your code. /// </summary> /// <param name="connection"></param> /// <param name="channel"></param> /// <param name="header"></param> /// <param name="invoke"></param> protected abstract void OnInvoke(RtmpConnection connection, RtmpChannel channel, RtmpHeader header, Notify invoke);
public static RtmptRequest DecodeBuffer(RtmpConnection connection, ByteBuffer stream) { RtmpContext context = connection.Context; int position = (int)stream.Position; try { BufferStreamReader sr = new BufferStreamReader(stream); string request = sr.ReadLine(); string[] tokens = request.Split(new char[] { ' ' }); string method = tokens[0]; string url = tokens[1]; // Decode all encoded parts of the URL using the built in URI processing class int i = 0; while ((i = url.IndexOf("%", i)) != -1) { url = url.Substring(0, i) + Uri.HexUnescape(url, ref i) + url.Substring(i); } // Lets just make sure we are using HTTP, thats about all I care about string protocol = tokens[2]; // "HTTP/" //Read headers Hashtable headers = new Hashtable(); string line; string name = null; while ((line = sr.ReadLine()) != null && line != string.Empty) { // If the value begins with a space or a hard tab then this // is an extension of the value of the previous header and // should be appended if (name != null && Char.IsWhiteSpace(line[0])) { headers[name] += line; continue; } // Headers consist of [NAME]: [VALUE] + possible extension lines int firstColon = line.IndexOf(":"); if (firstColon != -1) { name = line.Substring(0, firstColon); string value = line.Substring(firstColon + 1).Trim(); headers[name] = value; } else { //400, "Bad header: " + line break; } } RtmptRequest rtmptRequest = new RtmptRequest(connection, url, protocol, method, headers); if (stream.Remaining == rtmptRequest.ContentLength) { stream.Compact(); rtmptRequest.Data = ByteBuffer.Wrap(stream.ToArray()); stream.Flip(); return(rtmptRequest); } else { // Move the position back to the start stream.Position = position; } } catch { // Move the position back to the start stream.Position = position; throw; } return(null); }
private void SendNSFailed(RtmpConnection connection, string description, string name, int streamId) { StatusASO failed = new StatusASO(StatusASO.NS_FAILED); failed.clientid = streamId; failed.description = description; failed.details = name; failed.level = "error"; // FIXME: there should be a direct way to send the status RtmpChannel channel = connection.GetChannel((byte)(4 + ((streamId - 1) * 5))); channel.SendStatus(failed); }
internal void OnSharedObject(RtmpConnection connection, RtmpChannel channel, RtmpHeader header, SharedObjectMessage message) { RemoteSharedObject.Dispatch(message); }
public override void ConnectionClosed(RtmpConnection connection) { base.ConnectionClosed(connection); this._netConnection.RaiseDisconnect(); }
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); } } }
/// <summary> /// This method supports the infrastructure and is not intended to be used directly from your code. /// </summary> /// <param name="connection"></param> /// <param name="channel"></param> /// <param name="source"></param> /// <param name="ping"></param> protected abstract void OnPing(RtmpConnection connection, RtmpChannel channel, RtmpHeader source, Ping ping);
/// <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); } } }
/// <summary> /// This method supports the infrastructure and is not intended to be used directly from your code. /// </summary> /// <param name="connection"></param> /// <param name="channel"></param> /// <param name="header"></param> /// <param name="message"></param> protected abstract void OnSharedObject(RtmpConnection connection, RtmpChannel channel, RtmpHeader header, SharedObjectMessage message);
protected override void OnClientBW(RtmpConnection connection, RtmpChannel channel, RtmpHeader source, ClientBW clientBW) { }
/// <summary> /// This method supports the infrastructure and is not intended to be used directly from your code. /// </summary> /// <param name="connection"></param> /// <param name="channel"></param> /// <param name="source"></param> /// <param name="serverBW"></param> protected abstract void OnServerBW(RtmpConnection connection, RtmpChannel channel, RtmpHeader source, ServerBW serverBW);
protected override void OnInvoke(RtmpConnection connection, RtmpChannel channel, RtmpHeader header, Notify invoke) { IServiceCall serviceCall = invoke.ServiceCall; // If it's a callback for server remote call then pass it over to callbacks handler // and return if (serviceCall.ServiceMethodName.Equals("_result") || serviceCall.ServiceMethodName.Equals("_error")) { HandlePendingCallResult(connection, invoke); return; } bool disconnectOnReturn = false; string action = null; if (serviceCall.ServiceName == null) { action = serviceCall.ServiceMethodName; switch (action) { case ACTION_CONNECT: { if (!connection.IsConnected) { IDictionary parameters = invoke.ConnectionParameters; string host = null; if (parameters.Contains("tcUrl")) { host = GetHostname(parameters["tcUrl"] as string); } if (host != null && host.IndexOf(":") != -1) { // Remove default port from connection string host = host.Substring(0, host.IndexOf(":")); } string app = parameters["app"] as string; string path = parameters["app"] as string; // App name as path, but without query string if there is one if (path != null && path.IndexOf("?") != -1) { int idx = path.IndexOf("?"); parameters["queryString"] = path.Substring(idx); path = path.Substring(0, idx); } parameters["path"] = path; connection.Setup(host, path, parameters); try { //IGlobalScope global = this.Endpoint.LookupGlobal(host, path); IGlobalScope global = this.Endpoint.GetMessageBroker().GlobalScope; if (global == null) { serviceCall.Status = Call.STATUS_SERVICE_NOT_FOUND; if (serviceCall is IPendingServiceCall) { StatusASO status = StatusASO.GetStatusObject(StatusASO.NC_CONNECT_INVALID_APPLICATION, connection.ObjectEncoding); status.description = "No global scope on this server."; (serviceCall as IPendingServiceCall).Result = status; } log.Info(string.Format("No application scope found for {0} on host {1}. Misspelled or missing application folder?", path, host)); disconnectOnReturn = true; } else { IScopeContext context = global.Context; IScope scope = null; try { scope = context.ResolveScope(global, path); } catch (ScopeNotFoundException /*exception*/) { if (log.IsErrorEnabled) { log.Error(__Res.GetString(__Res.Scope_NotFound, path)); } serviceCall.Status = Call.STATUS_SERVICE_NOT_FOUND; if (serviceCall is IPendingServiceCall) { StatusASO status = StatusASO.GetStatusObject(StatusASO.NC_CONNECT_REJECTED, connection.ObjectEncoding); status.description = "No scope \"" + path + "\" on this server."; (serviceCall as IPendingServiceCall).Result = status; } disconnectOnReturn = true; } catch (ScopeShuttingDownException) { serviceCall.Status = Call.STATUS_APP_SHUTTING_DOWN; if (serviceCall is IPendingServiceCall) { StatusASO status = StatusASO.GetStatusObject(StatusASO.NC_CONNECT_APPSHUTDOWN, connection.ObjectEncoding); status.description = "Application at \"" + path + "\" is currently shutting down."; (serviceCall as IPendingServiceCall).Result = status; } log.Info(string.Format("Application at {0} currently shutting down on {1}", path, host)); disconnectOnReturn = true; } if (scope != null) { if (log.IsInfoEnabled) { log.Info(__Res.GetString(__Res.Scope_Connect, scope.Name)); } bool okayToConnect; try { //The only way to differentiate NetConnection.connect() and Consumer.subscribe() seems to be the app name if (app == string.Empty) { connection.SetIsFlexClient(true); okayToConnect = connection.Connect(scope, serviceCall.Arguments); if (okayToConnect) { if (serviceCall.Arguments != null && serviceCall.Arguments.Length >= 3) { string credentials = serviceCall.Arguments[2] as string; if (credentials != null && credentials != string.Empty) { MessageBroker messageBroker = this.Endpoint.GetMessageBroker(); AuthenticationService authenticationService = messageBroker.GetService(AuthenticationService.ServiceId) as AuthenticationService; authenticationService.Authenticate(credentials); } } //FDS 2.0.1 fds.swc if (serviceCall.Arguments != null && serviceCall.Arguments.Length == 1) { string credentials = serviceCall.Arguments[0] as string; if (credentials != null && credentials != string.Empty) { MessageBroker messageBroker = this.Endpoint.GetMessageBroker(); AuthenticationService authenticationService = messageBroker.GetService(AuthenticationService.ServiceId) as AuthenticationService; authenticationService.Authenticate(credentials); } } } } else { connection.SetIsFlexClient(false); okayToConnect = connection.Connect(scope, serviceCall.Arguments); } if (okayToConnect) { if (log.IsDebugEnabled) { log.Debug("Connected RtmpClient: " + connection.Client.Id); } serviceCall.Status = Call.STATUS_SUCCESS_RESULT; if (serviceCall is IPendingServiceCall) { StatusASO statusASO = StatusASO.GetStatusObject(StatusASO.NC_CONNECT_SUCCESS, connection.ObjectEncoding); statusASO.Add("id", connection.Client.Id); (serviceCall as IPendingServiceCall).Result = statusASO; } // Measure initial roundtrip time after connecting connection.GetChannel((byte)2).Write(new Ping(Ping.StreamBegin, 0, -1)); connection.StartRoundTripMeasurement(); } else { if (log.IsDebugEnabled) { log.Debug("Connect failed"); } serviceCall.Status = Call.STATUS_ACCESS_DENIED; if (serviceCall is IPendingServiceCall) { (serviceCall as IPendingServiceCall).Result = StatusASO.GetStatusObject(StatusASO.NC_CONNECT_REJECTED, connection.ObjectEncoding); } disconnectOnReturn = true; } } catch (ClientRejectedException rejected) { if (log.IsDebugEnabled) { log.Debug("Connect rejected"); } serviceCall.Status = Call.STATUS_ACCESS_DENIED; if (serviceCall is IPendingServiceCall) { StatusASO statusASO = StatusASO.GetStatusObject(StatusASO.NC_CONNECT_REJECTED, connection.ObjectEncoding); statusASO.Application = rejected.Reason; (serviceCall as IPendingServiceCall).Result = statusASO; } disconnectOnReturn = true; } } } } catch (Exception ex) { if (log.IsErrorEnabled) { log.Error("Error connecting", ex); } serviceCall.Status = Call.STATUS_GENERAL_EXCEPTION; if (serviceCall is IPendingServiceCall) { (serviceCall as IPendingServiceCall).Result = StatusASO.GetStatusObject(StatusASO.NC_CONNECT_FAILED, connection.ObjectEncoding); } disconnectOnReturn = true; } } else { // Service calls, must be connected. InvokeCall(connection, serviceCall); } } break; case ACTION_DISCONNECT: connection.Close(); break; case ACTION_CREATE_STREAM: case ACTION_DELETE_STREAM: case ACTION_RELEASE_STREAM: case ACTION_PUBLISH: case ACTION_PLAY: case ACTION_SEEK: case ACTION_PAUSE: case ACTION_CLOSE_STREAM: case ACTION_RECEIVE_VIDEO: case ACTION_RECEIVE_AUDIO: { IStreamService streamService = ScopeUtils.GetScopeService(connection.Scope, typeof(IStreamService)) as IStreamService; StatusASO status = null; try { if (!InvokeCall(connection, serviceCall, streamService)) { status = StatusASO.GetStatusObject(StatusASO.NS_INVALID_ARGUMENT, connection.ObjectEncoding); status.description = "Failed to " + action + " (stream ID: " + header.StreamId + ")"; } } catch (Exception ex) { log.Error("Error while invoking " + action + " on stream service.", ex); status = StatusASO.GetStatusObject(StatusASO.NS_FAILED, connection.ObjectEncoding); status.description = "Error while invoking " + action + " (stream ID: " + header.StreamId + ")"; status.details = ex.Message; } if (status != null) { channel.SendStatus(status); } } break; default: if (connection.IsConnected) { InvokeCall(connection, serviceCall); } else { // Warn user attemps to call service without being connected if (log.IsWarnEnabled) { log.Warn("Not connected, closing connection"); } connection.Close(); } break; } } /* * if(invoke is FlexInvoke) * { * FlexInvoke reply = new FlexInvoke(); * reply.InvokeId = invoke.InvokeId; * reply.SetResponseSuccess(); * //TODO * if( serviceCall is IPendingServiceCall ) * { * IPendingServiceCall pendingCall = (IPendingServiceCall)serviceCall; * reply.Response = pendingCall.Result; * } * channel.Write(reply); * } * else if(invoke is Invoke) */ if (invoke is Invoke) { if ((header.StreamId != 0) && (serviceCall.Status == Call.STATUS_SUCCESS_VOID || serviceCall.Status == Call.STATUS_SUCCESS_NULL)) { if (log.IsDebugEnabled) { log.Debug("Method does not have return value, do not reply"); } return; } // The client expects a result for the method call. Invoke reply = new Invoke(); reply.ServiceCall = serviceCall; reply.InvokeId = invoke.InvokeId; //sending reply channel.Write(reply); } if (disconnectOnReturn) { connection.Close(); } if (action == ACTION_CONNECT) { connection.Context.ObjectEncoding = connection.ObjectEncoding; } }
internal RtmpChannel(RtmpConnection connection, int channelId) { _connection = connection; _channelId = channelId; }
/// <summary> /// Connection open event. /// </summary> /// <param name="connection">Connection object.</param> public virtual void ConnectionOpened(RtmpConnection connection) { }
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; } }
/// <summary> /// Message recieved. /// </summary> /// <param name="connection">Connection object.</param> /// <param name="obj">Message object.</param> public void MessageReceived(RtmpConnection connection, object obj) { IRtmpEvent message = null; RtmpPacket packet = null; RtmpHeader header = null; RtmpChannel channel = null; IClientStream stream = null; try { packet = obj as RtmpPacket; message = packet.Message; header = packet.Header; channel = connection.GetChannel(header.ChannelId); if (connection is IStreamCapableConnection) { stream = (connection as IStreamCapableConnection).GetStreamById(header.StreamId); } // Support stream ids #if !SILVERLIGHT FluorineContext.ValidateContext(); FluorineContext.Current.Connection.SetAttribute(FluorineContext.FluorineStreamIdKey, header.StreamId); #endif // Increase number of received messages connection.MessageReceived(); #if !SILVERLIGHT if (log != null && log.IsDebugEnabled) { log.Debug("RtmpConnection message received, type = " + header.DataType); } #endif if (message != null) { message.Source = connection; } switch (header.DataType) { case Constants.TypeInvoke: OnInvoke(connection, channel, header, message as Invoke); if (message.Header.StreamId != 0 && (message as Invoke).ServiceCall.ServiceName == null && (message as Invoke).ServiceCall.ServiceMethodName == BaseRtmpHandler.ACTION_PUBLISH) { if (stream != null) //Dispatch if stream was created { (stream as IEventDispatcher).DispatchEvent(message); } } break; case Constants.TypeFlexInvoke: OnFlexInvoke(connection, channel, header, message as FlexInvoke); if (message.Header.StreamId != 0 && (message as Invoke).ServiceCall.ServiceName == null && (message as Invoke).ServiceCall.ServiceMethodName == BaseRtmpHandler.ACTION_PUBLISH) { if (stream != null) //Dispatch if stream was created { (stream as IEventDispatcher).DispatchEvent(message); } } break; case Constants.TypeNotify: // just like invoke, but does not return if ((message as Notify).Data != null && stream != null) { // Stream metadata (stream as IEventDispatcher).DispatchEvent(message); } else { OnInvoke(connection, channel, header, message as Notify); } break; case Constants.TypePing: OnPing(connection, channel, header, message as Ping); break; case Constants.TypeBytesRead: OnStreamBytesRead(connection, channel, header, message as BytesRead); break; case Constants.TypeSharedObject: case Constants.TypeFlexSharedObject: OnSharedObject(connection, channel, header, message as SharedObjectMessage); break; case Constants.TypeFlexStreamEnd: if (stream != null) { (stream as IEventDispatcher).DispatchEvent(message); } break; case Constants.TypeChunkSize: OnChunkSize(connection, channel, header, message as ChunkSize); break; case Constants.TypeAudioData: case Constants.TypeVideoData: // NOTE: If we respond to "publish" with "NetStream.Publish.BadName", // the client sends a few stream packets before stopping. We need to // ignore them. if (stream != null) { ((IEventDispatcher)stream).DispatchEvent(message); } break; case Constants.TypeServerBandwidth: OnServerBW(connection, channel, header, message as ServerBW); break; case Constants.TypeClientBandwidth: OnClientBW(connection, channel, header, message as ClientBW); break; default: #if !SILVERLIGHT if (log != null && log.IsDebugEnabled) { log.Debug("RtmpService event not handled: " + header.DataType); } #endif break; } } catch (Exception ex) { #if !SILVERLIGHT if (log.IsErrorEnabled) { log.Error(__Res.GetString(__Res.Rtmp_HandlerError), ex); log.Error(__Res.GetString(__Res.Error_ContextDump)); //log.Error(Environment.NewLine); log.Error(packet); } #endif } }
protected override void OnClientBW(RtmpConnection connection, RtmpChannel channel, RtmpHeader source, ClientBW clientBw) { channel.Write(new ServerBW(clientBw.Bandwidth)); }
/// <summary> /// Connection closed. /// </summary> /// <param name="connection">Connection object.</param> public virtual void ConnectionClosed(RtmpConnection connection) { connection.Close(); }
protected override void OnSharedObject(RtmpConnection connection, RtmpChannel channel, RtmpHeader header, SharedObjectMessage message) { _netConnection.OnSharedObject(connection, channel, header, message); }
/// <summary> /// This method supports the infrastructure and is not intended to be used directly from your code. /// </summary> /// <param name="connection"></param> /// <param name="channel"></param> /// <param name="source"></param> /// <param name="streamBytesRead"></param> protected void OnStreamBytesRead(RtmpConnection connection, RtmpChannel channel, RtmpHeader source, BytesRead streamBytesRead) { connection.ReceivedBytesRead(streamBytesRead.Bytes); }
public override void ConnectionClosed(RtmpConnection connection) { base.ConnectionClosed(connection); _netConnection.RaiseNetStatus(StatusASO.GetStatusObject(StatusASO.NC_CONNECT_CLOSED, _netConnection.ObjectEncoding)); _netConnection.RaiseDisconnect(); }
/// <summary> /// This method supports the infrastructure and is not intended to be used directly from your code. /// </summary> /// <param name="connection"></param> /// <param name="channel"></param> /// <param name="source"></param> /// <param name="chunkSize"></param> protected abstract void OnChunkSize(RtmpConnection connection, RtmpChannel channel, RtmpHeader source, ChunkSize chunkSize);