Table of Contents

Integrating Secondary Outputs

In Wwise, a secondary output designates any physical audio end-point that is not the regular TV audio output. The most common secondary outputs are the game controller speakers and headsets. The Secondary Output feature allows you to define a separate mix for each of these outputs, leaving the main speaker/TV mix unaffected. The same Wwise feature set applies to the secondary outputs as for the regular mix, without any particular restrictions except that the output targets controllers instead of the speaker/TV.

Routing to Secondary Output Bus

On the authoring side, sounds routed to the Secondary Bus hierarchy will be sent to the secondary output using one of the two following approaches:

  • By setting the Output Bus property of a sound directly to any bus in the Secondary Bus hierarchy. This is the preferred method for sounds that are normally tied to only one secondary output instance. For example, player-initiated gun shots, tennis racket whack, PDA sounds, gameplay feedback, etc.
  • Routing a sound through any bus in the Master Audio Bus hierarchy and adding a user or game send to an auxiliary bus inside the Secondary Bus hierarchy. This is the preferred method if the same sound is going to be heard in multiple outputs and the TV at the same time. For example: spy camera, announcements, etc.

It is possible to play the same sound on multiple controllers and on TV at the same time, using the same source. On the design side, there is no knowledge of how many players might be playing the game. This is why there is only one Master Secondary Bus, even if there are multiple outputs possible. This bus hierarchy will be used as a template for routing for each output registered from the game. So each output may have a different mix and effect applied, depending on the sources played, RTPC and switch values active on the game objects . See an example of this in the example section below.

A note on synchronization of outputs

When outputting the same audio on many devices, such as the TV and a game controller, you will probably notice latency between the devices. This is unavoidable due to different hardware in the audio signal's path. On the controller side, the signal may have to travel through a wireless channel, which might give a different delay than for wired controllers. For the TV, once the signal is out of the console, it goes through a receiver and/or a TV, which processors add a certain amount of delay. Since the delay produced by the AV setup is different for each system, it’s not possible to synchronize sounds routed simultaneously to the speaker/TV and the game controllers.Your sound design may need to take this constraint in consideration.

Setting up devices, listeners and game objects for multiple outputs

To represent the device in-game, the regular Listener/GameObject concept is used. See Concept: Listeners for more information. It is the responsability of the game programmer to associate the output device with a listener using AK::SoundEngine::AddSecondaryOutput. The programmer must also setup the listener mask of the Game Objects that should be heard by this listener using AK::SoundEngine::SetActiveListeners or Ak::SoundEngine::RegisterGameObj. Don't forget to add the Listener for the TV if this sound goes on TV too (usually Listener 0).

Note.gif
Note: The game code is responsible for calling AddSecondaryOutput and RemoveSecondaryOutput whenever a game controller (or any other type of audio endpoint) whenever they are connected or disconnected from the system. Wwise can't know automatically how to associate which device to which listener and, conceptually, which player.

Examples

These examples are written for the PS4. Please check the documentation for the function AK::SoundEngine::AddSecondaryOutput, for it has very different parameters for each platform.

Code to getting the UserIDs (PS4 only):

SceUserServiceLoginUserIdList list;
sceUserServiceGetLoginUserIdList(&list);

Sound on one game controller output:

//Add a secondary output connected to the headphones endpoint for player 0, associated with listener #1 (listener 0 is for TV).
AddSecondaryOutput(list.userId[0] /*Player ID (first player)*/, AkSink_PAD,  0x2 /*Listener 1*/);

//Setup a game object to emit sound to the listener 1
RegisterGameObj(MY_GAME_OBJECT, 0x2);

//Play an event.  This sound must be routed to the Master Secondary Bus (or any sub bus)
PostEvent("Play_Pow", MY_GAME_OBJECT);

Same sound on two different controllers:

//Add a secondary output connected to the headphones output for player 0, associated with listener #1 (listener 0 is for TV).
AddSecondaryOutput(list.userId[0] /*Player ID (first player)*/, AkSink_PAD,  0x2 /*Listener 1*/);
AddSecondaryOutput(list.userId[1] /*Player ID (second player)*/, AkSink_PAD,  0x4 /*Listener 2*/);

//Set a game object to emit sound to the listener 1(player 0) and 2 (player 1)
SetActiveListeners(EXISTING_GAME_OBJECT, 0x6);

//Play an event.  This sound must be routed to the Master Secondary Bus (or any sub bus)
PostEvent("Play_Pow", EXISTING_GAME_OBJECT);

Different sounds on two different controllers:

//Add a secondary output connected to the headphones output for player 0, associated with listener #1 (listener 0 is for TV).
AddSecondaryOutput(list.userId[0] /*Player ID (first player)*/, AkSink_PAD,  0x2 /*Listener 1*/);
AddSecondaryOutput(list.userId[1] /*Player ID (second player)*/, AkSink_PAD,  0x4 /*Listener 2*/);

//Set a game object to emit sound to the proper listeners
RegisterGameObj(MY_GAME_OBJECT1, 0x2);  
RegisterGameObj(MY_GAME_OBJECT2, 0x4);  

//Play an event.  These sounds must be routed to the Master Secondary Bus (or any sub bus) 
PostEvent("Play_Pow", MY_GAME_OBJECT1);
PostEvent("Play_Pif", MY_GAME_OBJECT2);

Same sound on one game controller output and on the TV:

//Add a secondary output connected to the headphones output for player 0, associated with listener #1 (listener 0 is for TV).
AddSecondaryOutput(list.userId[0] /*Player ID (first player)*/, AkSink_PAD,  0x2 /*Listener 1*/);

//Set a game object to emit sound to the listener 0 (TV) and 1 (controller for player 0)
RegisterGameObj(MY_GAME_OBJECT, 0x3);

//Play an event.  This sound must be routed to the Master Secondary Bus (or any sub bus) plus have a send to an auxiliary bus in the main hierarchy.
PostEvent("Play_Pow", MY_GAME_OBJECT);