This sample demonstrates the usage of the Web Audio notifications that Coherent UI provides through the Coherent::UI::ViewListener class and its derivates.
The sample solution is already configured and you only have to compile and run it.
It uses a sample mini game framework that provides very basic functionality.
The output will be in the Coherent/Samples/UI/bin directory.
Create notification will contain information about the audio stream format. More details about each one follow in the sample walkthrough.Play notification, you should start consuming data using the Coherent::UI::View::GetAudioData API.Pause notification is received since this API call informs the Coherent UI Host that the stream playback has progressed.Close notification you can release all related resources.Coherent::UI::View::GetAudioData might stop before a stream Pause notification is received, causing possible deadlocks.The sample utilizes a very basic audio system framework. It consists of the following interfaces:
IAudioSystem - manages audio device creation and update, sound creation and destructionISound - provides an API for sound manipulationIMoreDataProvider - and interface that can be passed to an ISound, which will then be used as a callback when more audio data needs to be buffered.The sample provides two implementations - using OpenAL and FMOD.
inc and lib directories located in the FMOD_SDK/api/lowlevel folder into Coherent/Samples/UI/C++/Sample_ClientAudio/external/FMOD.The first important thing to do when you want to play web audio yourself is to use the EnableClientAudioPlayback property in the ContextSettings structure before initializing the View Context:
The sample view listener handles the web audio stream notifications. Those are:
The view listener keeps a collection of the streams and information about them. When the OnAudioStreamCreated event is received, a new entry in the collection is added with information about the stream with the received ID. This information also contains a pointer to an ISound instance, which is null initially. The information is contained in this structure:
When the OnAudioStreamPlay event is received, a new ISound is created that will be responsible for playing the data from the stream. The entry in the collection for the corresponding stream ID is updated so we can identify the ISound by stream ID. A reverse map is also maintained so we can identify the stream ID by an ISound instance. Next, a very important call is made. The newly created ISound instance is assigned an IMoreDataProvider - in the case of this sample, this is the view listener, which implements the interface.
Now that the ISound is ready for playing, we have to provide the actual audio data. The ISound uses the IMoreDataProvider that was set to get it. In our case, as we already saw, the IMoreDataProvider is the view listener. The view listener is a convenient audio data provider since it already has access to the Coherent::UI::View instance. The Coherent::UI::View instance is used to obtain more data using the Coherent::UI::View::GetAudioData API. The GetAudioData method provides the ISound instance which requested the data. Using the reverse map in the view listener, we can obtain the stream ID for the corresponding ISound and use it in the API call.
Here's the whole method:
OnAudioStreamPlay until a OnAudioStreamPause event is received. Failure to do so can result in program exceptions and deadlocks.Coherent::UI::ViewContext::Update. Usually, GetAudioData will be called from the audio dedicated thread, in which case it's recommended that you use the same thread for managing you Audio and UI calls.When the OnAudioStreamPause event is received, we can release the ISound instance or pause it. In this sample we're just releasing it and creating new ones on each 'Play'.
When the OnAudioStreamClose event is received we just clear the information about the corresponding stream ID.
As a very brief summary, when we receive a Create notification we save the information about the stream; when we receive a Play notification we create a new sound and continuously request data until we receive Pause. The requested data is played by the audio system. Upon Close we delete the saved information.
We encourage you to play with the sample for a more hands-on experience.