You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
#rb None #lockdown Nick.Penwarden ========================== MAJOR FEATURES + CHANGES ========================== Change 3021479 on 2016/06/21 by Marc.Audy Fix child actor properties set in the parent's construction script from being wiped out (4.12) #jira UE-31956 Change 3021703 on 2016/06/21 by Marc.Audy Fix crash due to copying properties to registered components and then reregistering them. (4.12) #jira UE-31973 Change 3022105 on 2016/06/21 by Jeremy.Ernst -new test assets for James for PSD node Change 3022621 on 2016/06/22 by James.Golding Add AnimBP for testing PSD Change 3022622 on 2016/06/22 by James.Golding Only restrict anim asset selection for UAnimGraphNode_AssetPlayerBase derived nodes Change 3022656 on 2016/06/22 by James.Golding UE-30537 Fix solid collision geom drawing not working when mirrored Change 3022657 on 2016/06/22 by James.Golding Don't crash in FAnimGraphNodeDetails::OnShouldFilterAnimAsset if AnimAsset doesn't have Skeleton asset registry tag (shouldn't happen, but shouldn't crash) Change 3022663 on 2016/06/22 by James.Golding UE-31283 Additional extensibility for anim and physics PR #2434: Morpheme integration changes (Contributed by NaturalMotionTechnology) Change 3022683 on 2016/06/22 by James.Golding - Change OrientationDriver to always use PoseAsset for target poses - Remove NumPoses from PoseAsset and use GetAssetRegistryTags instead Change 3022891 on 2016/06/22 by mason.seay Test asset for component hit Change 3023203 on 2016/06/22 by mason.seay Updated map to use more noticeable sound assets Change 3023335 on 2016/06/22 by Marc.Audy Use AddReferencedObjects instead of iterating array manuallly Change 3023351 on 2016/06/22 by Ori.Cohen Fix the case where physics hit events were passing the wrong component's bone info to the hit event. #JIRA UE-32376 Change 3023368 on 2016/06/22 by mason.seay Renamed actors in World Outliner Change 3023425 on 2016/06/22 by mason.seay Moved asset to new folder and fixed deprecated node Change 3023429 on 2016/06/22 by mason.seay Disabled collision on proc mesh Change 3023553 on 2016/06/22 by Jon.Nabozny Fix issue where MaxAngularVelocity resets to default on UPrimitiveComponent->BodyInstance. Replicated from CL 3009477. #JIRA UE-31670 Change 3024669 on 2016/06/23 by James.Golding Update PSD test assets (removing unused) Change 3024864 on 2016/06/23 by Marc.Audy Audio Threading! Change 3024877 on 2016/06/23 by James.Golding PR #2375: Allow the creation of custom IStreamingManager (Contributed by bozaro) Change 3024880 on 2016/06/23 by James.Golding PR #2209: Fix UGameplayStatics::*Game*Slot documentation (Contributed by Lectem) Change 3024939 on 2016/06/23 by James.Golding - Add SwingOnly options to OrientationDriver - Move EBoneAxis from AnimNode_RotationMultiplier.h to AnimTypes.h - Calculate gaussian radius per pose, not globally Change 3024940 on 2016/06/23 by James.Golding PoseAsset editor improvements - Replace pose edit box with inline-editable style (with validation) - Add filter highlight - Show curve values for each pose when selected - Add different background for curve list - Filter box only searches pose list, moved location to indicate that Change 3024949 on 2016/06/23 by James.Golding Small update to PSD test AnimBP Change 3025002 on 2016/06/23 by Ori.Cohen Fix the case where fixed frame rate combined with t.maxfps would lead to negative delta time. We now take the min of t.maxfps and fixed frame rate. #JIRA UE-32219 Change 3025214 on 2016/06/23 by mason.seay Updated Character Movement Map Change 3025319 on 2016/06/23 by Ori.Cohen Make sure changing skeletal mesh updates the bone index on body instances already created. Change 3025435 on 2016/06/23 by Ori.Cohen Fix welded bodies not updating their collision profile when calling SetCollisionProfile #JIRA UE-32394 Change 3025581 on 2016/06/23 by mason.seay Test asset for slicing procedural mesh Change 3026483 on 2016/06/24 by Marc.Audy Don't reschedule multiple times tick functions used as prerequisites #jira UE-32414 Change 3026498 on 2016/06/24 by mason.seay Updating blueprint for bug repro Change 3026547 on 2016/06/24 by Thomas.Sarkanen Fixed crash in FKismetDebugUtilities::GetWatchText() Crash reported by this UDN: https://udn.unrealengine.com/questions/300110/crash-in-kismetdebugutilities-when-printing-watchp.html Change3026598on 2016/06/24 by James.Golding Double clicking on poses now toggles them between 1.0 and 0.0 strength Change 3026768 on 2016/06/24 by Marc.Audy Change up suspend audio thread cvar sink warning about disabled threading to avoid inappropriate warnings #jira UE-32468 Change 3026802 on 2016/06/24 by Lina.Halper #Pose Asset work # additive blending change : additive scale is saved to [targetscale/sourcescale - 1] where it used to be [targetscale/sourcescale] since blending doesn't work with it - Blending should work once we save to [targetscale/sourcescale - 1] as normal - i.e. if you blend 0.3, it should not shrink the mesh because you applyed additive to 0.3 - When apply the scale to base, it should multiply [additive scale + 1 ] where additive scale is [targetscale/sourcescale - 1] - Changed FTransform::Blend to FTransform::Lerp since it's literally just Lerp. Name Blend should be used for Accumulate but changing the name now is dangerous, so I'm keeping Accumulate but changed Blend to Lerp # pose asset preview fix - made sure it adds to curve, so you don't have to use delegate to apply - PreviewOverride is now added to output curve, so we don't have to apply that curve later - only reason of anim instance delegate is now for normal anim blueprint. #pose asset change - Curve extraction happens with ExtractContext, the output curve is stricly output curve - Pose Asset supports Shrink now, but only shrink if full pose - Added PoseHandler to handle most of common stuff between different pose nodes - Still have to work on how to update pose asset - wip - todo: clean up single node player to handle pose asset in a function #code review:Martin.Wilson, James.Golding Change 3026978 on 2016/06/24 by Lina.Halper - Delete DrivePose Curve type - Renamed TriggerEvent to DriveAttribute for consistency - Replaced drive pose to drive attribute - right now it can't have 0 curve type flags, so everything is DriveAttribute #code review: James.Golding, Martin.Wilson Change 3027113 on 2016/06/24 by mason.seay Test Pose Assets Change 3027454 on 2016/06/24 by Aaron.McLeran UE-32492 Fix for cleaning up xaudio2 source voices and xaudio2 buffers if the source fails to initialize https://answers.unrealengine.com/questions/441080/audio-crash.html http://crashreporter/Crashes/Show/5689478 Change 3027519 on 2016/06/24 by Lina.Halper Reverted FTransform name change as that causes compile errors due to lack of deprecated messages - not worth to keep the old functions and add new one #code review: Martin.Wilson Change 3027887 on 2016/06/25 by Lina.Halper Fix clang build warning Change 3028703 on 2016/06/27 by Lukasz.Furman gameplay debugger config improvements, categories and extensions can now be toggled while PIE/simulate is active #ue4 Change 3028792 on 2016/06/27 by Lukasz.Furman compilation fix for gameplay debugger Change 3028950 on 2016/06/27 by Lukasz.Furman compilation fix for gameplay debugger Change3029003on 2016/06/27 by Ori.Cohen Added PhysicalAnimation component that allows us to physically drive skeletal mesh from animation Change3029019on 2016/06/27 by Lina.Halper Update pose from source asset Change 3029094 on 2016/06/27 by Marc.Audy If Player->StartSpot is null disregard ShouldSpawnAtStartPoint returned true. Change 3029308 on 2016/06/27 by Jeremy.Ernst -adding test animation for PSD node. Has morphs built in to compare against driver result Change 3029372 on 2016/06/27 by Marc.Audy Fix compile error after merge Also just fix the logic to be explicit rather than using suppression for static analysis warning Change 3029493 on 2016/06/27 by Ori.Cohen Move PhysicsAsset.h out of public engine header. Change 3029550 on 2016/06/27 by Lina.Halper Fix crash with Nan when additive blending of poses\ Change 3029659 on 2016/06/27 by Aaron.McLeran Adding new minor feature to add new concurrency mode - stop by lowest priorty but prevent new rather than stop oldest. Change 3029673 on 2016/06/27 by Aaron.McLeran #JIRA FORT-24936 Disable EQ on AMD machines since it is causing them to stall and starve other important threads. This is only a temporary solution until a better one is found. Implementation in CL 3024124 Change 3030470 on 2016/06/28 by Ori.Cohen Fix OnConstraintBrokenWrapper being accidently wrapped with if WITH_CLOTHING #JIRA UE-32561 Change 3030586 on 2016/06/28 by Lina.Halper Preview curve fix from anim curve viewer #code review: Martin.Wilson Change 3031054 on 2016/06/28 by Aaron.McLeran #jira UE-32566 Incorrectly copied CL 3024124 to Dev-Framework Change 3031535 on 2016/06/28 by mason.seay Re-saving concurrency asset Change 3031691 on 2016/06/28 by Marc.Audy Fix stat sounds not turning on correctly unless a sort was specified #jira UE-32597 Change 3031883 on 2016/06/28 by Zak.Middleton #ue4 - Prevent bNotifyJumpApex from being editable, and clean up comments. Change 3031898 on 2016/06/28 by Zak.Middleton #ue4 - Fix mesh smoothing on clients popping briefly when crouching. This was due to the change in 4.12 where we started smoothing Z location rather than always zeroing it (in certain movement modes). #udn https://udn.unrealengine.com/questions/300494/networked-crouching-jitter.html Change 3032539 on 2016/06/29 by Marc.Audy Don't destroy AudioDevices before draining audio commands and stopping audio thread #jira UE-32611 Change 3032633 on 2016/06/29 by Marc.Audy In the same way that SpawnActor doesn't work during world teardown, don't allow new components to be added which could introduce recursion within the destroy logic. #jira UE-32574 Change 3032644 on 2016/06/29 by Lina.Halper - Fixed issue where pose node evaluator doesn't show up in the menu with asset - it showed twice of pose node (none) - jira UE-32358 - Fixed issue where anim evaluator/pose asset by name/blend space evaluator failed to display assets properly - jira UE-32359 - support create pose menu from create asset - UE-32596 - added create pose asset from current pose - update source should refresh list - UE-32576 - fixed blendspace to be in the blendspaces category Change 3032847 on 2016/06/29 by Tom.Looman Added PredictProjectilePath and SuggestProjectileVelocity_MediumArc utilities to UGameplayStatics. Updated SuggestProjectileVelocity to avoid floating point precision errors on gravity value comparison. #jira UE-32103 Change 3033124 on 2016/06/29 by Jon.Nabozny Fix issue where InstancedStaticMeshComponent InstanceBodies don't move when the mesh is updated. #JIRA: UE-13673 Change 3033155 on 2016/06/29 by Lina.Halper - montage is playing and montage is pure - made montage parameter to be mostly const (except play), and made it consistently pointer Change 3033157 on 2016/06/29 by Lina.Halper Check in missing file Change 3033456 on 2016/06/29 by Lukasz.Furman fixed path following changes broken by merge #ue4 Change 3033956 on 2016/06/30 by bruce.nesbit PR #2483: Fix/Improvment Move Component To Rotation (Contributed by Nachtmahr87) #test PIE Change 3034019 on 2016/06/30 by Benn.Gallagher Anim blueprint sub-instances, allowing anim blueprints to run within anim blueprints and expose parameters back to the "parent" instance. Caveats: - Slots and state machine names are unique and boxed per instance, meaning playing a montage on a slot will only affect slots in the outermost instance and state machine getters are local to their instance. #jira UEFW-1 Change 3034085 on 2016/06/30 by Benn.Gallagher Missed LOCTEXT_NAMESPACE undefs from the subinstance checkin, for some reason doesn't get caught on windows, likely how the unity files are stuck together. Change 3034162 on 2016/06/30 by Martin.Wilson Refactor bone reference widget so that selection tree can be used seperately Change 3034205 on 2016/06/30 by Lina.Halper #ANIM: fix issue with addiitve blending with non-full weight applying wrong scale #jira: UE-32643, UE-32593 Change 3034339 on 2016/06/30 by James.Golding Moving functionality from Skeleton Curves tab into Anim Curve Viewer tab Change 3034426 on 2016/06/30 by Martin.Wilson CIS Fix Change 3034629 on 2016/06/30 by Lina.Halper Support non-zero curves to be stippred out upon importing Change 3035863 on 2016/07/01 by Marc.Audy When pasting components in to a blueprint, make the relative position and rotation of the root 0,0,0 #jira UE-31344 Change 3035916 on 2016/07/01 by Jon.Nabozny Fixed PaperGroupedSprite doesn't update InstanceBodies data in physics. This change is related to CL-3033124 Change 3035973 on 2016/07/01 by Lukasz.Furman fixed hash function for FRecastDebugPathfindingNode #ue4 Change 3036024 on 2016/07/01 by Zak.Middleton #ue4 - Avoid filling in array in AActor::FixupNativeActorComponents() unless we detect a null scene component. Avoid copying TWeakObjectPtr in ValidateDeferredTransformCache(). Change 3036157 on 2016/07/01 by Marc.Audy Protect against running commands on game thread when the audio device has already been freed #jira UE-32611 Change 3036178 on 2016/07/01 by Marc.Audy Don't bitpack the gamethread specific boolean. Change 3036906 on 2016/07/04 by bruce.nesbit Fixed a typo in HasDefaultBuildSettings - (bCompi8leLeanAndMeanUE should be bCompileLeanAndMeanUE) #tests Compiled Change 3036929 on 2016/07/04 by James.Golding UE-32405 Label Rotator components X/Y/Z instead of Roll/Pitch/Yaw Change 3036930 on 2016/07/04 by James.Golding UE-30414 Move constraint warnings to Message Log Change 3036931 on 2016/07/04 by James.Golding PR #2427: SkeletalMeshMerge now can transform the UVs of the source meshes. (Contributed by Bogustus) Change 3037123 on 2016/07/04 by Ori.Cohen Added physical animation preview in PhAT as well as physical animation profiles. Change 3037420 on 2016/07/05 by Jurre.deBaare Moved BodySetup_DEPRECATED out of WITH_EDITORONLY_DATA since it's being used in postload (fixes shipping builds) #jira UE-32771 Change 3037702 on 2016/07/05 by Thomas.Sarkanen Copying change 3037701 from Release-4.12: Fixed crash when viewing uncompressed animation Made sure that objects required by the animation evaluation are set up when performing game-thread side work in the editor. #jira UE-32715 - Crash when selecting "show" > "uncompressed animation" in Persona Change 3037837 on 2016/07/05 by Marc.Audy sound stats will now still be displayed when creating a new audio device #jira UE-32743 [CL 3038035 by Marc Audy in Main branch]
603 lines
18 KiB
C++
603 lines
18 KiB
C++
// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved.
|
|
|
|
/*------------------------------------------------------------------------------------
|
|
FSLESSoundSource.
|
|
------------------------------------------------------------------------------------*/
|
|
|
|
#include "AndroidAudioDevice.h"
|
|
#include "AudioDecompress.h"
|
|
#include "Engine.h"
|
|
|
|
// Callback that is registered if the source needs to loop
|
|
void OpenSLBufferQueueCallback( SLAndroidSimpleBufferQueueItf InQueueInterface, void* pContext )
|
|
{
|
|
FSLESSoundSource* SoundSource = (FSLESSoundSource*)pContext;
|
|
if( SoundSource )
|
|
{
|
|
SoundSource->OnRequeueBufferCallback( InQueueInterface );
|
|
}
|
|
}
|
|
|
|
// Requeues buffer to loop Sound Source
|
|
void FSLESSoundSource::OnRequeueBufferCallback( SLAndroidSimpleBufferQueueItf InQueueInterface )
|
|
{
|
|
if (!bStreamedSound)
|
|
{
|
|
SLresult result = (*SL_PlayerBufferQueue)->Enqueue(SL_PlayerBufferQueue, Buffer->AudioData, Buffer->GetSize() );
|
|
if(result != SL_RESULT_SUCCESS)
|
|
{
|
|
UE_LOG( LogAndroidAudio, Warning, TEXT("FAILED OPENSL BUFFER Enqueue SL_PlayerBufferQueue (Requeing)"));
|
|
}
|
|
bHasLooped = true;
|
|
}
|
|
else
|
|
{
|
|
// Enqueue the previously decoded buffer
|
|
if (RealtimeAsyncTask)
|
|
{
|
|
RealtimeAsyncTask->EnsureCompletion();
|
|
switch(RealtimeAsyncTask->GetTask().GetTaskType())
|
|
{
|
|
case ERealtimeAudioTaskType::Decompress:
|
|
bHasLooped = RealtimeAsyncTask->GetTask().GetBufferLooped();
|
|
break;
|
|
|
|
case ERealtimeAudioTaskType::Procedural:
|
|
AudioBuffers[BufferInUse].AudioDataSize = RealtimeAsyncTask->GetTask().GetBytesWritten();
|
|
break;
|
|
}
|
|
|
|
delete RealtimeAsyncTask;
|
|
RealtimeAsyncTask = nullptr;
|
|
}
|
|
|
|
// Sound decoding is complete, just waiting to finish playing
|
|
if (bBuffersToFlush)
|
|
{
|
|
// set the player's state to stopped
|
|
SLresult result = (*SL_PlayerPlayInterface)->SetPlayState(SL_PlayerPlayInterface, SL_PLAYSTATE_STOPPED);
|
|
check(SL_RESULT_SUCCESS == result);
|
|
|
|
return;
|
|
}
|
|
|
|
SLresult result = (*SL_PlayerBufferQueue)->Enqueue(SL_PlayerBufferQueue, AudioBuffers[BufferInUse].AudioData, AudioBuffers[BufferInUse].AudioDataSize );
|
|
if(result != SL_RESULT_SUCCESS)
|
|
{
|
|
UE_LOG( LogAndroidAudio, Warning, TEXT("FAILED OPENSL BUFFER Enqueue SL_PlayerBufferQueue (Requeing)"));
|
|
}
|
|
|
|
// Switch to the next buffer and decode for the next time the callback fires if we didn't just get the last buffer
|
|
BufferInUse = !BufferInUse;
|
|
if (bHasLooped == false || WaveInstance->LoopingMode != LOOP_Never)
|
|
{
|
|
// Do this in the callback thread instead of creating an asynchronous task (thread id from callback is not consistent and use of TLS for stats causes issues)
|
|
if (ReadMorePCMData(BufferInUse, EDataReadMode::Synchronous))
|
|
{
|
|
// If this is a synchronous source we may get notified immediately that we have looped
|
|
bHasLooped = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
bool FSLESSoundSource::CreatePlayer()
|
|
{
|
|
// data info
|
|
SLDataLocator_AndroidSimpleBufferQueue LocationBuffer = { SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 1 };
|
|
|
|
// PCM Info
|
|
SLDataFormat_PCM PCM_Format = { SL_DATAFORMAT_PCM, SLuint32(Buffer->NumChannels), SLuint32( Buffer->SampleRate * 1000 ),
|
|
SL_PCMSAMPLEFORMAT_FIXED_16, SL_PCMSAMPLEFORMAT_FIXED_16,
|
|
Buffer->NumChannels == 2 ? ( SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT ) : SL_SPEAKER_FRONT_CENTER,
|
|
SL_BYTEORDER_LITTLEENDIAN };
|
|
|
|
SLDataSource SoundDataSource = { &LocationBuffer, &PCM_Format};
|
|
|
|
// configure audio sink
|
|
SLDataLocator_OutputMix Output_Mix = { SL_DATALOCATOR_OUTPUTMIX, ((FSLESAudioDevice *)AudioDevice)->SL_OutputMixObject};
|
|
SLDataSink AudioSink = { &Output_Mix, NULL};
|
|
|
|
// create audio player
|
|
const SLInterfaceID ids[] = {SL_IID_BUFFERQUEUE, SL_IID_VOLUME};
|
|
const SLboolean req[] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE};
|
|
SLresult result = (*Device->SL_EngineEngine)->CreateAudioPlayer( Device->SL_EngineEngine, &SL_PlayerObject,
|
|
&SoundDataSource, &AudioSink, sizeof(ids) / sizeof(SLInterfaceID), ids, req );
|
|
if(result != SL_RESULT_SUCCESS)
|
|
{
|
|
UE_LOG(LogAndroidAudio, Warning, TEXT("FAILED OPENSL BUFFER CreateAudioPlayer 0x%x"), result);
|
|
return false;
|
|
}
|
|
|
|
bool bFailedSetup = false;
|
|
|
|
// realize the player
|
|
result = (*SL_PlayerObject)->Realize(SL_PlayerObject, SL_BOOLEAN_FALSE);
|
|
if (result != SL_RESULT_SUCCESS) { UE_LOG(LogAndroidAudio, Warning, TEXT("FAILED OPENSL BUFFER Realize 0x%x"), result); return false; }
|
|
|
|
// get the play interface
|
|
result = (*SL_PlayerObject)->GetInterface(SL_PlayerObject, SL_IID_PLAY, &SL_PlayerPlayInterface);
|
|
if (result != SL_RESULT_SUCCESS) { UE_LOG(LogAndroidAudio, Warning, TEXT("FAILED OPENSL BUFFER GetInterface SL_IID_PLAY 0x%x"), result); bFailedSetup |= true; }
|
|
// volume
|
|
result = (*SL_PlayerObject)->GetInterface(SL_PlayerObject, SL_IID_VOLUME, &SL_VolumeInterface);
|
|
if (result != SL_RESULT_SUCCESS) { UE_LOG(LogAndroidAudio, Warning, TEXT("FAILED OPENSL BUFFER GetInterface SL_IID_VOLUME 0x%x"), result); bFailedSetup |= true; }
|
|
// buffer system
|
|
result = (*SL_PlayerObject)->GetInterface(SL_PlayerObject, SL_IID_BUFFERQUEUE, &SL_PlayerBufferQueue);
|
|
if (result != SL_RESULT_SUCCESS) { UE_LOG(LogAndroidAudio, Warning, TEXT("FAILED OPENSL BUFFER GetInterface SL_IID_BUFFERQUEUE 0x%x"), result); bFailedSetup |= true; }
|
|
|
|
return bFailedSetup == false;
|
|
}
|
|
|
|
void FSLESSoundSource::DestroyPlayer()
|
|
{
|
|
if( SL_PlayerObject )
|
|
{
|
|
// close it down...
|
|
(*SL_PlayerObject)->Destroy(SL_PlayerObject);
|
|
SL_PlayerObject = NULL;
|
|
SL_PlayerPlayInterface = NULL;
|
|
SL_PlayerBufferQueue = NULL;
|
|
SL_VolumeInterface = NULL;
|
|
}
|
|
}
|
|
|
|
bool FSLESSoundSource::EnqueuePCMBuffer( bool bLoop)
|
|
{
|
|
SLresult result;
|
|
// If looping, register a callback to requeue the buffer
|
|
if( bLoop )
|
|
{
|
|
result = (*SL_PlayerBufferQueue)->RegisterCallback(SL_PlayerBufferQueue, OpenSLBufferQueueCallback, (void*)this);
|
|
if (result != SL_RESULT_SUCCESS) { UE_LOG(LogAndroidAudio, Warning, TEXT("FAILED OPENSL BUFFER QUEUE RegisterCallback 0x%x "), result); return false; }
|
|
}
|
|
|
|
result = (*SL_PlayerBufferQueue)->Enqueue(SL_PlayerBufferQueue, Buffer->AudioData, Buffer->GetSize() );
|
|
if (result != SL_RESULT_SUCCESS) {
|
|
UE_LOG(LogAndroidAudio, Warning, TEXT("FAILED OPENSL BUFFER Enqueue SL_PlayerBufferQueue 0x%x params( %p, %d)"), result, Buffer->AudioData, int32(Buffer->GetSize()));
|
|
if (bLoop)
|
|
{
|
|
result = (*SL_PlayerBufferQueue)->RegisterCallback(SL_PlayerBufferQueue, NULL, NULL);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bStreamedSound = false;
|
|
bHasLooped = false;
|
|
bBuffersToFlush = false;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool FSLESSoundSource::ReadMorePCMData(const int32 BufferIndex, EDataReadMode DataReadMode)
|
|
{
|
|
USoundWave* WaveData = WaveInstance->WaveData;
|
|
if (WaveData && WaveData->bProcedural)
|
|
{
|
|
const int32 MaxSamples = BufferSize / sizeof(int16);
|
|
if (DataReadMode == EDataReadMode::Synchronous || WaveData->bCanProcessAsync == false)
|
|
{
|
|
const int32 BytesWritten = WaveData->GeneratePCMData(AudioBuffers[BufferIndex].AudioData, MaxSamples);
|
|
AudioBuffers[BufferIndex].AudioDataSize = BytesWritten;
|
|
}
|
|
else
|
|
{
|
|
RealtimeAsyncTask = new FAsyncRealtimeAudioTask(WaveData, AudioBuffers[BufferIndex].AudioData, MaxSamples);
|
|
RealtimeAsyncTask->StartBackgroundTask();
|
|
}
|
|
|
|
// we're never actually "looping" here.
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
if (DataReadMode == EDataReadMode::Synchronous)
|
|
{
|
|
return Buffer->ReadCompressedData(AudioBuffers[BufferIndex].AudioData, WaveInstance->LoopingMode != LOOP_Never);
|
|
}
|
|
else
|
|
{
|
|
RealtimeAsyncTask = new FAsyncRealtimeAudioTask(Buffer, AudioBuffers[BufferIndex].AudioData, WaveInstance->LoopingMode != LOOP_Never, DataReadMode == EDataReadMode::AsynchronousSkipFirstFrame);
|
|
RealtimeAsyncTask->StartBackgroundTask();
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
bool FSLESSoundSource::EnqueuePCMRTBuffer( bool bLoop )
|
|
{
|
|
if (AudioBuffers[0].AudioData || AudioBuffers[1].AudioData)
|
|
{
|
|
UE_LOG( LogAndroidAudio, Warning, TEXT("Enqueue PCMRT with buffers already allocated"));
|
|
}
|
|
FMemory::Memzero( AudioBuffers, sizeof( SLESAudioBuffer ) * 2 );
|
|
|
|
// Set up double buffer area to decompress to
|
|
BufferSize = Buffer->GetRTBufferSize() * Buffer->NumChannels;
|
|
|
|
AudioBuffers[0].AudioData = (uint8*)FMemory::Malloc(BufferSize);
|
|
AudioBuffers[0].AudioDataSize = BufferSize;
|
|
|
|
AudioBuffers[1].AudioData = (uint8*)FMemory::Malloc(BufferSize);
|
|
AudioBuffers[1].AudioDataSize = BufferSize;
|
|
|
|
// Only use the cached data if we're starting from the beginning, otherwise we'll have to take a synchronous hit
|
|
if (WaveInstance->WaveData && WaveInstance->WaveData->CachedRealtimeFirstBuffer && WaveInstance->StartTime == 0.f)
|
|
{
|
|
FMemory::Memcpy((uint8*)AudioBuffers[0].AudioData, WaveInstance->WaveData->CachedRealtimeFirstBuffer, BufferSize);
|
|
ReadMorePCMData(1, EDataReadMode::AsynchronousSkipFirstFrame);
|
|
}
|
|
else
|
|
{
|
|
ReadMorePCMData(0, EDataReadMode::Synchronous);
|
|
ReadMorePCMData(1, EDataReadMode::Asynchronous);
|
|
}
|
|
|
|
SLresult result;
|
|
|
|
// callback is used to submit and decompress next buffer
|
|
result = (*SL_PlayerBufferQueue)->RegisterCallback(SL_PlayerBufferQueue, OpenSLBufferQueueCallback, (void*)this);
|
|
|
|
// queue one sound buffer, as that is all Android will accept
|
|
if(result == SL_RESULT_SUCCESS)
|
|
{
|
|
result = (*SL_PlayerBufferQueue)->Enqueue(SL_PlayerBufferQueue, AudioBuffers[0].AudioData, AudioBuffers[0].AudioDataSize );
|
|
if (result != SL_RESULT_SUCCESS) { UE_LOG(LogAndroidAudio, Warning, TEXT("FAILED OPENSL BUFFER Enqueue SL_PlayerBufferQueue 0x%x params( %p, %d)"), result, Buffer->AudioData, int32(Buffer->GetSize())); return false; }
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
|
|
bStreamedSound = true;
|
|
bHasLooped = false;
|
|
bBuffersToFlush = false;
|
|
BufferInUse = 1;
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Initializes a source with a given wave instance and prepares it for playback.
|
|
*
|
|
* @param WaveInstance wave instance being primed for playback
|
|
* @return TRUE if initialization was successful, FALSE otherwise
|
|
*/
|
|
bool FSLESSoundSource::Init( FWaveInstance* InWaveInstance )
|
|
{
|
|
// don't do anything if no volume! THIS APPEARS TO HAVE THE VOLUME IN TIME, CHECK HERE THOUGH IF ISSUES
|
|
if( InWaveInstance && ( InWaveInstance->Volume * InWaveInstance->VolumeMultiplier ) <= 0 )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (Buffer && Buffer->ResourceID == 0)
|
|
{
|
|
UE_LOG( LogAndroidAudio, Warning, TEXT(" InitSoundSouce with Buffer already allocated"));
|
|
delete Buffer;
|
|
Buffer = 0;
|
|
}
|
|
|
|
if (SL_PlayerObject)
|
|
{
|
|
UE_LOG( LogAndroidAudio, Warning, TEXT(" InitSoundSouce with PlayerObject not NULL, possible leak"));
|
|
}
|
|
|
|
// Find matching buffer.
|
|
Buffer = FSLESSoundBuffer::Init( (FSLESAudioDevice *)AudioDevice, InWaveInstance->WaveData );
|
|
|
|
if( Buffer && InWaveInstance->WaveData->NumChannels <= 2 && InWaveInstance->WaveData->SampleRate <= 48000 )
|
|
{
|
|
SCOPE_CYCLE_COUNTER( STAT_AudioSourceInitTime );
|
|
|
|
bool bFailedSetup = false;
|
|
|
|
if (CreatePlayer())
|
|
{
|
|
WaveInstance = InWaveInstance;
|
|
|
|
if (WaveInstance->StartTime > 0.f)
|
|
{
|
|
Buffer->Seek(WaveInstance->StartTime);
|
|
}
|
|
|
|
switch( Buffer->Format)
|
|
{
|
|
case SoundFormat_PCM:
|
|
bFailedSetup |= !EnqueuePCMBuffer( InWaveInstance->LoopingMode != LOOP_Never );
|
|
break;
|
|
case SoundFormat_PCMRT:
|
|
bFailedSetup |= !EnqueuePCMRTBuffer( InWaveInstance->LoopingMode != LOOP_Never );
|
|
break;
|
|
default:
|
|
bFailedSetup = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
bFailedSetup = true;
|
|
}
|
|
|
|
// clean up the madness if anything we need failed
|
|
if( bFailedSetup )
|
|
{
|
|
UE_LOG( LogAndroidAudio, Warning, TEXT(" Setup failed %s"), *InWaveInstance->WaveData->GetName());
|
|
DestroyPlayer();
|
|
return false;
|
|
}
|
|
|
|
Update();
|
|
|
|
// Initialization was successful.
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
// Failed to initialize source.
|
|
// These occurences appear to potentially lead to leaks
|
|
UE_LOG( LogAndroidAudio, Warning, TEXT("Init SoundSource failed on %s"), *InWaveInstance->WaveData->GetName());
|
|
UE_LOG( LogAndroidAudio, Warning, TEXT(" SampleRate %d"), InWaveInstance->WaveData->SampleRate);
|
|
UE_LOG( LogAndroidAudio, Warning, TEXT(" Channels %d"), InWaveInstance->WaveData->NumChannels);
|
|
|
|
if (Buffer && Buffer->ResourceID == 0)
|
|
{
|
|
delete Buffer;
|
|
Buffer = 0;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
FSLESSoundSource::FSLESSoundSource( class FAudioDevice* InAudioDevice )
|
|
: FSoundSource( InAudioDevice ),
|
|
Device((FSLESAudioDevice *)InAudioDevice),
|
|
Buffer( NULL ),
|
|
bStreamedSound(false),
|
|
bBuffersToFlush(false),
|
|
BufferSize(0),
|
|
BufferInUse(0),
|
|
VolumePreviousUpdate(-1.0f),
|
|
bHasLooped(false),
|
|
SL_PlayerObject(NULL),
|
|
SL_PlayerPlayInterface(NULL),
|
|
SL_PlayerBufferQueue(NULL),
|
|
SL_VolumeInterface(NULL),
|
|
RealtimeAsyncTask(NULL)
|
|
{
|
|
FMemory::Memzero( AudioBuffers, sizeof( AudioBuffers ) );
|
|
}
|
|
|
|
/**
|
|
* Clean up any hardware referenced by the sound source
|
|
*/
|
|
FSLESSoundSource::~FSLESSoundSource( void )
|
|
{
|
|
DestroyPlayer();
|
|
|
|
ReleaseResources();
|
|
}
|
|
|
|
void FSLESSoundSource::ReleaseResources()
|
|
{
|
|
if (RealtimeAsyncTask)
|
|
{
|
|
RealtimeAsyncTask->EnsureCompletion();
|
|
delete RealtimeAsyncTask;
|
|
RealtimeAsyncTask = nullptr;
|
|
}
|
|
|
|
FMemory::Free( AudioBuffers[0].AudioData);
|
|
FMemory::Free( AudioBuffers[1].AudioData);
|
|
|
|
FMemory::Memzero( AudioBuffers, sizeof( AudioBuffers ) );
|
|
|
|
if (Buffer && Buffer->ResourceID == 0)
|
|
{
|
|
delete Buffer;
|
|
}
|
|
Buffer = NULL;
|
|
}
|
|
|
|
/**
|
|
* Updates the source specific parameter like e.g. volume and pitch based on the associated
|
|
* wave instance.
|
|
*/
|
|
void FSLESSoundSource::Update( void )
|
|
{
|
|
SCOPE_CYCLE_COUNTER( STAT_AudioUpdateSources );
|
|
|
|
if( !WaveInstance || Paused )
|
|
{
|
|
return;
|
|
}
|
|
|
|
float Volume = WaveInstance->Volume * WaveInstance->VolumeMultiplier;
|
|
if (SetStereoBleed())
|
|
{
|
|
// Emulate the bleed to rear speakers followed by stereo fold down
|
|
Volume *= 1.25f;
|
|
}
|
|
Volume *= AudioDevice->GetPlatformAudioHeadroom();
|
|
Volume = FMath::Clamp(Volume, 0.0f, MAX_VOLUME);
|
|
|
|
const float Pitch = FMath::Clamp<float>(WaveInstance->Pitch, MIN_PITCH, MAX_PITCH);
|
|
|
|
// Set whether to apply reverb
|
|
SetReverbApplied(true);
|
|
|
|
SetFilterFrequency();
|
|
|
|
FVector Location;
|
|
FVector Velocity;
|
|
|
|
// See file header for coordinate system explanation.
|
|
Location.X = WaveInstance->Location.X;
|
|
Location.Y = WaveInstance->Location.Z; // Z/Y swapped to match UE coordinate system
|
|
Location.Z = WaveInstance->Location.Y; // Z/Y swapped to match UE coordinate system
|
|
|
|
Velocity.X = WaveInstance->Velocity.X;
|
|
Velocity.Y = WaveInstance->Velocity.Z; // Z/Y swapped to match UE coordinate system
|
|
Velocity.Z = WaveInstance->Velocity.Y; // Z/Y swapped to match UE coordinate system
|
|
|
|
// We're using a relative coordinate system for un- spatialized sounds.
|
|
if( !WaveInstance->bUseSpatialization )
|
|
{
|
|
Location = FVector( 0.f, 0.f, 0.f );
|
|
}
|
|
|
|
// Set volume (Pitch changes are not supported on current Android platforms!)
|
|
// also Location & Velocity
|
|
|
|
// Avoid doing the log calculation each update by only doing it if the volume changed
|
|
if (Volume != VolumePreviousUpdate)
|
|
{
|
|
VolumePreviousUpdate = Volume;
|
|
static const int64 MinVolumeMillibel = -12000;
|
|
if (Volume > 0.0f)
|
|
{
|
|
// Convert volume to millibels.
|
|
SLmillibel MaxMillibel = 0;
|
|
(*SL_VolumeInterface)->GetMaxVolumeLevel(SL_VolumeInterface, &MaxMillibel);
|
|
SLmillibel VolumeMillibel = (SLmillibel)FMath::Clamp<int64>((int64)(2000.0f * log10f(Volume)), MinVolumeMillibel, (int64)MaxMillibel);
|
|
SLresult result = (*SL_VolumeInterface)->SetVolumeLevel(SL_VolumeInterface, VolumeMillibel);
|
|
check(SL_RESULT_SUCCESS == result);
|
|
}
|
|
else
|
|
{
|
|
SLresult result = (*SL_VolumeInterface)->SetVolumeLevel(SL_VolumeInterface, MinVolumeMillibel);
|
|
check(SL_RESULT_SUCCESS == result);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* Plays the current wave instance.
|
|
*/
|
|
void FSLESSoundSource::Play( void )
|
|
{
|
|
if( WaveInstance )
|
|
{
|
|
// Reset the previous volume on play so it can be set at least once in the update function
|
|
VolumePreviousUpdate = -1.0f;
|
|
|
|
// Update volume now before starting play
|
|
Paused = false;
|
|
Update();
|
|
|
|
// set the player's state to playing
|
|
SLresult result = (*SL_PlayerPlayInterface)->SetPlayState(SL_PlayerPlayInterface, SL_PLAYSTATE_PLAYING);
|
|
check(SL_RESULT_SUCCESS == result);
|
|
|
|
Playing = true;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Stops the current wave instance and detaches it from the source.
|
|
*/
|
|
void FSLESSoundSource::Stop( void )
|
|
{
|
|
if( WaveInstance )
|
|
{
|
|
// set the player's state to stopped
|
|
SLresult result = (*SL_PlayerPlayInterface)->SetPlayState(SL_PlayerPlayInterface, SL_PLAYSTATE_STOPPED);
|
|
check(SL_RESULT_SUCCESS == result);
|
|
|
|
// Unregister looping callback
|
|
if( WaveInstance->LoopingMode != LOOP_Never )
|
|
{
|
|
result = (*SL_PlayerBufferQueue)->RegisterCallback(SL_PlayerBufferQueue, NULL, NULL);
|
|
}
|
|
|
|
DestroyPlayer();
|
|
ReleaseResources();
|
|
|
|
Paused = false;
|
|
Playing = false;
|
|
Buffer = NULL;
|
|
}
|
|
|
|
FSoundSource::Stop();
|
|
}
|
|
|
|
/**
|
|
* Pauses playback of current wave instance.
|
|
*/
|
|
void FSLESSoundSource::Pause( void )
|
|
{
|
|
if( WaveInstance )
|
|
{
|
|
Paused = true;
|
|
|
|
// set the player's state to paused
|
|
SLresult result = (*SL_PlayerPlayInterface)->SetPlayState(SL_PlayerPlayInterface, SL_PLAYSTATE_PAUSED);
|
|
check(SL_RESULT_SUCCESS == result);
|
|
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns TRUE if the source has finished playing
|
|
*/
|
|
bool FSLESSoundSource::IsSourceFinished( void )
|
|
{
|
|
SLuint32 PlayState;
|
|
|
|
// set the player's state to playing
|
|
SLresult result = (*SL_PlayerPlayInterface)->GetPlayState(SL_PlayerPlayInterface, &PlayState);
|
|
check(SL_RESULT_SUCCESS == result);
|
|
|
|
if( PlayState == SL_PLAYSTATE_STOPPED )
|
|
{
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Queries the status of the currently associated wave instance.
|
|
*
|
|
* @return TRUE if the wave instance/ source has finished playback and FALSE if it is
|
|
* currently playing or paused.
|
|
*/
|
|
bool FSLESSoundSource::IsFinished( void )
|
|
{
|
|
if( WaveInstance )
|
|
{
|
|
// Check for a non starved, stopped source
|
|
if( IsSourceFinished() )
|
|
{
|
|
// Notify the wave instance that it has finished playing
|
|
WaveInstance->NotifyFinished();
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
if (bHasLooped)
|
|
{
|
|
switch (WaveInstance->LoopingMode)
|
|
{
|
|
case LOOP_Forever:
|
|
bHasLooped = false;
|
|
break;
|
|
|
|
case LOOP_Never:
|
|
bBuffersToFlush = true;
|
|
break;
|
|
|
|
case LOOP_WithNotification:
|
|
bHasLooped = false;
|
|
// Notify the wave instance that it has finished playing.
|
|
WaveInstance->NotifyFinished();
|
|
break;
|
|
};
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|