// ############################################################################################################## void jevois::Gadget::streamOff() { JEVOIS_TRACE(2); // Note: we allow for several streamOff() without complaining, this happens, e.g., when destroying a Gadget that is // not currently streaming. LDEBUG("Turning off gadget stream"); // Abort stream in case it was not already done, which will introduce some sleeping in our run() thread, thereby // helping us acquire our needed double lock: abortStream(); JEVOIS_TIMED_LOCK(itsMtx); // Stop streaming over the USB link: int type = V4L2_BUF_TYPE_VIDEO_OUTPUT; try { XIOCTL_QUIET(itsFd, VIDIOC_STREAMOFF, &type); } catch (...) { } // Nuke all our buffers: if (itsBuffers) { delete itsBuffers; itsBuffers = nullptr; } itsImageQueue.clear(); itsDoneImgs.clear(); LDEBUG("Gadget stream is off"); }
// ############################################################################################################## void jevois::Camera::streamOff() { JEVOIS_TRACE(2); // Note: we allow for several streamOff() without complaining, this happens, e.g., when destroying a Camera that is // not currently streaming. LDEBUG("Turning off camera stream"); // Abort stream in case it was not already done, which will introduce some sleeping in our run() thread, thereby // helping us acquire our needed double lock: abortStream(); // We need a double lock here so that we can both turn off the stream and nuke our output image and done idx: std::unique_lock<std::timed_mutex> lk1(itsMtx, std::defer_lock); std::unique_lock<std::mutex> lk2(itsOutputMtx, std::defer_lock); std::lock(lk1, lk2); // Invalidate our output image: itsOutputImage.invalidate(); // User may have called done() but our run() thread has not yet gotten to requeueing this image, if so requeue it here // as it seems to keep the driver happier: if (itsBuffers) for (size_t idx : itsDoneIdx) try { itsBuffers->qbuf(idx); } catch (...) { jevois::warnAndIgnoreException(); } itsDoneIdx.clear(); // Stop streaming at the device level: int type = V4L2_BUF_TYPE_VIDEO_CAPTURE; try { XIOCTL_QUIET(itsFd, VIDIOC_STREAMOFF, &type); } catch (...) { } // Nuke all the buffers: if (itsBuffers) { delete itsBuffers; itsBuffers = nullptr; } // Unblock any get() that is waiting on itsOutputCondVar, it will then throw now that streaming is off: lk2.unlock(); itsOutputCondVar.notify_all(); LDEBUG("Camera stream is off"); }
bool audio::orchestra::api::Core::callbackEvent(AudioDeviceID _deviceId, const AudioBufferList *_inBufferList, const audio::Time& _inTime, const AudioBufferList *_outBufferList, const audio::Time& _outTime) { if ( m_state == audio::orchestra::state::stopped || m_state == audio::orchestra::state::stopping) { return true; } if (m_state == audio::orchestra::state::closed) { ATA_ERROR("the stream is closed ... this shouldn't happen!"); return false; } // Check if we were draining the stream and signal is finished. if (m_private->drainCounter > 3) { m_state = audio::orchestra::state::stopping; ATA_VERBOSE("Set state as stopping"); if (m_private->internalDrain == true) { new std::thread(&audio::orchestra::api::Core::coreStopStream, this); } else { // external call to stopStream() m_private->condition.notify_one(); } return true; } AudioDeviceID outputDevice = m_private->id[0]; // Invoke user callback to get fresh output data UNLESS we are // draining stream or duplex mode AND the input/output devices are // different AND this function is called for the input device. if (m_private->drainCounter == 0 && (m_mode != audio::orchestra::mode_duplex || _deviceId == outputDevice)) { std::vector<enum audio::orchestra::status> status; if ( m_mode != audio::orchestra::mode_input && m_private->xrun[0] == true) { status.push_back(audio::orchestra::status::underflow); m_private->xrun[0] = false; } if ( m_mode != audio::orchestra::mode_output && m_private->xrun[1] == true) { status.push_back(audio::orchestra::status::overflow); m_private->xrun[1] = false; } int32_t cbReturnValue = m_callback(&m_userBuffer[1][0], _inTime, &m_userBuffer[0][0], _outTime, m_bufferSize, status); if (cbReturnValue == 2) { m_state = audio::orchestra::state::stopping; ATA_VERBOSE("Set state as stopping"); m_private->drainCounter = 2; abortStream(); return true; } else if (cbReturnValue == 1) { m_private->drainCounter = 1; m_private->internalDrain = true; } } if ( m_mode == audio::orchestra::mode_output || ( m_mode == audio::orchestra::mode_duplex && _deviceId == outputDevice)) { if (m_private->drainCounter > 1) { // write zeros to the output stream if (m_private->nStreams[0] == 1) { memset(_outBufferList->mBuffers[m_private->iStream[0]].mData, 0, _outBufferList->mBuffers[m_private->iStream[0]].mDataByteSize); } else { // fill multiple streams with zeros for (uint32_t i=0; i<m_private->nStreams[0]; i++) { memset(_outBufferList->mBuffers[m_private->iStream[0]+i].mData, 0, _outBufferList->mBuffers[m_private->iStream[0]+i].mDataByteSize); } } } else if (m_private->nStreams[0] == 1) { if (m_doConvertBuffer[0]) { // convert directly to CoreAudio stream buffer convertBuffer((char*)_outBufferList->mBuffers[m_private->iStream[0]].mData, &m_userBuffer[0][0], m_convertInfo[0]); } else { // copy from user buffer memcpy(_outBufferList->mBuffers[m_private->iStream[0]].mData, &m_userBuffer[0][0], _outBufferList->mBuffers[m_private->iStream[0]].mDataByteSize); } } else { // fill multiple streams float *inBuffer = (float *) &m_userBuffer[0][0]; if (m_doConvertBuffer[0]) { convertBuffer(m_deviceBuffer, &m_userBuffer[0][0], m_convertInfo[0]); inBuffer = (float *) m_deviceBuffer; } if (m_deviceInterleaved[0] == false) { // mono mode uint32_t bufferBytes = _outBufferList->mBuffers[m_private->iStream[0]].mDataByteSize; for (uint32_t i=0; i<m_nUserChannels[0]; i++) { memcpy(_outBufferList->mBuffers[m_private->iStream[0]+i].mData, (void *)&inBuffer[i*m_bufferSize], bufferBytes); } } else { // fill multiple multi-channel streams with interleaved data uint32_t streamChannels, channelsLeft, inJump, outJump, inOffset; float *out, *in; bool inInterleaved = true; uint32_t inChannels = m_nUserChannels[0]; if (m_doConvertBuffer[0]) { inInterleaved = true; // device buffer will always be interleaved for nStreams > 1 and not mono mode inChannels = m_nDeviceChannels[0]; } if (inInterleaved) { inOffset = 1; } else { inOffset = m_bufferSize; } channelsLeft = inChannels; for (uint32_t i=0; i<m_private->nStreams[0]; i++) { in = inBuffer; out = (float *) _outBufferList->mBuffers[m_private->iStream[0]+i].mData; streamChannels = _outBufferList->mBuffers[m_private->iStream[0]+i].mNumberChannels; outJump = 0; // Account for possible channel offset in first stream if (i == 0 && m_channelOffset[0] > 0) { streamChannels -= m_channelOffset[0]; outJump = m_channelOffset[0]; out += outJump; } // Account for possible unfilled channels at end of the last stream if (streamChannels > channelsLeft) { outJump = streamChannels - channelsLeft; streamChannels = channelsLeft; } // Determine input buffer offsets and skips if (inInterleaved) { inJump = inChannels; in += inChannels - channelsLeft; } else { inJump = 1; in += (inChannels - channelsLeft) * inOffset; } for (uint32_t i=0; i<m_bufferSize; i++) { for (uint32_t j=0; j<streamChannels; j++) { *out++ = in[j*inOffset]; } out += outJump; in += inJump; } channelsLeft -= streamChannels; } } } if (m_private->drainCounter) { m_private->drainCounter++; goto unlock; } } AudioDeviceID inputDevice; inputDevice = m_private->id[1]; if ( m_mode == audio::orchestra::mode_input || ( m_mode == audio::orchestra::mode_duplex && _deviceId == inputDevice)) { if (m_private->nStreams[1] == 1) { if (m_doConvertBuffer[1]) { // convert directly from CoreAudio stream buffer convertBuffer(&m_userBuffer[1][0], (char *) _inBufferList->mBuffers[m_private->iStream[1]].mData, m_convertInfo[1]); } else { // copy to user buffer memcpy(&m_userBuffer[1][0], _inBufferList->mBuffers[m_private->iStream[1]].mData, _inBufferList->mBuffers[m_private->iStream[1]].mDataByteSize); } } else { // read from multiple streams float *outBuffer = (float *) &m_userBuffer[1][0]; if (m_doConvertBuffer[1]) { outBuffer = (float *) m_deviceBuffer; } if (m_deviceInterleaved[1] == false) { // mono mode uint32_t bufferBytes = _inBufferList->mBuffers[m_private->iStream[1]].mDataByteSize; for (uint32_t i=0; i<m_nUserChannels[1]; i++) { memcpy((void *)&outBuffer[i*m_bufferSize], _inBufferList->mBuffers[m_private->iStream[1]+i].mData, bufferBytes); } } else { // read from multiple multi-channel streams uint32_t streamChannels, channelsLeft, inJump, outJump, outOffset; float *out, *in; bool outInterleaved = true; uint32_t outChannels = m_nUserChannels[1]; if (m_doConvertBuffer[1]) { outInterleaved = true; // device buffer will always be interleaved for nStreams > 1 and not mono mode outChannels = m_nDeviceChannels[1]; } if (outInterleaved) { outOffset = 1; } else { outOffset = m_bufferSize; } channelsLeft = outChannels; for (uint32_t i=0; i<m_private->nStreams[1]; i++) { out = outBuffer; in = (float *) _inBufferList->mBuffers[m_private->iStream[1]+i].mData; streamChannels = _inBufferList->mBuffers[m_private->iStream[1]+i].mNumberChannels; inJump = 0; // Account for possible channel offset in first stream if (i == 0 && m_channelOffset[1] > 0) { streamChannels -= m_channelOffset[1]; inJump = m_channelOffset[1]; in += inJump; } // Account for possible unread channels at end of the last stream if (streamChannels > channelsLeft) { inJump = streamChannels - channelsLeft; streamChannels = channelsLeft; } // Determine output buffer offsets and skips if (outInterleaved) { outJump = outChannels; out += outChannels - channelsLeft; } else { outJump = 1; out += (outChannels - channelsLeft) * outOffset; } for (uint32_t i=0; i<m_bufferSize; i++) { for (uint32_t j=0; j<streamChannels; j++) { out[j*outOffset] = *in++; } out += outJump; in += inJump; } channelsLeft -= streamChannels; } } if (m_doConvertBuffer[1]) { // convert from our internal "device" buffer convertBuffer(&m_userBuffer[1][0], m_deviceBuffer, m_convertInfo[1]); } } } unlock: //m_mutex.unlock(); audio::orchestra::Api::tickStreamTime(); return true; }
static void saxStartElement( message_info_t *data, const xmlChar *name, const xmlChar **attrs ){ if ( data->ignore_depth == 0 ) { if ( data->bGeometry ) { // we have a handler data->pGeometry->saxStartElement( data, name, attrs ); } else { if ( strcmp( (char *)name, "q3map_feedback" ) == 0 ) { // check the correct version // old q3map don't send a version attribute // the ones we support .. send Q3MAP_STREAM_VERSION if ( !attrs[0] || !attrs[1] || ( strcmp( (char*)attrs[0],"version" ) != 0 ) ) { Sys_FPrintf( SYS_ERR, "No stream version given in the feedback stream, this is an old q3map version.\n" "Please turn off monitored compiling if you still wish to use this q3map executable\n" ); abortStream( data ); return; } else if ( strcmp( (char*)attrs[1],Q3MAP_STREAM_VERSION ) != 0 ) { Sys_FPrintf( SYS_ERR, "This version of Radiant reads version %s debug streams, I got an incoming connection with version %s\n" "Please make sure your versions of Radiant and q3map are matching.\n", Q3MAP_STREAM_VERSION, (char*)attrs[1] ); abortStream( data ); return; } } // we don't treat locally else if ( strcmp( (char *)name, "message" ) == 0 ) { data->msg_level = atoi( (char *)attrs[1] ); } else if ( strcmp( (char *)name, "polyline" ) == 0 ) { // polyline has a particular status .. right now we only use it for leakfile .. data->bGeometry = true; data->pGeometry = &g_pointfile; data->pGeometry->saxStartElement( data, name, attrs ); } else if ( strcmp( (char *)name, "select" ) == 0 ) { CSelectMsg *pSelect = new CSelectMsg(); data->bGeometry = true; data->pGeometry = pSelect; data->pGeometry->saxStartElement( data, name, attrs ); } else if ( strcmp( (char *)name, "pointmsg" ) == 0 ) { CPointMsg *pPoint = new CPointMsg(); data->bGeometry = true; data->pGeometry = pPoint; data->pGeometry->saxStartElement( data, name, attrs ); } else if ( strcmp( (char *)name, "windingmsg" ) == 0 ) { CWindingMsg *pWinding = new CWindingMsg(); data->bGeometry = true; data->pGeometry = pWinding; data->pGeometry->saxStartElement( data, name, attrs ); } else { Sys_FPrintf( SYS_WRN, "WARNING: ignoring unrecognized node in XML stream (%s)\n", name ); // we don't recognize this node, jump over it // (NOTE: the ignore mechanism is a bit screwed, only works when starting an ignore at the highest level) data->ignore_depth = data->recurse; } } } data->recurse++; }