Exemple #1
0
        private void CreatePlayback()
        {
            Playback = OpenALHelper.PlaybackDevices[0].OpenStream(Voice.SampleRate, OpenALAudioFormat.Mono16Bit);
            Playback.Listener.Position = new Vector3()
            {
                X = 0.0f, Y = 0.0f, Z = 0.0f
            };
            Playback.Listener.Velocity = new Vector3()
            {
                X = 0.0f, Y = 0.0f, Z = 0.0f
            };
            Playback.Listener.Orientation = new Orientation()
            {
                At = new Vector3()
                {
                    X = 0.0f, Y = 0.0f, Z = 1.0f
                },
                Up = new Vector3()
                {
                    X = 0.0f, Y = 1.0f, Z = 0.0f
                }
            };

            Playback.ALPosition = new Vector3()
            {
                X = 0.0f, Y = 0.0f, Z = 0.0f
            };
            Playback.Velocity = new Vector3()
            {
                X = 0.0f, Y = 0.0f, Z = 0.0f
            };
        }
Exemple #2
0
        private void CreatePlayback()
        {
            Playback = OpenALHelper.PlaybackDevices[0].OpenStream(Voice.SampleRate, OpenALAudioFormat.Mono16Bit);
            Playback.Listener.Position    = new Vector3(0f, 0f, 0f);
            Playback.Listener.Velocity    = new Vector3(0f, 0f, 0f);
            Playback.Listener.Orientation = new Orientation(new Vector3(0f, 0f, 1f), new Vector3(0f, 1f, 0f));

            Playback.ALPosition = new Vector3(0f, 0f, 0f);
            Playback.Velocity   = new Vector3(0f, 0f, 0f);

            Playback.SetVolume(Voice.Volume / 100f);
        }
        // Playback
        public byte[] StartPlayback()
        {
            if (_mode != Mode.Playback)
            {
                Debug.LogError("SessionCapture: Cannot call StartPlayback on record session.");
                return(null);
            }

            if (_playing)
            {
                Debug.LogError("SessionCapture: StartPlayback() has been called on a session that's already playing. Ignoring. This is a bug!");
                return(null);
            }

            // Create a queue to hold updates that are ready for playback
            _playbackDeltaUpdates = new Queue <DeltaUpdate>();

            // Create a dictionary of deserialized incoming reliable updates. These will be used to calculate roundtrip time.
            _clientToIncomingReliableUpdatesMap = new Dictionary <int, Dictionary <uint, DeltaUpdate> >();

            // Create a queue to hold updates that we've deserialized from the primary stream that haven't been processed yet.
            _primaryPlaybackDeltaUpdatesToBeProcessed = new Queue <DeltaUpdate>();

            // Open up file stream for the primary capture file
            _primaryPlaybackStream = new PlaybackStream(_primaryPlaybackFilePath);

            // Read the file header + initial datastore
            byte[] datastore = _primaryPlaybackStream.ReadHeader();

            // Start playback at the primary session capture start time.
            _playbackTime = _primaryPlaybackStream.startTimestamp;

            // Open up file streams for secondary capture files
            _secondaryPlaybackStreams = new Dictionary <int, PlaybackStream>();
            if (_secondaryPlaybackFilePaths != null)
            {
                foreach (string secondaryPlaybackFilePath in _secondaryPlaybackFilePaths)
                {
                    PlaybackStream playbackStream = new PlaybackStream(secondaryPlaybackFilePath);
                    playbackStream.ReadHeader();

                    // Fast forward to the primary stream start time
                    playbackStream.SkipToTime(_playbackTime);

                    _secondaryPlaybackStreams.Add(playbackStream.clientID, playbackStream);
                }
            }

            // Mark the session as playing
            _playing = true;

            return(datastore);
        }
