// 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; }
// 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_DEFERRED_LINED_UP. AKRESULT CAkDefaultIOHookDeferred::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_DEFERRED_LINED_UP ) { AKASSERT( !"CAkDefaultIOHookDeferred I/O hook only works with AK_SCHEDULER_DEFERRED_LINED_UP 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 ) { // Initialize structures needed to perform deferred transfers. AkUInt32 uPoolSize = (AkUInt32)( in_deviceSettings.uMaxConcurrentIO * sizeof( OVERLAPPED ) ); m_poolID = AK::MemoryMgr::CreatePool( NULL, uPoolSize, sizeof( OVERLAPPED ), AkMalloc | AkFixedSizeBlocksMode ); if ( m_poolID == AK_INVALID_POOL_ID ) { AKASSERT( !"Failed creating pool for asynchronous device" ); return AK_Fail; } AK_SETPOOLNAME( m_poolID, L"Deferred I/O hook" ); return AK_Success; } return AK_Fail; }
// Writes data to a file (asynchronous overload). AKRESULT CAkDefaultIOHookDeferred::Write( AkFileDesc & in_fileDesc, // File descriptor. const AkIoHeuristics & /*in_heuristics*/, // Heuristics for this data transfer (not used in this implementation). AkAsyncIOTransferInfo & io_transferInfo // Platform-specific asynchronous IO operation info. ) { AKASSERT( in_fileDesc.hFile != INVALID_HANDLE_VALUE && io_transferInfo.uRequestedSize > 0 ); // If this assert comes up, it might be beacause this hook's GetBlockSize() return value is incompatible // with the system's handling of file reading for this specific file handle. // Are you using the File Package Low-Level I/O with incompatible block size? (check -blocksize argument in the File Packager command line) AKASSERT( io_transferInfo.uFilePosition % GetBlockSize( in_fileDesc ) == 0 || !"Requested file position for I/O transfer is inconsistent with block size" ); OVERLAPPED * pOverlapped = GetFreeOverlapped( &io_transferInfo ); // Set file offset in OVERLAPPED structure. pOverlapped->Offset = (DWORD)( io_transferInfo.uFilePosition & 0xFFFFFFFF ); pOverlapped->OffsetHigh = (DWORD)( ( io_transferInfo.uFilePosition >> 32 ) & 0xFFFFFFFF ); // File was open with asynchronous flag. // Read overlapped. if ( ::WriteFileEx( in_fileDesc.hFile, io_transferInfo.pBuffer, io_transferInfo.uRequestedSize, pOverlapped, CAkDefaultIOHookDeferred::FileIOCompletionRoutine ) ) { return AK_Success; } ReleaseOverlapped( pOverlapped ); return AK_Fail; }
// Helper: Find a file entry by ID. const CAkFilePackageLUT::AkFileEntry * CAkFilePackageLUT::LookupFile( AkFileID in_uID, // File ID. const FileLUT * in_pLut, // LUT to search. bool in_bIsLanguageSpecific // True: match language ID. ) { const AkFileEntry * pTable = in_pLut->FileEntries(); AKASSERT( pTable && in_pLut->HasFiles() ); AkUInt16 uLangID = in_bIsLanguageSpecific ? m_curLangID : AK_INVALID_LANGUAGE_ID; // Binary search. LUT items should be sorted by fileID, then by language ID. AkInt32 uTop = 0, uBottom = in_pLut->NumFiles()-1; do { AkInt32 uThis = ( uBottom - uTop ) / 2 + uTop; if ( pTable[ uThis ].fileID > in_uID ) uBottom = uThis - 1; else if ( pTable[ uThis ].fileID < in_uID ) uTop = uThis + 1; else { // Correct ID. Check language. if ( pTable[ uThis ].uLanguageID > uLangID ) uBottom = uThis - 1; else if ( pTable[ uThis ].uLanguageID < uLangID ) uTop = uThis + 1; else return pTable + uThis; } } while ( uTop <= uBottom ); return NULL; }
AkUInt32 CAkFilePackageLUT::StringMap::GetID( const AkOSChar* in_pszString ) { // Make string lower case. size_t uStrLen = AKPLATFORM::OsStrLen(in_pszString)+1; AkOSChar * pszLowerCaseString = (AkOSChar*)AkAlloca(uStrLen*sizeof(AkOSChar)); AKASSERT( pszLowerCaseString ); AKPLATFORM::SafeStrCpy(pszLowerCaseString, in_pszString, uStrLen ); _MakeLower( pszLowerCaseString ); // 'this' is m_uNumStrings. +1 points to the beginning of the StringEntry array. StringEntry * pTable = (StringEntry*)((AkUInt32*)this + 1); // Binary search: strings are sorted (case sensitive). AkInt32 uTop = 0, uBottom = m_uNumStrings-1; do { AkInt32 uThis = ( uBottom - uTop ) / 2 + uTop; AkOSChar * pString = (AkOSChar*)((AkUInt8*)this + pTable[ uThis ].uOffset); int iCmp = AKPLATFORM::OsStrCmp( pString, pszLowerCaseString ); if ( 0 == iCmp ) return pTable[uThis].uID; else if ( iCmp > 0 ) //in_pTable[ uThis ].pString > pszLowerCaseString uBottom = uThis - 1; else //in_pTable[ uThis ].pString < pszLowerCaseString uTop = uThis + 1; } while ( uTop <= uBottom ); // ID not found. return AK_INVALID_UNIQUE_ID; }
AKRESULT CFileIOHandler_wwise::Init(AkDeviceSettings const& rDeviceSettings, bool const bAsyncOpen /* = false */) { AKRESULT eResult = AK_Fail; if (rDeviceSettings.uSchedulerTypeFlags == AK_SCHEDULER_BLOCKING) { m_bAsyncOpen = 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_nDeviceID = AK::StreamMgr::CreateDevice(rDeviceSettings, this); if (m_nDeviceID != AK_INVALID_DEVICE_ID) { eResult = AK_Success; } } else { AKASSERT(!"CAkDefaultIOHookBlocking I/O hook only works with AK_SCHEDULER_BLOCKING devices"); } return eResult; }
// 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; }
AKRESULT CFileIOHandler_wwise::Write(AkFileDesc& rFileDesc, AkIoHeuristics const& rHeuristics, void* pBuffer, AkIOTransferInfo& rTransferInfo) { AKASSERT(pBuffer != nullptr && rFileDesc.hFile != AkFileHandle(INVALID_HANDLE_VALUE)); FILE* const pFile = reinterpret_cast<FILE*>(rFileDesc.hFile); long const nCurrentFileWritePos = gEnv->pCryPak->FTell(pFile); long const nWantedFileWritePos = static_cast<long>(rTransferInfo.uFilePosition); if (nCurrentFileWritePos != nWantedFileWritePos) { gEnv->pCryPak->FSeek(pFile, nWantedFileWritePos, SEEK_SET); } size_t const nBytesWritten = gEnv->pCryPak->FWrite(pBuffer, 1, static_cast<size_t>(rTransferInfo.uRequestedSize), pFile); AKASSERT(nBytesWritten == static_cast<size_t>(rTransferInfo.uRequestedSize)); return (nBytesWritten > 0) ? AK_Success : AK_Fail; }
// Reads data from a file (asynchronous overload). AKRESULT CAkDefaultIOHookDeferred::Read( AkFileDesc & in_fileDesc, // File descriptor. const AkIoHeuristics & /*in_heuristics*/, // Heuristics for this data transfer (not used in this implementation). AkAsyncIOTransferInfo & io_transferInfo // Asynchronous data transfer info. ) { AKASSERT( in_fileDesc.hFile != INVALID_HANDLE_VALUE && io_transferInfo.uRequestedSize > 0 && io_transferInfo.uBufferSize >= io_transferInfo.uRequestedSize ); // If this assert comes up, it might be beacause this hook's GetBlockSize() return value is incompatible // with the system's handling of file reading for this specific file handle. // If you are using the File Package extension, did you create your package with a compatible // block size? It should be a multiple of WIN32_NO_BUFFERING_BLOCK_SIZE. (check -blocksize argument in the File Packager command line) AKASSERT( ( io_transferInfo.uFilePosition % WIN32_NO_BUFFERING_BLOCK_SIZE ) == 0 || !"Requested file position for I/O transfer is inconsistent with block size" ); OVERLAPPED * pOverlapped = GetFreeOverlapped( &io_transferInfo ); // Set file offset in OVERLAPPED structure. pOverlapped->Offset = (DWORD)( io_transferInfo.uFilePosition & 0xFFFFFFFF ); pOverlapped->OffsetHigh = (DWORD)( ( io_transferInfo.uFilePosition >> 32 ) & 0xFFFFFFFF ); // File was open with asynchronous flag. // Read overlapped. // Note: With a file handle opened with FILE_FLAG_NO_BUFFERING, ::ReadFileEx() supports read sizes that go beyond the end // of file. However, it does not support read sizes that are not a multiple of the drive's sector size. // Since the buffer size is always a multiple of the block size, let's use io_transferInfo.uBufferSize // instead of io_transferInfo.uRequestedSize. if ( ::ReadFileEx( in_fileDesc.hFile, io_transferInfo.pBuffer, io_transferInfo.uBufferSize, pOverlapped, CAkDefaultIOHookDeferred::FileIOCompletionRoutine ) ) { return AK_Success; } ReleaseOverlapped( pOverlapped ); return AK_Fail; }
// Find a file entry by ID. const CAkFilePackageLUT::AkFileEntry<AkUInt64> *CAkFilePackageLUT::LookupFile( AkUInt64 in_uID, // File ID. AkFileSystemFlags *in_pFlags // Special flags. Do not pass NULL. ) { AKASSERT( in_pFlags ); if ( in_pFlags->uCompanyID == AKCOMPANYID_AUDIOKINETIC_EXTERNAL && m_pExternals && m_pExternals->HasFiles() ) { return LookupFile<AkUInt64>( in_uID, m_pExternals, in_pFlags->bIsLanguageSpecific ); } // No table loaded. return NULL; }
AKRESULT CFileIOHandler_wwise::Close(AkFileDesc& rFileDesc) { AKRESULT eResult = AK_Fail; if (!gEnv->pCryPak->FClose(reinterpret_cast<FILE*>(rFileDesc.hFile))) { eResult = AK_Success; } else { AKASSERT(!"Failed to close file handle"); } return eResult; }
// 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 }
// Find a file entry by ID. const CAkFilePackageLUT::AkFileEntry<AkFileID> *CAkFilePackageLUT::LookupFile( AkFileID in_uID, // File ID. AkFileSystemFlags *in_pFlags // Special flags. Do not pass NULL. ) { AKASSERT( in_pFlags && in_pFlags->uCompanyID == AKCOMPANYID_AUDIOKINETIC ); if ( in_pFlags->uCodecID == AKCODECID_BANK && m_pSoundBanks && m_pSoundBanks->HasFiles() ) { return LookupFile<AkFileID>( in_uID, m_pSoundBanks, in_pFlags->bIsLanguageSpecific ); } else if ( m_pStmFiles && m_pStmFiles->HasFiles() ) { // We assume that the file is a streamed audio file. return LookupFile<AkFileID>( in_uID, m_pStmFiles, in_pFlags->bIsLanguageSpecific ); } // No table loaded. return NULL; }
AKRESULT CAkDefaultLowLevelIODispatcher::AddDevice( AK::StreamMgr::IAkFileLocationResolver * in_pHook ) { // Add the device in a free slot. for ( AkUInt32 uRecord = 0; uRecord < AK_MAX_IO_DEVICES; uRecord++ ) { if ( !m_arDevices[uRecord] ) { m_arDevices[uRecord] = in_pHook; ++m_uNumDevices; return AK_Success; } } AKASSERT( !"Cannot hold any more I/O devices" ); return AK_Fail; }
AKRESULT s3eIOHook::Init(const AkDeviceSettings &in_deviceSettings) { if ( in_deviceSettings.uSchedulerTypeFlags != AK_SCHEDULER_BLOCKING ) { AKASSERT( !"s3eIOHook I/O hook only works with AK_SCHEDULER_BLOCKING devices" ); return AK_Fail; } // 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; }
AKRESULT s3eIOHook::Open(const AkOSChar* in_pszFileName, AkOpenMode in_eOpenMode, AkFileSystemFlags *in_pFlags, bool &io_bSyncOpen, AkFileDesc &out_fileDesc) { io_bSyncOpen = true; const char *mode; switch ( in_eOpenMode ) { case AK_OpenModeRead: mode = "r"; break; case AK_OpenModeWrite: mode = "w"; break; case AK_OpenModeWriteOvrwr: mode = "w+"; break; case AK_OpenModeReadWrite: mode = "a"; break; default: AKASSERT( !"Invalid open mode" ); return AK_InvalidParameter; break; } s3eFile *file = s3eFileOpen(in_pszFileName, mode); if ( file != NULL ) { out_fileDesc.iFileSize = s3eFileGetSize(file); out_fileDesc.uSector = 0; out_fileDesc.deviceID = m_deviceID; out_fileDesc.pCustomParam = NULL; out_fileDesc.uCustomParamSize = 0; out_fileDesc.hFile = (AkFileHandle)file; return AK_Success; } return AK_Fail; }
// Local callback for overlapped I/O. VOID CALLBACK CAkDefaultIOHookDeferred::FileIOCompletionRoutine( DWORD dwErrorCode, DWORD #ifdef _DEBUG dwNumberOfBytesTransfered #endif , LPOVERLAPPED lpOverlapped ) { AkAsyncIOTransferInfo *pXferInfo = (AkAsyncIOTransferInfo *)(lpOverlapped->hEvent); ReleaseOverlapped( lpOverlapped ); AKRESULT eResult = AK_Fail; if ( ERROR_SUCCESS == dwErrorCode ) { eResult = AK_Success; AKASSERT( dwNumberOfBytesTransfered >= pXferInfo->uRequestedSize && dwNumberOfBytesTransfered <= pXferInfo->uBufferSize ); } pXferInfo->pCallback( pXferInfo, eResult ); }
// Returns a file descriptor for a given file ID. AKRESULT CAkDefaultLowLevelIODispatcher::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. ) { // Here, you need to define a strategy to determine which device is going to handle this file's I/O. // You could use the AkFileSystemFlags if it depends on file type, or define a map, or read the mapping // from an XML file... it is up to the game's organization. // Since this default implementation doesn't know anything about that, it forwards the calls to each // device until one of them succeeds. // Disable deferred opening because devices may usually return AK_Success if io_bSyncOpen=false, // and we count on the fact that they will return AK_Fail to select the proper device. io_bSyncOpen = true; AKRESULT eResult = AK_FileNotFound; AkUInt32 uDevice = 0; while ( uDevice < AK_MAX_IO_DEVICES && eResult != AK_Success ) { if ( m_arDevices[uDevice] ) { eResult = m_arDevices[uDevice]->Open( in_fileID, // File ID. in_eOpenMode, // Open mode. in_pFlags, // Special flags. Can pass NULL. 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. out_fileDesc // Returned file descriptor. ); AKASSERT( io_bSyncOpen || !"It is illegal to reset io_bSyncOpen" ); } ++uDevice; } return eResult; }
// ID overload. // The name of the file will be formatted as ID.ext. This is meant to be used with options // "Use SoundBank Names" unchecked, and/or "Copy Streamed Files" in the SoundBank Settings. // For more details, refer to the SoundBank Settings in Wwise Help, and to section "Identifying Banks" inside // "Sound Engine Integration Walkthrough > Integrate Wwise Elements into Your Game > Integrating Banks > // Integration Details - Banks > General Information" of the SDK documentation. // Returns AK_Success if input flags are supported and the resulting path is not too long. // Returns AK_Fail otherwise. AKRESULT CAkFileLocationBase::GetFullFilePath( AkFileID in_fileID, // File ID. AkFileSystemFlags * in_pFlags, // Special flags. AkOpenMode /* in_eOpenMode*/, // File open mode (read, write, ...). AkOSChar * out_pszFullFilePath // Full file path. ) { // If the file descriptor could not be found, or if the script-based FS does not exist, // map file ID to file descriptor (string based) for Audiokinetic IDs. if ( !in_pFlags || !(in_pFlags->uCompanyID == AKCOMPANYID_AUDIOKINETIC || in_pFlags->uCompanyID == AKCOMPANYID_AUDIOKINETIC_EXTERNAL)) { AKASSERT( !"Unhandled file type" ); return AK_Fail; } // Compute file name with file system paths. size_t uiPathSize = AKPLATFORM::OsStrLen( m_szBasePath ); // Copy base path. AKPLATFORM::SafeStrCpy( out_pszFullFilePath, m_szBasePath, AK_MAX_PATH ); // Concatenate path for AK banks or streamed audio files (everything except banks). if ( in_pFlags->uCodecID == AKCODECID_BANK ) { uiPathSize += AKPLATFORM::OsStrLen( m_szBankPath ); if ( uiPathSize >= AK_MAX_PATH ) { AKASSERT( !"Path is too large" ); return AK_Fail; } AKPLATFORM::SafeStrCat( out_pszFullFilePath, m_szBankPath, AK_MAX_PATH ); } else { uiPathSize += AKPLATFORM::OsStrLen( m_szAudioSrcPath ); if ( uiPathSize >= AK_MAX_PATH ) { AKASSERT( !"Path is too large" ); return AK_Fail; } AKPLATFORM::SafeStrCat( out_pszFullFilePath, m_szAudioSrcPath, AK_MAX_PATH ); } // Externally supplied source (see External Sources in SDK doc) // In this sample, we will assume that the file to load when receiving an external FileID is // simply the FileID.wem (e.g. "12345.wem"). If you use the External Source feature // you should modify this section to handle your FileIDs properly. /*if (in_pFlags->uCompanyID == AKCOMPANYID_AUDIOKINETIC_EXTERNAL) { }*/ // Add language directory name if needed. if ( in_pFlags->bIsLanguageSpecific ) { size_t uLanguageStrLen = AKPLATFORM::OsStrLen( AK::StreamMgr::GetCurrentLanguage() ); if ( uLanguageStrLen > 0 ) { uiPathSize += ( uLanguageStrLen + 1 ); if ( uiPathSize >= AK_MAX_PATH ) { AKASSERT( !"Path is too large" ); return AK_Fail; } AKPLATFORM::SafeStrCat( out_pszFullFilePath, AK::StreamMgr::GetCurrentLanguage(), AK_MAX_PATH ); AKPLATFORM::SafeStrCat( out_pszFullFilePath, AK_PATH_SEPARATOR, AK_MAX_PATH ); } } // Append file title. if ( ( uiPathSize + MAX_FILETITLE_SIZE ) <= AK_MAX_PATH ) { AkOSChar * pszTitle = out_pszFullFilePath + uiPathSize; if ( in_pFlags->uCodecID == AKCODECID_BANK ) AK_OSPRINTF( pszTitle, MAX_FILETITLE_SIZE, ID_TO_STRING_FORMAT_BANK, (unsigned int)in_fileID ); else AK_OSPRINTF( pszTitle, MAX_FILETITLE_SIZE, ID_TO_STRING_FORMAT_WEM, (unsigned int)in_fileID ); } else { AKASSERT( !"String buffer too small" ); return AK_Fail; } return AK_Success; }
AKRESULT CFileIOHandler_wwise::Open(AkOSChar const* sFileName, AkOpenMode eOpenMode, AkFileSystemFlags* pFlags, bool& rSyncOpen, AkFileDesc& rFileDesc) { AKRESULT eResult = AK_Fail; if (rSyncOpen || !m_bAsyncOpen) { rSyncOpen = true; AkOSChar sFinalFilePath[AK_MAX_PATH] = {'\0'}; AKPLATFORM::SafeStrCat(sFinalFilePath, m_sBankPath, AK_MAX_PATH); if (pFlags != nullptr && eOpenMode == AK_OpenModeRead) { // Add language folder if the file is localized. if (pFlags->uCompanyID == AKCOMPANYID_AUDIOKINETIC && pFlags->uCodecID == AKCODECID_BANK && pFlags->bIsLanguageSpecific) { AKPLATFORM::SafeStrCat(sFinalFilePath, m_sLanguageFolder, AK_MAX_PATH); } } AKPLATFORM::SafeStrCat(sFinalFilePath, sFileName, AK_MAX_PATH); char* sTemp = nullptr; CONVERT_OSCHAR_TO_CHAR(sFinalFilePath, sTemp); char const* sOpenMode = nullptr; switch (eOpenMode) { case AK_OpenModeRead: { sOpenMode = "rbx"; break; } case AK_OpenModeWrite: { sOpenMode = "wbx"; break; } case AK_OpenModeWriteOvrwr: { sOpenMode = "w+bx"; break; } case AK_OpenModeReadWrite: { sOpenMode = "abx"; break; } default: { AKASSERT(!"Unknown file open mode!"); break; } } FILE* const pFile = gEnv->pCryPak->FOpen(sTemp, sOpenMode, ICryPak::FOPEN_HINT_DIRECT_OPERATION); if (pFile != nullptr) { rFileDesc.iFileSize = static_cast<AkInt64>(gEnv->pCryPak->FGetSize(sTemp)); rFileDesc.hFile = GetFileHandle(pFile); rFileDesc.uSector = 0; rFileDesc.deviceID = m_nDeviceID; rFileDesc.pCustomParam = nullptr; rFileDesc.uCustomParamSize = 0; eResult = AK_Success; } } return eResult; }
// String overload. // Returns AK_Success if input flags are supported and the resulting path is not too long. // Returns AK_Fail otherwise. AKRESULT CAkFileLocationBase::GetFullFilePath( const AkOSChar* in_pszFileName, // File name. AkFileSystemFlags * in_pFlags, // Special flags. Can be NULL. AkOpenMode in_eOpenMode, // File open mode (read, write, ...). AkOSChar* out_pszFullFilePath // Full file path. ) { if ( !in_pszFileName ) { AKASSERT( !"Invalid file name" ); return AK_InvalidParameter; } // Prepend string path (basic file system logic). // Compute file name with file system paths. size_t uiPathSize = AKPLATFORM::OsStrLen( in_pszFileName ); if ( uiPathSize >= AK_MAX_PATH ) { AKASSERT( !"Input string too large" ); return AK_InvalidParameter; } #ifdef AK_WIN // MP3 files using the MP3 sample code, usually being provided by the gamer will // not be located in the game path, for these sounds, we are using the Full path // to access them. if ( in_pFlags != NULL && in_pFlags->uCodecID == AKSOURCEID_MP3 && in_pFlags->uCompanyID == AKCOMPANYID_AUDIOKINETIC ) { out_pszFullFilePath[0] = 0; } else #endif { AKPLATFORM::SafeStrCpy( out_pszFullFilePath, m_szBasePath, AK_MAX_PATH ); } if ( in_pFlags && in_eOpenMode == AK_OpenModeRead ) { // Add bank path if file is an AK sound bank. if ( in_pFlags->uCompanyID == AKCOMPANYID_AUDIOKINETIC && in_pFlags->uCodecID == AKCODECID_BANK ) { uiPathSize += AKPLATFORM::OsStrLen( m_szBankPath ); if ( uiPathSize >= AK_MAX_PATH ) { AKASSERT( !"Path is too large" ); return AK_Fail; } AKPLATFORM::SafeStrCat( out_pszFullFilePath, m_szBankPath, AK_MAX_PATH ); } // Note: Standard streaming files do not use this overload. On the other hand, streaming external // sources use it if you use AkExternalSourceInfo::szFile instead of AkExternalSourceInfo::idFile. // Externally supplied source (see External Sources in SDK doc) // In this sample, we will assume that the external source file name in_pszFileName // must be used as is (e.g. "myExternalSourceFile.wem"). If you use the External Source feature // you should modify this section to handle your FileIDs properly. /*if (in_pFlags->uCompanyID == AKCOMPANYID_AUDIOKINETIC_EXTERNAL) { }*/ // Add language directory name if needed. if ( in_pFlags->bIsLanguageSpecific ) { size_t uLanguageStrLen = AKPLATFORM::OsStrLen( AK::StreamMgr::GetCurrentLanguage() ); if ( uLanguageStrLen > 0 ) { uiPathSize += ( uLanguageStrLen + 1 ); if ( uiPathSize >= AK_MAX_PATH ) { AKASSERT( !"Path is too large" ); return AK_Fail; } AKPLATFORM::SafeStrCat( out_pszFullFilePath, AK::StreamMgr::GetCurrentLanguage(), AK_MAX_PATH ); AKPLATFORM::SafeStrCat( out_pszFullFilePath, AK_PATH_SEPARATOR, AK_MAX_PATH ); } } } // Append file title. uiPathSize += AKPLATFORM::OsStrLen( out_pszFullFilePath ); if ( uiPathSize >= AK_MAX_PATH ) { AKASSERT( !"File name string too large" ); return AK_Fail; } AKPLATFORM::SafeStrCat( out_pszFullFilePath, in_pszFileName, AK_MAX_PATH ); return AK_Success; }
AKRESULT Init( AkMemSettings * in_pMemSettings, AkStreamMgrSettings * in_pStmSettings, AkDeviceSettings * in_pDefaultDeviceSettings, AkInitSettings * in_pSettings, AkPlatformInitSettings * in_pPlatformSettings, AkMusicSettings * in_pMusicSettings ) { // Check required arguments. if ( !in_pMemSettings || !in_pStmSettings || !in_pDefaultDeviceSettings ) { AKASSERT( !"Invalid arguments" ); return AK_InvalidParameter; } // Create and initialise an instance of our memory manager. if ( AK::MemoryMgr::Init( in_pMemSettings ) != AK_Success ) { AKASSERT( !"Could not create the memory manager." ); return AK_Fail; } // Create and initialise an instance of the default stream manager. if ( !AK::StreamMgr::Create( *in_pStmSettings ) ) { AKASSERT( !"Could not create the Stream Manager" ); return AK_Fail; } // Create an IO device. #ifdef AK_ANDROID if (g_assetManager == NULL) { AKASSERT( !"Could not find Android asset manager" ); return AK_Fail; } g_lowLevelIO.SetAssetManager(g_assetManager); #endif if ( g_lowLevelIO.Init( *in_pDefaultDeviceSettings ) != AK_Success ) { AKASSERT( !"Cannot create streaming I/O device" ); return AK_Fail; } #ifdef AK_ANDROID in_pPlatformSettings->pJavaVM = java_vm; #endif #ifdef AK_IOS in_pPlatformSettings->bAppListensToInterruption = true; #endif // #ifdef AK_IOS // Initialize sound engine. if ( AK::SoundEngine::Init( in_pSettings, in_pPlatformSettings ) != AK_Success ) { AKASSERT( !"Cannot initialize sound engine" ); return AK_Fail; } // Initialize music engine. if ( AK::MusicEngine::Init( in_pMusicSettings ) != AK_Success ) { AKASSERT( !"Cannot initialize music engine" ); return AK_Fail; } #ifndef AK_OPTIMIZED #ifndef AK_METRO // Initialize communication. AkCommSettings settingsComm; AK::Comm::GetDefaultInitSettings( settingsComm ); if ( AK::Comm::Init( settingsComm ) != AK_Success ) { AKASSERT( !"Cannot initialize music communication" ); } #endif // #ifndef AK_METRO #endif // AK_OPTIMIZED // Register plugins if ( AK::SoundEngine::RegisterAllPlugins( ) != AK_Success ) { AKASSERT( !"Error while registering plug-ins" ); return AK_Fail; } return AK_Success; }