Exemplo n.º 1
0
bool MythRecorder::SetChannel(MythChannel &channel)
{
  m_recorder_t->Lock();
  if(!IsRecording())
  {
    XBMC->Log(LOG_ERROR,"%s: Recorder %i is not recording",__FUNCTION__,ID(),channel.Name().c_str());
    m_recorder_t->Unlock();
    return false;
  }
  CStdString channelNum;
  channelNum.Format("%i",channel.Number());
  if(CMYTH->RecorderPause(*m_recorder_t)!=0)
  {
    XBMC->Log(LOG_ERROR,"%s: Failed to pause recorder %i",__FUNCTION__,ID());
    m_recorder_t->Unlock();
    return false;
  }
  if(!CheckChannel(channel))
  {
    XBMC->Log(LOG_ERROR,"%s: Recorder %i doesn't provide channel %s",__FUNCTION__,ID(),channel.Name().c_str());
    m_recorder_t->Unlock();
    return false;
  }
  if(CMYTH->RecorderSetChannel(*m_recorder_t,channelNum.GetBuffer())!=0)
  {
    XBMC->Log(LOG_ERROR,"%s: Failed to change recorder %i to channel %s",__FUNCTION__,ID(),channel.Name().c_str());
    m_recorder_t->Unlock();
    return false;
  }
  if(CMYTH->LivetvChainSwitchLast(*m_recorder_t)!=1)
  {
    XBMC->Log(LOG_ERROR,"%s: Failed to switch chain for recorder %i",__FUNCTION__,ID(),channel.Name().c_str());
    m_recorder_t->Unlock();
    return false;
  }
  *livechainupdated=0;
  int i=20;
  while(*livechainupdated==0&&i--!=0)
  {
    m_recorder_t->Unlock();
    cSleep(100);
    m_recorder_t->Lock();
  }

  m_recorder_t->Unlock();
  for(int i=0;i<20;i++)
  {
    if(!IsRecording())
      cSleep(1);
    else
      break;
  }

  return true;
}
Exemplo n.º 2
0
bool PAPlayer::Record(bool bOnOff)
{
  if (!m_pShoutCastRipper) return false;
  if (bOnOff && IsRecording()) return true;
  if (bOnOff == false && IsRecording() == false) return true;
  if (bOnOff)
    return m_pShoutCastRipper->Record();

  m_pShoutCastRipper->StopRecording();
  return true;
}
Exemplo n.º 3
0
void GOrgueMidiRecorder::StopRecording()
{
	m_button[ID_MIDI_RECORDER_RECORD]->Display(false);
	m_button[ID_MIDI_RECORDER_RECORD_RENAME]->Display(false);
	m_organfile->DeleteTimer(this);
	if (!IsRecording())
		return;
	const unsigned char end[4] = { 0x01, 0xFF, 0x2F, 0x00 };
	Write(end, sizeof(end));
	Flush();
	m_FileLength -= sizeof(MIDIHeaderChunk) + sizeof(MIDIFileHeader);
	MIDIFileHeader h = { { 'M', 'T', 'r', 'k' }, m_FileLength };
	m_file.Seek(sizeof(MIDIHeaderChunk));
	m_file.Write(&h, sizeof(h));
	m_file.Flush();
	m_file.Close();
	if (!m_DoRename)
	{
		wxFileName name = m_Filename;
		GOSyncDirectory(name.GetPath());
	}
	else
		GOAskRenameFile(m_Filename, m_organfile->GetSettings().MidiRecorderPath(),_("MIDI files (*.mid)|*.mid"));
	UpdateDisplay();
}
Exemplo n.º 4
0
bool csMovieRecorder::EatKey (iEvent& event)
{
  SetupPlugin();
  bool down = csKeyEventHelper::GetEventType (&event) == csKeyEventTypeDown;
  csKeyModifiers m;
  csKeyEventHelper::GetModifiers (&event, m);
  bool alt = m.modifiers[csKeyModifierTypeAlt] != 0;
  bool ctrl = m.modifiers[csKeyModifierTypeCtrl] != 0;
  bool shift = m.modifiers[csKeyModifierTypeShift] != 0;
  utf32_char key = csKeyEventHelper::GetCookedCode (&event);

  if (down && (key == keyRecord.code) && (alt == keyRecord.alt) && 
      (ctrl == keyRecord.ctrl) && (shift == keyRecord.shift)) 
  {
    if (IsRecording())
	Stop();
    else
	Start();
    return true;
  }

  if (down && key==keyPause.code && alt==keyPause.alt && 
      ctrl==keyPause.ctrl && shift==keyPause.shift) 
  {
    if (IsPaused())
	UnPause();
    else
	Pause();
    return true;
  }

  return false;
}
uint32 FVoiceEngineSteam::StartLocalVoiceProcessing(uint32 LocalUserNum) 
{
	uint32 Return = E_FAIL;
	if (IsOwningUser(LocalUserNum))
	{
		if (!bIsCapturing)
		{
			// Update the current recording state, if VOIP data was still being read
			VoiceCaptureUpdate();

			if (!IsRecording())
			{
				StartRecording();
			}

			bIsCapturing = true;
		}

		Return = S_OK;
	}
	else
	{
		UE_LOG(LogVoiceEncode, Error, TEXT("StartLocalVoiceProcessing(): Device is currently owned by another user"));
	}

	return Return;
}
Exemplo n.º 6
0
void GOrgueMidiRecorder::UpdateDisplay()
{
	if (!IsRecording())
		m_RecordingTime.SetContent(_("-:--:--"));
	else
		m_RecordingTime.SetContent(wxString::Format(_("%d:%02d:%02d"), m_RecordSeconds / 3600, (m_RecordSeconds / 60) % 60, m_RecordSeconds % 60));
}
Exemplo n.º 7
0
void CameraObject::VideoUpdatedSlot()
{
    if( IsRecording() && GetState() == Ok )
    {
        m_recordingCamera->AddFrame( GetVideoOutput(), GetUncalibratedTransform()->GetMatrix() );
    }

    // Update representation if image size changed
    if( GetImageWidth() != m_cachedImageSize[0] || GetImageHeight() != m_cachedImageSize[1] )
        UpdateGeometricRepresentation();

    // Get the position of the transparency center from projection of the tracked pointer
    if( m_trackedTransparencyCenter )
    {
        Q_ASSERT( this->GetManager() );
        PointerObject * navPointer = this->GetManager()->GetNavigationPointerObject();
        if( navPointer )
        {
            // Get world space position of the tip
            double * tip = navPointer->GetTipPosition();
            double cx, cy;
            WorldToImage( tip, cx, cy );

            // Set new center for transparency
            SetTransparencyCenter( cx / GetImageWidth(), cy / GetImageHeight() );
        }
    }

    UpdateVtkCamera();

    emit VideoUpdatedSignal();
    emit ObjectModified();
}
Exemplo n.º 8
0
void csMovieRecorder::ClockAdvance ()
{
  csTicks lastFakeClockTicks = fakeClockTicks;
  realVirtualClock->Advance();
  csTicks realTicksPerFrame = realVirtualClock->GetElapsedTicks();

  /*
    To avoid 'jumps' in time when the clock is throttled/unthrottled
    we keep our own tick counter, which is either increased by the
    real elapsed time (normal mode) or the required frame time (recording).
   */
  if (!IsRecording() || IsPaused()) {
    fakeClockElapsed = realTicksPerFrame;
    fakeClockTicks += realTicksPerFrame;
  }
  else {
    ffakeClockTicks += fakeTicksPerFrame;
    fakeClockTicks = (csTicks)ffakeClockTicks;

    fakeClockElapsed = fakeClockTicks - 
      lastFakeClockTicks;
    // If we're rendering slower than real time, there's nothing we can do about it.
    // If we're rendering faster, put in a little delay here.
    if (throttle && ((fakeClockElapsed > realTicksPerFrame)))
    {
      csSleep(fakeClockElapsed - realTicksPerFrame);
    }
  } 
}
Exemplo n.º 9
0
void csMovieRecorder::Pause(void) 
{
  if (!IsRecording())
    return;
  paused = true;
  Report (CS_REPORTER_SEVERITY_NOTIFY, "Video recorder paused - %s", 
    movieFileName.GetData());
}
Exemplo n.º 10
0
// Writing is from the perspective of the host: this method handles
// incoming data from the host.
USB_PUBLIC uchar usbFunctionWrite(uchar *data, uchar len) {
  uchar i;

  if (currentRequest == WL_REQUEST_SET_WEBUSB_URLS) {
    eeprom_update_block(data,
                        EEPROM_WEBUSB_URLS_START + currentPosition, len);
    currentPosition += len;
    bytesRemaining -= len;
    return bytesRemaining == 0;
  }

  if (len > bytesRemaining) {
    len = bytesRemaining;
  }
  bytesRemaining -= len;
  for (i = 0; i < len; i++) {
    buffer[currentPosition++] = data[i];
  }

  if (bytesRemaining == 0) {
    switch (currentRequest) {
    case WL_REQUEST_COLOR:
      if (!IsRecording()) {
        Stop();
      }
      HandleTRANSITION(NONE, 0);
      HandleCOLOR(buffer[0], buffer[1], buffer[2]);
      break;
    case WL_REQUEST_PAUSE:
      if (IsRecording()) {
        HandlePAUSE((buffer[0] << 8) | buffer[1]);
      } else {
        // This doesn't make sense interactively. Ignore.
      }
      break;
    case WL_REQUEST_TRANSITION:
      if (!IsRecording()) {
        Stop();
      }
      HandleTRANSITION(buffer[0], (buffer[1] << 8) | buffer[2]);
      break;
    }
  }

  return bytesRemaining == 0;             // return 1 if we have all data
}
Exemplo n.º 11
0
void VideoInput::Stop()
{
    if(IsRecording()) {
        video_recorder.release();
    }else{
        video_src->Stop();
    }
}
Exemplo n.º 12
0
void GOrgueMidiRecorder::SendEvent(GOrgueMidiEvent& e)
{
	e.SetDevice(m_OutputDevice);
	if (m_OutputDevice)
		m_organfile->SendMidiMessage(e);
	if (IsRecording())
		WriteEvent(e);
}
Exemplo n.º 13
0
void csMovieRecorder::UnPause(void)
{
  if (!IsRecording())
    return;
  paused = false;
  ffakeClockTicks = fakeClockTicks;
  Report (CS_REPORTER_SEVERITY_NOTIFY, "Video recorder unpaused - %s", 
    movieFileName.GetData());
}
Exemplo n.º 14
0
void CHLTVDemoRecorder::RecordCommand( const char *cmdstring )
{
	if ( !IsRecording() )
		return;

	if ( !cmdstring || !cmdstring[0] )
		return;

	m_DemoFile.WriteConsoleCommand( cmdstring, GetRecordingTick() );
}
Exemplo n.º 15
0
/*
** ToggleRecording
*/
void
ACMIRecorder::ToggleRecording( void )
{
	F4EnterCriticalSection( _csect );
	if ( IsRecording() )
		StopRecording();
	else
		StartRecording();
	F4LeaveCriticalSection( _csect );
}
FString FVoiceEngineSteam::GetVoiceDebugState() const 
{
	FString Output;
	Output = FString::Printf(TEXT("IsRecording: %d\n DataReady: 0x%08x State:%s\n BufferRemaining: %d\n"),
		IsRecording(), 
		GetVoiceDataReadyFlags(),
		*SteamVoiceResult(AvailableVoiceResult),
		CompressedVoiceBuffer.Num()
		);

	return Output;
}
Exemplo n.º 17
0
void GOrgueMidiRecorder::SendMidiRecorderMessage(GOrgueMidiEvent& e)
{
	if (!m_OutputDevice && !IsRecording())
		return;
	if (!SetupMapping(e.GetDevice(), e.GetMidiType() == MIDI_NRPN))
		return;

	e.SetTime(wxGetLocalTimeMillis());
	e.SetChannel(m_Mappings[e.GetDevice()].channel);
	if (e.GetMidiType() == MIDI_NRPN)
		e.SetKey(m_Mappings[e.GetDevice()].key);

	SendEvent(e);
}
uint32 FVoiceEngineSteam::GetVoiceDataReadyFlags() const 
{
	// First check and update the internal state of VOIP recording
	VoiceCaptureUpdate();
	if (OwningUserIndex != INVALID_INDEX && IsRecording())
	{
		// Check if there is new data available via the Steam API
		if (AvailableVoiceResult == k_EVoiceResultOK && CompressedBytesAvailable > 0)
		{
			return 1 << OwningUserIndex;
		}
	}

	return 0;
}
Exemplo n.º 19
0
bool FVisualLogger::IsCategoryLogged(const struct FLogCategoryBase& Category) const
{
	if ((GEngine && GEngine->bDisableAILogging) || IsRecording() == false)
	{
		return false;
	}

	const FName CategoryName = Category.GetCategoryName();
	if (IsBlockedForAllCategories() && IsWhiteListed(CategoryName) == false)
	{
		return false;
	}

	return true;
}
Exemplo n.º 20
0
LRESULT	CMainFrame::OnHotKey(WPARAM wParam, LPARAM lParam)
{
	if (m_Options.m_Record.ActivationType == CRecordDlg::ACT_PROMPT) {
		if (IsIconic())	// if minimized
			ShowWindow(SW_RESTORE);	// restore so prompts are visible
	}
	switch (wParam) {
	case RECORD_PARMS::HK_START:
		Record(TRUE);	// start recording
		break;
	case RECORD_PARMS::HK_STOP:
		if (IsRecording()) {
			m_RecordDlg->Stop(CRecordDlg::SF_DEFAULT	// stop recording
				& ~CRecordDlg::SF_OPEN_RECORDING);	// don't open recording
		}
		break;
	}
	return(0);
}
Exemplo n.º 21
0
FString FVoiceEngineImpl::GetVoiceDebugState() const
{
	FString Output;
	Output = FString::Printf(TEXT("IsRecording: %d\n DataReady: 0x%08x State:%s\n UncompressedBytes: %d\n CompressedBytes: %d\n"),
		IsRecording(), 
		GetVoiceDataReadyFlags(),
		EVoiceCaptureState::ToString(AvailableVoiceResult),
		UncompressedBytesAvailable,
		CompressedBytesAvailable
		);

	// Add remainder size
	for (int32 Idx=0; Idx < MAX_SPLITSCREEN_TALKERS; Idx++)
	{
		Output += FString::Printf(TEXT("Remainder[%d] %d\n"), Idx, PlayerVoiceData[Idx].VoiceRemainderSize);
	}

	return Output;
}
Exemplo n.º 22
0
void Movie::AddFrame(FrameType ftype)
{
	if (!IsRecording())
		return;
	if (!av->inited)
	{
	  if (ftype == FRAME_FADE)
	    return;
	  if (!Setup())
	    return;
	}
	
	if (ftype == FRAME_FADE && get_keyboard_controller_status())
		return;
	
	SDL_SemWait(fillReady);
  	
	if (!MainScreenIsOpenGL())
	{
		SDL_Surface *video = MainScreenSurface();
		SDL_BlitSurface(video, &view_rect, temp_surface, NULL);
	}
#ifdef HAVE_OPENGL
	else
	{
		// Read OpenGL frame buffer
		glReadPixels(view_rect.x, view_rect.y, view_rect.w, view_rect.h, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, &videobuf.front());
		
		// Copy pixel buffer (which is upside-down) to surface
		for (int y = 0; y < view_rect.h; y++)
			memcpy((uint8 *)temp_surface->pixels + temp_surface->pitch * y, &videobuf.front() + view_rect.w * 4 * (view_rect.h - y - 1), view_rect.w * 4);
	}
#endif
	
	int audio_bytes_per_frame = audiobuf.size();
	Mixer *mx = Mixer::instance();
	int old_vol = mx->main_volume;
	mx->main_volume = 0x100;
	mx->Mix(&audiobuf.front(), audio_bytes_per_frame / 4, true, true, true);
	mx->main_volume = old_vol;
	
	SDL_SemPost(encodeReady);
}
Exemplo n.º 23
0
void AmInputTarget::HandleEvents(AmEvent* events)
{
	mQueue->Lock();
	if (mQueue->IsPerforming() && IsPerforming()) {
		mQueue->Unlock();
		mQueue->PerformEvents(mTrack, events->CopyChain());
		mQueue->Lock();
	}
	
	if (!mQueue->IsRecording() || !IsRecording()) {
		mQueue->Unlock();
		//printf("Dropping record:\n"); events->PrintChain();
		events->DeleteChain();
		return;
	}
	
	mQueue->Unlock();
	mQueue->RecordEvents(mTrack, events);
}
Exemplo n.º 24
0
void GOrgueMidiRecorder::WriteEvent(GOrgueMidiEvent& e)
{
	if (!IsRecording())
		return;
	std::vector<std::vector<unsigned char>> msg;
	e.ToMidi(msg, m_Map);
	for(unsigned i = 0; i < msg.size(); i++)
	{
		EncodeLength((e.GetTime() - m_Last).GetValue());
		if (msg[i][0] == 0xF0)
		{
			Write(&msg[i][0], 1);
			EncodeLength(msg[i].size() - 1);
			Write(&msg[i][1], msg[i].size() - 1);
		}
		else
			Write(&msg[i][0], msg[i].size());
		m_Last = e.GetTime();
	}
}
Exemplo n.º 25
0
bool csMovieRecorder::HandleEndFrame (iEvent& /*event*/)
{
  if (IsRecording() && !IsPaused()) {
    csRef<iImage> img (csPtr<iImage> (G2D->ScreenShot ()));

    csTicks ticks = csGetTicks();
    csTicks thisFrameTime = ticks - frameStartTime;

    if (!img) {
      Report (CS_REPORTER_SEVERITY_ERROR, "This video driver doesn't support screen capture.");
      Stop();
      return false;
    }

    // If we're recording to a different resolution, try to scale the image
    if (img->GetWidth() != writer->width || img->GetHeight() != writer->height) {
      img = csImageManipulate::Rescale (img, writer->width, writer->height);
    }

    numFrames++;

    csTicks encodeTime, writeTime;
    unsigned char *buffer = (unsigned char *) img->GetImageData();
    writer->writeFrame(buffer, encodeTime, writeTime);

    totalFrameTime += thisFrameTime;
    minFrameTime = MIN (minFrameTime, thisFrameTime);
    maxFrameTime = MAX (maxFrameTime, thisFrameTime);

    totalFrameEncodeTime += encodeTime;
    minFrameEncodeTime = MIN (minFrameEncodeTime, encodeTime);
    maxFrameEncodeTime = MAX (maxFrameEncodeTime, encodeTime);

    totalWriteToDiskTime += writeTime;
    minWriteToDiskTime = MIN (minWriteToDiskTime, writeTime);
    maxWriteToDiskTime = MAX (maxWriteToDiskTime, writeTime);
  }

  return false;
}
Exemplo n.º 26
0
void csMovieRecorder::Start(void) 
{
  SetupPlugin();

  if (IsPaused()) {
    UnPause();
    return;
  }
  if (IsRecording())
    Stop();

  movieFileName = recordingFile != "" ? recordingFile : captureFormat.FindNextFilename (VFS);

  // If the config specified 0x0, that means we use the current resolution unscaled
  int w = recordWidth  ? recordWidth  : G2D->GetWidth();
  int h = recordHeight ? recordHeight : G2D->GetHeight();

  numFrames = 0;
  totalFrameEncodeTime = totalFrameTime = totalWriteToDiskTime = 0;
  minFrameEncodeTime = minFrameTime = minWriteToDiskTime = (csTicks)-1;
  maxFrameEncodeTime = maxFrameTime = maxWriteToDiskTime = 0;

  movieFile = VFS->Open (movieFileName, VFS_FILE_WRITE | VFS_FILE_UNCOMPRESSED);
  if (!movieFile)
  {
    Report (CS_REPORTER_SEVERITY_WARNING,
    	"Couldn't open file %s for recording", CS::Quote::Single (movieFileName.GetData()));
    return;
  }
  fakeTicksPerFrame = (1000 / frameRate);
  ffakeClockTicks = fakeClockTicks;

  frameStartTime = csGetTicks();

  writer = new NuppelWriter(w, h, &WriterCallback, this, frameRate,
			    rtjQuality, useRTJpeg, useLZO, useRGB);

  Report (CS_REPORTER_SEVERITY_NOTIFY, "Video recorder started - %s", 
    movieFileName.GetData());
}
Exemplo n.º 27
0
void csMovieRecorder::Stop(void)
{
  if (IsRecording()) {
    delete writer;
    writer = 0;
    movieFile = 0;
    Report (CS_REPORTER_SEVERITY_NOTIFY, "Video recorder stopped - %s", 
      movieFileName.GetData());

    if (numFrames != 0)
    {
      float avgFrameEncodeTime = ((float)totalFrameEncodeTime / (float)numFrames);
      float avgWriteToDiskTime = ((float)totalWriteToDiskTime / (float)numFrames);
      float avgFrameTime = ((float)totalFrameTime / (float)numFrames);
      
      Report (CS_REPORTER_SEVERITY_NOTIFY, 
	"Video recording statistics for %s:\n"
	" Number of frames: %d\n"
	" Time spent for:\n"
	"  encoding image data - total: %.3fs, per frame: %zu min/%g avg/%zu max ms\n"
	"  writing encoded data - total: %.3fs, per frame: %zu min/%g avg/%zu max ms\n"
	"  drawing frame - total: %.3fs, per frame: %zu min/%g avg/%zu max ms\n"
	"\n"
	" Frame time in relation to real time: x%.4f\n"
	" Theoretical video FPS recordable in real-time: %.2f\n",
	movieFileName.GetData(), 
	numFrames,
	((float)totalFrameEncodeTime / 1000.0f),
	  minFrameEncodeTime, avgFrameEncodeTime, maxFrameEncodeTime,
	((float)totalWriteToDiskTime / 1000.0f),
	  minWriteToDiskTime, avgWriteToDiskTime, maxWriteToDiskTime,
	((float)totalFrameTime / 1000.0f),
	  minFrameTime, avgFrameTime, maxFrameTime,
	((avgFrameEncodeTime + avgWriteToDiskTime + avgFrameTime) * 
	  frameRate) / 1000.0f,
	1000.0f / (avgFrameEncodeTime + avgWriteToDiskTime + avgFrameTime)
      );
    }
  }
}
Exemplo n.º 28
0
void UActorRecording::Tick(float DeltaSeconds, ULevelSequence* CurrentSequence, float CurrentSequenceTime)
{
	if (IsRecording())
	{
		if(CurrentSequence)
		{
			// check our components to see if they have changed
			static TArray<USceneComponent*> SceneComponents;
			GetSceneComponents(SceneComponents);

			if(TrackedComponents.Num() != SceneComponents.Num())
			{
				StartRecordingNewComponents(CurrentSequence, CurrentSequenceTime);
			}
		}

		for(auto& SectionRecorder : SectionRecorders)
		{
			SectionRecorder->Record(CurrentSequenceTime);
		}
	}
}
Exemplo n.º 29
0
void ProjectionFixed::ModifyProjection()
{
	for(int i=0;i<m_events.size();i++)
	{
		if(m_events[i]->IsOn())
			m_events[i]->Modify();

	}

	// record new weights if storing on evolution of weights

	if(IsRecording() && m_storeSamplingWeightsEvolution>0)
	{
		if(m_storeSamplingCounter % m_storeSamplingWeightsEvolution == 0)
		{
			m_storeSamplingCounter=0;

			// append
			for(int i=0;i<this->GetPostIds().size();i++)
			{
				long postId = this->GetPostIds()[i];
				vector<long> preIds = this->GetPreIds(postId);
				vector<float> ws(preIds.size());

				for(int j=0;j<preIds.size();j++)
				{
					ws[j] = m_network->GetWeight(preIds[j],postId);
				}

				m_recordedValues.push_back(ws);
			}
		}

		m_storeSamplingCounter++;
	}
}
uint32 FVoiceEngineSteam::ReadLocalVoiceData(uint32 LocalUserNum, uint8* Data, uint32* Size) 
{
	check(*Size > 0);

	// Before doing anything, check/update the current recording state
	VoiceCaptureUpdate();

	// Return data even if not capturing, if the final half-second of data from Steam is still pending
	if (IsOwningUser(LocalUserNum) && IsRecording())
	{
		CompressedVoiceBuffer.Empty(MAX_COMPRESSED_VOICE_BUFFER_SIZE);

		uint32 CompressedBytes = 0;
		EVoiceResult VoiceResult = SteamUserPtr->GetAvailableVoice(&CompressedBytes, NULL, 0);
		if (VoiceResult != k_EVoiceResultOK && VoiceResult != k_EVoiceResultNoData)
		{
			UE_LOG(LogVoiceEncode, Warning, TEXT("ReadLocalVoiceData: GetAvailableVoice failure: VoiceResult: %s"), *SteamVoiceResult(VoiceResult));
			return E_FAIL;
		}

		// This shouldn't happen, but just in case.
		if (CompressedBytes == 0)
		{
			UE_LOG(LogVoiceEncode, VeryVerbose, TEXT("ReadLocalVoiceData: No Data: VoiceResult: %s"), *SteamVoiceResult(VoiceResult));
			*Size = 0;
			return S_OK;
		}

		// Update the amount of data available for consumption (CompressedBytes can be more than AvailableWritten below)
		CompressedVoiceBuffer.AddUninitialized(CompressedBytes);

		uint32 AvailableWritten = 0;
		VoiceResult = SteamUserPtr->GetVoice(true, CompressedVoiceBuffer.GetData(), CompressedVoiceBuffer.Num(), &AvailableWritten, false, NULL, 0, NULL, 0);

		static double LastGetVoiceCallTime = 0.0;
		double CurTime = FPlatformTime::Seconds();
		double TimeSinceLastCall = LastGetVoiceCallTime > 0 ? (CurTime - LastGetVoiceCallTime) : 0.0;
		LastGetVoiceCallTime = CurTime;

		UE_LOG(LogVoiceEncode, Log, TEXT("ReadLocalVoiceData: GetVoice: Result: %s, Available: %i, LastCall: %0.3f"), *SteamVoiceResult(VoiceResult), AvailableWritten, TimeSinceLastCall);
		if (VoiceResult != k_EVoiceResultOK)
		{
			UE_LOG(LogVoiceEncode, Warning, TEXT("ReadLocalVoiceData: GetVoice failure: VoiceResult: %s"), *SteamVoiceResult(VoiceResult));
			*Size = 0;
			CompressedVoiceBuffer.Empty(MAX_COMPRESSED_VOICE_BUFFER_SIZE);
			return E_FAIL;
		}

		if (AvailableWritten > 0)
		{
			*Size = FMath::Min<int32>(*Size, AvailableWritten);
			FMemory::Memcpy(Data, CompressedVoiceBuffer.GetData(), *Size);

			UE_LOG(LogVoiceEncode, VeryVerbose, TEXT("ReadLocalVoiceData: Size: %d"), *Size);
			return S_OK;
		}
		else
		{
			*Size = 0;
		}
	}

	return E_FAIL;
}