xref: /aosp_15_r20/cts/apps/CtsVerifier/jni/megaaudio/player/OboePlayer.cpp (revision b7c941bb3fa97aba169d73cee0bed2de8ac964bf)
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 "OboePlayer.h"
19 
20 #include "WaveTableSource.h"
21 
22 #include "AudioSource.h"
23 
24 static const char * const TAG = "OboePlayer(native)";
25 
26 using namespace oboe;
27 
28 constexpr int32_t kBufferSizeInBursts = 2; // Use 2 bursts as the buffer size (double buffer)
29 
javaChannelMaskToOboeChannelMask(int32_t javaMask)30 ChannelMask OboePlayer::javaChannelMaskToOboeChannelMask(int32_t javaMask) {
31     return (ChannelMask) (javaMask >> 2);
32 }
33 
javaChannelMaskToChannelCount(int32_t javaMask)34 int32_t OboePlayer::javaChannelMaskToChannelCount(int32_t javaMask) {
35     // return the count of 1 bits
36     return __builtin_popcount(static_cast<uint32_t>(javaMask));
37 }
38 
OboePlayer(JNIEnv * env,AudioSource * source,int subtype)39 OboePlayer::OboePlayer(JNIEnv *env, AudioSource* source, int subtype)
40  : Player(source, subtype)
41 {
42     env->GetJavaVM(&mJvm);
43 
44     jclass clsAudioTimestamp = env->FindClass("android/media/AudioTimestamp");
45 
46     mFidFramePosition = env->GetFieldID(clsAudioTimestamp, "framePosition", "J");
47     mFidNanoTime = env->GetFieldID(clsAudioTimestamp, "nanoTime", "J");
48 }
49 
onAudioReady(AudioStream * oboeStream,void * audioData,int32_t numFrames)50 DataCallbackResult OboePlayer::onAudioReady(AudioStream *oboeStream, void *audioData,
51                                             int32_t numFrames) {
52     StreamState streamState = oboeStream->getState();
53     if (streamState != StreamState::Open && streamState != StreamState::Started) {
54         __android_log_print(ANDROID_LOG_ERROR, TAG, "  streamState:%d",
55                 static_cast<int>(streamState));
56     }
57     if (streamState == StreamState::Disconnected) {
58         __android_log_print(ANDROID_LOG_ERROR, TAG, "  streamState::Disconnected");
59     }
60 
61     // Pull the data here!
62     int numFramesRead = mAudioSource->pull((float*)audioData, numFrames, mNumExchangeChannels);
63     // may need to handle 0-filling if numFramesRead < numFrames
64 
65     return numFramesRead != 0 ? DataCallbackResult::Continue : DataCallbackResult::Stop;
66 }
67 
onErrorAfterClose(AudioStream * oboeStream,oboe::Result error)68 void OboePlayer::onErrorAfterClose(AudioStream *oboeStream, oboe::Result error) {
69 }
70 
onErrorBeforeClose(AudioStream *,oboe::Result error)71 void OboePlayer::onErrorBeforeClose(AudioStream *, oboe::Result error) {
72 }
73 
setupStream(int32_t channelCount,int32_t channelMask,int32_t sampleRate,int32_t performanceMode,int32_t sharingMode,int32_t routeDeviceId)74 StreamBase::Result OboePlayer::setupStream(int32_t channelCount, int32_t channelMask,
75                     int32_t sampleRate, int32_t performanceMode, int32_t sharingMode,
76                     int32_t routeDeviceId) {
77 
78     oboe::Result result = oboe::Result::ErrorInternal;
79     if (mAudioStream != nullptr) {
80         __android_log_print(ANDROID_LOG_ERROR, TAG,
81                             "ERROR_INVALID_STATE - Stream Already Open.");
82         return ERROR_INVALID_STATE;
83     } else {
84         std::lock_guard<std::mutex> lock(mStreamLock);
85 
86         mChannelCount = channelCount;
87         mChannelMask = channelMask;
88 
89         mSampleRate = sampleRate;
90         mRouteDeviceId = routeDeviceId;
91 
92         // Create an audio stream
93         AudioStreamBuilder builder;
94         if (mChannelCount != 0) {
95             builder.setChannelCount(mChannelCount);
96             mNumExchangeChannels = mChannelCount;
97         } else {
98             builder.setChannelMask(javaChannelMaskToOboeChannelMask(mChannelMask));
99             mNumExchangeChannels = javaChannelMaskToChannelCount(mChannelMask);
100         }
101         builder.setSampleRate(mSampleRate);
102         builder.setCallback(this);
103 
104         builder.setSampleRateConversionQuality(SampleRateConversionQuality::None);
105         builder.setDirection(Direction::Output);
106         switch (mSubtype) {
107         case SUB_TYPE_OBOE_AAUDIO:
108             builder.setAudioApi(AudioApi::AAudio);
109             break;
110 
111         case SUB_TYPE_OBOE_OPENSL_ES:
112             builder.setAudioApi(AudioApi::OpenSLES);
113             break;
114         }
115 
116         builder.setPerformanceMode((PerformanceMode) performanceMode);
117         builder.setSharingMode((SharingMode) sharingMode);
118 
119         if (mRouteDeviceId != ROUTING_DEVICE_NONE) {
120             builder.setDeviceId(mRouteDeviceId);
121         }
122 
123         result = builder.openStream(mAudioStream);
124         if (result != oboe::Result::OK){
125             __android_log_print(
126                     ANDROID_LOG_ERROR,
127                     TAG,
128                     "openStream failed. Error: %s", convertToText(result));
129         } else {
130             // Reduce stream latency by setting the buffer size to a multiple of the burst size
131             // Note: this will fail with ErrorUnimplemented if we are using a callback with
132             //  OpenSL ES. See oboe::AudioStreamBuffered::setBufferSizeInFrames
133             // This doesn't affect the success of opening the stream.
134             int32_t desiredSize = mAudioStream->getFramesPerBurst() * kBufferSizeInBursts;
135             mAudioStream->setBufferSizeInFrames(desiredSize);
136 
137             mAudioSource->init(desiredSize , mNumExchangeChannels);
138         }
139     }
140     __android_log_print(ANDROID_LOG_INFO, TAG, " Done - error:%d", static_cast<int>(result));
141     return OboeErrorToMegaAudioError(result);
142 }
143 
startStream()144 StreamBase::Result OboePlayer::startStream() {
145     StreamBase::Result result = Player::startStream();
146 
147     return result;
148 }
149 
getJavaTimestamp(jobject timestampObj)150 bool OboePlayer::getJavaTimestamp(jobject timestampObj) {
151     oboe::FrameTimestamp nativeStamp;
152     StreamBase::Result result = Player::getTimeStamp(&nativeStamp);
153     if (result == OK) {
154         JNIEnv* env;
155         mJvm->AttachCurrentThread(&env, NULL);
156 
157         env->SetLongField(timestampObj, mFidFramePosition, nativeStamp.position);
158         env->SetLongField(timestampObj, mFidNanoTime, nativeStamp.timestamp);
159     }
160 
161     return result == OK;
162 }
163 
getLastErrorCallbackResult()164 int OboePlayer::getLastErrorCallbackResult() {
165     return (int)(mAudioStream->getLastErrorCallbackResult());
166 }
167 
168 //
169 // JNI functions
170 //
171 #include <jni.h>
172 
173 extern "C" {
174 JNIEXPORT JNICALL jlong
Java_org_hyphonate_megaaudio_player_OboePlayer_allocNativePlayer(JNIEnv * env,jobject thiz,jlong native_audio_source,jint playerSubtype)175 Java_org_hyphonate_megaaudio_player_OboePlayer_allocNativePlayer(
176     JNIEnv *env, jobject thiz, jlong native_audio_source, jint playerSubtype) {
177 
178     return (jlong)new OboePlayer(env, (AudioSource*)native_audio_source, playerSubtype);
179 }
180 
Java_org_hyphonate_megaaudio_player_OboePlayer_setupStreamN(JNIEnv * env,jobject thiz,jlong native_player,jint channel_count,jint channel_mask,jint sample_rate,jint performanceMode,jint sharingMode,jint routeDeviceId)181 JNIEXPORT jint JNICALL Java_org_hyphonate_megaaudio_player_OboePlayer_setupStreamN(
182         JNIEnv *env, jobject thiz, jlong native_player,
183         jint channel_count, jint channel_mask, jint sample_rate, jint performanceMode,
184         jint sharingMode, jint routeDeviceId) {
185 
186     OboePlayer* player = (OboePlayer*)native_player;
187     return player->setupStream(channel_count, channel_mask, sample_rate, performanceMode,
188                                 sharingMode, routeDeviceId);
189 }
190 
Java_org_hyphonate_megaaudio_player_OboePlayer_teardownStreamN(JNIEnv * env,jobject thiz,jlong native_player)191 JNIEXPORT int JNICALL Java_org_hyphonate_megaaudio_player_OboePlayer_teardownStreamN(
192         JNIEnv *env, jobject thiz, jlong native_player) {
193 
194     OboePlayer* player = (OboePlayer*)native_player;
195     return player->teardownStream();
196 }
197 
Java_org_hyphonate_megaaudio_player_OboePlayer_startStreamN(JNIEnv * env,jobject thiz,jlong native_player,jint playerSubtype)198 JNIEXPORT JNICALL jint Java_org_hyphonate_megaaudio_player_OboePlayer_startStreamN(
199         JNIEnv *env, jobject thiz, jlong native_player, jint playerSubtype) {
200 
201     return ((OboePlayer*)(native_player))->startStream();
202 }
203 
204 JNIEXPORT JNICALL jint
Java_org_hyphonate_megaaudio_player_OboePlayer_stopN(JNIEnv * env,jobject thiz,jlong native_player)205 Java_org_hyphonate_megaaudio_player_OboePlayer_stopN(JNIEnv *env, jobject thiz,
206             jlong native_player) {
207 
208    return ((OboePlayer*)(native_player))->stopStream();
209 }
210 
211 JNIEXPORT jint JNICALL
Java_org_hyphonate_megaaudio_player_OboePlayer_getBufferFrameCountN(JNIEnv * env,jobject thiz,jlong native_player)212 Java_org_hyphonate_megaaudio_player_OboePlayer_getBufferFrameCountN(JNIEnv *env, jobject thiz,
213             jlong native_player) {
214     return ((OboePlayer*)(native_player))->getNumBufferFrames();
215 }
216 
Java_org_hyphonate_megaaudio_player_OboePlayer_getRoutedDeviceIdN(JNIEnv * env,jobject thiz,jlong native_player)217 JNIEXPORT jint JNICALL Java_org_hyphonate_megaaudio_player_OboePlayer_getRoutedDeviceIdN(
218             JNIEnv *env, jobject thiz, jlong native_player) {
219     return ((OboePlayer*)(native_player))->getRoutedDeviceId();
220 }
221 
Java_org_hyphonate_megaaudio_player_OboePlayer_getSharingModeN(JNIEnv * env,jobject thiz,jlong native_player)222 JNIEXPORT jint JNICALL Java_org_hyphonate_megaaudio_player_OboePlayer_getSharingModeN(
223             JNIEnv *env, jobject thiz, jlong native_player) {
224     return ((OboePlayer*)(native_player))->getSharingMode();
225 }
226 
Java_org_hyphonate_megaaudio_player_OboePlayer_getChannelCountN(JNIEnv * env,jobject thiz,jlong native_player)227 JNIEXPORT jint JNICALL Java_org_hyphonate_megaaudio_player_OboePlayer_getChannelCountN(
228             JNIEnv *env, jobject thiz, jlong native_player) {
229     return ((OboePlayer*)(native_player))->getChannelCount();
230 }
231 
Java_org_hyphonate_megaaudio_player_OboePlayer_isMMapN(JNIEnv * env,jobject thiz,jlong native_player)232 JNIEXPORT jboolean JNICALL Java_org_hyphonate_megaaudio_player_OboePlayer_isMMapN(
233             JNIEnv *env, jobject thiz, jlong native_player) {
234     return ((OboePlayer*)(native_player))->isMMap();
235 }
236 
Java_org_hyphonate_megaaudio_player_OboePlayer_getTimestampN(JNIEnv * env,jobject thiz,jlong native_player,jobject timestamp)237 JNIEXPORT jboolean JNICALL Java_org_hyphonate_megaaudio_player_OboePlayer_getTimestampN(
238             JNIEnv *env, jobject thiz, jlong native_player, jobject timestamp) {
239     return ((OboePlayer*)native_player)->getJavaTimestamp(timestamp);
240 }
241 
Java_org_hyphonate_megaaudio_player_OboePlayer_getStreamStateN(JNIEnv * env,jobject thiz,jlong native_player)242 JNIEXPORT jint JNICALL Java_org_hyphonate_megaaudio_player_OboePlayer_getStreamStateN(
243             JNIEnv *env, jobject thiz, jlong native_player) {
244     return (int)((OboePlayer*)(native_player))->getState();
245 }
246 
Java_org_hyphonate_megaaudio_player_OboePlayer_getLastErrorCallbackResultN(JNIEnv * env,jobject thiz,jlong native_player)247 JNIEXPORT jint JNICALL Java_org_hyphonate_megaaudio_player_OboePlayer_getLastErrorCallbackResultN(
248             JNIEnv *env, jobject thiz, jlong native_player) {
249     return (int)((OboePlayer*)(native_player))->getLastErrorCallbackResult();
250 }
251 
252 } // extern "C"
253