/// <summary> /// Write the packet to the stream /// </summary> protected override void OnWrite(Stream stream) { //this will automatically figure out its length... BinarySerializer.SerializeValue(stream, m_Timestamp); BinarySerializer.SerializeValue(stream, m_ClockDrift); byte[] rawData = m_SessionHeader.RawData(); stream.Write(rawData, 0, rawData.Length); }
/// <summary> /// Initialize the GLF writer for storing information about the current live session /// </summary> /// <param name="file">The file stream to write the session file into (should be empty)</param> /// <param name="sessionSummary"></param> /// <param name="fileSequence"></param> /// <param name="fileStartTime">Used during initial collection to indicate the real time this file became the active file.</param> /// <param name="majorVersion">Major version of the serialization protocol</param> /// <param name="minorVersion">Minor version of the serialization protocol</param> /// <remarks>The file header is configured with a copy of the session summary, assuming that we're about to make a copy of the /// session. For live data collection the caller should supply the file start time to reflect the true time period /// covered by this file. </remarks> public GLFWriter(Stream file, SessionSummary sessionSummary, int fileSequence, DateTimeOffset?fileStartTime, int majorVersion, int minorVersion) { //for use to use the stream, it has to support if (file.CanSeek == false) { throw new ArgumentException("Provided stream can't be used because it doesn't support seeking", nameof(file)); } m_SessionSummary = sessionSummary; m_OutputStream = file; // This logic will store GZip compressed files for protocol version 2 and beyond if (majorVersion > 1) { //we are explicitly *NOT* using the system GZipStream because it doesn't support flush. m_PacketStream = new GZipStream(m_OutputStream, CompressionMode.Compress, CompressionLevel.Default, true) { FlushMode = FlushType.Sync }; } else { m_PacketStream = new MemoryStream(BufferSize + MaxExpectedPacketSize); } m_PacketWriter = new PacketWriter(m_PacketStream, majorVersion, minorVersion); //initialize the stream with the file header and session header m_FileHeader = new FileHeader(majorVersion, minorVersion); m_SessionHeader = new SessionHeader(sessionSummary); //There are two variants of the GLF format: One for a whole session, one for a session fragment. if (fileStartTime.HasValue) { m_SessionHeader.FileId = Guid.NewGuid(); m_SessionHeader.FileSequence = fileSequence; m_SessionHeader.FileStartDateTime = fileStartTime.Value; m_SessionHeader.FileEndDateTime = m_SessionHeader.EndDateTime; //by default, this is the last file - it won't be if we open another. m_SessionHeader.IsLastFile = true; } //we need to know how big the session header will be (it's variable sized) before we can figure out the data offset. byte[] sessionHeader = m_SessionHeader.RawData(); //where are we going to start our data block? m_FileHeader.DataOffset = FileHeader.HeaderSize + sessionHeader.Length; byte[] header = m_FileHeader.RawData(); m_OutputStream.Position = 0; //move to the start of the stream, we rely on this. m_OutputStream.Write(header, 0, FileHeader.HeaderSize); m_OutputStream.Write(sessionHeader, 0, sessionHeader.Length); m_OutputStream.Flush(); m_OutputStream.Position = m_FileHeader.DataOffset; //so we are sure we start writing our data at the correct spot. // When we added GZip compression to streams we noticed that we were sometimes // losing a lot of data that went unflushed while programmers were testing in // Visual Studio. To address this, we have the GZip stream flush to disk much // more aggressively when we detect that the debugger is attached. #if !DEBUG // We only want this behavior for release builds, not for our own debug builds // we might prefer the writing to be the more typical optimized behavior. AutoFlush = Debugger.IsAttached; #endif }