public void Notify(IServiceCall serviceCall, byte channel) { FluorineFx.Messaging.Rtmp.Event.Notify message = new FluorineFx.Messaging.Rtmp.Event.Notify { ServiceCall = serviceCall }; this.GetChannel(channel).Write(message); }
protected RtmpPacket CreatePacket(Notify notify) { var header = new RtmpHeader { ChannelId = 3, DataType = notify.DataType, Timer = notify.Timestamp }; return new RtmpPacket(header, notify); }
/// <summary> /// Call blocks until the result is received. Use Send for a nonblocking call. /// </summary> /// <param name="notify">Call</param> /// <returns>Result or null if failed</returns> protected Notify Call(Notify notify) { var callresult = new CallResultWait(notify, true); lock (WaitLock) { WaitInvokeList.Add(callresult); } notify.InvokeId = CurrentInvoke.Increment(); SendPacket(notify); callresult.Wait.WaitOne(-1); return callresult.Result; }
/// <summary> /// Invokes the first client's Call method which will block. /// </summary> /// <param name="notify"></param> /// <returns>Result or null on failed</returns> public Notify CallWithInvoke(Notify notify) { RtmpsProxyClient client = null; lock (Clients) { if (Clients.Count < 1) return null; client = (RtmpsProxyClient)Clients[0]; } return client.Call(notify); }
/// <summary> /// Notifies service using service call object and channel. /// </summary> /// <param name="serviceCall">Service call object.</param> /// <param name="channel">Channel to use.</param> public void Notify(IServiceCall serviceCall, byte channel) { Notify notify = new Notify(); notify.ServiceCall = serviceCall; GetChannel(channel).Write(notify); }
static ByteBuffer EncodeNotifyOrInvoke(RtmpContext context, Notify invoke) { //MemoryStreamEx output = new MemoryStreamEx(); ByteBuffer output = ByteBuffer.Allocate(1024); output.AutoExpand = true; RtmpWriter writer = new RtmpWriter(output); //Set legacy collection flag from context writer.UseLegacyCollection = context.UseLegacyCollection; writer.UseLegacyThrowable = context.UseLegacyThrowable; IServiceCall serviceCall = invoke.ServiceCall; bool isPending = serviceCall.Status == Call.STATUS_PENDING; if (!isPending) { //log.debug("Call has been executed, send result"); writer.WriteData(context.ObjectEncoding, serviceCall.IsSuccess ? "_result" : "_error"); } else { //log.debug("This is a pending call, send request"); string action = (serviceCall.ServiceName == null) ? serviceCall.ServiceMethodName : serviceCall.ServiceName + "." + serviceCall.ServiceMethodName; writer.WriteData(context.ObjectEncoding, action); } if(invoke is Invoke) { writer.WriteData(context.ObjectEncoding, invoke.InvokeId); writer.WriteData(context.ObjectEncoding, invoke.ConnectionParameters); } if(!isPending && (invoke is Invoke)) { IPendingServiceCall pendingCall = (IPendingServiceCall)serviceCall; if (!serviceCall.IsSuccess && !(pendingCall.Result is StatusASO)) { StatusASO status = GenerateErrorResult(StatusASO.NC_CALL_FAILED, serviceCall.Exception); pendingCall.Result = status; } writer.WriteData(context.ObjectEncoding, pendingCall.Result); } else { //log.debug("Writing params"); object[] args = invoke.ServiceCall.Arguments; if (args != null) { foreach(object element in args) { writer.WriteData(context.ObjectEncoding, element); } } } return output; }
protected virtual void OnNotify(Notify notify) { }
protected void SendPacket(Notify notify) { var buf = RtmpProtocolEncoder.Encode(sourcecontext, CreatePacket(notify)); if (buf == null) { //StaticLogger.Fatal("Unable to encode " + notify); } else { var buff = buf.ToArray(); base.Send(buff, 0, buff.Length); } }
public virtual void OnProcessResults(object sender, Notify results) { var bodies = RtmpUtil.GetBodies(results); foreach (var obj in bodies) { OnProcessObject(this, obj.Item1, obj.Item2); } }
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; } }
public static bool IsError(Notify notify) { return notify.ServiceCall != null && notify.ServiceCall.ServiceMethodName == "_error"; }
public static bool IsResult(Notify notify) { return notify.ServiceCall != null && (notify.ServiceCall.ServiceMethodName == "_result" || notify.ServiceCall.ServiceMethodName == "_error"); }
/// <summary> /// Gets the bodies of all the message arguments. /// </summary> /// <param name="notify"></param> /// <returns>Tuple, Item1 = Body, Item2 = TimeStamp</returns> public static IEnumerable<Tuple<object, Int64>> GetBodies(Notify notify) { var ret = new List<Tuple<object, Int64>>(); foreach (var arg in notify.ServiceCall.Arguments) { Tuple<object, Int64> obj = null; if (arg is AbstractMessage) { var msg = (AbstractMessage)arg; obj = Tuple.Create(msg.Body, msg.TimeStamp); } else if (arg is MessageBase) { var msg = (MessageBase)arg; obj = Tuple.Create(msg.body, msg.timestamp); } if (obj != null) ret.Add(obj); } return ret; }
/// <summary> /// Gets the error message from the notify arguments. /// </summary> /// <param name="notify"></param> /// <returns></returns> public static ErrorMessage GetError(Notify notify) { foreach (var arg in notify.ServiceCall.Arguments) { if (arg is ErrorMessage) return (ErrorMessage)arg; } return null; }
private void SendOnPlayStatus(String code, int duration, long bytes) { MemoryStream ms = new MemoryStream(); AMFWriter writer = new AMFWriter(ms); writer.WriteString("onPlayStatus"); Hashtable props = new Hashtable(); props.Add("code", code); props.Add("level", "status"); props.Add("duration", duration); props.Add("bytes", bytes); writer.WriteAssociativeArray(ObjectEncoding.AMF0, props); ByteBuffer buffer = new ByteBuffer(ms); IRtmpEvent evt = new Notify(buffer); if (_lastMessage != null) { int timestamp = _lastMessage.Timestamp; evt.Timestamp = timestamp; } else { evt.Timestamp = 0; } RtmpMessage msg = new RtmpMessage(); msg.body = evt; DoPushMessage(msg); }
static Notify DecodeNotifyOrInvoke(Notify notify, ByteBuffer stream, RtmpHeader header) { long start = stream.Position; RtmpReader reader = new RtmpReader(stream); string action = reader.ReadData() as string; if(!(notify is Invoke)) { //Don't decode "NetStream.send" requests stream.Position = start; notify.Data = ByteBuffer.Allocate(stream.Remaining); notify.Data.Put(stream); //notify.setData(in.asReadOnlyBuffer()); return notify; } if(header == null || header.StreamId == 0) { double invokeId = (double)reader.ReadData(); notify.InvokeId = (int)invokeId; } object[] parameters = Call.EmptyArguments; if(stream.HasRemaining) { #if !(NET_1_1) List<object> paramList = new List<object>(); #else ArrayList paramList = new ArrayList(); #endif object obj = reader.ReadData(); if (obj is IDictionary) { // for connect we get a map notify.ConnectionParameters = obj as IDictionary; } else if (obj != null) { paramList.Add(obj); } while(stream.HasRemaining) { paramList.Add(reader.ReadData()); } parameters = paramList.ToArray(); } int dotIndex = action.LastIndexOf("."); string serviceName = (dotIndex == -1) ? null : action.Substring(0, dotIndex); string serviceMethod = (dotIndex == -1) ? action : action.Substring(dotIndex + 1, action.Length - dotIndex - 1); if (notify is Invoke) { PendingCall call = new PendingCall(serviceName, serviceMethod, parameters); notify.ServiceCall = call; } else { Call call = new Call(serviceName, serviceMethod, parameters); notify.ServiceCall = call; } return notify; }
static Notify DecodeStreamMetadata(ByteBuffer stream) { RtmpReader reader = new RtmpReader(stream); string action = reader.ReadData() as string; object obj = reader.ReadData(); Notify notify = new Notify(); int dotIndex = action.LastIndexOf("."); string serviceName = (dotIndex == -1) ? null : action.Substring(0, dotIndex); string serviceMethod = (dotIndex == -1) ? action : action.Substring(dotIndex + 1, action.Length - dotIndex - 1); object[] parameters = new object[1]{obj}; Call call = new Call(serviceName, serviceMethod, parameters); notify.ServiceCall = call; return notify; }
public virtual void OnCall(object sender, Notify call, Notify result) { if (CallResult != null) CallResult(sender, call, result); OnProcessResults(sender, result); }
public IMessage PullMessage(IPipe pipe) { lock (_syncLock) { if (_pipe != pipe) return null; if (_reader == null) Init(); if (!_reader.HasMoreTags()) { // TODO send OOBCM to notify EOF // Do not unsubscribe as this kills VOD seek while in buffer // this.pipe.unsubscribe(this); return null; } ITag tag = _reader.ReadTag(); IRtmpEvent msg = null; int timestamp = tag.Timestamp; switch (tag.DataType) { case Constants.TypeAudioData: msg = new AudioData(tag.Body); break; case Constants.TypeVideoData: msg = new VideoData(tag.Body); break; case Constants.TypeInvoke: msg = new Invoke(tag.Body); break; case Constants.TypeNotify: msg = new Notify(tag.Body); break; case Constants.TypeFlexStreamEnd: msg = new FlexStreamSend(tag.Body); break; default: log.Warn("Unexpected type " + tag.DataType); msg = new Unknown(tag.DataType, tag.Body); break; } msg.Timestamp = timestamp; RtmpMessage rtmpMsg = new RtmpMessage(); rtmpMsg.body = msg; return rtmpMsg; } }
public virtual void OnNotify(object sender, Notify notify) { if (Notify != null) Notify(sender, notify); OnProcessResults(this, notify); }
/// <summary> /// This method supports the Fluorine 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 void OnStreamEvent(Notify notify) { bool onStatus = notify.ServiceCall.ServiceMethodName.Equals("onStatus"); if (!onStatus) { if (notify.ServiceCall.ServiceMethodName.Equals("onMetaData")) RaiseOnMetaData(notify.ServiceCall.Arguments[0] as IDictionary); if (notify.ServiceCall.ServiceMethodName.Equals("onPlayStatus")) RaiseOnPlayStatus(notify.ServiceCall.Arguments[0] as IDictionary); MethodInfo mi = MethodHandler.GetMethod(_client.GetType(), notify.ServiceCall.ServiceMethodName, notify.ServiceCall.Arguments, false, false); if (mi != null) { ParameterInfo[] parameterInfos = mi.GetParameters(); object[] args = new object[parameterInfos.Length]; notify.ServiceCall.Arguments.CopyTo(args, 0); TypeHelper.NarrowValues(args, parameterInfos); try { InvocationHandler invocationHandler = new InvocationHandler(mi); object result = invocationHandler.Invoke(_client, args); } catch (Exception exception) { notify.ServiceCall.Exception = exception; notify.ServiceCall.Status = FluorineFx.Messaging.Rtmp.Service.Call.STATUS_INVOCATION_EXCEPTION; //log.Error("Error while invoking method " + call.ServiceMethodName + " on client", exception); } } else { string msg = __Res.GetString(__Res.Invocation_NoSuitableMethod, notify.ServiceCall.ServiceMethodName); this.RaiseNetStatus(new FluorineException(msg)); } } else { object[] args = notify.ServiceCall.Arguments; ASObject statusASO = null; if ((args != null) && (args.Length > 0)) statusASO = args[0] as ASObject; this.RaiseNetStatus(statusASO); } }
protected override void OnCall(Notify call, Notify result) { Form1.Log("OnCall"); }
protected virtual void OnCall(Notify call, Notify result) { }
protected override void OnNotify(Notify notfiy) { Form1.Log("OnNotify"); }
/// <summary> /// Send does not block and returns immediately. Use Call for a blocking call /// </summary> /// <param name="notify">Call</param> protected void Send(Notify notify) { //Might as well use the waitlist so InternalReceive doesn't freak out about the invoke id not being found. lock (WaitLock) { WaitInvokeList.Add(new CallResultWait(notify, false)); } notify.InvokeId = CurrentInvoke.Increment(); SendPacket(notify); }
static ByteBuffer EncodeNotify(RtmpContext context, Notify notify) { return EncodeNotifyOrInvoke(context, notify); }
/// <summary> /// Handler for pending call result. Dispatches results to all pending call handlers. /// </summary> /// <param name="connection">Connection.</param> /// <param name="invoke">Pending call result event context.</param> protected void HandlePendingCallResult(RtmpConnection connection, Notify invoke) { IServiceCall call = invoke.ServiceCall; IPendingServiceCall pendingCall = connection.RetrievePendingCall(invoke.InvokeId); if (pendingCall != null) { pendingCall.Status = call.Status; // The client sent a response to a previously made call. object[] args = call.Arguments; if ((args != null) && (args.Length > 0)) { pendingCall.Result = args[0]; } IPendingServiceCallback[] callbacks = pendingCall.GetCallbacks(); if (callbacks != null && callbacks.Length > 0) { foreach (IPendingServiceCallback callback in callbacks) { try { callback.ResultReceived(pendingCall); } catch (Exception ex) { #if !SILVERLIGHT log.Error("Error while executing callback " + callback, ex); #endif } } } } }
public CallResultWait(Notify call, bool blocking) { Blocking = blocking; Call = call; Wait = new AutoResetEvent(false); }
public void PushMessage(IPipe pipe, IMessage message) { if (message is ResetMessage) { _timeStamper.Reset(); } else if (message is StatusMessage) { StatusMessage statusMsg = message as StatusMessage; _data.SendStatus(statusMsg.body as StatusASO); } else if (message is RtmpMessage) { // Make sure chunk size has been sent if (!_chunkSizeSent) SendChunkSize(); RtmpMessage rtmpMsg = message as RtmpMessage; IRtmpEvent msg = rtmpMsg.body; int eventTime = msg.Timestamp; #if !SILVERLIGHT if(log.IsDebugEnabled) log.Debug(string.Format("Message timestamp: {0}", eventTime)); #endif if (eventTime < 0) { #if !SILVERLIGHT if (log.IsDebugEnabled) log.Debug(string.Format("Message has negative timestamp: {0}", eventTime)); #endif return; } byte dataType = msg.DataType; // Create a new header for the consumer RtmpHeader header = _timeStamper.GetTimeStamp(dataType, eventTime); switch (msg.DataType) { case Constants.TypeStreamMetadata: Notify notify = new Notify((msg as Notify).Data); notify.Header = header; notify.Timestamp = header.Timer; _data.Write(notify); break; case Constants.TypeFlexStreamEnd: // TODO: okay to send this also to AMF0 clients? FlexStreamSend send = new FlexStreamSend((msg as Notify).Data); send.Header = header; send.Timestamp = header.Timer; _data.Write(send); break; case Constants.TypeVideoData: VideoData videoData = new VideoData((msg as VideoData).Data); videoData.Header = header; videoData.Timestamp = header.Timer; _video.Write(videoData); break; case Constants.TypeAudioData: AudioData audioData = new AudioData((msg as AudioData).Data); audioData.Header = header; audioData.Timestamp = header.Timer; _audio.Write(audioData); break; case Constants.TypePing: Ping ping = new Ping((msg as Ping).PingType, (msg as Ping).Value2, (msg as Ping).Value3, (msg as Ping).Value4); ping.Header = header; _connection.Ping(ping); break; case Constants.TypeBytesRead: BytesRead bytesRead = new BytesRead((msg as BytesRead).Bytes); bytesRead.Header = header; bytesRead.Timestamp = header.Timer; _connection.GetChannel((byte)2).Write(bytesRead); break; default: _data.Write(msg); break; } } }
static ByteBuffer EncodeStreamMetadata(RtmpContext context, Notify metaData) { ByteBuffer output = metaData.Data; return output; }