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