1/*
2 *  Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
3 *
4 *  Use of this source code is governed by a BSD-style license
5 *  that can be found in the LICENSE file in the root of the source
6 *  tree. An additional intellectual property rights grant can be found
7 *  in the file PATENTS.  All contributing project authors may
8 *  be found in the AUTHORS file in the root of the source tree.
9 */
10
11#include <assert.h>
12#include <jni.h>
13
14#include "webrtc/examples/android/opensl_loopback/fake_audio_device_buffer.h"
15#include "webrtc/modules/audio_device/android/audio_device_template.h"
16#include "webrtc/modules/audio_device/android/audio_record_jni.h"
17#include "webrtc/modules/audio_device/android/audio_track_jni.h"
18#include "webrtc/modules/audio_device/android/opensles_input.h"
19#include "webrtc/modules/audio_device/android/opensles_output.h"
20#include "webrtc/system_wrappers/interface/scoped_ptr.h"
21
22// Java globals
23static JavaVM* g_vm = NULL;
24static jclass g_osr = NULL;
25
26namespace webrtc {
27
28template <class InputType, class OutputType>
29class OpenSlRunnerTemplate {
30 public:
31  OpenSlRunnerTemplate()
32      : output_(0),
33        input_(0, &output_) {
34    output_.AttachAudioBuffer(&audio_buffer_);
35    if (output_.Init() != 0) {
36      assert(false);
37    }
38    if (output_.InitPlayout() != 0) {
39      assert(false);
40    }
41    input_.AttachAudioBuffer(&audio_buffer_);
42    if (input_.Init() != 0) {
43      assert(false);
44    }
45    if (input_.InitRecording() != 0) {
46      assert(false);
47    }
48  }
49
50  ~OpenSlRunnerTemplate() {}
51
52  void StartPlayRecord() {
53    output_.StartPlayout();
54    input_.StartRecording();
55  }
56
57  void StopPlayRecord() {
58    // There are large enough buffers to compensate for recording and playing
59    // jitter such that the timing of stopping playing or recording should not
60    // result in over or underrun.
61    input_.StopRecording();
62    output_.StopPlayout();
63    audio_buffer_.ClearBuffer();
64  }
65
66 private:
67  OutputType output_;
68  InputType input_;
69  FakeAudioDeviceBuffer audio_buffer_;
70};
71
72class OpenSlRunner
73    : public OpenSlRunnerTemplate<OpenSlesInput, OpenSlesOutput> {
74 public:
75  // Global class implementing native code.
76  static OpenSlRunner* g_runner;
77
78
79  OpenSlRunner() {}
80  virtual ~OpenSlRunner() {}
81
82  static JNIEXPORT void JNICALL RegisterApplicationContext(
83      JNIEnv* env,
84      jobject obj,
85      jobject context) {
86    assert(!g_runner);  // Should only be called once.
87    OpenSlesInput::SetAndroidAudioDeviceObjects(g_vm, env, context);
88    OpenSlesOutput::SetAndroidAudioDeviceObjects(g_vm, env, context);
89    g_runner = new OpenSlRunner();
90  }
91
92  static JNIEXPORT void JNICALL Start(JNIEnv * env, jobject) {
93    g_runner->StartPlayRecord();
94  }
95
96  static JNIEXPORT void JNICALL Stop(JNIEnv * env, jobject) {
97    g_runner->StopPlayRecord();
98  }
99};
100
101OpenSlRunner* OpenSlRunner::g_runner = NULL;
102
103}  // namespace webrtc
104
105jint JNI_OnLoad(JavaVM* vm, void* reserved) {
106  // Only called once.
107  assert(!g_vm);
108  JNIEnv* env;
109  if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
110    return -1;
111  }
112
113  jclass local_osr = env->FindClass("org/webrtc/app/OpenSlRunner");
114  assert(local_osr != NULL);
115  g_osr = static_cast<jclass>(env->NewGlobalRef(local_osr));
116  JNINativeMethod nativeFunctions[] = {
117    {"RegisterApplicationContext", "(Landroid/content/Context;)V",
118     reinterpret_cast<void*>(
119         &webrtc::OpenSlRunner::RegisterApplicationContext)},
120    {"Start", "()V", reinterpret_cast<void*>(&webrtc::OpenSlRunner::Start)},
121    {"Stop",  "()V", reinterpret_cast<void*>(&webrtc::OpenSlRunner::Stop)}
122  };
123  int ret_val = env->RegisterNatives(g_osr, nativeFunctions, 3);
124  if (ret_val != 0) {
125    assert(false);
126  }
127  g_vm = vm;
128  return JNI_VERSION_1_6;
129}
130