| /* |
| * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. |
| * |
| * Use of this source code is governed by a BSD-style license |
| * that can be found in the LICENSE file in the root of the source |
| * tree. An additional intellectual property rights grant can be found |
| * in the file PATENTS. All contributing project authors may |
| * be found in the AUTHORS file in the root of the source tree. |
| */ |
| |
| #include <assert.h> |
| #include <jni.h> |
| |
| #include "webrtc/examples/android/opensl_loopback/fake_audio_device_buffer.h" |
| #include "webrtc/modules/audio_device/android/audio_device_template.h" |
| #include "webrtc/modules/audio_device/android/audio_record_jni.h" |
| #include "webrtc/modules/audio_device/android/audio_track_jni.h" |
| #include "webrtc/modules/audio_device/android/opensles_input.h" |
| #include "webrtc/modules/audio_device/android/opensles_output.h" |
| #include "webrtc/system_wrappers/interface/scoped_ptr.h" |
| |
| // Java globals |
| static JavaVM* g_vm = NULL; |
| static jclass g_osr = NULL; |
| |
| namespace webrtc { |
| |
| template <class InputType, class OutputType> |
| class OpenSlRunnerTemplate { |
| public: |
| OpenSlRunnerTemplate() |
| : output_(0), |
| input_(0, &output_) { |
| output_.AttachAudioBuffer(&audio_buffer_); |
| if (output_.Init() != 0) { |
| assert(false); |
| } |
| if (output_.InitPlayout() != 0) { |
| assert(false); |
| } |
| input_.AttachAudioBuffer(&audio_buffer_); |
| if (input_.Init() != 0) { |
| assert(false); |
| } |
| if (input_.InitRecording() != 0) { |
| assert(false); |
| } |
| } |
| |
| ~OpenSlRunnerTemplate() {} |
| |
| void StartPlayRecord() { |
| output_.StartPlayout(); |
| input_.StartRecording(); |
| } |
| |
| void StopPlayRecord() { |
| // There are large enough buffers to compensate for recording and playing |
| // jitter such that the timing of stopping playing or recording should not |
| // result in over or underrun. |
| input_.StopRecording(); |
| output_.StopPlayout(); |
| audio_buffer_.ClearBuffer(); |
| } |
| |
| private: |
| OutputType output_; |
| InputType input_; |
| FakeAudioDeviceBuffer audio_buffer_; |
| }; |
| |
| class OpenSlRunner |
| : public OpenSlRunnerTemplate<OpenSlesInput, OpenSlesOutput> { |
| public: |
| // Global class implementing native code. |
| static OpenSlRunner* g_runner; |
| |
| |
| OpenSlRunner() {} |
| virtual ~OpenSlRunner() {} |
| |
| static JNIEXPORT void JNICALL RegisterApplicationContext( |
| JNIEnv* env, |
| jobject obj, |
| jobject context) { |
| assert(!g_runner); // Should only be called once. |
| OpenSlesInput::SetAndroidAudioDeviceObjects(g_vm, env, context); |
| OpenSlesOutput::SetAndroidAudioDeviceObjects(g_vm, env, context); |
| g_runner = new OpenSlRunner(); |
| } |
| |
| static JNIEXPORT void JNICALL Start(JNIEnv * env, jobject) { |
| g_runner->StartPlayRecord(); |
| } |
| |
| static JNIEXPORT void JNICALL Stop(JNIEnv * env, jobject) { |
| g_runner->StopPlayRecord(); |
| } |
| }; |
| |
| OpenSlRunner* OpenSlRunner::g_runner = NULL; |
| |
| } // namespace webrtc |
| |
| jint JNI_OnLoad(JavaVM* vm, void* reserved) { |
| // Only called once. |
| assert(!g_vm); |
| JNIEnv* env; |
| if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) { |
| return -1; |
| } |
| |
| jclass local_osr = env->FindClass("org/webrtc/app/OpenSlRunner"); |
| assert(local_osr != NULL); |
| g_osr = static_cast<jclass>(env->NewGlobalRef(local_osr)); |
| JNINativeMethod nativeFunctions[] = { |
| {"RegisterApplicationContext", "(Landroid/content/Context;)V", |
| reinterpret_cast<void*>( |
| &webrtc::OpenSlRunner::RegisterApplicationContext)}, |
| {"Start", "()V", reinterpret_cast<void*>(&webrtc::OpenSlRunner::Start)}, |
| {"Stop", "()V", reinterpret_cast<void*>(&webrtc::OpenSlRunner::Stop)} |
| }; |
| int ret_val = env->RegisterNatives(g_osr, nativeFunctions, 3); |
| if (ret_val != 0) { |
| assert(false); |
| } |
| g_vm = vm; |
| return JNI_VERSION_1_6; |
| } |