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 routeDeviceId)36 StreamBase::Result OboeRecorder::setupStream(
37 int32_t channelCount, int32_t sampleRate, int32_t routeDeviceId)
38 {
39 //TODO much of this could be pulled up into OboeStream.
40
41 std::lock_guard<std::mutex> lock(mStreamLock);
42
43 oboe::Result result = oboe::Result::ErrorInternal;
44 if (mAudioStream != nullptr) {
45 return ERROR_INVALID_STATE;
46 } else {
47 mChannelCount = channelCount;
48 mSampleRate = sampleRate;
49 mRouteDeviceId = routeDeviceId;
50
51 // Create an audio stream
52 AudioStreamBuilder builder;
53 builder.setChannelCount(mChannelCount);
54 builder.setSampleRate(mSampleRate);
55 builder.setCallback(this);
56 if (mInputPreset != DEFAULT_INPUT_NONE) {
57 builder.setInputPreset((enum InputPreset)mInputPreset);
58 }
59 builder.setPerformanceMode(PerformanceMode::LowLatency);
60 // builder.setPerformanceMode(PerformanceMode::None);
61 builder.setSharingMode(SharingMode::Exclusive);
62 builder.setSampleRateConversionQuality(SampleRateConversionQuality::None);
63 builder.setDirection(Direction::Input);
64
65 if (mRouteDeviceId != -1) {
66 builder.setDeviceId(mRouteDeviceId);
67 }
68
69 if (mSubtype == SUB_TYPE_OBOE_AAUDIO) {
70 builder.setAudioApi(AudioApi::AAudio);
71 } else if (mSubtype == SUB_TYPE_OBOE_OPENSL_ES) {
72 builder.setAudioApi(AudioApi::OpenSLES);
73 }
74
75 result = builder.openStream(mAudioStream);
76 if (result != oboe::Result::OK){
77 __android_log_print(
78 ANDROID_LOG_ERROR,
79 TAG,
80 "openStream failed. Error: %s", convertToText(result));
81 } else {
82 mBufferSizeInFrames = mAudioStream->getFramesPerBurst();
83 mAudioSink->init(mBufferSizeInFrames, mChannelCount);
84 }
85 }
86
87 return OboeErrorToMegaAudioError(result);
88 }
89
startStream()90 StreamBase::Result OboeRecorder::startStream() {
91 StreamBase::Result result = Recorder::startStream();
92 if (result == OK) {
93 mAudioSink->start();
94 }
95 return result;
96 }
97
onAudioReady(oboe::AudioStream * audioStream,void * audioData,int numFrames)98 oboe::DataCallbackResult OboeRecorder::onAudioReady(
99 oboe::AudioStream *audioStream, void *audioData, int numFrames) {
100 mAudioSink->push((float*)audioData, numFrames, mChannelCount);
101 return oboe::DataCallbackResult::Continue;
102 }
103
104 #include <jni.h>
105
106 extern "C" {
107 JNIEXPORT jlong JNICALL
Java_org_hyphonate_megaaudio_recorder_OboeRecorder_allocNativeRecorder(JNIEnv * env,jobject thiz,jlong native_audio_sink,jint recorderSubtype)108 Java_org_hyphonate_megaaudio_recorder_OboeRecorder_allocNativeRecorder(JNIEnv *env, jobject thiz, jlong native_audio_sink, jint recorderSubtype) {
109 OboeRecorder* recorder = new OboeRecorder((AudioSink*)native_audio_sink, recorderSubtype);
110 return (jlong)recorder;
111 }
112
113 JNIEXPORT jint JNICALL
Java_org_hyphonate_megaaudio_recorder_OboeRecorder_getBufferFrameCountN(JNIEnv * env,jobject thiz,jlong native_recorder)114 Java_org_hyphonate_megaaudio_recorder_OboeRecorder_getBufferFrameCountN(
115 JNIEnv *env, jobject thiz, jlong native_recorder) {
116 return ((OboeRecorder*)native_recorder)->getNumBufferFrames();
117 }
118
119 JNIEXPORT void JNICALL
Java_org_hyphonate_megaaudio_recorder_OboeRecorder_setInputPresetN(JNIEnv * env,jobject thiz,jlong native_recorder,jint input_preset)120 Java_org_hyphonate_megaaudio_recorder_OboeRecorder_setInputPresetN(JNIEnv *env, jobject thiz,
121 jlong native_recorder,
122 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 route_device_id)127 Java_org_hyphonate_megaaudio_recorder_OboeRecorder_setupStreamN(JNIEnv *env, jobject thiz,
128 jlong native_recorder,
129 jint channel_count,
130 jint sample_rate,
131 jint route_device_id) {
132 return ((OboeRecorder*)native_recorder)->setupStream(channel_count, sample_rate, route_device_id);
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(JNIEnv *env, jobject thiz,
143 jlong native_recorder,
144 jint recorder_subtype) {
145 return ((OboeRecorder*)native_recorder)->startStream();
146 }
147
148 JNIEXPORT jint JNICALL
Java_org_hyphonate_megaaudio_recorder_OboeRecorder_stopN(JNIEnv * env,jobject thiz,jlong native_recorder)149 Java_org_hyphonate_megaaudio_recorder_OboeRecorder_stopN(JNIEnv *env, jobject thiz,
150 jlong native_recorder) {
151 return ((OboeRecorder*)native_recorder)->stopStream();
152 }
153
154 JNIEXPORT jboolean JNICALL
Java_org_hyphonate_megaaudio_recorder_OboeRecorder_isRecordingN(JNIEnv * env,jobject thiz,jlong native_recorder)155 Java_org_hyphonate_megaaudio_recorder_OboeRecorder_isRecordingN(
156 JNIEnv *env, jobject thiz, jlong native_recorder) {
157 OboeRecorder* nativeRecorder = ((OboeRecorder*)native_recorder);
158 return nativeRecorder->isRecording();
159 }
160
161 JNIEXPORT jint JNICALL
Java_org_hyphonate_megaaudio_recorder_OboeRecorder_getNumBufferFramesN(JNIEnv * env,jobject thiz,jlong native_recorder)162 Java_org_hyphonate_megaaudio_recorder_OboeRecorder_getNumBufferFramesN(
163 JNIEnv *env, jobject thiz, jlong native_recorder) {
164 OboeRecorder* nativeRecorder = ((OboeRecorder*)native_recorder);
165 return nativeRecorder->getNumBufferFrames();
166 }
167
168 extern "C"
169 JNIEXPORT jint JNICALL
Java_org_hyphonate_megaaudio_recorder_OboeRecorder_getRoutedDeviceIdN(JNIEnv * env,jobject thiz,jlong native_recorder)170 Java_org_hyphonate_megaaudio_recorder_OboeRecorder_getRoutedDeviceIdN(JNIEnv *env, jobject thiz, jlong native_recorder) {
171 return ((OboeRecorder*)native_recorder)->getRoutedDeviceId();
172 }
173
174 } // extern "C"
175