# Trying to play a Voice Data stream using a ByteArray in Unreal Engine 5

**URL:** <https://qa.fmod.com/t/trying-to-play-a-voice-data-stream-using-a-bytearray-in-unreal-engine-5/21306>\
**Category:** Unreal Engine\
**Tags:** cpp, ue5\
**Created:** [February 29, 2024, 1:39pm UTC](https://qa.fmod.com/t/trying-to-play-a-voice-data-stream-using-a-bytearray-in-unreal-engine-5/21306 "2024-02-29T13:39:45Z")\
**Posts on this page:** 14\
**Page:** 1

<div class="post-metadata">

**Author:** ![RobPotter](https://avatars.discourse-cdn.com/v4/letter/r/5daacb/32.png) [@RobPotter](https://qa.fmod.com/u/RobPotter)\
**Post date:** [February 29, 2024, 1:39pm UTC](https://qa.fmod.com/t/trying-to-play-a-voice-data-stream-using-a-bytearray-in-unreal-engine-5/21306/1 "2024-02-29T13:39:45Z")

</div>

Hello! I’m new to programming for FMOD (and just generally not that good at c++ programming) and so far I’ve managed to get the following:

```auto
void AProgrammerSoundTest::PlayVoiceAudio(UFMODAudioComponent* AudioComponent, const TArray<uint8>& ByteArray, UVoipAudioComponent* VoipAudioComponent)
{
	UncompressedVoiceData = VoipAudioComponent->GetDecodedVoiceData(ByteArray);
	
	if (AudioComponent)
	{
		const FMOD::Studio::System* System = IFMODStudioModule::Get().GetStudioSystem(EFMODSystemContext::Runtime);
		FMOD::System* CoreSystem = nullptr;
		System->getCoreSystem(&CoreSystem);
		
		FMOD::Sound* Sound = nullptr;

		FMOD_CREATESOUNDEXINFO soundExInfo = { 0 };
		soundExInfo.cbsize = sizeof(soundExInfo);
		soundExInfo.format = FMOD_SOUND_FORMAT_PCM16;
		soundExInfo.defaultfrequency = 16000;
		soundExInfo.numchannels = 1;
		soundExInfo.length = VoipAudioComponent->BytesWrittenPub;
		
		soundExInfo.pcmreadcallback = PCMReadCallback;
		
		const FMOD_RESULT result = CoreSystem->createStream("", FMOD_OPENUSER | FMOD_LOOP_OFF , &soundExInfo, &Sound);
		
		if (result == FMOD_OK)
		{
			AudioComponent->SetProgrammerSound(Sound);
			AudioComponent->Play();
		}
	}
}

FMOD_RESULT F_CALLBACK PCMReadCallback(FMOD_SOUND* Sound, void *data, unsigned int datalen)
{
	FMemory::Memcpy(data, &AProgrammerSoundTest::UncompressedVoiceData[0], datalen);
	return FMOD_OK;
}

```

After bashing my head against a wall for many hours the above is the result - it manages to play the data but the output is choppy and robotic. Beforehand is was just pure noise so this is a big improvement. I just can’t figure out the next step. Could anyone highlight where I’m going wrong or perhaps some missteps I’ve already made?  
For some added context I’m passing this function a compressed byte array and a component. The component (“VoipAudioComponent”) helps me decompress the byte array. I then attempt to use that with fmod via a programmer sound. The byte array and component are passed to this function in blueprints.

Thanks in advance!

---

<div class="post-metadata">

**Author:** ![Connor\_FMOD](https://yyz2.discourse-cdn.com/flex036/user_avatar/qa.fmod.com/connor_fmod/32/3685_2.png) [@Connor\_FMOD](https://qa.fmod.com/u/Connor_FMOD)\
**Post date:** [March 1, 2024, 4:28am UTC](https://qa.fmod.com/t/trying-to-play-a-voice-data-stream-using-a-bytearray-in-unreal-engine-5/21306/2 "2024-03-01T04:28:53Z")

</div>

Hi,

What version of the FMOD integration are you using?

Would it be possible to get a copy of your project or a stripped-down version displaying the issue [uploaded](https://fmod.com/profile#uploads) to your [profile](https://fmod.com/profile)? Please note you must register a project with us before uploading files.

---

<div class="post-metadata">

**Author:** ![RobPotter](https://avatars.discourse-cdn.com/v4/letter/r/5daacb/32.png) [@RobPotter](https://qa.fmod.com/u/RobPotter)\
**Post date:** [March 1, 2024, 5:38pm UTC](https://qa.fmod.com/t/trying-to-play-a-voice-data-stream-using-a-bytearray-in-unreal-engine-5/21306/3 "2024-03-01T17:38:22Z")

</div>

Hi Connor!  
I’m using 2.02.20. I’ve uploaded the project to my profile (Pilgrim\_FMOD\_Upload.zip).

After more head bashing today I’ve still not figured it out and have distilled my current “working” code to a very simple component called FmodVoice that is in the CH\_Character. In the CH\_Character there is a voice graph where the PlayVoiceAudioNew function is called.  
You can test to see if it’s working when speaking into a mic in the L\_VoiceTest map  
(found in Temp/Levels)  
In C++ the PlayVoiceAudioNew gets the DeCompressed PCM data from the VoipManager component (also in the CH\_Character) this is a marketplace plugin that I’m using to handle the voip.  
The problem is still that it sounds choppy and robotic. I’ve looked at the various examples in the API both user created sound the record one. But even when trying to recreate what the examples do in my own project I can’t seem to get it to work - I must be too thick to figure it out!  
Worth noting too that at one point I added in a \_Sleep(200) and that did the trick apart from lagging the game out. So went down that route for a while of introducing buffers and delays. Still no luck!

Thanks a lot for your help 🙂

---

<div class="post-metadata">

**Author:** ![Connor\_FMOD](https://yyz2.discourse-cdn.com/flex036/user_avatar/qa.fmod.com/connor_fmod/32/3685_2.png) [@Connor\_FMOD](https://qa.fmod.com/u/Connor_FMOD)\
**Post date:** [March 7, 2024, 2:02am UTC](https://qa.fmod.com/t/trying-to-play-a-voice-data-stream-using-a-bytearray-in-unreal-engine-5/21306/4 "2024-03-07T02:02:37Z")

</div>

Hi,

Thank you for the project.

An issue may be that you are passing the voice data straight to the sound without any drift compensation, resulting in the popping.

We have an example of [Video Playback](https://fmod.com/docs/2.02/unity/examples-video-playback.html) in Unity which shows how to implement drift compensation. This will have to be slightly modified for C++ and UE.

You will want to replace the `SamplesFramesAvailable` buffer with the data received from the VOIP.

Let me know how you go implementing drift compensation and if there is anything I can assist with please do not hesitate to ask!

---

<div class="post-metadata">

**Author:** ![RobPotter](https://avatars.discourse-cdn.com/v4/letter/r/5daacb/32.png) [@RobPotter](https://qa.fmod.com/u/RobPotter)\
**Post date:** [March 7, 2024, 4:13pm UTC](https://qa.fmod.com/t/trying-to-play-a-voice-data-stream-using-a-bytearray-in-unreal-engine-5/21306/5 "2024-03-07T16:13:01Z")

</div>

Thanks for taking a look at it!  
I’ve combed over the example and tried to implement it. But I still get more of the same crackling/popping and now I also get looped weirdness with the end of the audio repeating. If you wouldn’t mind taking another look at my latest attempt that would be amazing?

```auto
#include "FmodVoice.h"

FMOD_RESULT F_CALLBACK PCMReadCallback(FMOD_SOUND* sound, void *data, unsigned int datalen);

const int LATENCY_MS = 50;
const int DRIFT_MS = 1;
const float DRIFT_CORRECTION_PERCENTAGE = 0.5f;

FMOD::Channel* Channel = nullptr;
static inline TArray<uint8> Buffer;
FMOD::Sound* Sound = nullptr;
int SampleRate = 16000;
uint32 DriftThreshold;
uint32 TargetLatency;
uint32 AdjustedLatency;
uint32 ActualLatency;

uint32 TotalSamplesWritten;
uint32 MinimumSamplesWritten = UINT32_MAX;

uint32 LastReadPosition;
uint32 TotalSamplesRead;
const FMOD::Studio::System* System;
FMOD::System* CoreSystem = nullptr;

FMOD_CREATESOUNDEXINFO soundExInfo = { 0 };

UVoipManagerComponent* VOIP;

UFmodVoice::UFmodVoice()
{
	PrimaryComponentTick.bCanEverTick = true;
}

void UFmodVoice::BeginPlay()
{
	Super::BeginPlay();
	System = IFMODStudioModule::Get().GetStudioSystem(EFMODSystemContext::Runtime);
	
	System->getCoreSystem(&CoreSystem);
		
	DriftThreshold = static_cast<uint32>(SampleRate * DRIFT_MS) / 1000;
	TargetLatency = static_cast<uint32>(SampleRate * LATENCY_MS) / 1000;
	AdjustedLatency = TargetLatency;
	ActualLatency = static_cast<int>(TargetLatency);
	
	soundExInfo.cbsize = sizeof(soundExInfo);
	soundExInfo.format = FMOD_SOUND_FORMAT_PCM16;
	soundExInfo.defaultfrequency = SampleRate;
	soundExInfo.numchannels = 1;
	soundExInfo.length = TargetLatency * sizeof(uint8);
	soundExInfo.pcmreadcallback = PCMReadCallback;		
}

void UFmodVoice::BeginDestroy()
{
	Super::BeginDestroy();
	Channel->stop();
	Sound->release();
}

void UFmodVoice::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
{
	Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
	if (VOIP)
	{
		Buffer = VOIP->DecompressedVoiceBuffer;
	
		if (!Channel && TotalSamplesWritten > AdjustedLatency)
		{
			const FMOD_RESULT result = CoreSystem->createSound("", FMOD_OPENUSER | FMOD_LOOP_NORMAL , &soundExInfo, &Sound);
			CoreSystem->playSound(Sound, nullptr, false, &Channel);
		}

		if (Buffer.Num() > 0 && Channel)
		{
			uint32 readPosition;
			Channel->getPosition(&readPosition, FMOD_TIMEUNIT_PCMBYTES);
			UE_LOG(LogTemp, Warning, TEXT("Channel read position: %d"), readPosition);
			/*
			 * Account for wrapping
			 */
			int bytesRead = readPosition - LastReadPosition;
			if (readPosition < LastReadPosition)
			{
				bytesRead += soundExInfo.length;
			}

			if (bytesRead > 0 && Buffer.Num() >= bytesRead)
			{
				/*
				 * Fill previously read data with fresh samples
				 */
				void* ptr1;
				void* ptr2;
				uint32 len1, len2;              

				FMOD_RESULT result = Sound->lock(LastReadPosition, bytesRead, &ptr1, &ptr2, &len1, &len2);
            	
				if (result != FMOD_OK) UE_LOG(LogTemp, Warning, TEXT("VOIP Manager Size: %d"), result);
            	
				int sampleLen1 = static_cast<int>(len1 / sizeof(uint8));
				int sampleLen2 = static_cast<int>(len2 / sizeof(uint8));
				int samplesRead = sampleLen1 + sampleLen2;
				TArray<uint8> tmpBuffer;
            	
				tmpBuffer.Init(0, samplesRead);
				tmpBuffer.SetNum(Buffer.Num(), false);
            	
				// Directly copy the data from Buffer to tmpBuffer using FMemory::Memcpy
				if (Buffer.Num() > 0 && samplesRead <= Buffer.Num())
				{
					FMemory::Memcpy(tmpBuffer.GetData(), Buffer.GetData(), samplesRead);
				}
            	
				// Remove the copied range from mBuffer
				Buffer.RemoveAt(0, tmpBuffer.Num());
            	
				if (len1 > 0)
				{
					// Directly copy from the start of tmpBuffer
					FMemory::Memcpy(ptr1, tmpBuffer.GetData(), sampleLen1);
				}
				if (len2 > 0)
				{
					// Calculate the start index for the second copy by offsetting the source pointer
					// Note: This assumes sampleLen1 is the byte offset to start from for the second copy
					uint8* sourcePtrOffset = tmpBuffer.GetData() + sampleLen1;
					FMemory::Memcpy(ptr2, sourcePtrOffset, sampleLen2);
				}
            	
				result = Sound->unlock(ptr1, ptr2, len1, len2);
            	
				if (result != FMOD_OK) UE_LOG(LogTemp, Warning, TEXT("VOIP Manager Size: %d"), result);
				LastReadPosition = readPosition;
				TotalSamplesRead += static_cast<uint32>(samplesRead);
			}
		}

		//Drift compensation
		uint32 samplesWritten = Buffer.Num();

		TotalSamplesWritten += samplesWritten;

		if (samplesWritten != 0 && samplesWritten < MinimumSamplesWritten)
		{
			MinimumSamplesWritten = samplesWritten;
			AdjustedLatency = FMath::Max(samplesWritten, TargetLatency);
		}

		int32 latency = TotalSamplesWritten - TotalSamplesRead;
		ActualLatency = static_cast<uint32>((0.93f * ActualLatency) + (0.03f * latency));

	
		int32 PlaybackRate = SampleRate;
		if (ActualLatency < (AdjustedLatency - DriftThreshold))
		{
			PlaybackRate = SampleRate - static_cast<int32>(SampleRate * (DRIFT_CORRECTION_PERCENTAGE / 100.0f));
		}
		else if (ActualLatency > (AdjustedLatency + DriftThreshold))
		{
			PlaybackRate = SampleRate + static_cast<int32>(SampleRate * (DRIFT_CORRECTION_PERCENTAGE / 100.0f));
		}
		Channel->setFrequency(PlaybackRate);
	}
}

void UFmodVoice::InitComponent(UFMODAudioComponent* fmodAudioComponent, UVoipManagerComponent* VoipManager)
{
	VOIP = VoipManager;
}

FMOD_RESULT F_CALLBACK PCMReadCallback(FMOD_SOUND* sound, void *data, unsigned int datalen) {
	//FMemory::Memcpy(data, &UFmodVoice::UncompressedVoiceData[0], datalen);
	return FMOD_OK;
}

```

Thanks again!

---

<div class="post-metadata">

**Author:** ![Connor\_FMOD](https://yyz2.discourse-cdn.com/flex036/user_avatar/qa.fmod.com/connor_fmod/32/3685_2.png) [@Connor\_FMOD](https://qa.fmod.com/u/Connor_FMOD)\
**Post date:** [March 15, 2024, 4:03am UTC](https://qa.fmod.com/t/trying-to-play-a-voice-data-stream-using-a-bytearray-in-unreal-engine-5/21306/6 "2024-03-15T04:03:07Z")

</div>

Hi,

Apologies for the delayed response. Thank you for the updated code, I am working on the issue. Once I have an update I will post it here.

---

<div class="post-metadata">

**Author:** ![RobPotter](https://avatars.discourse-cdn.com/v4/letter/r/5daacb/32.png) [@RobPotter](https://qa.fmod.com/u/RobPotter)\
**Post date:** [March 15, 2024, 5:04pm UTC](https://qa.fmod.com/t/trying-to-play-a-voice-data-stream-using-a-bytearray-in-unreal-engine-5/21306/7 "2024-03-15T17:04:55Z")

</div>

Hi Cornnor, no worries! Thank you very much for taking the time to work on the issue. It’s very much appreciated!

---

<div class="post-metadata">

**Author:** ![Connor\_FMOD](https://yyz2.discourse-cdn.com/flex036/user_avatar/qa.fmod.com/connor_fmod/32/3685_2.png) [@Connor\_FMOD](https://qa.fmod.com/u/Connor_FMOD)\
**Post date:** [March 27, 2024, 1:06am UTC](https://qa.fmod.com/t/trying-to-play-a-voice-data-stream-using-a-bytearray-in-unreal-engine-5/21306/8 "2024-03-27T01:06:45Z")

</div>

Hi,

Thank you for your patience. I have other users also experiencing a similar issue so I am working to find a solution that will hopefully help everyone. Once I have some updates I will post them here!

---

<div class="post-metadata">

**Author:** ![RobPotter](https://avatars.discourse-cdn.com/v4/letter/r/5daacb/32.png) [@RobPotter](https://qa.fmod.com/u/RobPotter)\
**Post date:** [March 27, 2024, 10:03am UTC](https://qa.fmod.com/t/trying-to-play-a-voice-data-stream-using-a-bytearray-in-unreal-engine-5/21306/9 "2024-03-27T10:03:54Z")

</div>

Hi Connor,

Really appreciate the work you’re doing! I’ve still not figured out a solution yet - put it on the back burner whilst I wait 🙂 Looking forward to seeing what you come up with!  
Thanks Again!

---

<div class="post-metadata">

**Author:** ![Connor\_FMOD](https://yyz2.discourse-cdn.com/flex036/user_avatar/qa.fmod.com/connor_fmod/32/3685_2.png) [@Connor\_FMOD](https://qa.fmod.com/u/Connor_FMOD)\
**Post date:** [April 9, 2024, 5:03am UTC](https://qa.fmod.com/t/trying-to-play-a-voice-data-stream-using-a-bytearray-in-unreal-engine-5/21306/10 "2024-04-09T05:03:34Z")

</div>

Hi,

Unfortunately, I have not been able to find a solution. However, there is a task to improve this workflow and I have noted your interest. Once there are updates I will post them here. Thank you again for your patience and I apologize that I can not assist further.

---

<div class="post-metadata">

**Author:** ![RobPotter](https://avatars.discourse-cdn.com/v4/letter/r/5daacb/32.png) [@RobPotter](https://qa.fmod.com/u/RobPotter)\
**Post date:** [April 10, 2024, 2:11pm UTC](https://qa.fmod.com/t/trying-to-play-a-voice-data-stream-using-a-bytearray-in-unreal-engine-5/21306/11 "2024-04-10T14:11:42Z")

</div>

Hi Connor, ah that’s quite the shame! Thanks for all your efforts though - were you getting some of the same results I decribed? I’ll have another crack at it and post any results.  
I know it’s been done before with this plugin for unity! If only there was one for Unreal.

> **[Dissonance For FMOD (Playback) | Integration | Unity Asset Store](https://assetstore.unity.com/packages/tools/integration/dissonance-for-fmod-playback-213415)**
>
> Use the Dissonance For FMOD (Playback) from Placeholder Software on your next project. Find this integration tool & more on the Unity Asset Store.

EDIT:  
This is the plugin for realtime voice - the above one is for playback I think

> **[Dissonance Voice Chat | Audio | Unity Asset Store](https://assetstore.unity.com/packages/tools/audio/dissonance-voice-chat-70078)**
>
> Get the Dissonance Voice Chat package from Placeholder Software and speed up your game development process. Find this & other Audio options on the Unity Asset Store.

So there must be a way 🙂

---

<div class="post-metadata">

**Author:** ![Connor\_FMOD](https://yyz2.discourse-cdn.com/flex036/user_avatar/qa.fmod.com/connor_fmod/32/3685_2.png) [@Connor\_FMOD](https://qa.fmod.com/u/Connor_FMOD)\
**Post date:** [April 11, 2024, 1:59am UTC](https://qa.fmod.com/t/trying-to-play-a-voice-data-stream-using-a-bytearray-in-unreal-engine-5/21306/12 "2024-04-11T01:59:59Z")

</div>

Hi,

> [@RobPotter](#):
>
> I’ll have another crack at it and post any results.

That will be greatly appreciated, any findings you make I will note in the task.

> [@RobPotter](#):
>
> were you getting some of the same results I decribed?

Yes, I was able to reproduce the issue exactly. Your project was vital in being able to do this.

There are a lot of other users experiencing the same issue, as I have noted on the task, if there are any updates I will let you know!

---

<div class="post-metadata">

**Author:** ![Connor\_FMOD](https://yyz2.discourse-cdn.com/flex036/user_avatar/qa.fmod.com/connor_fmod/32/3685_2.png) [@Connor\_FMOD](https://qa.fmod.com/u/Connor_FMOD)\
**Post date:** [April 12, 2024, 6:39am UTC](https://qa.fmod.com/t/trying-to-play-a-voice-data-stream-using-a-bytearray-in-unreal-engine-5/21306/13 "2024-04-12T06:39:05Z")

</div>

Hi, I will just post this here: [Vivox to Unity OnAudioFilterRead to FMOD programmer sound. Stutters/crackling - #15 by dougmolina](https://qa.fmod.com/t/vivox-to-unity-onaudiofilterread-to-fmod-programmer-sound-stutters-crackling/21235/15).

A user may have found a solution working with Vivox which may work with your approach. I have not had time to test it in Unreal Engine but I will continue investigating.

---

<div class="post-metadata">

**Author:** ![RobPotter](https://avatars.discourse-cdn.com/v4/letter/r/5daacb/32.png) [@RobPotter](https://qa.fmod.com/u/RobPotter)\
**Post date:** [April 12, 2024, 11:01pm UTC](https://qa.fmod.com/t/trying-to-play-a-voice-data-stream-using-a-bytearray-in-unreal-engine-5/21306/14 "2024-04-12T23:01:27Z")

</div>

Hi, thanks for linking me this! I’ve had a shot at implementing it for UE in c++ as close as I could and then a whole bunch of other ways - unfortunely it always seems to give the same result as I had before sadly.  
Thanks again for your time connor, I hope you have better luck! Really need this to work! There’s no solution at all for Unreal Engine at the moment.  
Cheers 🙂
