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