1 /*
2 * Copyright (C) 2015 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 //#define LOG_NDEBUG 0
18 #define LOG_TAG "OpenSL-ES-Test-B-1-2-Recording"
19
20 #include "sl-utils.h"
21
22 /*
23 * See https://www.khronos.org/registry/sles/specs/OpenSL_ES_Specification_1.0.1.pdf
24 * Appendix B.1.2 sample code.
25 *
26 * Minor edits made to conform to Android coding style.
27 *
28 * Correction to code: SL_IID_AUDIOIODEVICECAPABILITIES is not supported.
29 * Detection of microphone should be made in Java layer.
30 */
31
32 #define MAX_NUMBER_INTERFACES 5
33 #define MAX_NUMBER_INPUT_DEVICES 3
34 #define POSITION_UPDATE_PERIOD 1000 /* 1 sec */
35
RecordEventCallback(SLRecordItf caller __unused,void * pContext __unused,SLuint32 recordevent __unused)36 static void RecordEventCallback(SLRecordItf caller __unused,
37 void *pContext __unused,
38 SLuint32 recordevent __unused)
39 {
40 /* Callback code goes here */
41 }
42
43 /*
44 * Test recording of audio from a microphone into a specified file
45 */
TestAudioRecording(SLObjectItf sl)46 static void TestAudioRecording(SLObjectItf sl)
47 {
48 SLObjectItf recorder;
49 SLRecordItf recordItf;
50 SLEngineItf EngineItf;
51 SLAudioIODeviceCapabilitiesItf AudioIODeviceCapabilitiesItf;
52 SLAudioInputDescriptor AudioInputDescriptor;
53 SLresult res;
54
55 SLDataSource audioSource;
56 SLDataLocator_IODevice locator_mic;
57 SLDeviceVolumeItf devicevolumeItf;
58 SLDataSink audioSink;
59
60 int i;
61 SLboolean required[MAX_NUMBER_INTERFACES];
62 SLInterfaceID iidArray[MAX_NUMBER_INTERFACES];
63
64 SLuint32 InputDeviceIDs[MAX_NUMBER_INPUT_DEVICES];
65 SLint32 numInputs = 0;
66 SLboolean mic_available = SL_BOOLEAN_FALSE;
67 SLuint32 mic_deviceID = 0;
68
69 /* Get the SL Engine Interface which is implicit */
70 res = (*sl)->GetInterface(sl, SL_IID_ENGINE, (void *)&EngineItf);
71 CheckErr(res);
72
73 AudioIODeviceCapabilitiesItf = NULL;
74 /* Get the Audio IO DEVICE CAPABILITIES interface, which is also
75 implicit */
76 res = (*sl)->GetInterface(sl, SL_IID_AUDIOIODEVICECAPABILITIES,
77 (void *)&AudioIODeviceCapabilitiesItf);
78 // ANDROID: obtaining SL_IID_AUDIOIODEVICECAPABILITIES may fail
79 if (AudioIODeviceCapabilitiesItf != NULL ) {
80 numInputs = MAX_NUMBER_INPUT_DEVICES;
81 res = (*AudioIODeviceCapabilitiesItf)->GetAvailableAudioInputs(
82 AudioIODeviceCapabilitiesItf, &numInputs, InputDeviceIDs);
83 CheckErr(res);
84 /* Search for either earpiece microphone or headset microphone input
85 device - with a preference for the latter */
86 for (i = 0; i < numInputs; i++) {
87 res = (*AudioIODeviceCapabilitiesItf)->QueryAudioInputCapabilities(
88 AudioIODeviceCapabilitiesItf, InputDeviceIDs[i], &AudioInputDescriptor);
89 CheckErr(res);
90 if ((AudioInputDescriptor.deviceConnection == SL_DEVCONNECTION_ATTACHED_WIRED)
91 && (AudioInputDescriptor.deviceScope == SL_DEVSCOPE_USER)
92 && (AudioInputDescriptor.deviceLocation == SL_DEVLOCATION_HEADSET)) {
93 mic_deviceID = InputDeviceIDs[i];
94 mic_available = SL_BOOLEAN_TRUE;
95 break;
96 }
97 else if ((AudioInputDescriptor.deviceConnection == SL_DEVCONNECTION_INTEGRATED)
98 && (AudioInputDescriptor.deviceScope == SL_DEVSCOPE_USER)
99 && (AudioInputDescriptor.deviceLocation == SL_DEVLOCATION_HANDSET)) {
100 mic_deviceID = InputDeviceIDs[i];
101 mic_available = SL_BOOLEAN_TRUE;
102 break;
103 }
104 }
105 } else {
106 mic_deviceID = SL_DEFAULTDEVICEID_AUDIOINPUT;
107 mic_available = true;
108 }
109
110 /* If neither of the preferred input audio devices is available, no
111 point in continuing */
112 if (!mic_available) {
113 /* Appropriate error message here */
114 ALOGW("No microphone available");
115 return;
116 }
117
118 /* Initialize arrays required[] and iidArray[] */
119 for (i = 0; i < MAX_NUMBER_INTERFACES; i++) {
120 required[i] = SL_BOOLEAN_FALSE;
121 iidArray[i] = SL_IID_NULL;
122 }
123
124 // ANDROID: the following may fail for volume
125 devicevolumeItf = NULL;
126 /* Get the optional DEVICE VOLUME interface from the engine */
127 res = (*sl)->GetInterface(sl, SL_IID_DEVICEVOLUME,
128 (void *)&devicevolumeItf);
129
130 /* Set recording volume of the microphone to -3 dB */
131 if (devicevolumeItf != NULL) { // ANDROID: Volume may not be supported
132 res = (*devicevolumeItf)->SetVolume(devicevolumeItf, mic_deviceID, -300);
133 CheckErr(res);
134 }
135
136 /* Setup the data source structure */
137 locator_mic.locatorType = SL_DATALOCATOR_IODEVICE;
138 locator_mic.deviceType = SL_IODEVICE_AUDIOINPUT;
139 locator_mic.deviceID = mic_deviceID;
140 locator_mic.device= NULL;
141
142 audioSource.pLocator = (void *)&locator_mic;
143 audioSource.pFormat = NULL;
144
145 #if 0
146 /* Setup the data sink structure */
147 uri.locatorType = SL_DATALOCATOR_URI;
148 uri.URI = (SLchar *) "file:///recordsample.wav";
149 mime.formatType = SL_DATAFORMAT_MIME;
150 mime.mimeType = (SLchar *) "audio/x-wav";
151 mime.containerType = SL_CONTAINERTYPE_WAV;
152 audioSink.pLocator = (void *)&uri;
153 audioSink.pFormat = (void *)&mime;
154 #else
155 // FIXME: Android requires SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE
156 // because the recorder makes the distinction from SL_DATALOCATOR_BUFFERQUEUE
157 // which the player does not.
158 SLDataLocator_AndroidSimpleBufferQueue loc_bq = {
159 SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 2
160 };
161 SLDataFormat_PCM format_pcm = {
162 SL_DATAFORMAT_PCM, 1, SL_SAMPLINGRATE_16,
163 SL_PCMSAMPLEFORMAT_FIXED_16, SL_PCMSAMPLEFORMAT_FIXED_16,
164 SL_SPEAKER_FRONT_LEFT, SL_BYTEORDER_LITTLEENDIAN
165 };
166 audioSink = { &loc_bq, &format_pcm };
167 #endif
168
169 /* Create audio recorder */
170 res = (*EngineItf)->CreateAudioRecorder(EngineItf, &recorder,
171 &audioSource, &audioSink, 0, iidArray, required);
172 CheckErr(res);
173
174 /* Realizing the recorder in synchronous mode. */
175 res = (*recorder)->Realize(recorder, SL_BOOLEAN_FALSE);
176 CheckErr(res);
177
178 /* Get the RECORD interface - it is an implicit interface */
179 res = (*recorder)->GetInterface(recorder, SL_IID_RECORD, (void *)&recordItf);
180 CheckErr(res);
181
182 // ANDROID: Should register SL_IID_ANDROIDSIMPLEBUFFERQUEUE interface for callback.
183 // but does original SL_DATALOCATOR_BUFFERQUEUE variant work just as well ?
184
185 /* Setup to receive position event callbacks */
186 res = (*recordItf)->RegisterCallback(recordItf, RecordEventCallback, NULL);
187 CheckErr(res);
188
189 /* Set notifications to occur after every second - may be useful in
190 updating a recording progress bar */
191 res = (*recordItf)->SetPositionUpdatePeriod(recordItf, POSITION_UPDATE_PERIOD);
192 CheckErr(res);
193 res = (*recordItf)->SetCallbackEventsMask(recordItf, SL_RECORDEVENT_HEADATNEWPOS);
194 CheckErr(res);
195
196 /* Set the duration of the recording - 30 seconds (30,000
197 milliseconds) */
198 res = (*recordItf)->SetDurationLimit(recordItf, 30000);
199 CheckErr(res);
200
201 /* Record the audio */
202 res = (*recordItf)->SetRecordState(recordItf, SL_RECORDSTATE_RECORDING);
203 CheckErr(res);
204
205 // ANDROID: BUG - we don't wait for anything to record!
206
207 /* Destroy the recorder object */
208 (*recorder)->Destroy(recorder);
209 }
210
Java_android_media_cts_AudioNativeTest_nativeAppendixBRecording(JNIEnv *,jclass)211 extern "C" void Java_android_media_cts_AudioNativeTest_nativeAppendixBRecording(
212 JNIEnv * /* env */, jclass /* clazz */)
213 {
214 SLObjectItf engineObject = android::OpenSLEngine();
215 LOG_ALWAYS_FATAL_IF(engineObject == NULL, "cannot open OpenSL ES engine");
216
217 TestAudioRecording(engineObject);
218 android::CloseSLEngine(engineObject);
219 }
220