1 /*
2 * Copyright 2020 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 #include <android/log.h>
17
18 #include "OboeRecorder.h"
19
20 #include "AudioSink.h"
21
22 static const char * const TAG = "OboeRecorder(native)";
23
24 using namespace oboe;
25
26 constexpr int32_t kBufferSizeInBursts = 2; // Use 2 bursts as the buffer size (double buffer)
27
OboeRecorder(AudioSink * sink,int32_t subtype)28 OboeRecorder::OboeRecorder(AudioSink* sink, int32_t subtype)
29 : Recorder(sink, subtype),
30 mInputPreset(-1)
31 {}
32
33 //
34 // State
35 //
setupStream(int32_t channelCount,int32_t sampleRate,int32_t performanceMode,int32_t sharingMode,int32_t routeDeviceId,int32_t inputPreset)36 StreamBase::Result OboeRecorder::setupStream(int32_t channelCount, int32_t sampleRate,
37 int32_t performanceMode, int32_t sharingMode, int32_t routeDeviceId,
38 int32_t inputPreset)
39 {
40 //TODO much of this could be pulled up into OboeStream.
41
42 std::lock_guard<std::mutex> lock(mStreamLock);
43
44 oboe::Result result = oboe::Result::ErrorInternal;
45 if (mAudioStream != nullptr) {
46 return ERROR_INVALID_STATE;
47 } else {
48 mChannelCount = channelCount;
49 mSampleRate = sampleRate;
50 mRouteDeviceId = routeDeviceId;
51 mInputPreset = inputPreset;
52
53 // Create an audio stream
54 AudioStreamBuilder builder;
55 builder.setChannelCount(mChannelCount);
56 builder.setSampleRate(mSampleRate);
57 builder.setCallback(this);
58 if (mInputPreset != DEFAULT_INPUT_NONE) {
59 builder.setInputPreset((enum InputPreset)mInputPreset);
60 }
61 builder.setPerformanceMode((PerformanceMode) performanceMode);
62 builder.setSharingMode((SharingMode) sharingMode);
63 builder.setSampleRateConversionQuality(SampleRateConversionQuality::None);
64 builder.setDirection(Direction::Input);
65
66 if (mRouteDeviceId != -1) {
67 builder.setDeviceId(mRouteDeviceId);
68 }
69
70 if (mSubtype == SUB_TYPE_OBOE_AAUDIO) {
71 builder.setAudioApi(AudioApi::AAudio);
72 } else if (mSubtype == SUB_TYPE_OBOE_OPENSL_ES) {
73 builder.setAudioApi(AudioApi::OpenSLES);
74 }
75
76 result = builder.openStream(mAudioStream);
77 if (result != oboe::Result::OK){
78 __android_log_print(
79 ANDROID_LOG_ERROR,
80 TAG,
81 "openStream failed. Error: %s", convertToText(result));
82 } else {
83 mBufferSizeInFrames = mAudioStream->getFramesPerBurst();
84 mAudioSink->init(mBufferSizeInFrames, mChannelCount);
85 }
86 }
87
88 return OboeErrorToMegaAudioError(result);
89 }
90
startStream()91 StreamBase::Result OboeRecorder::startStream() {
92 StreamBase::Result result = Recorder::startStream();
93 if (result == OK) {
94 mAudioSink->start();
95 }
96 return result;
97 }
98
onAudioReady(oboe::AudioStream * audioStream,void * audioData,int numFrames)99 oboe::DataCallbackResult OboeRecorder::onAudioReady(
100 oboe::AudioStream *audioStream, void *audioData, int numFrames) {
101 mAudioSink->push((float*)audioData, numFrames, mChannelCount);
102 return oboe::DataCallbackResult::Continue;
103 }
104
105 #include <jni.h>
106
107 extern "C" {
108 JNIEXPORT jlong JNICALL
Java_org_hyphonate_megaaudio_recorder_OboeRecorder_allocNativeRecorder(JNIEnv * env,jobject thiz,jlong native_audio_sink,jint recorderSubtype)109 Java_org_hyphonate_megaaudio_recorder_OboeRecorder_allocNativeRecorder(JNIEnv *env, jobject thiz, jlong native_audio_sink, jint recorderSubtype) {
110 OboeRecorder* recorder = new OboeRecorder((AudioSink*)native_audio_sink, recorderSubtype);
111 return (jlong)recorder;
112 }
113
114 JNIEXPORT jint JNICALL
Java_org_hyphonate_megaaudio_recorder_OboeRecorder_getBufferFrameCountN(JNIEnv * env,jobject thiz,jlong native_recorder)115 Java_org_hyphonate_megaaudio_recorder_OboeRecorder_getBufferFrameCountN(
116 JNIEnv *env, jobject thiz, jlong native_recorder) {
117 return ((OboeRecorder*)native_recorder)->getNumBufferFrames();
118 }
119
120 JNIEXPORT void JNICALL
Java_org_hyphonate_megaaudio_recorder_OboeRecorder_setInputPresetN(JNIEnv * env,jobject thiz,jlong native_recorder,jint input_preset)121 Java_org_hyphonate_megaaudio_recorder_OboeRecorder_setInputPresetN(
122 JNIEnv *env, jobject thiz, jlong native_recorder, jint input_preset) {
123 ((OboeRecorder*)native_recorder)->setInputPreset(input_preset);
124 }
125
126 JNIEXPORT jint JNICALL
Java_org_hyphonate_megaaudio_recorder_OboeRecorder_setupStreamN(JNIEnv * env,jobject thiz,jlong native_recorder,jint channel_count,jint sample_rate,jint performanceMode,jint sharingMode,jint route_device_id,jint input_preset)127 Java_org_hyphonate_megaaudio_recorder_OboeRecorder_setupStreamN(
128 JNIEnv *env, jobject thiz, jlong native_recorder, jint channel_count, jint sample_rate,
129 jint performanceMode, jint sharingMode, jint route_device_id, jint input_preset) {
130 return ((OboeRecorder*)native_recorder)->setupStream(
131 channel_count, sample_rate, performanceMode, sharingMode, route_device_id,
132 input_preset);
133 }
134
135 JNIEXPORT jint JNICALL
Java_org_hyphonate_megaaudio_recorder_OboeRecorder_teardownStreamN(JNIEnv * env,jobject thiz,jlong native_recorder)136 Java_org_hyphonate_megaaudio_recorder_OboeRecorder_teardownStreamN(
137 JNIEnv *env, jobject thiz, jlong native_recorder) {
138 return ((OboeRecorder*)native_recorder)->teardownStream();
139 }
140
141 JNIEXPORT jint JNICALL
Java_org_hyphonate_megaaudio_recorder_OboeRecorder_startStreamN(JNIEnv * env,jobject thiz,jlong native_recorder,jint recorder_subtype)142 Java_org_hyphonate_megaaudio_recorder_OboeRecorder_startStreamN(
143 JNIEnv *env, jobject thiz, jlong native_recorder, jint recorder_subtype) {
144 return ((OboeRecorder*)native_recorder)->startStream();
145 }
146
147 JNIEXPORT jint JNICALL
Java_org_hyphonate_megaaudio_recorder_OboeRecorder_stopN(JNIEnv * env,jobject thiz,jlong native_recorder)148 Java_org_hyphonate_megaaudio_recorder_OboeRecorder_stopN(
149 JNIEnv *env, jobject thiz, jlong native_recorder) {
150 return ((OboeRecorder*)native_recorder)->stopStream();
151 }
152
153 JNIEXPORT jboolean JNICALL
Java_org_hyphonate_megaaudio_recorder_OboeRecorder_isRecordingN(JNIEnv * env,jobject thiz,jlong native_recorder)154 Java_org_hyphonate_megaaudio_recorder_OboeRecorder_isRecordingN(
155 JNIEnv *env, jobject thiz, jlong native_recorder) {
156 OboeRecorder* nativeRecorder = ((OboeRecorder*)native_recorder);
157 return nativeRecorder->isRecording();
158 }
159
160 JNIEXPORT jint JNICALL
Java_org_hyphonate_megaaudio_recorder_OboeRecorder_getNumBufferFramesN(JNIEnv * env,jobject thiz,jlong native_recorder)161 Java_org_hyphonate_megaaudio_recorder_OboeRecorder_getNumBufferFramesN(
162 JNIEnv *env, jobject thiz, jlong native_recorder) {
163 OboeRecorder* nativeRecorder = ((OboeRecorder*)native_recorder);
164 return nativeRecorder->getNumBufferFrames();
165 }
166
167 extern "C"
168 JNIEXPORT jint JNICALL
Java_org_hyphonate_megaaudio_recorder_OboeRecorder_getRoutedDeviceIdN(JNIEnv * env,jobject thiz,jlong native_recorder)169 Java_org_hyphonate_megaaudio_recorder_OboeRecorder_getRoutedDeviceIdN(
170 JNIEnv *env, jobject thiz, jlong native_recorder) {
171 return ((OboeRecorder*)native_recorder)->getRoutedDeviceId();
172 }
173
174 JNIEXPORT jint JNICALL
Java_org_hyphonate_megaaudio_recorder_OboeRecorder_getSharingModeN(JNIEnv * env,jobject thiz,jlong native_recorder)175 Java_org_hyphonate_megaaudio_recorder_OboeRecorder_getSharingModeN(
176 JNIEnv *env, jobject thiz, jlong native_recorder) {
177 return ((OboeRecorder*)native_recorder)->getSharingMode();
178 }
179
180 JNIEXPORT jint JNICALL
Java_org_hyphonate_megaaudio_recorder_OboeRecorder_getChannelCountN(JNIEnv * env,jobject thiz,jlong native_recorder)181 Java_org_hyphonate_megaaudio_recorder_OboeRecorder_getChannelCountN(
182 JNIEnv *env, jobject thiz, jlong native_recorder) {
183 return ((OboeRecorder*)native_recorder)->getChannelCount();
184 }
185
186 JNIEXPORT jboolean JNICALL
Java_org_hyphonate_megaaudio_recorder_OboeRecorder_isMMapN(JNIEnv * env,jobject thiz,jlong native_recorder)187 Java_org_hyphonate_megaaudio_recorder_OboeRecorder_isMMapN(
188 JNIEnv *env, jobject thiz, jlong native_recorder) {
189 return ((OboeRecorder*)native_recorder)->isMMap();
190 }
191
Java_org_hyphonate_megaaudio_recorder_OboeRecorder_getStreamStateN(JNIEnv * env,jobject thiz,jlong native_recorder)192 JNIEXPORT jint JNICALL Java_org_hyphonate_megaaudio_recorder_OboeRecorder_getStreamStateN(
193 JNIEnv *env, jobject thiz, jlong native_recorder) {
194 return (int)((OboeRecorder*)(native_recorder))->getState();
195 }
196
197 JNIEXPORT jint JNICALL
Java_org_hyphonate_megaaudio_recorder_OboeRecorder_getLastErrorCallbackResultN(JNIEnv * env,jobject thiz,jlong native_recorder)198 Java_org_hyphonate_megaaudio_recorder_OboeRecorder_getLastErrorCallbackResultN(
199 JNIEnv *env, jobject thiz, jlong native_recorder) {
200 return (int)((OboeRecorder*)(native_recorder))->getLastErrorCallbackResult();
201 }
202
203 } // extern "C"
204