Table of Contents

Initialize the Different Modules of the Sound Engine

Introduction

The first step in integrating the Wwise sound engine is to properly initialize the various modules that make up the sound engine when the game starts up.

In this sample project, the following function is defined to perform everything related to initialization of the sound engine:

bool InitSoundEngine()
{
    ... Initialization will be done here ...

    return true;
}

It is called at the beginning of the main function. Let's look at the various items that need initializing:

Memory Hooks

Every project that links with the Wwise sound engine must define several hooks. These can then be used to monitor calls to memory access methods.

Windows
/////////////////////////////////////////////////////////////////////////////////
// Custom alloc/free functions. These are declared as "extern" in AkMemoryMgr.h
// and MUST be defined by the game developer.
/////////////////////////////////////////////////////////////////////////////////
namespace AK
{
#ifdef WIN32
    void * AllocHook( size_t in_size )
    {
        return malloc( in_size );
    }
    void FreeHook( void * in_ptr )
    {
        free( in_ptr );
    }
    // Note: VirtualAllocHook() may be used by I/O pools of the default implementation
    // of the Stream Manager, to allow "true" unbuffered I/O (using FILE_FLAG_NO_BUFFERING
    // - refer to the Windows SDK documentation for more details). This is NOT mandatory;
    // you may implement it with a simple malloc().
    void * VirtualAllocHook(
        void * in_pMemAddress,
        size_t in_size,
        DWORD in_dwAllocationType,
        DWORD in_dwProtect
        )
    {
        return VirtualAlloc( in_pMemAddress, in_size, in_dwAllocationType, in_dwProtect );
    }
    void VirtualFreeHook( 
        void * in_pMemAddress,
        size_t in_size,
        DWORD in_dwFreeType
        )
    {
        VirtualFree( in_pMemAddress, in_size, in_dwFreeType );
    }
#endif
}
Mac OS X
/////////////////////////////////////////////////////////////////////////////////
// Custom alloc/free functions. These are declared as "extern" in AkMemoryMgr.h
// and MUST be defined by the game developer.
/////////////////////////////////////////////////////////////////////////////////
namespace AK
{
#ifdef AK_APPLE
    void * AllocHook( size_t in_size )
    {
        return malloc( in_size );
    }
    void FreeHook( void * in_ptr )
    {
        free( in_ptr );
    }
#endif
}
iOS
/////////////////////////////////////////////////////////////////////////////////
// Custom alloc/free functions. These are declared as "extern" in AkMemoryMgr.h
// and MUST be defined by the game developer.
/////////////////////////////////////////////////////////////////////////////////
namespace AK
{
#ifdef AK_APPLE
    void * AllocHook( size_t in_size )
    {
        return malloc( in_size );
    }
    void FreeHook( void * in_ptr )
    {
        free( in_ptr );
    }
#endif
}

Initializing the Memory Manager

The first thing you must initialize is the Memory Manager. The following code creates the default Memory Manager with twenty memory pools:

#include <AK/SoundEngine/Common/AkMemoryMgr.h>                  // Memory Manager
#include <AK/SoundEngine/Common/AkModule.h>                     // Default memory and stream managers

(...)

bool InitSoundEngine()
{
    //
    // Create and initialize an instance of the default memory manager. Note
    // that you can override the default memory manager with your own. Refer
    // to the SDK documentation for more information.
    //

    AkMemSettings memSettings;
    memSettings.uMaxNumPools = 20;

    if ( AK::MemoryMgr::Init( &memSettings ) != AK_Success )
    {
        assert( ! "Could not create the memory manager." );
        return false;
    }
    
    (...)
}
Note.gif
Note: You can override the Memory Manager, in which case the code presented above must be adapted as needed. Refer to Overriding the memory manager for more information.

Refer to Memory Manager for more details regarding the Memory Manager.

Initializing the Streaming Manager

Once the Memory Manager has been initialized, we can move on to the Streaming Manager.

The following code initializes the default Streaming Manager. It requires an instance of AK::StreamMgr::IAkFileLocationResolver, and creates a streaming device. This requires an instance of AK::StreamMgr::IAkIOHookBlocking or AK::StreamMgr::IAkIOHookDeferred, depending on the streaming device scheduler type (AK_DEVICE_BLOCKING or AK_DEVICE_DEFERRED_LINED_UP). These interfaces are defined in AkStreamMgrModule.h, which contains all definitions that are specific to the default Stream Manager implementation provided with the SDK.

