Skip to main content

Adding the Dolby API to your Unity Project

·1475 words·7 mins

While developing Notespace with Amorse Inc, we decided to implement the Dolby API into our tablet based game. The game is a interactive musical activity book for girls so it makes a whole bunch of sense. As of the date of this post, the Dolby API is integrated into the following:

  • Acer Iconia Tab 10 2014
  • Amazon Kindle Fire HDX 7 2012
  • Amazon Kindle Fire HDX 8.9 2012
  • Amazon Kindle Fire HD 7 2013
  • Amazon Kindle Fire HDX 7 2013
  • Amazon Kindle Fire HDX 8.9 2013
  • Amazon Fire HDX 7 2014
  • Amazon Fire HDX 8.9 2014
  • Amazon Fire HD 6 2014
  • Fujitsu Arrow F-06E
  • Lenovo Yoga 8 2013
  • Lenovo Yoga 10 2013
  • Lenovo Yoga Tablet 2 8” 2014
  • Lenovo Yoga Tablet 2 10” 2014
  • Lenovo Yoga Tablet 2 Pro 2014
  • Samsung Galaxy Tab 3 8.0 2013
  • Samsung Galaxy Tab 3 10.1 2013
  • Tesco Hudle2 Tablet
  • ZTE Grand S Flex
  • ZTE Grand S
  • ZTE Grand Memo LTE
  • ZTE Grand Memo N5S
  • ZTE Nubia Z5S
  • ZTE Nubia Z5S Mini
  • ZTE V975
  • ZTE N5S
  • ZTE Geek U988S
  • ZTE Boost Max
  • ZTE ZMax
  • ZTE BladeBox

As you can see, we know that its not on iOS devices (boo) but is on every Kindle Fire device past first gen. Thats a sizable market to optimize our experience for! We also know, for development down the road, that every Windows 8 device will have Dolby hardware. This is not necessarily true for Windows 8 mobile though, so don’t get them mixed up.

First, we are targeting the Kindle Fire tablet so we need to get our android environment set up and our Amazon environment set up. Their are many tutorials on this but the one on the Amazon developer site is perfect. Their are a few gotchas to be aware of:

  • OSX 10.10 / Java Versions: I am currently using the latest Android SDK and OSX 10.10 (Yosemite) and had my build fail. The error message was:
warning: java/lang/Object.class(java/lang:Object.class): major version 51 is newer than 50, the highest major version supported by this compiler.

The reason for this was that I needed to update my Java version to above 1.6 which is what is installed on OSX. Java 1.7 was notoriously bad for OSX, especially when creating Android key stores, but it seems like 1.8 is fine. I’ll do my best to keep you up to date with any issues I have had. To fix this error, just follow the solution found here. Take special note of the OSX 10.10 instructions further down.

  • Android Manifest: If you are using other Android plugins, double check you AndroidManifest.xml file in Plugins/Android to ensure that one plugin is not overwriting the other’s manifest entries.

