private void InitUpdate() { if (Identity != null && Identity.IsInitialized) { initialized = true; if (Receiver == null || Recorder == null) { throw new NullReferenceException("VoiceHandler requeires 2 valid components VoiceReceiver and VoiceRecorder"); } //Compatibility check between self, receiver and recorder AudioDataTypeFlag res = Receiver.AvailableTypes & Recorder.AvailableTypes & SelfFlag; if (res == AudioDataTypeFlag.None) { throw new ArgumentException("The voice handler underlying receiver and recorder components are incompatible"); } //Set the compatibility value of this handler AvailableTypes = res; OnEnable(); OnVoiceChatEnabledChanged(); } }
/// <summary> /// Create a new struct instance /// </summary> /// <param name="frequency">audio frequency</param> /// <param name="channels">audio channels</param> /// <param name="format">audio format</param> /// <param name="valid">is packet valid?</param> public VoicePacketInfo(ushort frequency, byte channels, AudioDataTypeFlag format, bool valid = true) { Frequency = frequency; Channels = channels; Format = format; ValidPacketInfo = valid; }
/// <summary> /// Adds the handler /// </summary> /// <param name="handler">handler to add</param> public void AddVoiceHandler(IVoiceHandler handler) { //check if workflow is initialized if (manipulator == null) { throw new Exception("The current manipulator is null, be sure to initialize the workflow properly before any other action"); } //Compatibility check between handler to add and manipulator AudioDataTypeFlag res = manipulator.AvailableTypes & handler.AvailableTypes; if (res == AudioDataTypeFlag.None) { throw new ArgumentException("the given handler type is incompatible with the current audio data manipulator"); } //handler is added and callback for when mic data is available is set on the handler handlers.Add(handler.Identity.NetworkId, handler); handler.SetOnMicDataProcessed(OnMicDataProcessed); }
/// <summary> /// Adds the handler. Handler should already be initialized before calling this method /// </summary> /// <param name="handler">handler to add</param> public override void AddVoiceHandler(VoiceHandler handler) { //Compatibility check between handler to add and manipulator AudioDataTypeFlag res = Manipulator.AvailableTypes & handler.AvailableTypes; if (res == AudioDataTypeFlag.None) { throw new ArgumentException("the given handler type is incompatible with the current audio data manipulator"); } ulong id = handler.NetID; //handler is added and callback for when mic data is available is set on the handler handlers.Add(id, handler); IsHandlerMuted(handler, false); if (!handler.IsRecorder && (mutedIds[id] & MuteStatus.RemoteHasMutedLocal) == 0) { activeIdsToSendTo.Add(id); } }
void Awake() { //Get all required components Identity = GetComponent <INetworkIdentity>(); Receiver = GetComponent <IVoiceReceiver>(); Recorder = GetComponent <IVoiceRecorder>(); //Compatibility check between self, receiver and recorder AudioDataTypeFlag res = Receiver.AvailableTypes & Recorder.AvailableTypes & SelfFlag; if (res == AudioDataTypeFlag.None) { throw new ArgumentException("The given handler type is incompatible with its underlying receiver and recorder components"); } //Set the compatibility value of this handler AvailableTypes = res; if (IsRecorder) { Manager.Settings.PushToTalkChanged += OnPushToTalkChanged; } }
/// <summary> /// Processes mic data from the given handler /// </summary> /// <param name="handler">handler which has available mic data</param> public override void ProcessMicData(VoiceHandler handler) { //If voice chat is disabled or if the given handler is not a recorder do nothing if (!Settings.VoiceChatEnabled || Settings.MuteSelf || !handler.IsRecorder) { return; } //Compatibility check between manipulator and handler. If they are incompatible throw exception AudioDataTypeFlag res = handler.AvailableTypes & Manipulator.AvailableTypes; if (res == AudioDataTypeFlag.None) { throw new ArgumentException("the given handler type is incompatible with the current audio data manipulator"); } VoicePacketInfo info; //determine which data format to use. if (res == AudioDataTypeFlag.Both) { res = formatToUse; } bool useSingle = res == AudioDataTypeFlag.Single; //Retrive data from handler input int count; if (useSingle) { info = handler.GetMicData(dataBuffer, 0, dataBuffer.Length, out count); } else { info = handler.GetMicDataInt16(dataBufferInt16, 0, dataBufferInt16.Length, out count); } //if data is valid go on if (info.ValidPacketInfo) { //packet buffer used to create the final packet is prepared packetBuffer.ResetSeekLength(); //data recovered from input is manipulated and stored into the gamepacket if (useSingle) { Manipulator.FromAudioDataToPacket(dataBuffer, 0, count, ref info, packetBuffer); } else { Manipulator.FromAudioDataToPacketInt16(dataBufferInt16, 0, count, ref info, packetBuffer); } packetBuffer.CurrentSeek = 0; //if packet is valid send to transport if (info.ValidPacketInfo) { Transport.SendToAll(packetBuffer, info, activeIdsToSendTo); } } }
/// <summary> /// Process the received packet data. /// </summary> /// <param name="receivedData">received raw data</param> /// <param name="startIndex">received raw data start index</param> /// <param name="length">received raw data length</param> /// <param name="netId">sender net id</param> public override void ProcessReceivedPacket(byte[] receivedData, int startIndex, int length, ulong netId) { //If voice chat is disabled do nothing if (!Settings.VoiceChatEnabled) { return; } //resets packet buffer packetBuffer.ResetSeekLength(); //receive packet VoicePacketInfo info = Transport.ProcessReceivedData(packetBuffer, receivedData, startIndex, length, netId); //if packet is invalid or if there is not an handler for the given netid discard the packet received if (!info.ValidPacketInfo || !handlers.ContainsKey(netId)) { return; } VoiceHandler handler = handlers[netId]; //Do nothing if handler is either muted or if it is a recorder if (handler.IsOutputMuted || handler.IsRecorder) { return; } //Compatibility check between manipulator, handler and packet; if incompatible throw exception AudioDataTypeFlag res = Manipulator.AvailableTypes & handler.AvailableTypes & info.Format; if (res == AudioDataTypeFlag.None) { throw new ArgumentException("the given handler type is incompatible with the current audio data manipulator and the received packet format"); } //determine which data format to use. if (res == AudioDataTypeFlag.Both) { res = formatToUse; } bool useSingle = res == AudioDataTypeFlag.Single; //packet received Seek to zero to prepare for data manipulation packetBuffer.CurrentSeek = 0; //Different methods between Int16 and Single format. Data manipulation is done and, if no error occurred, audio data is sent to the handler in order to be used as output sound if (useSingle) { int count = Manipulator.FromPacketToAudioData(packetBuffer, ref info, dataBuffer, 0); if (info.ValidPacketInfo) { handler.ReceiveAudioData(dataBuffer, 0, count, info); } } else { int count = Manipulator.FromPacketToAudioDataInt16(packetBuffer, ref info, dataBufferInt16, 0); if (info.ValidPacketInfo) { handler.ReceiveAudioDataInt16(dataBufferInt16, 0, count, info); } } }
private void OnMicDataProcessed(IVoiceHandler handler) { //throw exception if workflow is not initialized correctly if (manipulator == null || transport == null) { throw new Exception("The current manipulator or transport is null, be sure to initialize the workflow properly before any other action"); } //If voice chat is disabled or if the given handler is not a recorder do nothing if (!Settings.VoiceChatEnabled || Settings.MuteSelf || !handler.IsRecorder) { return; } //Compatibility check between manipulator and handler. If they are incompatible throw exception AudioDataTypeFlag res = handler.AvailableTypes & manipulator.AvailableTypes; if (res == AudioDataTypeFlag.None) { throw new ArgumentException("the given handler type is incompatible with the current audio data manipulator"); } VoicePacketInfo info; //determine which data format to use. Gives priority to Single format bool useSingle = (res & AudioDataTypeFlag.Single) != 0; //Retrive data from handler input uint count; if (useSingle) { info = handler.GetMicData(micDataBuffer, 0, micDataBuffer.Length, out count); } else { info = handler.GetMicDataInt16(micDataBufferInt16, 0, micDataBufferInt16.Length, out count); } //if data is valid go on if (info.ValidPacketInfo) { //packet buffer used to create the final packet is prepared packetSender.ResetSeekLength(); //data recovered from input is manipulated and stored into the gamepacket if (useSingle) { manipulator.FromAudioDataToPacket(micDataBuffer, 0, (int)count, ref info, packetSender); } else { manipulator.FromAudioDataToPacketInt16(micDataBufferInt16, 0, (int)count, ref info, packetSender); } //if packet is valid send to transport if (info.ValidPacketInfo) { transport.SendToAllOthers(packetSender, info); } } }
private void OnPacketAvailable() { //throw exception if workflow is not initialized correctly if (manipulator == null || transport == null) { throw new Exception("The current manipulator or transport is null, be sure to initialize the workflow properly before any other action"); } //If voice chat is disabled do nothing if (!Settings.VoiceChatEnabled) { return; } //Cycle that iterates as long as there are packets available in the transport while (transport.IsPacketAvailable) { //resets packet buffer packetReceiver.ResetSeekLength(); //receive packet VoicePacketInfo info = transport.Receive(packetReceiver); //if packet is invalid or if there is not an handler for the given netid discard the packet received if (!info.ValidPacketInfo || !handlers.ContainsKey(info.NetId)) { continue; } IVoiceHandler handler = handlers[info.NetId]; //Do nothing if handler is either muted or if it is a recorder if (handler.IsOutputMuted || handler.IsRecorder) { return; } //Compatibility check between manipulator, handler and packet; if incompatible throw exception AudioDataTypeFlag res = manipulator.AvailableTypes & handler.AvailableTypes & info.Format; if (res == AudioDataTypeFlag.None) { throw new ArgumentException("the given handler type is incompatible with the current audio data manipulator and the received packet format"); } //determine which data format to use. Gives priority to Single format bool useSingle = (res & AudioDataTypeFlag.Single) != 0; int count; //packet received Seek to zero to prepare for data manipulation packetReceiver.CurrentSeek = 0; //Different methods between Int16 and Single format. Data manipulation is done and, if no error occurred, audio data is sent to the handler in order to be used as output sound if (useSingle) { manipulator.FromPacketToAudioData(packetReceiver, ref info, receivedDataBuffer, 0, out count); if (info.ValidPacketInfo) { handler.ReceiveAudioData(receivedDataBuffer, 0, count, info); } } else { manipulator.FromPacketToAudioDataInt16(packetReceiver, ref info, receivedDataBufferInt16, 0, out count); if (info.ValidPacketInfo) { handler.ReceiveAudioDataInt16(receivedDataBufferInt16, 0, count, info); } } } }