The recommended way of integrating the sound engine with regards to disk I/O is to use the default Stream Manager implementation, and implement the interfaces defined in AkStreamMgrModule.h. These interfaces constitute the Low-Level I/O submodule. Refer to Streaming / Stream Manager for more information.

This example uses the sample CAkFilePackageLowLevelIOBlocking as is. This class implements both AK::StreamMgr::IAkFileLocationResolver and AK::StreamMgr::IAkIOHookBlocking interfaces, and is able to load file packages generated with the File Packager utility (refer to File Package Low-Level I/O Implementation and File Packager Utility for more information about the File Packager and how it works in the Low-Level I/O).

Refer to Low-Level I/O for more information about the Low-Level I/O.

#include <AK/SoundEngine/Common/IAkStreamMgr.h>                 // Streaming Manager
#include <AK/Tools/Common/AkPlatformFuncs.h>                    // Thread defines
#include <AkFilePackageLowLevelIOBlocking.h>                    // Sample low-level I/O implementation

(...)

// We're using the default Low-Level I/O implementation that's part
// of the SDK's sample code, with the file package extension
CAkFilePackageLowLevelIOBlocking g_lowLevelIO;

(...)

bool InitSoundEngine()
{
    (...)
        
    //
    // Create and initialize an instance of the default streaming manager. Note
    // that you can override the default streaming manager with your own. Refer
    // to the SDK documentation for more information.
    //

    AkStreamMgrSettings stmSettings;
    AK::StreamMgr::GetDefaultSettings( stmSettings );
    
    // Customize the Stream Manager settings here.
    
    if ( !AK::StreamMgr::Create( stmSettings ) )
    {
        assert( ! "Could not create the Streaming Manager" );
        return false;
    }
    
    //
    // Create a streaming device with blocking low-level I/O handshaking.
    // Note that you can override the default low-level I/O module with your own. Refer
    // to the SDK documentation for more information.      
    //
    AkDeviceSettings deviceSettings;
    AK::StreamMgr::GetDefaultDeviceSettings( deviceSettings );
    
    // Customize the streaming device settings here.
    
    // CAkFilePackageLowLevelIOBlocking::Init() creates a streaming device
    // in the Stream Manager, and registers itself as the File Location Resolver.
    if ( g_lowLevelIO.Init( deviceSettings ) != AK_Success )
    {
        assert( ! "Could not create the streaming device and Low-Level I/O system" );
        return false;
    }
    
    (...)
}

For more information about the initialization settings of the default Stream Manager and streaming devices, refer to Audiokinetic Stream Manager Initialization Settings.

Caution.gif
Caution: Some of the initialization settings use member structures that are platform specific, like the AkThreadProperties.

If you decide to override the default Low-Level IO implementation, or the complete Streaming Manager, this code will need to be adapted accordingly. Refer to Streaming / Stream Manager for more information.

Initializing the Sound Engine

Now that the basic modules have been initialized, we're ready to initialize the sound engine itself:

#include <AK/SoundEngine/Common/AkSoundEngine.h>                // Sound engine

(...)

bool InitSoundEngine()
{
    (...)

    //
    // Create the Sound Engine
    // Using default initialization parameters
    //
    
    AkInitSettings initSettings;
    AkPlatformInitSettings platformInitSettings;
    AK::SoundEngine::GetDefaultInitSettings( initSettings );
    AK::SoundEngine::GetDefaultPlatformInitSettings( platformInitSettings );

    if ( AK::SoundEngine::Init( &initSettings, &platformInitSettings ) != AK_Success )
    {
        assert( ! "Could not initialize the Sound Engine." );
        return false;
    }
    
    (...)
}

For more information about how to initialize the sound engine, refer to Advanced Sound Engine Integration

Initializing the Music Engine

If your project uses the Interactive Music feature, the music engine must be initialized after the sound engine.

#include <AK/MusicEngine/Common/AkMusicEngine.h>                // Music Engine

(...)

bool InitSoundEngine()
{
    (...)

    //
    // Initialize the music engine
    // Using default initialization parameters
    //
    
    AkMusicSettings musicInit;
    AK::MusicEngine::GetDefaultInitSettings( musicInit );
        
    if ( AK::MusicEngine::Init( &musicInit ) != AK_Success )
    {
        assert( ! "Could not initialize the Music Engine." );
        return false;
    }
    
    (...)
}

