Mercurial > audio-send
diff 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 |
line wrap: on
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/Alc/backends/opensl.c Tue Oct 25 13:02:31 2011 -0700 1.3 @@ -0,0 +1,425 @@ 1.4 +/* 1.5 + * Copyright (C) 2011 The Android Open Source Project 1.6 + * 1.7 + * Licensed under the Apache License, Version 2.0 (the "License"); 1.8 + * you may not use this file except in compliance with the License. 1.9 + * You may obtain a copy of the License at 1.10 + * 1.11 + * http://www.apache.org/licenses/LICENSE-2.0 1.12 + * 1.13 + * Unless required by applicable law or agreed to in writing, software 1.14 + * distributed under the License is distributed on an "AS IS" BASIS, 1.15 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1.16 + * See the License for the specific language governing permissions and 1.17 + * limitations under the License. 1.18 + */ 1.19 + 1.20 +/* This is an OpenAL backend for Android using the native audio APIs based on 1.21 + * OpenSL ES 1.0.1. It is based on source code for the native-audio sample app 1.22 + * bundled with NDK. 1.23 + */ 1.24 + 1.25 +#include "config.h" 1.26 + 1.27 +#include <stdlib.h> 1.28 +#include "alMain.h" 1.29 +#include "AL/al.h" 1.30 +#include "AL/alc.h" 1.31 + 1.32 + 1.33 +#include <SLES/OpenSLES.h> 1.34 +#if 1 1.35 +#include <SLES/OpenSLES_Android.h> 1.36 +#else 1.37 +extern SLAPIENTRY const SLInterfaceID SL_IID_ANDROIDSIMPLEBUFFERQUEUE; 1.38 + 1.39 +struct SLAndroidSimpleBufferQueueItf_; 1.40 +typedef const struct SLAndroidSimpleBufferQueueItf_ * const * SLAndroidSimpleBufferQueueItf; 1.41 + 1.42 +typedef void (*slAndroidSimpleBufferQueueCallback)(SLAndroidSimpleBufferQueueItf caller, void *pContext); 1.43 + 1.44 +typedef struct SLAndroidSimpleBufferQueueState_ { 1.45 + SLuint32 count; 1.46 + SLuint32 index; 1.47 +} SLAndroidSimpleBufferQueueState; 1.48 + 1.49 + 1.50 +struct SLAndroidSimpleBufferQueueItf_ { 1.51 + SLresult (*Enqueue) ( 1.52 + SLAndroidSimpleBufferQueueItf self, 1.53 + const void *pBuffer, 1.54 + SLuint32 size 1.55 + ); 1.56 + SLresult (*Clear) ( 1.57 + SLAndroidSimpleBufferQueueItf self 1.58 + ); 1.59 + SLresult (*GetState) ( 1.60 + SLAndroidSimpleBufferQueueItf self, 1.61 + SLAndroidSimpleBufferQueueState *pState 1.62 + ); 1.63 + SLresult (*RegisterCallback) ( 1.64 + SLAndroidSimpleBufferQueueItf self, 1.65 + slAndroidSimpleBufferQueueCallback callback, 1.66 + void* pContext 1.67 + ); 1.68 +}; 1.69 + 1.70 +#define SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE ((SLuint32) 0x800007BD) 1.71 + 1.72 +typedef struct SLDataLocator_AndroidSimpleBufferQueue { 1.73 + SLuint32 locatorType; 1.74 + SLuint32 numBuffers; 1.75 +} SLDataLocator_AndroidSimpleBufferQueue; 1.76 + 1.77 +#endif 1.78 + 1.79 +/* Helper macros */ 1.80 +#define SLObjectItf_Realize(a,b) ((*(a))->Realize((a),(b))) 1.81 +#define SLObjectItf_GetInterface(a,b,c) ((*(a))->GetInterface((a),(b),(c))) 1.82 +#define SLObjectItf_Destroy(a) ((*(a))->Destroy((a))) 1.83 + 1.84 +#define SLEngineItf_CreateOutputMix(a,b,c,d,e) ((*(a))->CreateOutputMix((a),(b),(c),(d),(e))) 1.85 +#define SLEngineItf_CreateAudioPlayer(a,b,c,d,e,f,g) ((*(a))->CreateAudioPlayer((a),(b),(c),(d),(e),(f),(g))) 1.86 + 1.87 +#define SLPlayItf_SetPlayState(a,b) ((*(a))->SetPlayState((a),(b))) 1.88 + 1.89 + 1.90 +typedef struct { 1.91 + /* engine interfaces */ 1.92 + SLObjectItf engineObject; 1.93 + SLEngineItf engine; 1.94 + 1.95 + /* output mix interfaces */ 1.96 + SLObjectItf outputMix; 1.97 + 1.98 + /* buffer queue player interfaces */ 1.99 + SLObjectItf bufferQueueObject; 1.100 + 1.101 + void *buffer; 1.102 + ALuint bufferSize; 1.103 + 1.104 + ALuint frameSize; 1.105 +} osl_data; 1.106 + 1.107 + 1.108 +static const ALCchar opensl_device[] = "OpenSL"; 1.109 + 1.110 + 1.111 +static SLuint32 GetChannelMask(enum DevFmtChannels chans) 1.112 +{ 1.113 + switch(chans) 1.114 + { 1.115 + case DevFmtMono: return SL_SPEAKER_FRONT_CENTER; 1.116 + case DevFmtStereo: return SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT; 1.117 + case DevFmtQuad: return SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT| 1.118 + SL_SPEAKER_BACK_LEFT|SL_SPEAKER_BACK_RIGHT; 1.119 + case DevFmtX51: return SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT| 1.120 + SL_SPEAKER_FRONT_CENTER|SL_SPEAKER_LOW_FREQUENCY| 1.121 + SL_SPEAKER_BACK_LEFT|SL_SPEAKER_BACK_RIGHT; 1.122 + case DevFmtX61: return SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT| 1.123 + SL_SPEAKER_FRONT_CENTER|SL_SPEAKER_LOW_FREQUENCY| 1.124 + SL_SPEAKER_BACK_CENTER| 1.125 + SL_SPEAKER_SIDE_LEFT|SL_SPEAKER_SIDE_RIGHT; 1.126 + case DevFmtX71: return SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT| 1.127 + SL_SPEAKER_FRONT_CENTER|SL_SPEAKER_LOW_FREQUENCY| 1.128 + SL_SPEAKER_BACK_LEFT|SL_SPEAKER_BACK_RIGHT| 1.129 + SL_SPEAKER_SIDE_LEFT|SL_SPEAKER_SIDE_RIGHT; 1.130 + case DevFmtX51Side: return SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT| 1.131 + SL_SPEAKER_FRONT_CENTER|SL_SPEAKER_LOW_FREQUENCY| 1.132 + SL_SPEAKER_SIDE_LEFT|SL_SPEAKER_SIDE_RIGHT; 1.133 + } 1.134 + return 0; 1.135 +} 1.136 + 1.137 +static const char *res_str(SLresult result) 1.138 +{ 1.139 + switch(result) 1.140 + { 1.141 + case SL_RESULT_SUCCESS: return "Success"; 1.142 + case SL_RESULT_PRECONDITIONS_VIOLATED: return "Preconditions violated"; 1.143 + case SL_RESULT_PARAMETER_INVALID: return "Parameter invalid"; 1.144 + case SL_RESULT_MEMORY_FAILURE: return "Memory failure"; 1.145 + case SL_RESULT_RESOURCE_ERROR: return "Resource error"; 1.146 + case SL_RESULT_RESOURCE_LOST: return "Resource lost"; 1.147 + case SL_RESULT_IO_ERROR: return "I/O error"; 1.148 + case SL_RESULT_BUFFER_INSUFFICIENT: return "Buffer insufficient"; 1.149 + case SL_RESULT_CONTENT_CORRUPTED: return "Content corrupted"; 1.150 + case SL_RESULT_CONTENT_UNSUPPORTED: return "Content unsupported"; 1.151 + case SL_RESULT_CONTENT_NOT_FOUND: return "Content not found"; 1.152 + case SL_RESULT_PERMISSION_DENIED: return "Permission denied"; 1.153 + case SL_RESULT_FEATURE_UNSUPPORTED: return "Feature unsupported"; 1.154 + case SL_RESULT_INTERNAL_ERROR: return "Internal error"; 1.155 + case SL_RESULT_UNKNOWN_ERROR: return "Unknown error"; 1.156 + case SL_RESULT_OPERATION_ABORTED: return "Operation aborted"; 1.157 + case SL_RESULT_CONTROL_LOST: return "Control lost"; 1.158 + case SL_RESULT_READONLY: return "ReadOnly"; 1.159 + case SL_RESULT_ENGINEOPTION_UNSUPPORTED: return "Engine option unsupported"; 1.160 + case SL_RESULT_SOURCE_SINK_INCOMPATIBLE: return "Source/Sink incompatible"; 1.161 + } 1.162 + return "Unknown error code"; 1.163 +} 1.164 + 1.165 +#define PRINTERR(x, s) do { \ 1.166 + if((x) != SL_RESULT_SUCCESS) \ 1.167 + ERR("%s: %s\n", (s), res_str((x))); \ 1.168 +} while(0) 1.169 + 1.170 +/* this callback handler is called every time a buffer finishes playing */ 1.171 +static void opensl_callback(SLAndroidSimpleBufferQueueItf bq, void *context) 1.172 +{ 1.173 + ALCdevice *Device = context; 1.174 + osl_data *data = Device->ExtraData; 1.175 + SLresult result; 1.176 + 1.177 + aluMixData(Device, data->buffer, data->bufferSize/data->frameSize); 1.178 + 1.179 + result = (*bq)->Enqueue(bq, data->buffer, data->bufferSize); 1.180 + PRINTERR(result, "bq->Enqueue"); 1.181 +} 1.182 + 1.183 + 1.184 +static ALCboolean opensl_open_playback(ALCdevice *Device, const ALCchar *deviceName) 1.185 +{ 1.186 + osl_data *data = NULL; 1.187 + SLresult result; 1.188 + 1.189 + if(!deviceName) 1.190 + deviceName = opensl_device; 1.191 + else if(strcmp(deviceName, opensl_device) != 0) 1.192 + return ALC_FALSE; 1.193 + 1.194 + data = calloc(1, sizeof(*data)); 1.195 + if(!data) 1.196 + { 1.197 + alcSetError(Device, ALC_OUT_OF_MEMORY); 1.198 + return ALC_FALSE; 1.199 + } 1.200 + 1.201 + // create engine 1.202 + result = slCreateEngine(&data->engineObject, 0, NULL, 0, NULL, NULL); 1.203 + PRINTERR(result, "slCreateEngine"); 1.204 + if(SL_RESULT_SUCCESS == result) 1.205 + { 1.206 + result = SLObjectItf_Realize(data->engineObject, SL_BOOLEAN_FALSE); 1.207 + PRINTERR(result, "engine->Realize"); 1.208 + } 1.209 + if(SL_RESULT_SUCCESS == result) 1.210 + { 1.211 + result = SLObjectItf_GetInterface(data->engineObject, SL_IID_ENGINE, &data->engine); 1.212 + PRINTERR(result, "engine->GetInterface"); 1.213 + } 1.214 + if(SL_RESULT_SUCCESS == result) 1.215 + { 1.216 + result = SLEngineItf_CreateOutputMix(data->engine, &data->outputMix, 0, NULL, NULL); 1.217 + PRINTERR(result, "engine->CreateOutputMix"); 1.218 + } 1.219 + if(SL_RESULT_SUCCESS == result) 1.220 + { 1.221 + result = SLObjectItf_Realize(data->outputMix, SL_BOOLEAN_FALSE); 1.222 + PRINTERR(result, "outputMix->Realize"); 1.223 + } 1.224 + 1.225 + if(SL_RESULT_SUCCESS != result) 1.226 + { 1.227 + if(data->outputMix != NULL) 1.228 + SLObjectItf_Destroy(data->outputMix); 1.229 + data->outputMix = NULL; 1.230 + 1.231 + if(data->engineObject != NULL) 1.232 + SLObjectItf_Destroy(data->engineObject); 1.233 + data->engineObject = NULL; 1.234 + data->engine = NULL; 1.235 + 1.236 + free(data); 1.237 + return ALC_FALSE; 1.238 + } 1.239 + 1.240 + Device->szDeviceName = strdup(deviceName); 1.241 + Device->ExtraData = data; 1.242 + 1.243 + return ALC_TRUE; 1.244 +} 1.245 + 1.246 + 1.247 +static void opensl_close_playback(ALCdevice *Device) 1.248 +{ 1.249 + osl_data *data = Device->ExtraData; 1.250 + 1.251 + SLObjectItf_Destroy(data->outputMix); 1.252 + data->outputMix = NULL; 1.253 + 1.254 + SLObjectItf_Destroy(data->engineObject); 1.255 + data->engineObject = NULL; 1.256 + data->engine = NULL; 1.257 + 1.258 + free(data); 1.259 + Device->ExtraData = NULL; 1.260 +} 1.261 + 1.262 +static ALCboolean opensl_reset_playback(ALCdevice *Device) 1.263 +{ 1.264 + osl_data *data = Device->ExtraData; 1.265 + SLDataLocator_AndroidSimpleBufferQueue loc_bufq; 1.266 + SLAndroidSimpleBufferQueueItf bufferQueue; 1.267 + SLDataLocator_OutputMix loc_outmix; 1.268 + SLDataFormat_PCM format_pcm; 1.269 + SLDataSource audioSrc; 1.270 + SLDataSink audioSnk; 1.271 + SLPlayItf player; 1.272 + SLInterfaceID id; 1.273 + SLboolean req; 1.274 + SLresult result; 1.275 + ALuint i; 1.276 + 1.277 + 1.278 + Device->UpdateSize = (ALuint64)Device->UpdateSize * 44100 / Device->Frequency; 1.279 + Device->UpdateSize = Device->UpdateSize * Device->NumUpdates / 2; 1.280 + Device->NumUpdates = 2; 1.281 + 1.282 + Device->Frequency = 44100; 1.283 + Device->FmtChans = DevFmtStereo; 1.284 + Device->FmtType = DevFmtShort; 1.285 + 1.286 + SetDefaultWFXChannelOrder(Device); 1.287 + 1.288 + 1.289 + id = SL_IID_ANDROIDSIMPLEBUFFERQUEUE; 1.290 + req = SL_BOOLEAN_TRUE; 1.291 + 1.292 + loc_bufq.locatorType = SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE; 1.293 + loc_bufq.numBuffers = Device->NumUpdates; 1.294 + 1.295 + format_pcm.formatType = SL_DATAFORMAT_PCM; 1.296 + format_pcm.numChannels = ChannelsFromDevFmt(Device->FmtChans); 1.297 + format_pcm.samplesPerSec = Device->Frequency * 1000; 1.298 + format_pcm.bitsPerSample = BytesFromDevFmt(Device->FmtType) * 8; 1.299 + format_pcm.containerSize = format_pcm.bitsPerSample; 1.300 + format_pcm.channelMask = GetChannelMask(Device->FmtChans); 1.301 + format_pcm.endianness = SL_BYTEORDER_NATIVE; 1.302 + 1.303 + audioSrc.pLocator = &loc_bufq; 1.304 + audioSrc.pFormat = &format_pcm; 1.305 + 1.306 + loc_outmix.locatorType = SL_DATALOCATOR_OUTPUTMIX; 1.307 + loc_outmix.outputMix = data->outputMix; 1.308 + audioSnk.pLocator = &loc_outmix; 1.309 + audioSnk.pFormat = NULL; 1.310 + 1.311 + 1.312 + result = SLEngineItf_CreateAudioPlayer(data->engine, &data->bufferQueueObject, &audioSrc, &audioSnk, 1, &id, &req); 1.313 + PRINTERR(result, "engine->CreateAudioPlayer"); 1.314 + if(SL_RESULT_SUCCESS == result) 1.315 + { 1.316 + result = SLObjectItf_Realize(data->bufferQueueObject, SL_BOOLEAN_FALSE); 1.317 + PRINTERR(result, "bufferQueue->Realize"); 1.318 + } 1.319 + if(SL_RESULT_SUCCESS == result) 1.320 + { 1.321 + result = SLObjectItf_GetInterface(data->bufferQueueObject, SL_IID_BUFFERQUEUE, &bufferQueue); 1.322 + PRINTERR(result, "bufferQueue->GetInterface"); 1.323 + } 1.324 + if(SL_RESULT_SUCCESS == result) 1.325 + { 1.326 + result = (*bufferQueue)->RegisterCallback(bufferQueue, opensl_callback, Device); 1.327 + PRINTERR(result, "bufferQueue->RegisterCallback"); 1.328 + } 1.329 + if(SL_RESULT_SUCCESS == result) 1.330 + { 1.331 + data->frameSize = FrameSizeFromDevFmt(Device->FmtChans, Device->FmtType); 1.332 + data->bufferSize = Device->UpdateSize * data->frameSize; 1.333 + data->buffer = calloc(1, data->bufferSize); 1.334 + if(!data->buffer) 1.335 + { 1.336 + result = SL_RESULT_MEMORY_FAILURE; 1.337 + PRINTERR(result, "calloc"); 1.338 + } 1.339 + } 1.340 + /* enqueue the first buffer to kick off the callbacks */ 1.341 + for(i = 0;i < Device->NumUpdates;i++) 1.342 + { 1.343 + if(SL_RESULT_SUCCESS == result) 1.344 + { 1.345 + result = (*bufferQueue)->Enqueue(bufferQueue, data->buffer, data->bufferSize); 1.346 + PRINTERR(result, "bufferQueue->Enqueue"); 1.347 + } 1.348 + } 1.349 + if(SL_RESULT_SUCCESS == result) 1.350 + { 1.351 + result = SLObjectItf_GetInterface(data->bufferQueueObject, SL_IID_PLAY, &player); 1.352 + PRINTERR(result, "bufferQueue->GetInterface"); 1.353 + } 1.354 + if(SL_RESULT_SUCCESS == result) 1.355 + { 1.356 + result = SLPlayItf_SetPlayState(player, SL_PLAYSTATE_PLAYING); 1.357 + PRINTERR(result, "player->SetPlayState"); 1.358 + } 1.359 + 1.360 + if(SL_RESULT_SUCCESS != result) 1.361 + { 1.362 + if(data->bufferQueueObject != NULL) 1.363 + SLObjectItf_Destroy(data->bufferQueueObject); 1.364 + data->bufferQueueObject = NULL; 1.365 + 1.366 + free(data->buffer); 1.367 + data->buffer = NULL; 1.368 + data->bufferSize = 0; 1.369 + 1.370 + return ALC_FALSE; 1.371 + } 1.372 + 1.373 + return ALC_TRUE; 1.374 +} 1.375 + 1.376 + 1.377 +static void opensl_stop_playback(ALCdevice *Device) 1.378 +{ 1.379 + osl_data *data = Device->ExtraData; 1.380 + 1.381 + if(data->bufferQueueObject != NULL) 1.382 + SLObjectItf_Destroy(data->bufferQueueObject); 1.383 + data->bufferQueueObject = NULL; 1.384 + 1.385 + free(data->buffer); 1.386 + data->buffer = NULL; 1.387 + data->bufferSize = 0; 1.388 +} 1.389 + 1.390 + 1.391 +static const BackendFuncs opensl_funcs = { 1.392 + opensl_open_playback, 1.393 + opensl_close_playback, 1.394 + opensl_reset_playback, 1.395 + opensl_stop_playback, 1.396 + NULL, 1.397 + NULL, 1.398 + NULL, 1.399 + NULL, 1.400 + NULL, 1.401 + NULL 1.402 +}; 1.403 + 1.404 + 1.405 +ALCboolean alc_opensl_init(BackendFuncs *func_list) 1.406 +{ 1.407 + *func_list = opensl_funcs; 1.408 + return ALC_TRUE; 1.409 +} 1.410 + 1.411 +void alc_opensl_deinit(void) 1.412 +{ 1.413 +} 1.414 + 1.415 +void alc_opensl_probe(enum DevProbe type) 1.416 +{ 1.417 + switch(type) 1.418 + { 1.419 + case DEVICE_PROBE: 1.420 + AppendDeviceList(opensl_device); 1.421 + break; 1.422 + case ALL_DEVICE_PROBE: 1.423 + AppendAllDeviceList(opensl_device); 1.424 + break; 1.425 + case CAPTURE_DEVICE_PROBE: 1.426 + break; 1.427 + } 1.428 +}