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.
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:
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, and the RTPC and Switch values active on the game objects. See an example of this in the Examples section below.
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.
To represent the device in-game, the regular Listener/GameObject concept is used. See Concept: Listeners for more information. It is the responsibility of the game programmer to associate the output device with a listener using AK::SoundEngine::AddSecondaryOutput
. The programmer must also choose which listener Game Objects are associated with each emitter Game Object, using AK::SoundEngine::SetListeners
or Ak::SoundEngine::SetDefaultListeners
. Don't forget to add the Listener for the TV to each emitter Game Object, if this sound goes to TV too.
|
Note: The game code is responsible for calling AddSecondaryOutput and RemoveSecondaryOutput whenever a game controller (or any other type of audio endpoint) are connected or disconnected from the system. Wwise can't know automatically how to associate which device to which listener and, conceptually, which player. |
These examples are written for the PS4. Please check the documentation for the function AK::SoundEngine::AddSecondaryOutput
to understand the 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 AddSecondaryOutput(list.userId[0] /*Player ID (first player)*/, AkSink_PAD, listenerArray1, 1); // Setup listeners RegisterGameObj(MY_LISTENER1); RegisterGameObj(MY_LISTENER2); AkGameObjectID [] listenerArray1[] = {MY_LISTENER1} AkGameObjectID [] listenerArray2[] = {MY_LISTENER2} AkGameObjectID [] listenerArrayBoth = {MY_LISTENER1, MY_LISTENER2} // Set up a game object to emit sound to listener 1. RegisterGameObj(MY_GAME_OBJECT, MY_LISTENER1, 1); // 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 AddSecondaryOutput(list.userId[0] /*Player ID (first player)*/, AkSink_PAD, listenerArray1, 1); AddSecondaryOutput(list.userId[1] /*Player ID (second player)*/, AkSink_PAD, listenerArray2, 1); // Set a game object to emit sound to the listener 1(player 0) and 2 (player 1) SetActiveListeners(EXISTING_GAME_OBJECT, listenerArrayBoth, 2); // 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 AddSecondaryOutput(list.userId[0] /*Player ID (first player)*/, AkSink_PAD, listenerArray1, 1); AddSecondaryOutput(list.userId[1] /*Player ID (second player)*/, AkSink_PAD, listenerArray2, 1); // Set a game object to emit sound to the proper listeners RegisterGameObj(MY_GAME_OBJECT1, listenerArray1, 1); RegisterGameObj(MY_GAME_OBJECT2, listenerArray2, 1); // 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 AddSecondaryOutput(list.userId[0] /*Player ID (first player)*/, AkSink_PAD, listenerArray1, 1); // Set a game object to emit sound to the listener 0 (TV) and 1 (controller for player 0) AkGameObjectID [] listenerArrayWithDefault = {MY_MAIN_LISTENER, MY_LISTENER1}; // MY_MAIN_LISTENER is the listener you normally use, defined by AK::SoundEngine::SetDefaultListeners. RegisterGameObj(MY_GAME_OBJECT, listenerArrayWithDefault, 2); // 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);
Here's an example of adding a SecondaryOutput on Windows, playing on the headphones:
// Will search for a device that has "Headphones" in its name. uDeviceID = AK::GetDeviceIDFromName("Headphones"); // Add a secondary output connected to the device found previously, associated with listener1 AddSecondaryOutput(uDeviceID, AkSink_Secondary, listenerArray1, 1); // Register a game object associated only with listener1. RegisterGameObj(MY_GAME_OBJECT, listenerArray1, 1); // 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);
Questions? Problems? Need more info? Contact us, and we can help!
Visit our Support pageRegister your project and we'll help you get started with no strings attached!
Get started with Wwise