Initializing Communications

If you want to be able to use the Wwise authoring application to connect to your game and perform in-game mixing, profiling and troubleshooting, the next step is to initialize communications. It is strongly recommended to do so, as in-game mixing, profiling and troubleshooting are extremely powerful ways for the sound designer to work on your game's audio in a more efficient way.

Note.gif
Note: To use communications, you need to link with the CommunicationCentral module.
Note.gif
Note: Communications are available in the Debug and Profile configurations of the sound engine only. They are not needed in the retail version of your game, so they are not part of the Release build of the sound engine. The following code uses the AK_OPTIMIZED symbol to leave communication-specific code out of the release build.
// Include for communication between Wwise and the game -- Not needed in the release version
#ifndef AK_OPTIMIZED
    #include <AK/Comm/AkCommunication.h>
#endif // AK_OPTIMIZED

(...)

bool InitSoundEngine()
{
    (...)

#ifndef AK_OPTIMIZED
    //
    // Initialize communications (not in release build!)
    //
    AkCommSettings commSettings;
    AK::Comm::GetDefaultInitSettings( commSettings );
    if ( AK::Comm::Init( commSettings ) != AK_Success )
    {
        assert( ! "Could not initialize communication." );
        return false;
    }
#endif // AK_OPTIMIZED

    (...)
}

You have now initialized all of the sound engine's modules. You should then register the plug-ins (see Plug-in Example). Refer to Create Recurring Calls to Perform Audio Processing for details on the calls you must make in your game loop to process the audio.

Console specific communication library

Some console communication libraries don't balance the initialization/termination calls properly; therefore, calling AK::Comm::Term will terminate the underlying low-level communication library for the console. This effectively closes all TCP/IP communication for the game. If your game needs to keep the communication libraries enabled after termination, AkCommSettings (used with Ak::Comm:Init) has a parameter to initialize the system library or not. If you choose to initialize the communication library yourself, check the code used by the Wwise sound engine below. The game should do something similar.

Windows

Windows sockets initialization:

WSAData wsaData = { 0 };
::WSAStartup( MAKEWORD( 2, 2 ), &wsaData )  

Termination:

::WSACleanup();

Communication Ports

The AkCommSettings::ports member of the AkCommSettings structure represents network ports used for communication between the Wwise authoring application and the sound engine. All of these ports are opened in the game when Wwise communication is enabled.

One Fixed Port: Discovery Broadcast

One of the ports, AkCommSettings::Ports::uDiscoveryBroadcast, cannot be dynamic (cannot be set to 0). The authoring application needs to be aware of it in order to discover games on the network. Furthermore, the value specified here must be the same value specified in the Network tab of the Project Settings within the authoring application.

Tip.gif
Tip: If your team is working on multiple games using Wwise, you might want to use different Discovery Broadcast ports for each game. That way when you open the Remote Connections window in the Wwise authoring application, only games corresponding to the currently opened Wwise project will be listed. When changing this port, be sure to change it both in the Project Settings within the authoring application and in the AkCommSettings structure you pass to AK::Comm::Init() in the game.

Two Dynamic Ports

The two other ports in the structure can be dynamic (or "ephemeral"). This means that instead of using a fixed port, one is automatically picked by the operating system:

These ports are dynamic by default. It is recommended to keep them dynamic in order to minimize chances of conflicts with other applications.

Wwise requires three sequential channels to works properly, and they must be ordered in the order they are presented in the Port structure. In Wwise, you can select the base port (By default 8).

If they conflict with ports used by other components of your game, simply change them in the AkCommSettings structure before calling AK::Comm::Init().

Note.gif
Note: In a multi-platform game, it is valid to use different ports on different platforms for AkCommSettings::Ports::uCommand and AkCommSettings::Ports::uNotification.
Tip.gif

Tip: For more information on dynamic/ephemeral ports, please consult these web sites:

One More Port (Authoring Application Only)

There is one more port involved in Wwise communications, but since it is opened in the authoring application only, it is not part of the AkCommSettings::Ports structure.

That port is used by the authoring application to receive reponses to the Discovery Broadcast messages sent to detect games running on the network. It is dynamic by default (set to 0) but can be changed in the Project Settings within the authoring application.