blob: 48f5358b8242236c5a7fa9b7979e31eb19fb39ef [file] [log] [blame]
Phil Burk64c55f42017-12-13 18:36:53 -08001/*
2 * Copyright 2017 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
Phil Burk9a147a12017-12-13 20:23:25 -080017#include <cassert>
18
19#include <SLES/OpenSLES.h>
20#include <SLES/OpenSLES_Android.h>
21
Phil Burk64c55f42017-12-13 18:36:53 -080022#include "oboe/AudioStreamBuilder.h"
23#include "AudioOutputStreamOpenSLES.h"
24#include "AudioStreamOpenSLES.h"
Phil Burk9a147a12017-12-13 20:23:25 -080025#include "OpenSLESUtilities.h"
Phil Burk420715b2017-12-14 12:26:38 -080026#include "OutputMixerOpenSLES.h"
Phil Burk64c55f42017-12-13 18:36:53 -080027
28using namespace oboe;
29
Phil Burk64c55f42017-12-13 18:36:53 -080030AudioOutputStreamOpenSLES::AudioOutputStreamOpenSLES(const AudioStreamBuilder &builder)
31 : AudioStreamOpenSLES(builder) {
32}
33
34AudioOutputStreamOpenSLES::~AudioOutputStreamOpenSLES() {
Phil Burk9a147a12017-12-13 20:23:25 -080035}
36
37// These will wind up in <SLES/OpenSLES_Android.h>
Phil Burk7040a9d2017-12-15 10:54:38 -080038constexpr int SL_ANDROID_SPEAKER_STEREO = (SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT);
Phil Burk9a147a12017-12-13 20:23:25 -080039
Phil Burk7040a9d2017-12-15 10:54:38 -080040constexpr int SL_ANDROID_SPEAKER_QUAD = (SL_ANDROID_SPEAKER_STEREO
41 | SL_SPEAKER_BACK_LEFT | SL_SPEAKER_BACK_RIGHT);
Phil Burk9a147a12017-12-13 20:23:25 -080042
Phil Burk7040a9d2017-12-15 10:54:38 -080043constexpr int SL_ANDROID_SPEAKER_5DOT1 = (SL_ANDROID_SPEAKER_QUAD
44 | SL_SPEAKER_FRONT_CENTER | SL_SPEAKER_LOW_FREQUENCY);
45
46constexpr int SL_ANDROID_SPEAKER_7DOT1 = (SL_ANDROID_SPEAKER_5DOT1 | SL_SPEAKER_SIDE_LEFT
47 | SL_SPEAKER_SIDE_RIGHT);
Phil Burk9a147a12017-12-13 20:23:25 -080048
49int AudioOutputStreamOpenSLES::chanCountToChanMask(int chanCount) {
50 int channelMask = 0;
51
52 switch (chanCount) {
53 case 1:
54 channelMask = SL_SPEAKER_FRONT_CENTER;
55 break;
56
57 case 2:
Phil Burk7040a9d2017-12-15 10:54:38 -080058 channelMask = SL_ANDROID_SPEAKER_STEREO;
Phil Burk9a147a12017-12-13 20:23:25 -080059 break;
60
61 case 4: // Quad
62 channelMask = SL_ANDROID_SPEAKER_QUAD;
63 break;
64
65 case 6: // 5.1
66 channelMask = SL_ANDROID_SPEAKER_5DOT1;
67 break;
68
69 case 8: // 7.1
70 channelMask = SL_ANDROID_SPEAKER_7DOT1;
71 break;
72 }
73 return channelMask;
74}
75
Phil Burk9a147a12017-12-13 20:23:25 -080076Result AudioOutputStreamOpenSLES::open() {
Phil Burk9a147a12017-12-13 20:23:25 -080077 Result oboeResult = AudioStreamOpenSLES::open();
78 if (Result::OK != oboeResult) return oboeResult;
79
Phil Burk7040a9d2017-12-15 10:54:38 -080080 SLresult result = OutputMixerOpenSL::getInstance().open();
Phil Burkd9703b02017-12-14 12:40:48 -080081 if (SL_RESULT_SUCCESS != result) {
82 AudioStreamOpenSLES::close();
83 return Result::ErrorInternal;
84 }
85
Phil Burk7040a9d2017-12-15 10:54:38 -080086 SLuint32 bitsPerSample = getBytesPerSample() * kBitsPerByte;
Phil Burk9a147a12017-12-13 20:23:25 -080087
88 // configure audio source
89 SLDataLocator_AndroidSimpleBufferQueue loc_bufq = {
90 SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, // locatorType
Phil Burka5d66372018-02-09 14:38:23 -080091 static_cast<SLuint32>(kBufferQueueLength)}; // numBuffers
Phil Burk9a147a12017-12-13 20:23:25 -080092
93 // Define the audio data format.
94 SLDataFormat_PCM format_pcm = {
95 SL_DATAFORMAT_PCM, // formatType
96 (SLuint32) mChannelCount, // numChannels
97 (SLuint32) (mSampleRate * kMillisPerSecond), // milliSamplesPerSec
98 bitsPerSample, // bitsPerSample
99 bitsPerSample, // containerSize;
100 (SLuint32) chanCountToChanMask(mChannelCount), // channelMask
101 getDefaultByteOrder(),
102 };
103
104 SLDataSource audioSrc = {&loc_bufq, &format_pcm};
105
106 /**
107 * API 21 (Lollipop) introduced support for floating-point data representation and an extended
108 * data format type: SLAndroidDataFormat_PCM_EX. If running on API 21+ use this newer format
109 * type, creating it from our original format.
110 */
Phil Burk6d952912017-12-14 10:10:00 -0800111 SLAndroidDataFormat_PCM_EX format_pcm_ex;
Phil Burk09643562018-03-27 06:55:03 -0700112 if (getSdkVersion() >= __ANDROID_API_L__) {
Phil Burk9a147a12017-12-13 20:23:25 -0800113 SLuint32 representation = OpenSLES_ConvertFormatToRepresentation(getFormat());
Phil Burk6d952912017-12-14 10:10:00 -0800114 // Fill in the format structure.
115 format_pcm_ex = OpenSLES_createExtendedFormat(format_pcm, representation);
116 // Use in place of the previous format.
Phil Burk9a147a12017-12-13 20:23:25 -0800117 audioSrc.pFormat = &format_pcm_ex;
118 }
119
Phil Burk7040a9d2017-12-15 10:54:38 -0800120 result = OutputMixerOpenSL::getInstance().createAudioPlayer(&mObjectInterface,
Phil Burk9a147a12017-12-13 20:23:25 -0800121 &audioSrc);
122 if (SL_RESULT_SUCCESS != result) {
123 LOGE("createAudioPlayer() result:%s", getSLErrStr(result));
124 goto error;
125 }
126
Phil Burk6d952912017-12-14 10:10:00 -0800127 result = (*mObjectInterface)->Realize(mObjectInterface, SL_BOOLEAN_FALSE);
Phil Burk9a147a12017-12-13 20:23:25 -0800128 if (SL_RESULT_SUCCESS != result) {
129 LOGE("Realize player object result:%s", getSLErrStr(result));
130 goto error;
131 }
132
Phil Burk6d952912017-12-14 10:10:00 -0800133 result = (*mObjectInterface)->GetInterface(mObjectInterface, SL_IID_PLAY, &mPlayInterface);
Phil Burk9a147a12017-12-13 20:23:25 -0800134 if (SL_RESULT_SUCCESS != result) {
Phil Burk7040a9d2017-12-15 10:54:38 -0800135 LOGE("GetInterface PLAY result:%s", getSLErrStr(result));
Phil Burk9a147a12017-12-13 20:23:25 -0800136 goto error;
137 }
138
Phil Burk6d952912017-12-14 10:10:00 -0800139 result = AudioStreamOpenSLES::registerBufferQueueCallback();
Phil Burk9a147a12017-12-13 20:23:25 -0800140 if (SL_RESULT_SUCCESS != result) {
Phil Burk9a147a12017-12-13 20:23:25 -0800141 goto error;
142 }
143
Phil Burka5d66372018-02-09 14:38:23 -0800144 allocateFifo();
Phil Burk34217a72018-02-07 20:37:17 -0800145
Phil Burk9a147a12017-12-13 20:23:25 -0800146 return Result::OK;
147error:
148 return Result::ErrorInternal; // TODO convert error from SLES to OBOE
149}
150
151Result AudioOutputStreamOpenSLES::close() {
152 requestPause();
Phil Burk6d952912017-12-14 10:10:00 -0800153 // invalidate any interfaces
154 mPlayInterface = NULL;
Phil Burk7040a9d2017-12-15 10:54:38 -0800155 OutputMixerOpenSL::getInstance().close();
Phil Burk9a147a12017-12-13 20:23:25 -0800156 return AudioStreamOpenSLES::close();
157}
158
159Result AudioOutputStreamOpenSLES::setPlayState(SLuint32 newState) {
160 Result result = Result::OK;
161 LOGD("AudioOutputStreamOpenSLES(): setPlayState()");
Phil Burk6d952912017-12-14 10:10:00 -0800162 if (mPlayInterface == NULL) {
Phil Burk9a147a12017-12-13 20:23:25 -0800163 return Result::ErrorInvalidState;
164 }
Phil Burk6d952912017-12-14 10:10:00 -0800165 SLresult slResult = (*mPlayInterface)->SetPlayState(mPlayInterface, newState);
Phil Burk9a147a12017-12-13 20:23:25 -0800166 if(SL_RESULT_SUCCESS != slResult) {
167 LOGD("AudioOutputStreamOpenSLES(): setPlayState() returned %s", getSLErrStr(slResult));
168 result = Result::ErrorInvalidState; // TODO review
169 } else {
170 setState(StreamState::Pausing);
171 }
172 return result;
173}
174
175Result AudioOutputStreamOpenSLES::requestStart() {
176 LOGD("AudioOutputStreamOpenSLES(): requestStart()");
177 Result result = setPlayState(SL_PLAYSTATE_PLAYING);
178 if(result != Result::OK) {
179 result = Result::ErrorInvalidState; // TODO review
180 } else {
Phil Burk6d952912017-12-14 10:10:00 -0800181 processBufferCallback(mSimpleBufferQueueInterface);
Phil Burk9a147a12017-12-13 20:23:25 -0800182 setState(StreamState::Starting);
183 }
184 return result;
185}
186
187Result AudioOutputStreamOpenSLES::requestPause() {
188 LOGD("AudioOutputStreamOpenSLES(): requestPause()");
189 Result result = setPlayState(SL_PLAYSTATE_PAUSED);
190 if(result != Result::OK) {
191 result = Result::ErrorInvalidState; // TODO review
192 } else {
193 setState(StreamState::Pausing);
Phil Burkf2a70532018-05-09 18:36:21 -0700194 // Note that OpenSL ES does NOT reset its millisecond position when OUTPUT is paused.
195 int64_t framesWritten = getFramesWritten();
196 if (framesWritten >= 0) {
197 setFramesRead(framesWritten);
198 }
Phil Burk9a147a12017-12-13 20:23:25 -0800199 }
200 return result;
201}
202
203Result AudioOutputStreamOpenSLES::requestFlush() {
204 LOGD("AudioOutputStreamOpenSLES(): requestFlush()");
Phil Burk6d952912017-12-14 10:10:00 -0800205 if (mPlayInterface == NULL) {
Phil Burk9a147a12017-12-13 20:23:25 -0800206 return Result::ErrorInvalidState;
207 }
208 return Result::ErrorUnimplemented; // TODO
209}
210
211Result AudioOutputStreamOpenSLES::requestStop() {
212 LOGD("AudioOutputStreamOpenSLES(): requestStop()");
213 Result result = setPlayState(SL_PLAYSTATE_STOPPED);
214 if(result != Result::OK) {
215 result = Result::ErrorInvalidState; // TODO review
216 } else {
217 setState(StreamState::Stopping);
Phil Burkf2a70532018-05-09 18:36:21 -0700218 mPositionMillis.reset32(); // OpenSL ES resets its millisecond position when stopped.
219 int64_t framesWritten = getFramesWritten();
220 if (framesWritten >= 0) {
221 setFramesRead(framesWritten);
222 }
Phil Burk9a147a12017-12-13 20:23:25 -0800223 }
224 return result;
225}
226
Phil Burkf2a70532018-05-09 18:36:21 -0700227void AudioOutputStreamOpenSLES::setFramesRead(int64_t framesRead) {
228 int64_t millisWritten = framesRead * kMillisPerSecond / getSampleRate();
229 mPositionMillis.set(millisWritten);
230}
231
232int64_t AudioOutputStreamOpenSLES::getFramesRead() const {
Phil Burkb09eb332018-05-21 17:40:52 -0700233 return getFramesProcessedByServer();
Phil Burkf2a70532018-05-09 18:36:21 -0700234}
235
Phil Burk9a147a12017-12-13 20:23:25 -0800236Result AudioOutputStreamOpenSLES::waitForStateChange(StreamState currentState,
237 StreamState *nextState,
238 int64_t timeoutNanoseconds) {
239 LOGD("AudioOutputStreamOpenSLES::waitForStateChange()");
Phil Burk6d952912017-12-14 10:10:00 -0800240 if (mPlayInterface == NULL) {
Phil Burk9a147a12017-12-13 20:23:25 -0800241 return Result::ErrorInvalidState;
242 }
243 return Result::ErrorUnimplemented; // TODO
Phil Burk64c55f42017-12-13 18:36:53 -0800244}
Phil Burkf2a70532018-05-09 18:36:21 -0700245
246Result AudioOutputStreamOpenSLES::updateServiceFrameCounter() {
247 if (mPlayInterface == NULL) {
248 return Result::ErrorNull;
249 }
250 SLmillisecond msec = 0;
251 SLresult slResult = (*mPlayInterface)->GetPosition(mPlayInterface, &msec);
252 Result result = Result::OK;
253 if(SL_RESULT_SUCCESS != slResult) {
254 LOGD("%s(): GetPosition() returned %s", __func__, getSLErrStr(slResult));
255 // set result based on SLresult
256 result = Result::ErrorInternal;
257 } else {
258 mPositionMillis.update32(msec);
259 }
260 return result;
261}