annotate Alc/backends/opensl.c @ 0:f9476ff7637e

initial forking of open-al to create multiple listeners
author Robert McIntyre <rlm@mit.edu>
date Tue, 25 Oct 2011 13:02:31 -0700
parents
children
rev   line source
rlm@0 1 /*
rlm@0 2 * Copyright (C) 2011 The Android Open Source Project
rlm@0 3 *
rlm@0 4 * Licensed under the Apache License, Version 2.0 (the "License");
rlm@0 5 * you may not use this file except in compliance with the License.
rlm@0 6 * You may obtain a copy of the License at
rlm@0 7 *
rlm@0 8 * http://www.apache.org/licenses/LICENSE-2.0
rlm@0 9 *
rlm@0 10 * Unless required by applicable law or agreed to in writing, software
rlm@0 11 * distributed under the License is distributed on an "AS IS" BASIS,
rlm@0 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
rlm@0 13 * See the License for the specific language governing permissions and
rlm@0 14 * limitations under the License.
rlm@0 15 */
rlm@0 16
rlm@0 17 /* This is an OpenAL backend for Android using the native audio APIs based on
rlm@0 18 * OpenSL ES 1.0.1. It is based on source code for the native-audio sample app
rlm@0 19 * bundled with NDK.
rlm@0 20 */
rlm@0 21
rlm@0 22 #include "config.h"
rlm@0 23
rlm@0 24 #include <stdlib.h>
rlm@0 25 #include "alMain.h"
rlm@0 26 #include "AL/al.h"
rlm@0 27 #include "AL/alc.h"
rlm@0 28
rlm@0 29
rlm@0 30 #include <SLES/OpenSLES.h>
rlm@0 31 #if 1
rlm@0 32 #include <SLES/OpenSLES_Android.h>
rlm@0 33 #else
rlm@0 34 extern SLAPIENTRY const SLInterfaceID SL_IID_ANDROIDSIMPLEBUFFERQUEUE;
rlm@0 35
rlm@0 36 struct SLAndroidSimpleBufferQueueItf_;
rlm@0 37 typedef const struct SLAndroidSimpleBufferQueueItf_ * const * SLAndroidSimpleBufferQueueItf;
rlm@0 38
rlm@0 39 typedef void (*slAndroidSimpleBufferQueueCallback)(SLAndroidSimpleBufferQueueItf caller, void *pContext);
rlm@0 40
rlm@0 41 typedef struct SLAndroidSimpleBufferQueueState_ {
rlm@0 42 SLuint32 count;
rlm@0 43 SLuint32 index;
rlm@0 44 } SLAndroidSimpleBufferQueueState;
rlm@0 45
rlm@0 46
rlm@0 47 struct SLAndroidSimpleBufferQueueItf_ {
rlm@0 48 SLresult (*Enqueue) (
rlm@0 49 SLAndroidSimpleBufferQueueItf self,
rlm@0 50 const void *pBuffer,
rlm@0 51 SLuint32 size
rlm@0 52 );
rlm@0 53 SLresult (*Clear) (
rlm@0 54 SLAndroidSimpleBufferQueueItf self
rlm@0 55 );
rlm@0 56 SLresult (*GetState) (
rlm@0 57 SLAndroidSimpleBufferQueueItf self,
rlm@0 58 SLAndroidSimpleBufferQueueState *pState
rlm@0 59 );
rlm@0 60 SLresult (*RegisterCallback) (
rlm@0 61 SLAndroidSimpleBufferQueueItf self,
rlm@0 62 slAndroidSimpleBufferQueueCallback callback,
rlm@0 63 void* pContext
rlm@0 64 );
rlm@0 65 };
rlm@0 66
rlm@0 67 #define SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE ((SLuint32) 0x800007BD)
rlm@0 68
rlm@0 69 typedef struct SLDataLocator_AndroidSimpleBufferQueue {
rlm@0 70 SLuint32 locatorType;
rlm@0 71 SLuint32 numBuffers;
rlm@0 72 } SLDataLocator_AndroidSimpleBufferQueue;
rlm@0 73
rlm@0 74 #endif
rlm@0 75
rlm@0 76 /* Helper macros */
rlm@0 77 #define SLObjectItf_Realize(a,b) ((*(a))->Realize((a),(b)))
rlm@0 78 #define SLObjectItf_GetInterface(a,b,c) ((*(a))->GetInterface((a),(b),(c)))
rlm@0 79 #define SLObjectItf_Destroy(a) ((*(a))->Destroy((a)))
rlm@0 80
rlm@0 81 #define SLEngineItf_CreateOutputMix(a,b,c,d,e) ((*(a))->CreateOutputMix((a),(b),(c),(d),(e)))
rlm@0 82 #define SLEngineItf_CreateAudioPlayer(a,b,c,d,e,f,g) ((*(a))->CreateAudioPlayer((a),(b),(c),(d),(e),(f),(g)))
rlm@0 83
rlm@0 84 #define SLPlayItf_SetPlayState(a,b) ((*(a))->SetPlayState((a),(b)))
rlm@0 85
rlm@0 86
rlm@0 87 typedef struct {
rlm@0 88 /* engine interfaces */
rlm@0 89 SLObjectItf engineObject;
rlm@0 90 SLEngineItf engine;
rlm@0 91
rlm@0 92 /* output mix interfaces */
rlm@0 93 SLObjectItf outputMix;
rlm@0 94
rlm@0 95 /* buffer queue player interfaces */
rlm@0 96 SLObjectItf bufferQueueObject;
rlm@0 97
rlm@0 98 void *buffer;
rlm@0 99 ALuint bufferSize;
rlm@0 100
rlm@0 101 ALuint frameSize;
rlm@0 102 } osl_data;
rlm@0 103
rlm@0 104
rlm@0 105 static const ALCchar opensl_device[] = "OpenSL";
rlm@0 106
rlm@0 107
rlm@0 108 static SLuint32 GetChannelMask(enum DevFmtChannels chans)
rlm@0 109 {
rlm@0 110 switch(chans)
rlm@0 111 {
rlm@0 112 case DevFmtMono: return SL_SPEAKER_FRONT_CENTER;
rlm@0 113 case DevFmtStereo: return SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT;
rlm@0 114 case DevFmtQuad: return SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT|
rlm@0 115 SL_SPEAKER_BACK_LEFT|SL_SPEAKER_BACK_RIGHT;
rlm@0 116 case DevFmtX51: return SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT|
rlm@0 117 SL_SPEAKER_FRONT_CENTER|SL_SPEAKER_LOW_FREQUENCY|
rlm@0 118 SL_SPEAKER_BACK_LEFT|SL_SPEAKER_BACK_RIGHT;
rlm@0 119 case DevFmtX61: return SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT|
rlm@0 120 SL_SPEAKER_FRONT_CENTER|SL_SPEAKER_LOW_FREQUENCY|
rlm@0 121 SL_SPEAKER_BACK_CENTER|
rlm@0 122 SL_SPEAKER_SIDE_LEFT|SL_SPEAKER_SIDE_RIGHT;
rlm@0 123 case DevFmtX71: return SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT|
rlm@0 124 SL_SPEAKER_FRONT_CENTER|SL_SPEAKER_LOW_FREQUENCY|
rlm@0 125 SL_SPEAKER_BACK_LEFT|SL_SPEAKER_BACK_RIGHT|
rlm@0 126 SL_SPEAKER_SIDE_LEFT|SL_SPEAKER_SIDE_RIGHT;
rlm@0 127 case DevFmtX51Side: return SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT|
rlm@0 128 SL_SPEAKER_FRONT_CENTER|SL_SPEAKER_LOW_FREQUENCY|
rlm@0 129 SL_SPEAKER_SIDE_LEFT|SL_SPEAKER_SIDE_RIGHT;
rlm@0 130 }
rlm@0 131 return 0;
rlm@0 132 }
rlm@0 133
rlm@0 134 static const char *res_str(SLresult result)
rlm@0 135 {
rlm@0 136 switch(result)
rlm@0 137 {
rlm@0 138 case SL_RESULT_SUCCESS: return "Success";
rlm@0 139 case SL_RESULT_PRECONDITIONS_VIOLATED: return "Preconditions violated";
rlm@0 140 case SL_RESULT_PARAMETER_INVALID: return "Parameter invalid";
rlm@0 141 case SL_RESULT_MEMORY_FAILURE: return "Memory failure";
rlm@0 142 case SL_RESULT_RESOURCE_ERROR: return "Resource error";
rlm@0 143 case SL_RESULT_RESOURCE_LOST: return "Resource lost";
rlm@0 144 case SL_RESULT_IO_ERROR: return "I/O error";
rlm@0 145 case SL_RESULT_BUFFER_INSUFFICIENT: return "Buffer insufficient";
rlm@0 146 case SL_RESULT_CONTENT_CORRUPTED: return "Content corrupted";
rlm@0 147 case SL_RESULT_CONTENT_UNSUPPORTED: return "Content unsupported";
rlm@0 148 case SL_RESULT_CONTENT_NOT_FOUND: return "Content not found";
rlm@0 149 case SL_RESULT_PERMISSION_DENIED: return "Permission denied";
rlm@0 150 case SL_RESULT_FEATURE_UNSUPPORTED: return "Feature unsupported";
rlm@0 151 case SL_RESULT_INTERNAL_ERROR: return "Internal error";
rlm@0 152 case SL_RESULT_UNKNOWN_ERROR: return "Unknown error";
rlm@0 153 case SL_RESULT_OPERATION_ABORTED: return "Operation aborted";
rlm@0 154 case SL_RESULT_CONTROL_LOST: return "Control lost";
rlm@0 155 case SL_RESULT_READONLY: return "ReadOnly";
rlm@0 156 case SL_RESULT_ENGINEOPTION_UNSUPPORTED: return "Engine option unsupported";
rlm@0 157 case SL_RESULT_SOURCE_SINK_INCOMPATIBLE: return "Source/Sink incompatible";
rlm@0 158 }
rlm@0 159 return "Unknown error code";
rlm@0 160 }
rlm@0 161
rlm@0 162 #define PRINTERR(x, s) do { \
rlm@0 163 if((x) != SL_RESULT_SUCCESS) \
rlm@0 164 ERR("%s: %s\n", (s), res_str((x))); \
rlm@0 165 } while(0)
rlm@0 166
rlm@0 167 /* this callback handler is called every time a buffer finishes playing */
rlm@0 168 static void opensl_callback(SLAndroidSimpleBufferQueueItf bq, void *context)
rlm@0 169 {
rlm@0 170 ALCdevice *Device = context;
rlm@0 171 osl_data *data = Device->ExtraData;
rlm@0 172 SLresult result;
rlm@0 173
rlm@0 174 aluMixData(Device, data->buffer, data->bufferSize/data->frameSize);
rlm@0 175
rlm@0 176 result = (*bq)->Enqueue(bq, data->buffer, data->bufferSize);
rlm@0 177 PRINTERR(result, "bq->Enqueue");
rlm@0 178 }
rlm@0 179
rlm@0 180
rlm@0 181 static ALCboolean opensl_open_playback(ALCdevice *Device, const ALCchar *deviceName)
rlm@0 182 {
rlm@0 183 osl_data *data = NULL;
rlm@0 184 SLresult result;
rlm@0 185
rlm@0 186 if(!deviceName)
rlm@0 187 deviceName = opensl_device;
rlm@0 188 else if(strcmp(deviceName, opensl_device) != 0)
rlm@0 189 return ALC_FALSE;
rlm@0 190
rlm@0 191 data = calloc(1, sizeof(*data));
rlm@0 192 if(!data)
rlm@0 193 {
rlm@0 194 alcSetError(Device, ALC_OUT_OF_MEMORY);
rlm@0 195 return ALC_FALSE;
rlm@0 196 }
rlm@0 197
rlm@0 198 // create engine
rlm@0 199 result = slCreateEngine(&data->engineObject, 0, NULL, 0, NULL, NULL);
rlm@0 200 PRINTERR(result, "slCreateEngine");
rlm@0 201 if(SL_RESULT_SUCCESS == result)
rlm@0 202 {
rlm@0 203 result = SLObjectItf_Realize(data->engineObject, SL_BOOLEAN_FALSE);
rlm@0 204 PRINTERR(result, "engine->Realize");
rlm@0 205 }
rlm@0 206 if(SL_RESULT_SUCCESS == result)
rlm@0 207 {
rlm@0 208 result = SLObjectItf_GetInterface(data->engineObject, SL_IID_ENGINE, &data->engine);
rlm@0 209 PRINTERR(result, "engine->GetInterface");
rlm@0 210 }
rlm@0 211 if(SL_RESULT_SUCCESS == result)
rlm@0 212 {
rlm@0 213 result = SLEngineItf_CreateOutputMix(data->engine, &data->outputMix, 0, NULL, NULL);
rlm@0 214 PRINTERR(result, "engine->CreateOutputMix");
rlm@0 215 }
rlm@0 216 if(SL_RESULT_SUCCESS == result)
rlm@0 217 {
rlm@0 218 result = SLObjectItf_Realize(data->outputMix, SL_BOOLEAN_FALSE);
rlm@0 219 PRINTERR(result, "outputMix->Realize");
rlm@0 220 }
rlm@0 221
rlm@0 222 if(SL_RESULT_SUCCESS != result)
rlm@0 223 {
rlm@0 224 if(data->outputMix != NULL)
rlm@0 225 SLObjectItf_Destroy(data->outputMix);
rlm@0 226 data->outputMix = NULL;
rlm@0 227
rlm@0 228 if(data->engineObject != NULL)
rlm@0 229 SLObjectItf_Destroy(data->engineObject);
rlm@0 230 data->engineObject = NULL;
rlm@0 231 data->engine = NULL;
rlm@0 232
rlm@0 233 free(data);
rlm@0 234 return ALC_FALSE;
rlm@0 235 }
rlm@0 236
rlm@0 237 Device->szDeviceName = strdup(deviceName);
rlm@0 238 Device->ExtraData = data;
rlm@0 239
rlm@0 240 return ALC_TRUE;
rlm@0 241 }
rlm@0 242
rlm@0 243
rlm@0 244 static void opensl_close_playback(ALCdevice *Device)
rlm@0 245 {
rlm@0 246 osl_data *data = Device->ExtraData;
rlm@0 247
rlm@0 248 SLObjectItf_Destroy(data->outputMix);
rlm@0 249 data->outputMix = NULL;
rlm@0 250
rlm@0 251 SLObjectItf_Destroy(data->engineObject);
rlm@0 252 data->engineObject = NULL;
rlm@0 253 data->engine = NULL;
rlm@0 254
rlm@0 255 free(data);
rlm@0 256 Device->ExtraData = NULL;
rlm@0 257 }
rlm@0 258
rlm@0 259 static ALCboolean opensl_reset_playback(ALCdevice *Device)
rlm@0 260 {
rlm@0 261 osl_data *data = Device->ExtraData;
rlm@0 262 SLDataLocator_AndroidSimpleBufferQueue loc_bufq;
rlm@0 263 SLAndroidSimpleBufferQueueItf bufferQueue;
rlm@0 264 SLDataLocator_OutputMix loc_outmix;
rlm@0 265 SLDataFormat_PCM format_pcm;
rlm@0 266 SLDataSource audioSrc;
rlm@0 267 SLDataSink audioSnk;
rlm@0 268 SLPlayItf player;
rlm@0 269 SLInterfaceID id;
rlm@0 270 SLboolean req;
rlm@0 271 SLresult result;
rlm@0 272 ALuint i;
rlm@0 273
rlm@0 274
rlm@0 275 Device->UpdateSize = (ALuint64)Device->UpdateSize * 44100 / Device->Frequency;
rlm@0 276 Device->UpdateSize = Device->UpdateSize * Device->NumUpdates / 2;
rlm@0 277 Device->NumUpdates = 2;
rlm@0 278
rlm@0 279 Device->Frequency = 44100;
rlm@0 280 Device->FmtChans = DevFmtStereo;
rlm@0 281 Device->FmtType = DevFmtShort;
rlm@0 282
rlm@0 283 SetDefaultWFXChannelOrder(Device);
rlm@0 284
rlm@0 285
rlm@0 286 id = SL_IID_ANDROIDSIMPLEBUFFERQUEUE;
rlm@0 287 req = SL_BOOLEAN_TRUE;
rlm@0 288
rlm@0 289 loc_bufq.locatorType = SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE;
rlm@0 290 loc_bufq.numBuffers = Device->NumUpdates;
rlm@0 291
rlm@0 292 format_pcm.formatType = SL_DATAFORMAT_PCM;
rlm@0 293 format_pcm.numChannels = ChannelsFromDevFmt(Device->FmtChans);
rlm@0 294 format_pcm.samplesPerSec = Device->Frequency * 1000;
rlm@0 295 format_pcm.bitsPerSample = BytesFromDevFmt(Device->FmtType) * 8;
rlm@0 296 format_pcm.containerSize = format_pcm.bitsPerSample;
rlm@0 297 format_pcm.channelMask = GetChannelMask(Device->FmtChans);
rlm@0 298 format_pcm.endianness = SL_BYTEORDER_NATIVE;
rlm@0 299
rlm@0 300 audioSrc.pLocator = &loc_bufq;
rlm@0 301 audioSrc.pFormat = &format_pcm;
rlm@0 302
rlm@0 303 loc_outmix.locatorType = SL_DATALOCATOR_OUTPUTMIX;
rlm@0 304 loc_outmix.outputMix = data->outputMix;
rlm@0 305 audioSnk.pLocator = &loc_outmix;
rlm@0 306 audioSnk.pFormat = NULL;
rlm@0 307
rlm@0 308
rlm@0 309 result = SLEngineItf_CreateAudioPlayer(data->engine, &data->bufferQueueObject, &audioSrc, &audioSnk, 1, &id, &req);
rlm@0 310 PRINTERR(result, "engine->CreateAudioPlayer");
rlm@0 311 if(SL_RESULT_SUCCESS == result)
rlm@0 312 {
rlm@0 313 result = SLObjectItf_Realize(data->bufferQueueObject, SL_BOOLEAN_FALSE);
rlm@0 314 PRINTERR(result, "bufferQueue->Realize");
rlm@0 315 }
rlm@0 316 if(SL_RESULT_SUCCESS == result)
rlm@0 317 {
rlm@0 318 result = SLObjectItf_GetInterface(data->bufferQueueObject, SL_IID_BUFFERQUEUE, &bufferQueue);
rlm@0 319 PRINTERR(result, "bufferQueue->GetInterface");
rlm@0 320 }
rlm@0 321 if(SL_RESULT_SUCCESS == result)
rlm@0 322 {
rlm@0 323 result = (*bufferQueue)->RegisterCallback(bufferQueue, opensl_callback, Device);
rlm@0 324 PRINTERR(result, "bufferQueue->RegisterCallback");
rlm@0 325 }
rlm@0 326 if(SL_RESULT_SUCCESS == result)
rlm@0 327 {
rlm@0 328 data->frameSize = FrameSizeFromDevFmt(Device->FmtChans, Device->FmtType);
rlm@0 329 data->bufferSize = Device->UpdateSize * data->frameSize;
rlm@0 330 data->buffer = calloc(1, data->bufferSize);
rlm@0 331 if(!data->buffer)
rlm@0 332 {
rlm@0 333 result = SL_RESULT_MEMORY_FAILURE;
rlm@0 334 PRINTERR(result, "calloc");
rlm@0 335 }
rlm@0 336 }
rlm@0 337 /* enqueue the first buffer to kick off the callbacks */
rlm@0 338 for(i = 0;i < Device->NumUpdates;i++)
rlm@0 339 {
rlm@0 340 if(SL_RESULT_SUCCESS == result)
rlm@0 341 {
rlm@0 342 result = (*bufferQueue)->Enqueue(bufferQueue, data->buffer, data->bufferSize);
rlm@0 343 PRINTERR(result, "bufferQueue->Enqueue");
rlm@0 344 }
rlm@0 345 }
rlm@0 346 if(SL_RESULT_SUCCESS == result)
rlm@0 347 {
rlm@0 348 result = SLObjectItf_GetInterface(data->bufferQueueObject, SL_IID_PLAY, &player);
rlm@0 349 PRINTERR(result, "bufferQueue->GetInterface");
rlm@0 350 }
rlm@0 351 if(SL_RESULT_SUCCESS == result)
rlm@0 352 {
rlm@0 353 result = SLPlayItf_SetPlayState(player, SL_PLAYSTATE_PLAYING);
rlm@0 354 PRINTERR(result, "player->SetPlayState");
rlm@0 355 }
rlm@0 356
rlm@0 357 if(SL_RESULT_SUCCESS != result)
rlm@0 358 {
rlm@0 359 if(data->bufferQueueObject != NULL)
rlm@0 360 SLObjectItf_Destroy(data->bufferQueueObject);
rlm@0 361 data->bufferQueueObject = NULL;
rlm@0 362
rlm@0 363 free(data->buffer);
rlm@0 364 data->buffer = NULL;
rlm@0 365 data->bufferSize = 0;
rlm@0 366
rlm@0 367 return ALC_FALSE;
rlm@0 368 }
rlm@0 369
rlm@0 370 return ALC_TRUE;
rlm@0 371 }
rlm@0 372
rlm@0 373
rlm@0 374 static void opensl_stop_playback(ALCdevice *Device)
rlm@0 375 {
rlm@0 376 osl_data *data = Device->ExtraData;
rlm@0 377
rlm@0 378 if(data->bufferQueueObject != NULL)
rlm@0 379 SLObjectItf_Destroy(data->bufferQueueObject);
rlm@0 380 data->bufferQueueObject = NULL;
rlm@0 381
rlm@0 382 free(data->buffer);
rlm@0 383 data->buffer = NULL;
rlm@0 384 data->bufferSize = 0;
rlm@0 385 }
rlm@0 386
rlm@0 387
rlm@0 388 static const BackendFuncs opensl_funcs = {
rlm@0 389 opensl_open_playback,
rlm@0 390 opensl_close_playback,
rlm@0 391 opensl_reset_playback,
rlm@0 392 opensl_stop_playback,
rlm@0 393 NULL,
rlm@0 394 NULL,
rlm@0 395 NULL,
rlm@0 396 NULL,
rlm@0 397 NULL,
rlm@0 398 NULL
rlm@0 399 };
rlm@0 400
rlm@0 401
rlm@0 402 ALCboolean alc_opensl_init(BackendFuncs *func_list)
rlm@0 403 {
rlm@0 404 *func_list = opensl_funcs;
rlm@0 405 return ALC_TRUE;
rlm@0 406 }
rlm@0 407
rlm@0 408 void alc_opensl_deinit(void)
rlm@0 409 {
rlm@0 410 }
rlm@0 411
rlm@0 412 void alc_opensl_probe(enum DevProbe type)
rlm@0 413 {
rlm@0 414 switch(type)
rlm@0 415 {
rlm@0 416 case DEVICE_PROBE:
rlm@0 417 AppendDeviceList(opensl_device);
rlm@0 418 break;
rlm@0 419 case ALL_DEVICE_PROBE:
rlm@0 420 AppendAllDeviceList(opensl_device);
rlm@0 421 break;
rlm@0 422 case CAPTURE_DEVICE_PROBE:
rlm@0 423 break;
rlm@0 424 }
rlm@0 425 }