1d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch/* 2d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch * Copyright (C) 2016 The Android Open Source Project 3d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch * 4d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch * Licensed under the Apache License, Version 2.0 (the "License"); 5d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch * you may not use this file except in compliance with the License. 6d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch * You may obtain a copy of the License at 7d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch * 8d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch * http://www.apache.org/licenses/LICENSE-2.0 9d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch * 10d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch * Unless required by applicable law or agreed to in writing, software 11d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch * distributed under the License is distributed on an "AS IS" BASIS, 12d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch * See the License for the specific language governing permissions and 14d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch * limitations under the License. 15d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch * 16d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch */ 17d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch 18d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch// cribbed from samples/native-audio 19d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch 20d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch#include "audioplay.h" 21d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch 22d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch#define CHATTY ALOGD 23197e47979a5c76d817d40039678afdd4f68c2a27Eric Laurent#define LOG_TAG "audioplay" 24d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch 25d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch#include <string.h> 26d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch 27d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch#include <utils/Log.h> 28d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch 29d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch// for native audio 30d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch#include <SLES/OpenSLES.h> 31d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch#include <SLES/OpenSLES_Android.h> 32d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch 33d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitschnamespace audioplay { 34d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitschnamespace { 35d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch 36d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch// engine interfaces 37d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitschstatic SLObjectItf engineObject = NULL; 38d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitschstatic SLEngineItf engineEngine; 39d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch 40d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch// output mix interfaces 41d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitschstatic SLObjectItf outputMixObject = NULL; 42d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch 43d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch// buffer queue player interfaces 44d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitschstatic SLObjectItf bqPlayerObject = NULL; 45d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitschstatic SLPlayItf bqPlayerPlay; 46d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitschstatic SLAndroidSimpleBufferQueueItf bqPlayerBufferQueue; 47d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitschstatic SLMuteSoloItf bqPlayerMuteSolo; 48d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitschstatic SLVolumeItf bqPlayerVolume; 49d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch 50d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch// pointer and size of the next player buffer to enqueue, and number of remaining buffers 51d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitschstatic const uint8_t* nextBuffer; 52d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitschstatic unsigned nextSize; 53d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch 54d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitschstatic const uint32_t ID_RIFF = 0x46464952; 55d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitschstatic const uint32_t ID_WAVE = 0x45564157; 56d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitschstatic const uint32_t ID_FMT = 0x20746d66; 57d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitschstatic const uint32_t ID_DATA = 0x61746164; 58d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch 59d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitschstruct RiffWaveHeader { 60d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch uint32_t riff_id; 61d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch uint32_t riff_sz; 62d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch uint32_t wave_id; 63d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch}; 64d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch 65d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitschstruct ChunkHeader { 66d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch uint32_t id; 67d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch uint32_t sz; 68d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch}; 69d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch 70d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitschstruct ChunkFormat { 71d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch uint16_t audio_format; 72d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch uint16_t num_channels; 73d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch uint32_t sample_rate; 74d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch uint32_t byte_rate; 75d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch uint16_t block_align; 76d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch uint16_t bits_per_sample; 77d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch}; 78d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch 79d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch// this callback handler is called every time a buffer finishes playing 80d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitschvoid bqPlayerCallback(SLAndroidSimpleBufferQueueItf bq, void *context) { 81d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch (void)bq; 82d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch (void)context; 83d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch audioplay::setPlaying(false); 84d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch} 85d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch 86d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitschbool hasPlayer() { 87d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch return (engineObject != NULL && bqPlayerObject != NULL); 88d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch} 89d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch 90d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch// create the engine and output mix objects 91a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitschbool createEngine() { 92d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch SLresult result; 93d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch 94d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch // create engine 95d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch result = slCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL); 96a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch if (result != SL_RESULT_SUCCESS) { 97a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch ALOGE("slCreateEngine failed with result %d", result); 98a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch return false; 99a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch } 100d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch (void)result; 101d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch 102d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch // realize the engine 103d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE); 104a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch if (result != SL_RESULT_SUCCESS) { 105a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch ALOGE("sl engine Realize failed with result %d", result); 106a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch return false; 107a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch } 108d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch (void)result; 109d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch 110d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch // get the engine interface, which is needed in order to create other objects 111d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine); 112a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch if (result != SL_RESULT_SUCCESS) { 113a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch ALOGE("sl engine GetInterface failed with result %d", result); 114a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch return false; 115a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch } 116d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch (void)result; 117d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch 118197e47979a5c76d817d40039678afdd4f68c2a27Eric Laurent // create output mix 119197e47979a5c76d817d40039678afdd4f68c2a27Eric Laurent result = (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, 0, NULL, NULL); 120a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch if (result != SL_RESULT_SUCCESS) { 121a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch ALOGE("sl engine CreateOutputMix failed with result %d", result); 122a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch return false; 123a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch } 124d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch (void)result; 125d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch 126d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch // realize the output mix 127d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch result = (*outputMixObject)->Realize(outputMixObject, SL_BOOLEAN_FALSE); 128a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch if (result != SL_RESULT_SUCCESS) { 129a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch ALOGE("sl outputMix Realize failed with result %d", result); 130a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch return false; 131a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch } 132d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch (void)result; 133a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch 134a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch return true; 135d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch} 136d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch 137d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch// create buffer queue audio player 138a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitschbool createBufferQueueAudioPlayer(const ChunkFormat* chunkFormat) { 139d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch SLresult result; 140d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch 141d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch // configure audio source 142d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch SLDataLocator_AndroidSimpleBufferQueue loc_bufq = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 1}; 143d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch 144db90897b5fa23aa46ce50494e0fb4808948f4524Geoffrey Pitsch // Determine channelMask from num_channels 145db90897b5fa23aa46ce50494e0fb4808948f4524Geoffrey Pitsch SLuint32 channelMask; 146db90897b5fa23aa46ce50494e0fb4808948f4524Geoffrey Pitsch switch (chunkFormat->num_channels) { 147db90897b5fa23aa46ce50494e0fb4808948f4524Geoffrey Pitsch case 1: 148db90897b5fa23aa46ce50494e0fb4808948f4524Geoffrey Pitsch channelMask = SL_SPEAKER_FRONT_CENTER; 149db90897b5fa23aa46ce50494e0fb4808948f4524Geoffrey Pitsch break; 150db90897b5fa23aa46ce50494e0fb4808948f4524Geoffrey Pitsch case 2: 151db90897b5fa23aa46ce50494e0fb4808948f4524Geoffrey Pitsch channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT; 152db90897b5fa23aa46ce50494e0fb4808948f4524Geoffrey Pitsch break; 153db90897b5fa23aa46ce50494e0fb4808948f4524Geoffrey Pitsch default: 154db90897b5fa23aa46ce50494e0fb4808948f4524Geoffrey Pitsch // Default of 0 will derive mask from num_channels and log a warning. 155db90897b5fa23aa46ce50494e0fb4808948f4524Geoffrey Pitsch channelMask = 0; 156db90897b5fa23aa46ce50494e0fb4808948f4524Geoffrey Pitsch } 157db90897b5fa23aa46ce50494e0fb4808948f4524Geoffrey Pitsch 158d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch SLDataFormat_PCM format_pcm = { 159d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch SL_DATAFORMAT_PCM, 160d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch chunkFormat->num_channels, 161d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch chunkFormat->sample_rate * 1000, // convert to milliHz 162d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch chunkFormat->bits_per_sample, 163d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch 16, 164db90897b5fa23aa46ce50494e0fb4808948f4524Geoffrey Pitsch channelMask, 165d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch SL_BYTEORDER_LITTLEENDIAN 166d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch }; 167d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch SLDataSource audioSrc = {&loc_bufq, &format_pcm}; 168d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch 169d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch // configure audio sink 170d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch SLDataLocator_OutputMix loc_outmix = {SL_DATALOCATOR_OUTPUTMIX, outputMixObject}; 171d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch SLDataSink audioSnk = {&loc_outmix, NULL}; 172d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch 173d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch // create audio player 1745613313533e28c1c95e91b52e9997d657bf2a479Geoffrey Pitsch const SLInterfaceID ids[3] = {SL_IID_BUFFERQUEUE, SL_IID_VOLUME, SL_IID_ANDROIDCONFIGURATION}; 1755613313533e28c1c95e91b52e9997d657bf2a479Geoffrey Pitsch const SLboolean req[3] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE}; 176d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch result = (*engineEngine)->CreateAudioPlayer(engineEngine, &bqPlayerObject, &audioSrc, &audioSnk, 1775613313533e28c1c95e91b52e9997d657bf2a479Geoffrey Pitsch 3, ids, req); 178a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch if (result != SL_RESULT_SUCCESS) { 179a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch ALOGE("sl CreateAudioPlayer failed with result %d", result); 180a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch return false; 181a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch } 182d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch (void)result; 183d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch 1845613313533e28c1c95e91b52e9997d657bf2a479Geoffrey Pitsch // Use the System stream for boot sound playback. 1855613313533e28c1c95e91b52e9997d657bf2a479Geoffrey Pitsch SLAndroidConfigurationItf playerConfig; 1865613313533e28c1c95e91b52e9997d657bf2a479Geoffrey Pitsch result = (*bqPlayerObject)->GetInterface(bqPlayerObject, 1875613313533e28c1c95e91b52e9997d657bf2a479Geoffrey Pitsch SL_IID_ANDROIDCONFIGURATION, &playerConfig); 1885613313533e28c1c95e91b52e9997d657bf2a479Geoffrey Pitsch if (result != SL_RESULT_SUCCESS) { 1895613313533e28c1c95e91b52e9997d657bf2a479Geoffrey Pitsch ALOGE("config GetInterface failed with result %d", result); 1905613313533e28c1c95e91b52e9997d657bf2a479Geoffrey Pitsch return false; 1915613313533e28c1c95e91b52e9997d657bf2a479Geoffrey Pitsch } 1925613313533e28c1c95e91b52e9997d657bf2a479Geoffrey Pitsch SLint32 streamType = SL_ANDROID_STREAM_SYSTEM; 1935613313533e28c1c95e91b52e9997d657bf2a479Geoffrey Pitsch result = (*playerConfig)->SetConfiguration(playerConfig, 1945613313533e28c1c95e91b52e9997d657bf2a479Geoffrey Pitsch SL_ANDROID_KEY_STREAM_TYPE, &streamType, sizeof(SLint32)); 1955613313533e28c1c95e91b52e9997d657bf2a479Geoffrey Pitsch if (result != SL_RESULT_SUCCESS) { 1965613313533e28c1c95e91b52e9997d657bf2a479Geoffrey Pitsch ALOGE("SetConfiguration failed with result %d", result); 1975613313533e28c1c95e91b52e9997d657bf2a479Geoffrey Pitsch return false; 1985613313533e28c1c95e91b52e9997d657bf2a479Geoffrey Pitsch } 199197e47979a5c76d817d40039678afdd4f68c2a27Eric Laurent // use normal performance mode as low latency is not needed. This is not mandatory so 200197e47979a5c76d817d40039678afdd4f68c2a27Eric Laurent // do not bail if we fail 201197e47979a5c76d817d40039678afdd4f68c2a27Eric Laurent SLuint32 performanceMode = SL_ANDROID_PERFORMANCE_NONE; 202197e47979a5c76d817d40039678afdd4f68c2a27Eric Laurent result = (*playerConfig)->SetConfiguration( 203197e47979a5c76d817d40039678afdd4f68c2a27Eric Laurent playerConfig, SL_ANDROID_KEY_PERFORMANCE_MODE, &performanceMode, sizeof(SLuint32)); 204197e47979a5c76d817d40039678afdd4f68c2a27Eric Laurent ALOGW_IF(result != SL_RESULT_SUCCESS, 205197e47979a5c76d817d40039678afdd4f68c2a27Eric Laurent "could not set performance mode on player, error %d", result); 206197e47979a5c76d817d40039678afdd4f68c2a27Eric Laurent (void)result; 2075613313533e28c1c95e91b52e9997d657bf2a479Geoffrey Pitsch 208d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch // realize the player 209d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch result = (*bqPlayerObject)->Realize(bqPlayerObject, SL_BOOLEAN_FALSE); 210a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch if (result != SL_RESULT_SUCCESS) { 211a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch ALOGE("sl player Realize failed with result %d", result); 212a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch return false; 213a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch } 214d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch (void)result; 215d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch 216d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch // get the play interface 217d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_PLAY, &bqPlayerPlay); 218a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch if (result != SL_RESULT_SUCCESS) { 219a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch ALOGE("sl player GetInterface failed with result %d", result); 220a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch return false; 221a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch } 222d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch (void)result; 223d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch 224d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch // get the buffer queue interface 225d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_BUFFERQUEUE, 226d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch &bqPlayerBufferQueue); 227a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch if (result != SL_RESULT_SUCCESS) { 228a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch ALOGE("sl playberBufferQueue GetInterface failed with result %d", result); 229a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch return false; 230a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch } 231d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch (void)result; 232d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch 233d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch // register callback on the buffer queue 234d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch result = (*bqPlayerBufferQueue)->RegisterCallback(bqPlayerBufferQueue, bqPlayerCallback, NULL); 235a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch if (result != SL_RESULT_SUCCESS) { 236a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch ALOGE("sl bqPlayerBufferQueue RegisterCallback failed with result %d", result); 237a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch return false; 238a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch } 239d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch (void)result; 240d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch 241d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch // get the volume interface 242d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_VOLUME, &bqPlayerVolume); 243a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch if (result != SL_RESULT_SUCCESS) { 244a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch ALOGE("sl volume GetInterface failed with result %d", result); 245a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch return false; 246a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch } 247d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch (void)result; 248d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch 249d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch // set the player's state to playing 250d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch audioplay::setPlaying(true); 251d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch CHATTY("Created buffer queue player: %p", bqPlayerBufferQueue); 252a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch return true; 253d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch} 254d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch 255a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitschbool parseClipBuf(const uint8_t* clipBuf, int clipBufSize, const ChunkFormat** oChunkFormat, 256a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch const uint8_t** oSoundBuf, unsigned* oSoundBufSize) { 257a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch *oSoundBuf = clipBuf; 258a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch *oSoundBufSize = clipBufSize; 259a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch *oChunkFormat = NULL; 260a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch const RiffWaveHeader* wavHeader = (const RiffWaveHeader*)*oSoundBuf; 261a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch if (*oSoundBufSize < sizeof(*wavHeader) || (wavHeader->riff_id != ID_RIFF) || 262d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch (wavHeader->wave_id != ID_WAVE)) { 263d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch ALOGE("Error: audio file is not a riff/wave file\n"); 264d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch return false; 265d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch } 266a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch *oSoundBuf += sizeof(*wavHeader); 267a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch *oSoundBufSize -= sizeof(*wavHeader); 268d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch 269d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch while (true) { 270a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch const ChunkHeader* chunkHeader = (const ChunkHeader*)*oSoundBuf; 271a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch if (*oSoundBufSize < sizeof(*chunkHeader)) { 272d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch ALOGE("EOF reading chunk headers"); 273d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch return false; 274d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch } 275d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch 276a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch *oSoundBuf += sizeof(*chunkHeader); 277a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch *oSoundBufSize -= sizeof(*chunkHeader); 278d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch 279d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch bool endLoop = false; 280d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch switch (chunkHeader->id) { 281d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch case ID_FMT: 282a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch *oChunkFormat = (const ChunkFormat*)*oSoundBuf; 283a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch *oSoundBuf += chunkHeader->sz; 284a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch *oSoundBufSize -= chunkHeader->sz; 285d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch break; 286d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch case ID_DATA: 287d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch /* Stop looking for chunks */ 288197e47979a5c76d817d40039678afdd4f68c2a27Eric Laurent *oSoundBufSize = chunkHeader->sz; 289d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch endLoop = true; 290d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch break; 291d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch default: 292d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch /* Unknown chunk, skip bytes */ 293a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch *oSoundBuf += chunkHeader->sz; 294a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch *oSoundBufSize -= chunkHeader->sz; 295d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch } 296d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch if (endLoop) { 297d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch break; 298d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch } 299d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch } 300d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch 301a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch if (*oChunkFormat == NULL) { 302d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch ALOGE("format not found in WAV file"); 303d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch return false; 304d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch } 305a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch return true; 306a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch} 307d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch 308a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch} // namespace 309a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch 310a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitschbool create(const uint8_t* exampleClipBuf, int exampleClipBufSize) { 311a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch if (!createEngine()) { 312a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch return false; 313d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch } 314d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch 315a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch // Parse the example clip. 316a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch const ChunkFormat* chunkFormat; 317a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch const uint8_t* soundBuf; 318a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch unsigned soundBufSize; 319a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch if (!parseClipBuf(exampleClipBuf, exampleClipBufSize, &chunkFormat, &soundBuf, &soundBufSize)) { 320a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch return false; 321a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch } 322a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch 323a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch // Initialize the BufferQueue based on this clip's format. 324a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch if (!createBufferQueueAudioPlayer(chunkFormat)) { 325a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch return false; 326a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch } 327a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch return true; 328a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch} 329a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch 330a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitschbool playClip(const uint8_t* buf, int size) { 331a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch // Parse the WAV header 332a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch const ChunkFormat* chunkFormat; 333a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch if (!parseClipBuf(buf, size, &chunkFormat, &nextBuffer, &nextSize)) { 334a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch return false; 335a91a2d737586ebd0040129333055d8093899751bGeoffrey Pitsch } 336d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch 337d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch if (!hasPlayer()) { 338d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch ALOGD("cannot play clip %p without a player", buf); 339d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch return false; 340d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch } 341d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch 342197e47979a5c76d817d40039678afdd4f68c2a27Eric Laurent CHATTY("playClip on player %p: buf=%p size=%d nextSize %d", 343197e47979a5c76d817d40039678afdd4f68c2a27Eric Laurent bqPlayerBufferQueue, buf, size, nextSize); 344d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch 345d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch if (nextSize > 0) { 346d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch // here we only enqueue one buffer because it is a long clip, 347d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch // but for streaming playback we would typically enqueue at least 2 buffers to start 348d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch SLresult result; 349d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch result = (*bqPlayerBufferQueue)->Enqueue(bqPlayerBufferQueue, nextBuffer, nextSize); 350d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch if (SL_RESULT_SUCCESS != result) { 351d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch return false; 352d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch } 353d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch audioplay::setPlaying(true); 354d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch } 355d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch 356d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch return true; 357d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch} 358d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch 359d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch// set the playing state for the buffer queue audio player 360d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitschvoid setPlaying(bool isPlaying) { 361d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch if (!hasPlayer()) return; 362d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch 363d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch SLresult result; 364d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch 365d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch if (NULL != bqPlayerPlay) { 366d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch // set the player's state 367d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch result = (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, 368d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch isPlaying ? SL_PLAYSTATE_PLAYING : SL_PLAYSTATE_STOPPED); 369d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch } 370d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch 371d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch} 372d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch 373d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitschvoid destroy() { 374d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch // destroy buffer queue audio player object, and invalidate all associated interfaces 375d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch if (bqPlayerObject != NULL) { 376d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch CHATTY("destroying audio player"); 377d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch (*bqPlayerObject)->Destroy(bqPlayerObject); 378d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch bqPlayerObject = NULL; 379d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch bqPlayerPlay = NULL; 380d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch bqPlayerBufferQueue = NULL; 381d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch bqPlayerMuteSolo = NULL; 382d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch bqPlayerVolume = NULL; 383d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch } 384d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch 385d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch // destroy output mix object, and invalidate all associated interfaces 386d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch if (outputMixObject != NULL) { 387d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch (*outputMixObject)->Destroy(outputMixObject); 388d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch outputMixObject = NULL; 389d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch } 390d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch 391d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch // destroy engine object, and invalidate all associated interfaces 392d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch if (engineObject != NULL) { 393d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch CHATTY("destroying audio engine"); 394d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch (*engineObject)->Destroy(engineObject); 395d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch engineObject = NULL; 396d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch engineEngine = NULL; 397d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch } 398d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch} 399d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch 400d6d9a1d0b9cf6fa740d9fe410015b094475c5a4cGeoffrey Pitsch} // namespace audioplay 401