diff --git a/CMakeLists.txt b/CMakeLists.txt
index c2766714b216fd544919e03a8a3cf549fa70aed3..2904201a71f944dbe17468c20dfdb9e9ab84d3c5 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -424,6 +424,9 @@ if(ANDROID)
 	endif()
 endif()
 
+if(ENABLE_JAVA_WRAPPER AND NOT ANDROID)
+	find_package(JNI REQUIRED)
+endif()
 
 include_directories(
 	include
@@ -659,15 +662,6 @@ elseif(WIN32 AND CMAKE_SYSTEM_NAME STREQUAL "WindowsStore")#Fix error on 'vccorl
 	list(APPEND LINK_OPTIONS_RELEASE "/nodefaultlib:vccorlib" "/nodefaultlib:msvcrt" "vccorlib.lib" "msvcrt.lib")
 endif()
 
-set(MEDIASTREAMER2_CPPFLAGS )
-if(NOT BUILD_SHARED_LIBS)
-	list(APPEND MEDIASTREAMER2_CPPFLAGS "-DMS2_STATIC")
-endif()
-if(MEDIASTREAMER2_CPPFLAGS)
-	list(REMOVE_DUPLICATES MEDIASTREAMER2_CPPFLAGS)
-	add_definitions(${MEDIASTREAMER2_CPPFLAGS})
-endif()
-
 set(STRICT_OPTIONS_CPP )
 set(STRICT_OPTIONS_C )
 set(STRICT_OPTIONS_OBJC "-Wno-error")
diff --git a/include/mediastreamer2/msjava.h b/include/mediastreamer2/msjava.h
index 0a059c8d609e1b18982765fc2cfed81243cabe8b..538af7f22c5e18d1bc033d2099414d41445f1773 100644
--- a/include/mediastreamer2/msjava.h
+++ b/include/mediastreamer2/msjava.h
@@ -26,15 +26,17 @@
 #include <bctoolbox/list.h>
 #include <jni.h>
 
+#include "mediastreamer2/mscommon.h"
+
 #ifdef __cplusplus
 extern "C" {
 #endif
 
-void ms_set_jvm(JavaVM *vm);
+MS2_PUBLIC void ms_set_jvm(JavaVM *vm);
 
-JavaVM *ms_get_jvm(void);
+MS2_PUBLIC JavaVM *ms_get_jvm(void);
 
-JNIEnv *ms_get_jni_env(void);
+MS2_PUBLIC JNIEnv *ms_get_jni_env(void);
 
 #ifdef __ANDROID__
 int ms_get_android_sdk_version(void);
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index f332756cc23b7b8e11167231579eb08cc9f4c5e5..0d34a2432df758c2f5e51dd08c8f80d2e7bffe67 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -44,7 +44,8 @@ set(BASE_SOURCE_FILES_C
 	otherfilters/tee.c
 	otherfilters/void.c
 )
-if(ANDROID)
+
+if(ANDROID OR ENABLE_JAVA_WRAPPER)
 	list(APPEND BASE_SOURCE_FILES_C utils/msjava.c)
 endif()
 
@@ -151,7 +152,8 @@ endif()
 if(ENABLE_ALSA)
 	list(APPEND VOIP_SOURCE_FILES_C audiofilters/alsa.c)
 endif()
-if(ANDROID)
+
+if(ANDROID OR ENABLE_JAVA_WRAPPER)
 	list(APPEND VOIP_SOURCE_FILES_CXX voip/msvoip_jni.cc)
 endif()
 if(ENABLE_ANDROIDSND)
@@ -614,6 +616,11 @@ if(BV16_FOUND AND BV16_USE_BUILD_INTERFACE)
 	target_compile_definitions(mediastreamer2 PRIVATE BV16_USE_BUILD_INTERFACE)
 endif()
 
+if(JNI_FOUND)
+	target_include_directories(mediastreamer2 PRIVATE ${JNI_INCLUDE_DIRS})
+	target_link_libraries(mediastreamer2 PRIVATE ${JNI_LIBRARIES})
+endif()
+
 if(BUILD_SHARED_LIBS)
 	if(APPLE)
 		set_target_properties(mediastreamer2 PROPERTIES
@@ -698,6 +705,10 @@ if(BUILD_SHARED_LIBS)
 		endif()
 	endif()
 
+else()
+
+	target_compile_definitions(mediastreamer2 PUBLIC "MS2_STATIC")
+
 endif()
 
 install(TARGETS mediastreamer2 EXPORT ${PROJECT_NAME}Targets
diff --git a/src/utils/msjava.c b/src/utils/msjava.c
index 05c7d6d3a4dd06516f6c6c6a74db54c3f9991efe..5606d510fca9fd80c78d6cc7176744fe0936898c 100644
--- a/src/utils/msjava.c
+++ b/src/utils/msjava.c
@@ -25,7 +25,11 @@
 
 static JavaVM *ms2_vm = NULL;
 
-#ifndef _WIN32
+#ifdef _WIN32
+
+static DWORD jnienv_key;
+
+#else
 #include <pthread.h>
 
 static pthread_key_t jnienv_key;
@@ -47,14 +51,24 @@ void _android_key_cleanup(void *data) {
 
 void ms_set_jvm_from_env(JNIEnv *env) {
 	(*env)->GetJavaVM(env, &ms2_vm);
-#ifndef _WIN32
+#ifdef _WIN32
+	jnienv_key = TlsAlloc();
+	if (jnienv_key == TLS_OUT_OF_INDEXES) {
+		bctbx_error("TlsAlloc(): TLS_OUT_OF_INDEXES.");
+	}
+#else
 	pthread_key_create(&jnienv_key, _android_key_cleanup);
 #endif
 }
 
 void ms_set_jvm(JavaVM *vm) {
 	ms2_vm = vm;
-#ifndef _WIN32
+#ifdef _WIN32
+	jnienv_key = TlsAlloc();
+	if (jnienv_key == TLS_OUT_OF_INDEXES) {
+		bctbx_error("TlsAlloc(): TLS_OUT_OF_INDEXES.");
+	}
+#else
 	pthread_key_create(&jnienv_key, _android_key_cleanup);
 #endif
 }
@@ -68,18 +82,22 @@ JNIEnv *ms_get_jni_env(void) {
 	if (ms2_vm == NULL) {
 		ms_fatal("Calling ms_get_jni_env() while no jvm has been set using ms_set_jvm().");
 	} else {
-#ifndef _WIN32
+#ifdef _WIN32
+		env = (JNIEnv *)TlsGetValue(jnienv_key);
+#else
 		env = (JNIEnv *)pthread_getspecific(jnienv_key);
+#endif
 		if (env == NULL) {
-			if ((*ms2_vm)->AttachCurrentThread(ms2_vm, &env, NULL) != 0) {
+			if ((*ms2_vm)->AttachCurrentThread(ms2_vm, (void *)&env, NULL) != 0) {
 				ms_fatal("AttachCurrentThread() failed !");
 				return NULL;
 			}
-			pthread_setspecific(jnienv_key, env);
-		}
+#ifdef _WIN32
+			TlsSetValue(jnienv_key, (void *)env);
 #else
-		ms_fatal("ms_get_jni_env() not implemented on windows.");
+			pthread_setspecific(jnienv_key, env);
 #endif
+		}
 	}
 	return env;
 }