blob: 6e9710f242edbeb670985f40057ae7d2afaf8e30 [file] [log] [blame]
perkj@webrtc.org96e4db92015-02-13 12:46:51 +00001/*
2 * libjingle
3 * Copyright 2015 Google Inc.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 *
27 */
28
29#include "talk/app/webrtc/java/jni/androidvideocapturer_jni.h"
30
31#include "talk/app/webrtc/java/jni/classreferenceholder.h"
perkj@webrtc.org3db042e2015-02-19 08:43:38 +000032#include "webrtc/base/bind.h"
perkj@webrtc.org96e4db92015-02-13 12:46:51 +000033
34namespace webrtc_jni {
35
36jobject AndroidVideoCapturerJni::application_context_ = nullptr;
37
perkj@webrtc.org3db042e2015-02-19 08:43:38 +000038// JavaCaptureProxy is responsible for marshaling calls from the
39// Java VideoCapturerAndroid to the C++ class AndroidVideoCapturer.
40// Calls from Java occur on a Java thread and are marshaled to
41// AndroidVideoCapturer on the thread that creates an instance of this object.
42//
43// An instance is created when AndroidVideoCapturerJni::Start is called and
44// ownership is passed to an instance of the Java class NativeObserver.
45// JavaCaptureProxy is destroyed when NativeObserver has reported that the
46// capturer has stopped, see
47// VideoCapturerAndroid_00024NativeObserver_nativeCapturerStopped.
48// Marshaling is done as long as JavaCaptureProxy has a pointer to the
49// AndroidVideoCapturer.
50class JavaCaptureProxy {
51 public:
52 JavaCaptureProxy() : thread_(rtc::Thread::Current()), capturer_(nullptr) {
53 }
54
55 ~JavaCaptureProxy() {
56 }
57
58 void SetAndroidCapturer(webrtc::AndroidVideoCapturer* capturer) {
59 DCHECK(thread_->IsCurrent());
60 capturer_ = capturer;
61 }
62
63 void OnCapturerStarted(bool success) {
64 thread_->Invoke<void>(
65 rtc::Bind(&JavaCaptureProxy::OnCapturerStarted_w, this, success));
66 }
67
68 void OnIncomingFrame(signed char* video_frame,
69 int length,
70 int rotation,
71 int64 time_stamp) {
72 thread_->Invoke<void>(
73 rtc::Bind(&JavaCaptureProxy::OnIncomingFrame_w, this, video_frame,
74 length, rotation, time_stamp));
75 }
76
77 private:
78 void OnCapturerStarted_w(bool success) {
79 DCHECK(thread_->IsCurrent());
80 if (capturer_)
81 capturer_->OnCapturerStarted(success);
82 }
83 void OnIncomingFrame_w(signed char* video_frame,
84 int length,
85 int rotation,
86 int64 time_stamp) {
87 DCHECK(thread_->IsCurrent());
88 if (capturer_)
89 capturer_->OnIncomingFrame(video_frame, length, rotation, time_stamp);
90 }
91
92 rtc::Thread* thread_;
93 webrtc::AndroidVideoCapturer* capturer_;
94};
95
perkj@webrtc.org96e4db92015-02-13 12:46:51 +000096// static
97int AndroidVideoCapturerJni::SetAndroidObjects(JNIEnv* jni,
98 jobject appliction_context) {
99 if (application_context_) {
100 jni->DeleteGlobalRef(application_context_);
101 }
102 application_context_ = NewGlobalRef(jni, appliction_context);
103
104 return 0;
105}
106
107AndroidVideoCapturerJni::AndroidVideoCapturerJni(JNIEnv* jni,
108 jobject j_video_capturer)
109 : j_capturer_global_(jni, j_video_capturer),
110 j_video_capturer_class_(
111 jni, FindClass(jni, "org/webrtc/VideoCapturerAndroid")),
perkj@webrtc.org3db042e2015-02-19 08:43:38 +0000112 j_observer_class_(
perkj@webrtc.org96e4db92015-02-13 12:46:51 +0000113 jni,
114 FindClass(jni,
perkj@webrtc.org3db042e2015-02-19 08:43:38 +0000115 "org/webrtc/VideoCapturerAndroid$NativeObserver")),
116 proxy_(nullptr) {
117 thread_checker_.DetachFromThread();
118}
perkj@webrtc.org96e4db92015-02-13 12:46:51 +0000119
perkj@webrtc.org3db042e2015-02-19 08:43:38 +0000120bool AndroidVideoCapturerJni::Init(jstring device_name) {
121 const jmethodID m(GetMethodID(
122 jni(), *j_video_capturer_class_, "init", "(Ljava/lang/String;)Z"));
123 if (!jni()->CallBooleanMethod(*j_capturer_global_, m, device_name)) {
124 return false;
125 }
126 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
127 return true;
128}
129
130AndroidVideoCapturerJni::~AndroidVideoCapturerJni() {
131 DeInit();
132}
133
134void AndroidVideoCapturerJni::DeInit() {
135 DCHECK(proxy_ == nullptr);
136 jmethodID m = GetMethodID(jni(), *j_video_capturer_class_, "deInit", "()V");
137 jni()->CallVoidMethod(*j_capturer_global_, m);
138 CHECK_EXCEPTION(jni()) << "error during VideoCapturerAndroid.DeInit";
139}
perkj@webrtc.org96e4db92015-02-13 12:46:51 +0000140
141void AndroidVideoCapturerJni::Start(int width, int height, int framerate,
142 webrtc::AndroidVideoCapturer* capturer) {
perkj@webrtc.org3db042e2015-02-19 08:43:38 +0000143 DCHECK(thread_checker_.CalledOnValidThread());
144 DCHECK(proxy_ == nullptr);
145 proxy_ = new JavaCaptureProxy();
146 proxy_->SetAndroidCapturer(capturer);
147
perkj@webrtc.org96e4db92015-02-13 12:46:51 +0000148 j_frame_observer_ = NewGlobalRef(
149 jni(),
perkj@webrtc.org3db042e2015-02-19 08:43:38 +0000150 jni()->NewObject(*j_observer_class_,
perkj@webrtc.org96e4db92015-02-13 12:46:51 +0000151 GetMethodID(jni(),
perkj@webrtc.org3db042e2015-02-19 08:43:38 +0000152 *j_observer_class_,
perkj@webrtc.org96e4db92015-02-13 12:46:51 +0000153 "<init>",
154 "(J)V"),
perkj@webrtc.org3db042e2015-02-19 08:43:38 +0000155 jlongFromPointer(proxy_)));
perkj@webrtc.org96e4db92015-02-13 12:46:51 +0000156 CHECK_EXCEPTION(jni()) << "error during NewObject";
157
158 jmethodID m = GetMethodID(
159 jni(), *j_video_capturer_class_, "startCapture",
160 "(IIILandroid/content/Context;"
161 "Lorg/webrtc/VideoCapturerAndroid$CapturerObserver;)V");
162 jni()->CallVoidMethod(*j_capturer_global_,
163 m, width, height,
164 framerate,
165 application_context_,
166 j_frame_observer_);
167 CHECK_EXCEPTION(jni()) << "error during VideoCapturerAndroid.startCapture";
168}
169
perkj@webrtc.org3db042e2015-02-19 08:43:38 +0000170void AndroidVideoCapturerJni::Stop() {
171 DCHECK(thread_checker_.CalledOnValidThread());
172 proxy_->SetAndroidCapturer(nullptr);
173 proxy_ = nullptr;
perkj@webrtc.org96e4db92015-02-13 12:46:51 +0000174 jmethodID m = GetMethodID(jni(), *j_video_capturer_class_,
perkj@webrtc.org3db042e2015-02-19 08:43:38 +0000175 "stopCapture", "()V");
176 jni()->CallVoidMethod(*j_capturer_global_, m);
perkj@webrtc.org96e4db92015-02-13 12:46:51 +0000177 CHECK_EXCEPTION(jni()) << "error during VideoCapturerAndroid.stopCapture";
178 DeleteGlobalRef(jni(), j_frame_observer_);
perkj@webrtc.org96e4db92015-02-13 12:46:51 +0000179}
180
181std::string AndroidVideoCapturerJni::GetSupportedFormats() {
182 jmethodID m =
183 GetMethodID(jni(), *j_video_capturer_class_,
184 "getSupportedFormatsAsJson", "()Ljava/lang/String;");
185 jstring j_json_caps =
186 (jstring) jni()->CallObjectMethod(*j_capturer_global_, m);
187 CHECK_EXCEPTION(jni()) << "error during supportedFormatsAsJson";
188 return JavaToStdString(jni(), j_json_caps);
189}
190
191JNIEnv* AndroidVideoCapturerJni::jni() { return AttachCurrentThreadIfNeeded(); }
192
perkj@webrtc.org3db042e2015-02-19 08:43:38 +0000193JOW(void, VideoCapturerAndroid_00024NativeObserver_nativeOnFrameCaptured)
194 (JNIEnv* jni, jclass, jlong j_proxy, jbyteArray j_frame,
perkj@webrtc.org96e4db92015-02-13 12:46:51 +0000195 jint rotation, jlong ts) {
196 jbyte* bytes = jni->GetByteArrayElements(j_frame, NULL);
perkj@webrtc.org3db042e2015-02-19 08:43:38 +0000197 reinterpret_cast<JavaCaptureProxy*>(
198 j_proxy)->OnIncomingFrame(bytes, jni->GetArrayLength(j_frame), rotation,
199 ts);
perkj@webrtc.org96e4db92015-02-13 12:46:51 +0000200 jni->ReleaseByteArrayElements(j_frame, bytes, JNI_ABORT);
201}
202
perkj@webrtc.org3db042e2015-02-19 08:43:38 +0000203JOW(void, VideoCapturerAndroid_00024NativeObserver_nativeCapturerStarted)
204 (JNIEnv* jni, jclass, jlong j_proxy, jboolean j_success) {
205 JavaCaptureProxy* proxy = reinterpret_cast<JavaCaptureProxy*>(j_proxy);
206 proxy->OnCapturerStarted(j_success);
207 if (!j_success)
208 delete proxy;
209}
210
211JOW(void, VideoCapturerAndroid_00024NativeObserver_nativeCapturerStopped)
212 (JNIEnv* jni, jclass, jlong j_proxy) {
213 delete reinterpret_cast<JavaCaptureProxy*>(j_proxy);
perkj@webrtc.org96e4db92015-02-13 12:46:51 +0000214}
215
216} // namespace webrtc_jni
217