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