mirror of
https://github.com/beefytech/Beef.git
synced 2025-07-04 23:36:00 +02:00
Initial checkin
This commit is contained in:
parent
c74712dad9
commit
078564ac9e
3242 changed files with 1616395 additions and 0 deletions
324
BeefySysLib/sound/Win32/AkDefaultIOHookBlocking.cpp
Normal file
324
BeefySysLib/sound/Win32/AkDefaultIOHookBlocking.cpp
Normal file
|
@ -0,0 +1,324 @@
|
|||
#include "BFPlatform.h"
|
||||
|
||||
#ifdef BF_WWISE_ENABLED
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// AkDefaultIOHookBlocking.cpp
|
||||
//
|
||||
// Default blocking low level IO hook (AK::StreamMgr::IAkIOHookBlocking)
|
||||
// and file system (AK::StreamMgr::IAkFileLocationResolver) implementation
|
||||
// on Windows. It can be used as a standalone implementation of the
|
||||
// Low-Level I/O system.
|
||||
//
|
||||
// AK::StreamMgr::IAkFileLocationResolver:
|
||||
// Resolves file location using simple path concatenation logic
|
||||
// (implemented in ../Common/CAkFileLocationBase). It can be used as a
|
||||
// standalone Low-Level IO system, or as part of a multi device system.
|
||||
// In the latter case, you should manage multiple devices by implementing
|
||||
// AK::StreamMgr::IAkFileLocationResolver elsewhere (you may take a look
|
||||
// at class CAkDefaultLowLevelIODispatcher).
|
||||
//
|
||||
// AK::StreamMgr::IAkIOHookBlocking:
|
||||
// Uses platform API for I/O. Calls to ::ReadFile() and ::WriteFile()
|
||||
// block because files are opened without the FILE_FLAG_OVERLAPPED flag.
|
||||
// The AK::StreamMgr::IAkIOHookBlocking interface is meant to be used with
|
||||
// AK_SCHEDULER_BLOCKING streaming devices.
|
||||
//
|
||||
// Init() creates a streaming device (by calling AK::StreamMgr::CreateDevice()).
|
||||
// AkDeviceSettings::uSchedulerTypeFlags is set inside to AK_SCHEDULER_BLOCKING.
|
||||
// If there was no AK::StreamMgr::IAkFileLocationResolver previously registered
|
||||
// to the Stream Manager, this object registers itself as the File Location Resolver.
|
||||
//
|
||||
// Copyright (c) 2006 Audiokinetic Inc. / All Rights Reserved
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "Common.h"
|
||||
#include "AkDefaultIOHookBlocking.h"
|
||||
#include "AkFileHelpers.h"
|
||||
|
||||
|
||||
#define WIN32_BLOCKING_DEVICE_NAME (AKTEXT("Win32 Blocking")) // Default blocking device name.
|
||||
|
||||
CAkDefaultIOHookBlocking::CAkDefaultIOHookBlocking()
|
||||
: m_deviceID( AK_INVALID_DEVICE_ID )
|
||||
, m_bAsyncOpen( false )
|
||||
{
|
||||
}
|
||||
|
||||
CAkDefaultIOHookBlocking::~CAkDefaultIOHookBlocking()
|
||||
{
|
||||
}
|
||||
|
||||
// Initialization/termination. Init() registers this object as the one and
|
||||
// only File Location Resolver if none were registered before. Then
|
||||
// it creates a streaming device with scheduler type AK_SCHEDULER_BLOCKING.
|
||||
AKRESULT CAkDefaultIOHookBlocking::Init(
|
||||
const AkDeviceSettings & in_deviceSettings, // Device settings.
|
||||
bool in_bAsyncOpen/*=false*/ // If true, files are opened asynchronously when possible.
|
||||
)
|
||||
{
|
||||
if ( in_deviceSettings.uSchedulerTypeFlags != AK_SCHEDULER_BLOCKING )
|
||||
{
|
||||
AKASSERT( !"CAkDefaultIOHookBlocking I/O hook only works with AK_SCHEDULER_BLOCKING devices" );
|
||||
return AK_Fail;
|
||||
}
|
||||
|
||||
m_bAsyncOpen = in_bAsyncOpen;
|
||||
|
||||
// If the Stream Manager's File Location Resolver was not set yet, set this object as the
|
||||
// File Location Resolver (this I/O hook is also able to resolve file location).
|
||||
if ( !AK::StreamMgr::GetFileLocationResolver() )
|
||||
AK::StreamMgr::SetFileLocationResolver( this );
|
||||
|
||||
// Create a device in the Stream Manager, specifying this as the hook.
|
||||
m_deviceID = AK::StreamMgr::CreateDevice( in_deviceSettings, this );
|
||||
if ( m_deviceID != AK_INVALID_DEVICE_ID )
|
||||
return AK_Success;
|
||||
|
||||
return AK_Fail;
|
||||
}
|
||||
|
||||
void CAkDefaultIOHookBlocking::Term()
|
||||
{
|
||||
if ( AK::StreamMgr::GetFileLocationResolver() == this )
|
||||
AK::StreamMgr::SetFileLocationResolver( NULL );
|
||||
AK::StreamMgr::DestroyDevice( m_deviceID );
|
||||
}
|
||||
|
||||
//
|
||||
// IAkFileLocationAware interface.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// Returns a file descriptor for a given file name (string).
|
||||
AKRESULT CAkDefaultIOHookBlocking::Open(
|
||||
const AkOSChar* in_pszFileName, // File name.
|
||||
AkOpenMode in_eOpenMode, // Open mode.
|
||||
AkFileSystemFlags * in_pFlags, // Special flags. Can pass NULL.
|
||||
bool & io_bSyncOpen, // If true, the file must be opened synchronously. Otherwise it is left at the File Location Resolver's discretion. Return false if Open needs to be deferred.
|
||||
AkFileDesc & out_fileDesc // Returned file descriptor.
|
||||
)
|
||||
{
|
||||
// We normally consider that calls to ::CreateFile() on a hard drive are fast enough to execute in the
|
||||
// client thread. If you want files to be opened asynchronously when it is possible, this device should
|
||||
// be initialized with the flag in_bAsyncOpen set to true.
|
||||
if ( io_bSyncOpen || !m_bAsyncOpen )
|
||||
{
|
||||
io_bSyncOpen = true;
|
||||
|
||||
// Get the full file path, using path concatenation logic.
|
||||
AkOSChar szFullFilePath[AK_MAX_PATH];
|
||||
if ( GetFullFilePath( in_pszFileName, in_pFlags, in_eOpenMode, szFullFilePath ) == AK_Success )
|
||||
{
|
||||
// Open the file without FILE_FLAG_OVERLAPPED and FILE_FLAG_NO_BUFFERING flags.
|
||||
AKRESULT eResult = CAkFileHelpers::OpenFile(
|
||||
szFullFilePath,
|
||||
in_eOpenMode,
|
||||
false,
|
||||
false,
|
||||
out_fileDesc.hFile );
|
||||
if ( eResult == AK_Success )
|
||||
{
|
||||
#ifdef AK_USE_METRO_API
|
||||
FILE_STANDARD_INFO info;
|
||||
::GetFileInformationByHandleEx( out_fileDesc.hFile, FileStandardInfo, &info, sizeof(info) );
|
||||
out_fileDesc.iFileSize = info.EndOfFile.QuadPart;
|
||||
#else
|
||||
ULARGE_INTEGER Temp;
|
||||
Temp.LowPart = ::GetFileSize( out_fileDesc.hFile,(LPDWORD)&Temp.HighPart );
|
||||
out_fileDesc.iFileSize = Temp.QuadPart;
|
||||
#endif
|
||||
out_fileDesc.uSector = 0;
|
||||
out_fileDesc.deviceID = m_deviceID;
|
||||
out_fileDesc.pCustomParam = NULL;
|
||||
out_fileDesc.uCustomParamSize = 0;
|
||||
}
|
||||
return eResult;
|
||||
}
|
||||
|
||||
return AK_Fail;
|
||||
}
|
||||
else
|
||||
{
|
||||
// The client allows us to perform asynchronous opening.
|
||||
// We only need to specify the deviceID, and leave the boolean to false.
|
||||
out_fileDesc.iFileSize = 0;
|
||||
out_fileDesc.uSector = 0;
|
||||
out_fileDesc.deviceID = m_deviceID;
|
||||
out_fileDesc.pCustomParam = NULL;
|
||||
out_fileDesc.uCustomParamSize = 0;
|
||||
return AK_Success;
|
||||
}
|
||||
}
|
||||
|
||||
// Returns a file descriptor for a given file ID.
|
||||
AKRESULT CAkDefaultIOHookBlocking::Open(
|
||||
AkFileID in_fileID, // File ID.
|
||||
AkOpenMode in_eOpenMode, // Open mode.
|
||||
AkFileSystemFlags * in_pFlags, // Special flags. Can pass NULL.
|
||||
bool & io_bSyncOpen, // If true, the file must be opened synchronously. Otherwise it is left at the File Location Resolver's discretion. Return false if Open needs to be deferred.
|
||||
AkFileDesc & out_fileDesc // Returned file descriptor.
|
||||
)
|
||||
{
|
||||
// We normally consider that calls to ::CreateFile() on a hard drive are fast enough to execute in the
|
||||
// client thread. If you want files to be opened asynchronously when it is possible, this device should
|
||||
// be initialized with the flag in_bAsyncOpen set to true.
|
||||
if ( io_bSyncOpen || !m_bAsyncOpen )
|
||||
{
|
||||
io_bSyncOpen = true;
|
||||
|
||||
// Get the full file path, using path concatenation logic.
|
||||
AkOSChar szFullFilePath[AK_MAX_PATH];
|
||||
if ( GetFullFilePath( in_fileID, in_pFlags, in_eOpenMode, szFullFilePath ) == AK_Success )
|
||||
{
|
||||
// Open the file without FILE_FLAG_OVERLAPPED and FILE_FLAG_NO_BUFFERING flags.
|
||||
AKRESULT eResult = CAkFileHelpers::OpenFile(
|
||||
szFullFilePath,
|
||||
in_eOpenMode,
|
||||
false,
|
||||
false,
|
||||
out_fileDesc.hFile );
|
||||
if ( eResult == AK_Success )
|
||||
{
|
||||
#ifdef AK_USE_METRO_API
|
||||
FILE_STANDARD_INFO info;
|
||||
::GetFileInformationByHandleEx( out_fileDesc.hFile, FileStandardInfo, &info, sizeof(info) );
|
||||
out_fileDesc.iFileSize = info.EndOfFile.QuadPart;
|
||||
#else
|
||||
ULARGE_INTEGER Temp;
|
||||
Temp.LowPart = ::GetFileSize( out_fileDesc.hFile,(LPDWORD)&Temp.HighPart );
|
||||
out_fileDesc.iFileSize = Temp.QuadPart;
|
||||
#endif
|
||||
out_fileDesc.uSector = 0;
|
||||
out_fileDesc.deviceID = m_deviceID;
|
||||
out_fileDesc.pCustomParam = NULL;
|
||||
out_fileDesc.uCustomParamSize = 0;
|
||||
}
|
||||
return eResult;
|
||||
}
|
||||
|
||||
return AK_Fail;
|
||||
}
|
||||
else
|
||||
{
|
||||
// The client allows us to perform asynchronous opening.
|
||||
// We only need to specify the deviceID, and leave the boolean to false.
|
||||
out_fileDesc.iFileSize = 0;
|
||||
out_fileDesc.uSector = 0;
|
||||
out_fileDesc.deviceID = m_deviceID;
|
||||
out_fileDesc.pCustomParam = NULL;
|
||||
out_fileDesc.uCustomParamSize = 0;
|
||||
return AK_Success;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// IAkIOHookBlocking implementation.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// Reads data from a file (synchronous).
|
||||
AKRESULT CAkDefaultIOHookBlocking::Read(
|
||||
AkFileDesc & in_fileDesc, // File descriptor.
|
||||
const AkIoHeuristics & /*in_heuristics*/, // Heuristics for this data transfer (not used in this implementation).
|
||||
void * out_pBuffer, // Buffer to be filled with data.
|
||||
AkIOTransferInfo & io_transferInfo // Synchronous data transfer info.
|
||||
)
|
||||
{
|
||||
AKASSERT( out_pBuffer &&
|
||||
in_fileDesc.hFile != INVALID_HANDLE_VALUE );
|
||||
|
||||
OVERLAPPED overlapped;
|
||||
overlapped.Offset = (DWORD)( io_transferInfo.uFilePosition & 0xFFFFFFFF );
|
||||
overlapped.OffsetHigh = (DWORD)( ( io_transferInfo.uFilePosition >> 32 ) & 0xFFFFFFFF );
|
||||
overlapped.hEvent = NULL;
|
||||
|
||||
AkUInt32 uSizeTransferred;
|
||||
|
||||
if ( ::ReadFile(
|
||||
in_fileDesc.hFile,
|
||||
out_pBuffer,
|
||||
io_transferInfo.uRequestedSize,
|
||||
&uSizeTransferred,
|
||||
&overlapped ) )
|
||||
{
|
||||
AKASSERT( uSizeTransferred == io_transferInfo.uRequestedSize );
|
||||
return AK_Success;
|
||||
}
|
||||
return AK_Fail;
|
||||
}
|
||||
|
||||
// Writes data to a file (synchronous).
|
||||
AKRESULT CAkDefaultIOHookBlocking::Write(
|
||||
AkFileDesc & in_fileDesc, // File descriptor.
|
||||
const AkIoHeuristics & /*in_heuristics*/, // Heuristics for this data transfer (not used in this implementation).
|
||||
void * in_pData, // Data to be written.
|
||||
AkIOTransferInfo & io_transferInfo // Synchronous data transfer info.
|
||||
)
|
||||
{
|
||||
AKASSERT( in_pData &&
|
||||
in_fileDesc.hFile != INVALID_HANDLE_VALUE );
|
||||
|
||||
OVERLAPPED overlapped;
|
||||
overlapped.Offset = (DWORD)( io_transferInfo.uFilePosition & 0xFFFFFFFF );
|
||||
overlapped.OffsetHigh = (DWORD)( ( io_transferInfo.uFilePosition >> 32 ) & 0xFFFFFFFF );
|
||||
overlapped.hEvent = NULL;
|
||||
|
||||
AkUInt32 uSizeTransferred;
|
||||
|
||||
if ( ::WriteFile(
|
||||
in_fileDesc.hFile,
|
||||
in_pData,
|
||||
io_transferInfo.uRequestedSize,
|
||||
&uSizeTransferred,
|
||||
&overlapped ) )
|
||||
{
|
||||
AKASSERT( uSizeTransferred == io_transferInfo.uRequestedSize );
|
||||
return AK_Success;
|
||||
}
|
||||
return AK_Fail;
|
||||
}
|
||||
|
||||
// Cleans up a file.
|
||||
AKRESULT CAkDefaultIOHookBlocking::Close(
|
||||
AkFileDesc & in_fileDesc // File descriptor.
|
||||
)
|
||||
{
|
||||
return CAkFileHelpers::CloseFile( in_fileDesc.hFile );
|
||||
}
|
||||
|
||||
// Returns the block size for the file or its storage device.
|
||||
AkUInt32 CAkDefaultIOHookBlocking::GetBlockSize(
|
||||
AkFileDesc & /*in_fileDesc*/ // File descriptor.
|
||||
)
|
||||
{
|
||||
// No constraint on block size (file seeking).
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
// Returns a description for the streaming device above this low-level hook.
|
||||
void CAkDefaultIOHookBlocking::GetDeviceDesc(
|
||||
AkDeviceDesc &
|
||||
#ifndef AK_OPTIMIZED
|
||||
out_deviceDesc // Description of associated low-level I/O device.
|
||||
#endif
|
||||
)
|
||||
{
|
||||
#ifndef AK_OPTIMIZED
|
||||
AKASSERT( m_deviceID != AK_INVALID_DEVICE_ID || !"Low-Level device was not initialized" );
|
||||
out_deviceDesc.deviceID = m_deviceID;
|
||||
out_deviceDesc.bCanRead = true;
|
||||
out_deviceDesc.bCanWrite = true;
|
||||
AKPLATFORM::SafeStrCpy( out_deviceDesc.szDeviceName, WIN32_BLOCKING_DEVICE_NAME, AK_MONITOR_DEVICENAME_MAXLENGTH );
|
||||
out_deviceDesc.uStringSize = (AkUInt32)wcslen( out_deviceDesc.szDeviceName ) + 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Returns custom profiling data: 1 if file opens are asynchronous, 0 otherwise.
|
||||
AkUInt32 CAkDefaultIOHookBlocking::GetDeviceData()
|
||||
{
|
||||
return ( m_bAsyncOpen ) ? 1 : 0;
|
||||
}
|
||||
|
||||
#endif
|
Loading…
Add table
Add a link
Reference in a new issue