size_t StreamProcessor::DispatchProcessPacket(const UInt32 packetID, DataVector::iterator curr, DataVector::iterator bufferEnd) { for(UInt32 i=0; i<m_numPacketTypes; i++) { const PacketDescriptorPacket &desc = m_packetDescriptors[i]; if(desc.packetID == packetID) { const ProcessPacketFunc processFunc = m_packetProcessors[i]; if(processFunc) { return processFunc(*this, curr, bufferEnd); } else { // No process function available for this packet type! Attempt to skip it! switch(desc.sizeofPayloadSizeType) { case 0: return SkipPacket( (size_t)desc.sizeofPacket, curr, bufferEnd ); case 1: return SkipPacketWithPayload<UInt8>( (size_t)desc.sizeofPacket, curr, bufferEnd ); case 2: return SkipPacketWithPayload<UInt16>( (size_t)desc.sizeofPacket, curr, bufferEnd ); case 4: return SkipPacketWithPayload<UInt32>( (size_t)desc.sizeofPacket, curr, bufferEnd ); } } } } // We should never reach here... // typically means unknown packet type, so any further reading from the socket will yield undefined results... OVR_CAPTURE_ASSERT(0); return 0; }
// Flushes all available packets over the network... returns number of bytes sent bool AsyncStream::Flush(Socket &s) { OVR_CAPTURE_CPU_ZONE(AsyncStream_Flush); bool okay = true; // Take ownership of any pending data... SpinLock(m_bufferLock); Swap(m_cacheBegin, m_flushBegin); Swap(m_cacheTail, m_flushTail); Swap(m_cacheEnd, m_flushEnd); SpinUnlock(m_bufferLock); // Signal that we just swapped in a new buffer... wake up any threads that were waiting on us to flush. m_gate.Open(); if(m_flushTail > m_flushBegin) { const size_t sendSize = (size_t)(m_flushTail-m_flushBegin); // first send stream header... StreamHeaderPacket streamheader; streamheader.threadID = m_threadID; streamheader.streamSize = sendSize; okay = s.Send(&streamheader, sizeof(streamheader)); // This send payload... okay = okay && s.Send(m_flushBegin, sendSize); m_flushTail = m_flushBegin; } OVR_CAPTURE_ASSERT(m_flushBegin == m_flushTail); // should be empty at this point... return okay; }
// does not check whether value is new void VarStore::Set(key_t key, var_t var, bool isClient) { m_tableLock.WriteLock(); VarInfo *varRet = FindUnsafe(key); if (varRet == NULL) { m_varTable.push_back(VarInfo(key, var, isClient)); } else { OVR_CAPTURE_ASSERT(varRet->key == key); varRet->valCur = var; varRet->isClient = isClient; } OVR_CAPTURE_ASSERT(FindUnsafe(key) != NULL); m_tableLock.WriteUnlock(); }
// Closes the capture system... no other Capture calls on *any* thead should be called after this. void Shutdown(void) { if(g_server) { delete g_server; g_server = NULL; } OVR_CAPTURE_ASSERT(!g_connectionFlags); g_initFlags = 0; g_connectionFlags = 0; }
void Thread::Start(void) { OVR_CAPTURE_ASSERT(!m_thread && !m_quitSignaled); #if defined(OVR_CAPTURE_POSIX) pthread_attr_init(&m_threadAttrs); pthread_create(&m_thread, &m_threadAttrs, ThreadEntry, this); #elif defined(OVR_CAPTURE_WINDOWS) m_thread = CreateThread(NULL, 0, ThreadEntry, this, 0, NULL); #else #error Unknown Platform! #endif }
// Initializes the Capture system... should be called before any other Capture call. bool Init(const char *packageName, UInt32 flags) { OVR_CAPTURE_ASSERT(!g_initFlags && !g_connectionFlags); // sanitze input flags; flags = flags & All_Flags; // If no capture features are enabled... then don't initialize anything! if(!flags) return false; g_initFlags = flags; g_connectionFlags = 0; // Initialize the pre-thread stream system... AsyncStream::Init(); OVR_CAPTURE_ASSERT(!g_server); g_server = new Server(packageName); g_server->Start(); return true; }
// Upload the framebuffer for the current frame... should be called once a frame! void FrameBuffer(UInt64 timestamp, FrameBufferFormat format, UInt32 width, UInt32 height, const void *buffer) { if(CheckConnectionFlag(Enable_FrameBuffer_Capture)) { UInt32 pixelSize = 0; switch(format) { case FrameBuffer_RGB_565: pixelSize=2; break; case FrameBuffer_RGBA_8888: pixelSize=4; break; } OVR_CAPTURE_ASSERT(pixelSize); const UInt32 payloadSize = pixelSize * width * height; FrameBufferPacket packet; packet.format = format; packet.width = width; packet.height = height; packet.timestamp = timestamp; // TODO: we should probably just send framebuffer packets directly over the network rather than // caching them due to their size and to reduce latency. AsyncStream::Acquire()->WritePacket(packet, buffer, payloadSize); } }
// Initialize the per-thread stream system... MUST be called before being connected! void AsyncStream::Init(void) { OVR_CAPTURE_ASSERT(g_tlskey == NullThreadLocalKey); g_tlskey = CreateThreadLocalKey(ThreadDetach); }
bool StreamProcessor::ProcessData(const void *buffer, size_t bufferSize) { // First, append the incoming data to our unprocessed data buffer... m_buffer.insert(m_buffer.end(), (const UInt8*)buffer, ((const UInt8*)buffer)+bufferSize); const DataVector::iterator begin = m_buffer.begin(); const DataVector::iterator end = m_buffer.end(); DataVector::iterator curr = begin; // 1) read ConnectionHeaderPacket if(!m_hasReadConnectionHeader && std::distance(curr, end) > (DataVector::difference_type)sizeof(ConnectionHeaderPacket)) { ConnectionHeaderPacket connectionHeader; memcpy(&connectionHeader, &*curr, sizeof(connectionHeader)); curr += sizeof(connectionHeader); m_hasReadConnectionHeader = true; if(connectionHeader.size != sizeof(connectionHeader)) { onStreamError("Connection header size mismatch!"); return false; } if(connectionHeader.version != ConnectionHeaderPacket::s_version) { onStreamError("Connection header version mismatch!"); return false; } if(connectionHeader.flags == 0) { onStreamError("No capture features enabled!"); return false; } } // Have not successfully read the connection header but no error, so return until we have more data if(!m_hasReadConnectionHeader) return true; // 2) read PacketDescriptorHeaderPacket if(!m_hasReadPacketDescriptorHeader && std::distance(curr, end) > (DataVector::difference_type)sizeof(PacketDescriptorHeaderPacket)) { PacketDescriptorHeaderPacket packetDescHeader; memcpy(&packetDescHeader, &*curr, sizeof(packetDescHeader)); curr += sizeof(packetDescHeader); m_hasReadPacketDescriptorHeader = true; m_numPacketTypes = packetDescHeader.numPacketTypes; if(m_numPacketTypes == 0) { onStreamError("No packet types received!"); return false; } if(m_numPacketTypes > 1024) { onStreamError("Too many packet types received!"); return false; } } // Have not successfully read the packet descriptor header but no error, so return until we have more data if(!m_hasReadPacketDescriptorHeader) return true; // 3) read array of PacketDescriptorPacket if(!m_hasReadPacketDescriptors && std::distance(curr, end) > (DataVector::difference_type)(sizeof(PacketDescriptorPacket)*m_numPacketTypes)) { m_packetDescriptors = new PacketDescriptorPacket[m_numPacketTypes]; m_packetProcessors = new ProcessPacketFunc[m_numPacketTypes]; for(UInt32 i=0; i<m_numPacketTypes; i++) { memcpy(&m_packetDescriptors[i], &*curr, sizeof(PacketDescriptorPacket)); curr += sizeof(PacketDescriptorPacket); m_packetProcessors[i] = GetProcessPacketFunction(m_packetDescriptors[i].packetID, m_packetDescriptors[i].version); } m_hasReadPacketDescriptors = true; } // Have not successfully read the packet descriptors but no error, so return until we have more data if(!m_hasReadPacketDescriptors) return true; // 4) read streams... while(curr < end) { // Compute the end of the readable stream... // We take the minimum end point between end of buffer actually read in and stream size... // because we don't want to overrun the stream or the buffer that is actually read in... const DataVector::iterator streamEnd = curr + std::min((size_t)(end - curr), m_streamBytesRemaining); // If we are currently in a stream... try parsing packets out of it... while(curr < streamEnd) { const size_t s = LoadAndProcessNextPacket(curr, streamEnd); if(!s) break; OVR_CAPTURE_ASSERT(curr+s <= streamEnd); curr += s; m_streamBytesRemaining -= s; } // If we are at the end of the stream... that means the next data available will be a stream header... // so load that if we can. And once loaded stay in the loop and try parsing the following packets... if(curr == streamEnd && sizeof(StreamHeaderPacket) <= (size_t)(end - curr)) { StreamHeaderPacket streamHeader = {0}; memcpy(&streamHeader, &*curr, sizeof(streamHeader)); m_streamThreadID = streamHeader.threadID; m_streamBytesRemaining = streamHeader.streamSize; curr += sizeof(streamHeader); } else { // If we ran out of parsable data we need to exit and allow the CaptureThread to load more data... break; } } // Finally, remove processed data... // Note: we so cannot do this if we decide the DataVector should // shrink on popAll if(curr > begin) { m_buffer.erase(m_buffer.begin(), curr); } return true; }