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