Exemple #4
0
        static void Main(string[] args)
        {
            _readBuffer = new byte[960];
            Console.WriteLine("Opening \"{0}\" for playback", OpenALHelper.PlaybackDevices[0].DeviceName);
            Console.WriteLine("Opening \"{0}\" for capture", OpenALHelper.CaptureDevices[0].DeviceName);

            _playback = OpenALHelper.PlaybackDevices[0].OpenStream(48000, OpenALAudioFormat.Mono16Bit);
            _playback.Listener.Position = new Vector3()
            {
                X = 0.0f, Y = 0.0f, Z = 0.0f
            };
            _playback.Listener.Velocity = new Vector3()
            {
                X = 0.0f, Y = 0.0f, Z = 0.0f
            };
            _playback.Listener.Orientation = new Orientation()
            {
                At = new Vector3()
                {
                    X = 0.0f, Y = 0.0f, Z = 1.0f
                },
                Up = new Vector3()
                {
                    X = 0.0f, Y = 1.0f, Z = 0.0f
                }
            };
            _playback.ALPosition = new Vector3()
            {
                X = 0.0f, Y = 0.0f, Z = 0.0f
            };
            _playback.Velocity = new Vector3()
            {
                X = 0.0f, Y = 0.0f, Z = 0.0f
            };
            _capture = OpenALHelper.CaptureDevices[0].OpenStream(48000, OpenALAudioFormat.Mono16Bit, 10);
            _capture.BeginRead(_readBuffer, 0, _readBuffer.Length, Callback, null);

            while (true)
            {
                PrintUI();
                if (ProcessInput())
                {
                    break;
                }
            }

            _playback.Close();
            _playback.Dispose();
            _capture.Close();
            _capture.Dispose();
        }
        public void StopPlayback()
        {
            // Dispose playback streams
            if (_primaryPlaybackStream != null)
            {
                _primaryPlaybackStream.Dispose();
                _primaryPlaybackStream = null;
            }
            if (_secondaryPlaybackStreams != null)
            {
                foreach (KeyValuePair <int, PlaybackStream> secondaryPlaybackStream in _secondaryPlaybackStreams)
                {
                    secondaryPlaybackStream.Value.Dispose();
                }
                _secondaryPlaybackStreams.Clear();
                _secondaryPlaybackStreams = null;
            }

            _playing = false;
        }
        private static bool AdjustPlaybackStreamSendTimestampOffsetWithOutgoingReliableDeltaUpdate(PlaybackStream playbackStream, Dictionary <uint, DeltaUpdate> incomingReliableUpdates, DeltaUpdate outgoingReliableDeltaUpdate)
        {
            // Check for a matching reliable delta update. If we haven't received it yet, then bail, it's not time to decode this update yet.
            DeltaUpdate incomingReliableDeltaUpdate;

            if (incomingReliableUpdates == null || !incomingReliableUpdates.TryGetValue(outgoingReliableDeltaUpdate.updateID, out incomingReliableDeltaUpdate))
            {
                return(false);
            }

            // Found a matching reliable update. Use the round trip time to adjust outgoing unreliable updates.
            playbackStream.sendTimestampOffset = incomingReliableDeltaUpdate.timestamp - outgoingReliableDeltaUpdate.timestamp;

            // Remove from incoming reliable updates
            incomingReliableUpdates.Remove(outgoingReliableDeltaUpdate.updateID);

            return(true);
        }
        private static bool AdjustOutgoingUnreliableDeltaUpdateTimestamp(double playbackTime, PlaybackStream playbackStream, DeltaUpdate deltaUpdate)
        {
            // Adjust the timestamp
            double timestamp = deltaUpdate.timestamp + playbackStream.sendTimestampOffset;

            // If the update is now newer than the current playback time, then bail.
            if (timestamp > playbackTime)
            {
                return(false);
            }

            // Adjust update timestamp
            deltaUpdate.timestamp += playbackStream.sendTimestampOffset;

            return(true);
        }
        public void PlaybackTick(double deltaTime)
        {
            if (!_playing)
            {
                return;
            }

            // Increment playback time
            _playbackTime += deltaTime;

            // Keep track of whether this frame produced any updates for playback
            bool didAddDeltaUpdateToPlaybackQueue = false;

            // Read delta updates from primary playback stream
            DeltaUpdate deltaUpdate = new DeltaUpdate();

            while (_primaryPlaybackStream.ReadDeltaUpdate(_playbackTime, deltaUpdate))
            {
                // Add all outgoing updates to the queue to be processed
                if (deltaUpdate.outgoing)
                {
                    _primaryPlaybackDeltaUpdatesToBeProcessed.Enqueue(deltaUpdate);
                }

                // If it's an incoming reliable update, keep track so we can use the timestamp to calculate timestamp offsets.
                if (deltaUpdate.incoming && deltaUpdate.reliable)
                {
                    // If this is an incoming reliable update, add it directly to the queue of updates to play back. It doesn't need any timestamp adjustments or anything.
                    _playbackDeltaUpdates.Enqueue(deltaUpdate);
                    didAddDeltaUpdateToPlaybackQueue = true;

                    // Retrieve dictionary for this sender. Create a new one if needed.
                    Dictionary <uint, DeltaUpdate> incomingReliableUpdates;
                    if (!_clientToIncomingReliableUpdatesMap.TryGetValue(deltaUpdate.sender, out incomingReliableUpdates))
                    {
                        incomingReliableUpdates = new Dictionary <uint, DeltaUpdate>();
                        _clientToIncomingReliableUpdatesMap.Add(deltaUpdate.sender, incomingReliableUpdates);
                    }

                    // Add the update
                    incomingReliableUpdates.Add(deltaUpdate.updateID, deltaUpdate);
                }

                // Create a new update for the next loop
                deltaUpdate = new DeltaUpdate();
            }

            // Adjust the timestamps for outgoing unreliable messages by measuring the roundtrip time on reliable messages.
            // We're using incoming reliable updates for playback (because the server assigns uniqueIDs and things), but unreliable updates are recorded when they're sent.
            // That means that the reliable updates will have timestamps that are later than when they were actually sent. To fix this, we adjust the timestamps of the
            // unreliable updates to account for the roundtrip delay that we're seeing.

            // Grab the incoming reliable updates for the primary stream's client ID
            Dictionary <uint, DeltaUpdate> primaryPlaybackClientIncomingReliableUpdates;

            _clientToIncomingReliableUpdatesMap.TryGetValue(_primaryPlaybackStream.clientID, out primaryPlaybackClientIncomingReliableUpdates);

            // Loop through updates and process them until we run out or we hit one that requires us to wait for more time to pass / more frames to be decoded
            while (_primaryPlaybackDeltaUpdatesToBeProcessed.Count > 0)
            {
                // Peek at update
                deltaUpdate = _primaryPlaybackDeltaUpdatesToBeProcessed.Peek();

                // Outgoing unreliable update.
                if (deltaUpdate.outgoing && deltaUpdate.unreliable)
                {
                    bool success = AdjustOutgoingUnreliableDeltaUpdateTimestamp(_playbackTime, _primaryPlaybackStream, deltaUpdate);

                    // If we were unable to successfully adjust the update, break out of the loop. We'll try again next frame after more time has passed.
                    if (!success)
                    {
                        break;
                    }

                    // Add to outgoing updates
                    _playbackDeltaUpdates.Enqueue(deltaUpdate);
                    didAddDeltaUpdateToPlaybackQueue = true;
                }

                // Outgoing reliable update. Find the matching incoming reliable update and use it to adjust the unreliableTimestampOffset
                else if (deltaUpdate.outgoing && deltaUpdate.reliable)
                {
                    bool success = AdjustPlaybackStreamSendTimestampOffsetWithOutgoingReliableDeltaUpdate(_primaryPlaybackStream, primaryPlaybackClientIncomingReliableUpdates, deltaUpdate);

                    // If we were unable to successfully adjust the send timestamp offset, break out of the loop. We'll try again next frame after more time has passed.
                    if (!success)
                    {
                        break;
                    }
                }

                // If we hit this point, the update has been processed, dequeue it and move onto the next one.
                _primaryPlaybackDeltaUpdatesToBeProcessed.Dequeue();
            }

            // Loop through each secondary stream. Perform the timestamp adjustments and add them to the playback queue.
            foreach (KeyValuePair <int, PlaybackStream> secondaryPlaybackStream in _secondaryPlaybackStreams)
            {
                int            clientID       = secondaryPlaybackStream.Key;
                PlaybackStream playbackStream = secondaryPlaybackStream.Value;

                // Grab the incoming reliable updates for this stream's clientID
                Dictionary <uint, DeltaUpdate> incomingReliableUpdates;
                _clientToIncomingReliableUpdatesMap.TryGetValue(clientID, out incomingReliableUpdates);

                // Read updates up until playbackTime processing them as we go. Stop if we run out of updates or we hit an update that we can't process yet.
                deltaUpdate = new DeltaUpdate();
                while (playbackStream.ReadDeltaUpdate(_playbackTime, deltaUpdate))
                {
                    // Outgoing unreliable update.
                    if (deltaUpdate.outgoing && deltaUpdate.unreliable)
                    {
                        bool success = AdjustOutgoingUnreliableDeltaUpdateTimestamp(_playbackTime, playbackStream, deltaUpdate);

                        // If we were unable to successfully adjust the update, break out of the loop. We'll try again next frame after more time has passed.
                        if (!success)
                        {
                            break;
                        }

                        // Add to outgoing updates
                        _playbackDeltaUpdates.Enqueue(deltaUpdate);
                        didAddDeltaUpdateToPlaybackQueue = true;
                    }

                    // Outgoing reliable update. Find the matching incoming reliable update and use it to adjust the unreliableTimestampOffset
                    else if (deltaUpdate.outgoing && deltaUpdate.reliable)
                    {
                        bool success = AdjustPlaybackStreamSendTimestampOffsetWithOutgoingReliableDeltaUpdate(playbackStream, incomingReliableUpdates, deltaUpdate);

                        // If we were unable to successfully adjust the send timestamp offset, break out of the loop. We'll try again next frame after more time has passed.
                        if (!success)
                        {
                            break;
                        }
                    }
                }
            }

            // If we added any updates to the playback queue, sort it to make sure that they're in order after timestamp adjustments were made.
            if (didAddDeltaUpdateToPlaybackQueue)
            {
                _playbackDeltaUpdates = new Queue <DeltaUpdate>(_playbackDeltaUpdates.OrderBy(playbackDeltaUpdate => playbackDeltaUpdate.timestamp));
            }

            // If we've finished reading updates, we're done playing.
            _playing = _primaryPlaybackStream.reading;
        }