Use an al_string for the device name
[openal-soft.git] / Alc / backends / opensl.c
blob220e6e5ca25f6f26e4f7cff29ce275e80b3f77f3
1 /*
2 * Copyright (C) 2011 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 /* This is an OpenAL backend for Android using the native audio APIs based on
18 * OpenSL ES 1.0.1. It is based on source code for the native-audio sample app
19 * bundled with NDK.
22 #include "config.h"
24 #include <stdlib.h>
26 #include "alMain.h"
27 #include "alu.h"
30 #include <SLES/OpenSLES.h>
31 #include <SLES/OpenSLES_Android.h>
33 /* Helper macros */
34 #define VCALL(obj, func) ((*(obj))->func((obj), EXTRACT_VCALL_ARGS
35 #define VCALL0(obj, func) ((*(obj))->func((obj) EXTRACT_VCALL_ARGS
38 typedef struct {
39 /* engine interfaces */
40 SLObjectItf engineObject;
41 SLEngineItf engine;
43 /* output mix interfaces */
44 SLObjectItf outputMix;
46 /* buffer queue player interfaces */
47 SLObjectItf bufferQueueObject;
49 void *buffer;
50 ALuint bufferSize;
51 ALuint curBuffer;
53 ALuint frameSize;
54 } osl_data;
57 static const ALCchar opensl_device[] = "OpenSL";
60 static SLuint32 GetChannelMask(enum DevFmtChannels chans)
62 switch(chans)
64 case DevFmtMono: return SL_SPEAKER_FRONT_CENTER;
65 case DevFmtStereo: return SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT;
66 case DevFmtQuad: return SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT|
67 SL_SPEAKER_BACK_LEFT|SL_SPEAKER_BACK_RIGHT;
68 case DevFmtX51: return SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT|
69 SL_SPEAKER_FRONT_CENTER|SL_SPEAKER_LOW_FREQUENCY|
70 SL_SPEAKER_BACK_LEFT|SL_SPEAKER_BACK_RIGHT;
71 case DevFmtX61: return SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT|
72 SL_SPEAKER_FRONT_CENTER|SL_SPEAKER_LOW_FREQUENCY|
73 SL_SPEAKER_BACK_CENTER|
74 SL_SPEAKER_SIDE_LEFT|SL_SPEAKER_SIDE_RIGHT;
75 case DevFmtX71: return SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT|
76 SL_SPEAKER_FRONT_CENTER|SL_SPEAKER_LOW_FREQUENCY|
77 SL_SPEAKER_BACK_LEFT|SL_SPEAKER_BACK_RIGHT|
78 SL_SPEAKER_SIDE_LEFT|SL_SPEAKER_SIDE_RIGHT;
79 case DevFmtX51Side: return SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT|
80 SL_SPEAKER_FRONT_CENTER|SL_SPEAKER_LOW_FREQUENCY|
81 SL_SPEAKER_SIDE_LEFT|SL_SPEAKER_SIDE_RIGHT;
83 return 0;
86 static const char *res_str(SLresult result)
88 switch(result)
90 case SL_RESULT_SUCCESS: return "Success";
91 case SL_RESULT_PRECONDITIONS_VIOLATED: return "Preconditions violated";
92 case SL_RESULT_PARAMETER_INVALID: return "Parameter invalid";
93 case SL_RESULT_MEMORY_FAILURE: return "Memory failure";
94 case SL_RESULT_RESOURCE_ERROR: return "Resource error";
95 case SL_RESULT_RESOURCE_LOST: return "Resource lost";
96 case SL_RESULT_IO_ERROR: return "I/O error";
97 case SL_RESULT_BUFFER_INSUFFICIENT: return "Buffer insufficient";
98 case SL_RESULT_CONTENT_CORRUPTED: return "Content corrupted";
99 case SL_RESULT_CONTENT_UNSUPPORTED: return "Content unsupported";
100 case SL_RESULT_CONTENT_NOT_FOUND: return "Content not found";
101 case SL_RESULT_PERMISSION_DENIED: return "Permission denied";
102 case SL_RESULT_FEATURE_UNSUPPORTED: return "Feature unsupported";
103 case SL_RESULT_INTERNAL_ERROR: return "Internal error";
104 case SL_RESULT_UNKNOWN_ERROR: return "Unknown error";
105 case SL_RESULT_OPERATION_ABORTED: return "Operation aborted";
106 case SL_RESULT_CONTROL_LOST: return "Control lost";
107 #ifdef SL_RESULT_READONLY
108 case SL_RESULT_READONLY: return "ReadOnly";
109 #endif
110 #ifdef SL_RESULT_ENGINEOPTION_UNSUPPORTED
111 case SL_RESULT_ENGINEOPTION_UNSUPPORTED: return "Engine option unsupported";
112 #endif
113 #ifdef SL_RESULT_SOURCE_SINK_INCOMPATIBLE
114 case SL_RESULT_SOURCE_SINK_INCOMPATIBLE: return "Source/Sink incompatible";
115 #endif
117 return "Unknown error code";
120 #define PRINTERR(x, s) do { \
121 if((x) != SL_RESULT_SUCCESS) \
122 ERR("%s: %s\n", (s), res_str((x))); \
123 } while(0)
125 /* this callback handler is called every time a buffer finishes playing */
126 static void opensl_callback(SLAndroidSimpleBufferQueueItf bq, void *context)
128 ALCdevice *Device = context;
129 osl_data *data = Device->ExtraData;
130 ALvoid *buf;
131 SLresult result;
133 buf = (ALbyte*)data->buffer + data->curBuffer*data->bufferSize;
134 aluMixData(Device, buf, data->bufferSize/data->frameSize);
136 result = VCALL(bq,Enqueue)(buf, data->bufferSize);
137 PRINTERR(result, "bq->Enqueue");
139 data->curBuffer = (data->curBuffer+1) % Device->NumUpdates;
143 static ALCenum opensl_open_playback(ALCdevice *Device, const ALCchar *deviceName)
145 osl_data *data = NULL;
146 SLresult result;
148 if(!deviceName)
149 deviceName = opensl_device;
150 else if(strcmp(deviceName, opensl_device) != 0)
151 return ALC_INVALID_VALUE;
153 data = calloc(1, sizeof(*data));
154 if(!data)
155 return ALC_OUT_OF_MEMORY;
157 // create engine
158 result = slCreateEngine(&data->engineObject, 0, NULL, 0, NULL, NULL);
159 PRINTERR(result, "slCreateEngine");
160 if(SL_RESULT_SUCCESS == result)
162 result = VCALL(data->engineObject,Realize)(SL_BOOLEAN_FALSE);
163 PRINTERR(result, "engine->Realize");
165 if(SL_RESULT_SUCCESS == result)
167 result = VCALL(data->engineObject,GetInterface)(SL_IID_ENGINE, &data->engine);
168 PRINTERR(result, "engine->GetInterface");
170 if(SL_RESULT_SUCCESS == result)
172 result = VCALL(data->engine,CreateOutputMix)(&data->outputMix, 0, NULL, NULL);
173 PRINTERR(result, "engine->CreateOutputMix");
175 if(SL_RESULT_SUCCESS == result)
177 result = VCALL(data->outputMix,Realize)(SL_BOOLEAN_FALSE);
178 PRINTERR(result, "outputMix->Realize");
181 if(SL_RESULT_SUCCESS != result)
183 if(data->outputMix != NULL)
184 VCALL0(data->outputMix,Destroy)();
185 data->outputMix = NULL;
187 if(data->engineObject != NULL)
188 VCALL0(data->engineObject,Destroy)();
189 data->engineObject = NULL;
190 data->engine = NULL;
192 free(data);
193 return ALC_INVALID_VALUE;
196 al_string_copy_cstr(&Device->DeviceName, deviceName);
197 Device->ExtraData = data;
199 return ALC_NO_ERROR;
203 static void opensl_close_playback(ALCdevice *Device)
205 osl_data *data = Device->ExtraData;
207 if(data->bufferQueueObject != NULL)
208 VCALL0(data->bufferQueueObject,Destroy)();
209 data->bufferQueueObject = NULL;
211 VCALL0(data->outputMix,Destroy)();
212 data->outputMix = NULL;
214 VCALL0(data->engineObject,Destroy)();
215 data->engineObject = NULL;
216 data->engine = NULL;
218 free(data);
219 Device->ExtraData = NULL;
222 static ALCboolean opensl_reset_playback(ALCdevice *Device)
224 osl_data *data = Device->ExtraData;
225 SLDataLocator_AndroidSimpleBufferQueue loc_bufq;
226 SLDataLocator_OutputMix loc_outmix;
227 SLDataFormat_PCM format_pcm;
228 SLDataSource audioSrc;
229 SLDataSink audioSnk;
230 SLInterfaceID id;
231 SLboolean req;
232 SLresult result;
235 Device->UpdateSize = (ALuint64)Device->UpdateSize * 44100 / Device->Frequency;
236 Device->UpdateSize = Device->UpdateSize * Device->NumUpdates / 2;
237 Device->NumUpdates = 2;
239 Device->Frequency = 44100;
240 Device->FmtChans = DevFmtStereo;
241 Device->FmtType = DevFmtShort;
243 SetDefaultWFXChannelOrder(Device);
246 id = SL_IID_ANDROIDSIMPLEBUFFERQUEUE;
247 req = SL_BOOLEAN_TRUE;
249 loc_bufq.locatorType = SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE;
250 loc_bufq.numBuffers = Device->NumUpdates;
252 format_pcm.formatType = SL_DATAFORMAT_PCM;
253 format_pcm.numChannels = ChannelsFromDevFmt(Device->FmtChans);
254 format_pcm.samplesPerSec = Device->Frequency * 1000;
255 format_pcm.bitsPerSample = BytesFromDevFmt(Device->FmtType) * 8;
256 format_pcm.containerSize = format_pcm.bitsPerSample;
257 format_pcm.channelMask = GetChannelMask(Device->FmtChans);
258 format_pcm.endianness = IS_LITTLE_ENDIAN ? SL_BYTEORDER_LITTLEENDIAN :
259 SL_BYTEORDER_BIGENDIAN;
261 audioSrc.pLocator = &loc_bufq;
262 audioSrc.pFormat = &format_pcm;
264 loc_outmix.locatorType = SL_DATALOCATOR_OUTPUTMIX;
265 loc_outmix.outputMix = data->outputMix;
266 audioSnk.pLocator = &loc_outmix;
267 audioSnk.pFormat = NULL;
270 if(data->bufferQueueObject != NULL)
271 VCALL0(data->bufferQueueObject,Destroy)();
272 data->bufferQueueObject = NULL;
274 result = VCALL(data->engine,CreateAudioPlayer)(&data->bufferQueueObject, &audioSrc, &audioSnk, 1, &id, &req);
275 PRINTERR(result, "engine->CreateAudioPlayer");
276 if(SL_RESULT_SUCCESS == result)
278 result = VCALL(data->bufferQueueObject,Realize)(SL_BOOLEAN_FALSE);
279 PRINTERR(result, "bufferQueue->Realize");
282 if(SL_RESULT_SUCCESS != result)
284 if(data->bufferQueueObject != NULL)
285 VCALL0(data->bufferQueueObject,Destroy)();
286 data->bufferQueueObject = NULL;
288 return ALC_FALSE;
291 return ALC_TRUE;
294 static ALCboolean opensl_start_playback(ALCdevice *Device)
296 osl_data *data = Device->ExtraData;
297 SLAndroidSimpleBufferQueueItf bufferQueue;
298 SLPlayItf player;
299 SLresult result;
300 ALuint i;
302 result = VCALL(data->bufferQueueObject,GetInterface)(SL_IID_BUFFERQUEUE, &bufferQueue);
303 PRINTERR(result, "bufferQueue->GetInterface");
304 if(SL_RESULT_SUCCESS == result)
306 result = VCALL(bufferQueue,RegisterCallback)(opensl_callback, Device);
307 PRINTERR(result, "bufferQueue->RegisterCallback");
309 if(SL_RESULT_SUCCESS == result)
311 data->frameSize = FrameSizeFromDevFmt(Device->FmtChans, Device->FmtType);
312 data->bufferSize = Device->UpdateSize * data->frameSize;
313 data->buffer = calloc(Device->NumUpdates, data->bufferSize);
314 if(!data->buffer)
316 result = SL_RESULT_MEMORY_FAILURE;
317 PRINTERR(result, "calloc");
320 /* enqueue the first buffer to kick off the callbacks */
321 for(i = 0;i < Device->NumUpdates;i++)
323 if(SL_RESULT_SUCCESS == result)
325 ALvoid *buf = (ALbyte*)data->buffer + i*data->bufferSize;
326 result = VCALL(bufferQueue,Enqueue)(buf, data->bufferSize);
327 PRINTERR(result, "bufferQueue->Enqueue");
330 data->curBuffer = 0;
331 if(SL_RESULT_SUCCESS == result)
333 result = VCALL(data->bufferQueueObject,GetInterface)(SL_IID_PLAY, &player);
334 PRINTERR(result, "bufferQueue->GetInterface");
336 if(SL_RESULT_SUCCESS == result)
338 result = VCALL(player,SetPlayState)(SL_PLAYSTATE_PLAYING);
339 PRINTERR(result, "player->SetPlayState");
342 if(SL_RESULT_SUCCESS != result)
344 if(data->bufferQueueObject != NULL)
345 VCALL0(data->bufferQueueObject,Destroy)();
346 data->bufferQueueObject = NULL;
348 free(data->buffer);
349 data->buffer = NULL;
350 data->bufferSize = 0;
352 return ALC_FALSE;
355 return ALC_TRUE;
359 static void opensl_stop_playback(ALCdevice *Device)
361 osl_data *data = Device->ExtraData;
362 SLPlayItf player;
363 SLAndroidSimpleBufferQueueItf bufferQueue;
364 SLresult result;
366 result = VCALL(data->bufferQueueObject,GetInterface)(SL_IID_PLAY, &player);
367 PRINTERR(result, "bufferQueue->GetInterface");
368 if(SL_RESULT_SUCCESS == result)
370 result = VCALL(player,SetPlayState)(SL_PLAYSTATE_STOPPED);
371 PRINTERR(result, "player->SetPlayState");
374 result = VCALL(data->bufferQueueObject,GetInterface)(SL_IID_BUFFERQUEUE, &bufferQueue);
375 PRINTERR(result, "bufferQueue->GetInterface");
376 if(SL_RESULT_SUCCESS == result)
378 result = VCALL0(bufferQueue,Clear)();
379 PRINTERR(result, "bufferQueue->Clear");
382 free(data->buffer);
383 data->buffer = NULL;
384 data->bufferSize = 0;
388 static const BackendFuncs opensl_funcs = {
389 opensl_open_playback,
390 opensl_close_playback,
391 opensl_reset_playback,
392 opensl_start_playback,
393 opensl_stop_playback,
394 NULL,
395 NULL,
396 NULL,
397 NULL,
398 NULL,
399 NULL,
400 ALCdevice_GetLatencyDefault
404 ALCboolean alc_opensl_init(BackendFuncs *func_list)
406 *func_list = opensl_funcs;
407 return ALC_TRUE;
410 void alc_opensl_deinit(void)
414 void alc_opensl_probe(enum DevProbe type)
416 switch(type)
418 case ALL_DEVICE_PROBE:
419 AppendAllDevicesList(opensl_device);
420 break;
421 case CAPTURE_DEVICE_PROBE:
422 break;