Now that we have all of our Amazon stuff set up, our first Dolby step is to download the SDK from the Dolby Developer site ( http://developer.dolby.com). For Unity, go to the Frameworks section under “Tools & Tech”… or just click here. You can download the package from the Unity Asset Store but its the exact same thing as the SDK. You don’t get any free implementation doing it that way.

The first issue you will find is that you get a bunch of Android libs an no documentation telling you best practice on which one to use. I did a little research on my target audience min Android level and discovered that the lowest android level of the lowest end Kindle device that supported Dolby was 4.0 (Kindle Fire HD (2nd gen kindle fire)). So based on this assumption, I used the files from the “Android 4.0” folder. I am gathering that 4.0 is the lowest Android version that Dolby will go, so I have considered setting my min Android version in my Unity build settings to 4.0. All my target devices are 4.0 and up, my prime target being the Samsung Galaxy Tab 2 due to its market penetration. If you are looking for Kindle Fire tech specs, they are here. Interesting thing to note is that the GPU’s are not consistent which means we should make multiple binaries; one per texture compression method. I am using mainly 32bit RGBA so it doesn’t really phase me for this project.

Now that we have the files, lets get started:

  1. Copy the contents of the Android 4.0 folder into the Plugins/Android folder. Unfortunatelly, you can’t use subfolders for organization (I tried) which is a little bit of a bummer. So now you should have a DSJavaPlugin.jar and a libDSPlugin.so in your Plugins/Android folder. FYI, the .so is compiled C code and the .jar is the Java bridge file which basically tells Unity how to access the C library.
  2. Make a manager script to connect to the native Android Dolby plugin. Native Android basically means that the API was written in C for performance and then has a Java bridge that allows us to connect to it. This method allows you to use some useful C libraries (like an OGG Vorbis encoder!) in Unity. Now the Dolby API has some example files in it to do just this. One works and one does not due to faulty DLLImport code. Use this one, it works and has a little something extra to help cycle through the Dolby profiles
using UnityEngine;
using System;
using System.Collections;
#if UNITY_ANDROID
using System.Runtime.InteropServices; //Allows us to use DLLImport... Dont think this works on iOS
#endif

public class DolbyManager : MonoBehaviour {

	//*** DLL Imports
#if UNITY_ANDROID && !UNITY_EDITOR
	[DllImport("DSPlugin")]
	public static extern bool isAvailable();
	[DllImport("DSPlugin")]
	public static extern int initialize();
	[DllImport("DSPlugin")]
	public static extern int setProfile(int profileid);
	[DllImport("DSPlugin")]
	public static extern int suspendSession();
	[DllImport("DSPlugin")]
	public static extern int restartSession();
	[DllImport("DSPlugin")]
	public static extern void release();
#else

	//*** If Not desired Platform, return dummy data
	public static bool isAvailable(){return false;}
	public static int initialize(){return -1;}
	public static int setProfile(int profileid){return -1;}
	public static int suspendSession(){return -1;}
	public static int restartSession(){return -1;}
	public static void release(){}
#endif

	public enum DolbyProfile : int {
		Off = -1,
		Movie = 0,
		Music = 1,
		Game = 2,
		Voice = 3
	}
	
	[HideInInspector] public bool ready = false;
	[HideInInspector] public DolbyProfile profile = DolbyProfile.Game;

	private int initRetrys = 10;

	private void Awake(){
		Init();
	}
	private void OnDestroy(){
		release();
	}
	private void OnApplicationPause(bool pPauseStatus) {

		//*** IF Pausing and dolby is active
		if(
			(pPauseStatus)
			&&(profile != DolbyProfile.Off)
		) {
			suspendSession();
		}
	}
	private void OnApplicationFocus(bool pFocusStatus) {

		//*** If Gaining focus (being switched to) and not Off
		if(
			(pFocusStatus)
			&&(profile != DolbyProfile.Off)
		) {
			restartSession();
		}
	}
	private void OnApplicationQuit() {

		//*** Release Everything Dolby
		release();
	}

	private void Init(){

#if UNITY_ANDROID

		if (isAvailable()) {

			if (initialize() > -1) {

				ready = true;

				//*** Set the Default profile (cant be off)
				setProfile(Mathf.Min((int)profile, 0));
			}

			//*** Not Inited and not out of retrys
			else if (initRetrys > 0) {

				//*** Consume a retyr
				initRetrys --;

				//*** Wati and try again
				StartCoroutine(Delay());
			}
		}
#endif
	}
	private IEnumerator Delay(){

		// Wait 100ms to make sure Dolby service is enabled
		yield return new WaitForSeconds(0.1f);
		Init();
	}
	public void SwitchProfiles(){

		//*** Save Previous Profile
		DolbyProfile oProfile = profile;

		//*** Get Index of current profile
		int xIndex = (int)profile;

		//*** Inc and fold
		xIndex++;
		if(xIndex >= 4){
			xIndex = -1;
		}

		//*** Convert back to profile
		profile = (DolbyProfile)xIndex;

		//*** If Turning Off
		if(profile == DolbyProfile.Off) {

			//*** Susprend Session (turn Off)
			suspendSession();
		}

		//*** If Regular profile
		else {

			//*** If Just Tunred On
			if(oProfile == DolbyProfile.Off){

				//*** Turn On
				restartSession();
			}

			//*** Set Profile
			setProfile(xIndex);
		}
	}

	//****************************************
	//* STATIC METHODS
	//****************************************
	public static DolbyManager Create(){

		//*** Make Self
		GameObject oDolbyContainer = new GameObject("DolbyManager", new Type[]{ typeof(DolbyManager) });

		//*** Return Instance
		return oDolbyContainer.GetComponent<DolbyManager>();
	}
}
  1. Add your controller to the scene. You can do this either programmatically or just make a GameObject and slap it on. Either way, if this object is not nested under a global object that is not being being destroyed between scenes, you will need to add the following code to your “Awake” method:
//*** Do not destroy
DontDestroyOnLoad(gameObject);

And now we are done! If you want to switch through your Dolby profiles, use the SwitchProfiles() method. You will also need to reference this class somehow. I leave that up to you. You could either link it to your global / persistent object or make this class into a Singleton and access it through a static instance.

The results on the Kindle 8.9 HD was really astounding! With earphones, the audio sounded big. It felt like I wasn’t wearing headphones and was incredibly immersive. With out headphones, the audio was louder and more full. One of the problems I have had with the iPad is that the bass drops out on the speakers and even with the Kindle, with out the Dolby, the game was hard to hear even at full volume. Big thanks Dolby people, you have made my game better!



Roger Miller
Author
Roger Miller
With 25 years in the technology industry, 6 in XR, 10 in the game industry, and on 4 continents, Roger comes with a breadth of knowledge. He has worked with industry-leading companies such as Ogilvy One, Amazon, and Meta, been a vendor for entertainment companies such as Unity, Amazon, Disney, and HBO, created solutions for BMW and Deloitte, and been nominated for awards such as the IMGA. He has spoken at Unity Unite, is a frequent speaker at Unity User Groups all over the country, and founded the Unity User Group in Bend, OR.