Browse Source

Merged in AuahDark/love/androidmic (pull request #126)

Recording support for Android (C++ side)
Alex Szpakowski 5 years ago
parent
commit
5789a0b1b1

+ 53 - 0
src/common/android.cpp

@@ -266,6 +266,59 @@ bool hasBackgroundMusic()
 	return result;
 	return result;
 }
 }
 
 
+bool hasRecordingPermission()
+{
+	JNIEnv *env = (JNIEnv*) SDL_AndroidGetJNIEnv();
+	jobject activity = (jobject) SDL_AndroidGetActivity();
+
+	jclass clazz(env->GetObjectClass(activity));
+	jmethodID methodID = env->GetMethodID(clazz, "hasRecordAudioPermission", "()Z");
+	jboolean result = false;
+
+	if (methodID == nullptr)
+		env->ExceptionClear();
+	else
+		result = env->CallBooleanMethod(activity, methodID);
+
+	env->DeleteLocalRef(activity);
+	env->DeleteLocalRef(clazz);
+
+	return result;
+}
+
+
+void requestRecordingPermission()
+{
+	JNIEnv *env = (JNIEnv*) SDL_AndroidGetJNIEnv();
+	jobject activity = (jobject) SDL_AndroidGetActivity();
+	jclass clazz(env->GetObjectClass(activity));
+	jmethodID methodID = env->GetMethodID(clazz, "requestRecordAudioPermission", "()V");
+
+	if (methodID == nullptr)
+		env->ExceptionClear();
+	else
+		env->CallVoidMethod(activity, methodID);
+
+	env->DeleteLocalRef(clazz);
+	env->DeleteLocalRef(activity);
+}
+
+void showRecordingPermissionMissingDialog()
+{
+	JNIEnv *env = (JNIEnv*) SDL_AndroidGetJNIEnv();
+	jobject activity = (jobject) SDL_AndroidGetActivity();
+	jclass clazz(env->GetObjectClass(activity));
+	jmethodID methodID = env->GetMethodID(clazz, "showRecordingAudioPermissionMissingDialog", "()V");
+
+	if (methodID == nullptr)
+		env->ExceptionClear();
+	else
+		env->CallVoidMethod(activity, methodID);
+
+	env->DeleteLocalRef(clazz);
+	env->DeleteLocalRef(activity);
+}
+
 } // android
 } // android
 } // love
 } // love
 
 

+ 6 - 0
src/common/android.h

@@ -74,6 +74,12 @@ bool createStorageDirectories();
 
 
 bool hasBackgroundMusic();
 bool hasBackgroundMusic();
 
 
+bool hasRecordingPermission();
+
+void requestRecordingPermission();
+
+void showRecordingPermissionMissingDialog();
+
 } // android
 } // android
 } // love
 } // love
 
 

+ 39 - 1
src/modules/audio/Audio.cpp

@@ -21,8 +21,10 @@
 #include "Audio.h"
 #include "Audio.h"
 #include "common/config.h"
 #include "common/config.h"
 
 
-#ifdef LOVE_IOS
+#if defined(LOVE_IOS)
 #include "common/ios.h"
 #include "common/ios.h"
+#elif defined(LOVE_ANDROID)
+#include "common/android.h"
 #endif
 #endif
 
 
 namespace love
 namespace love
@@ -30,6 +32,42 @@ namespace love
 namespace audio
 namespace audio
 {
 {
 
 
+static bool requestRecPermission = false;
+
+void setRequestRecordingPermission(bool rec)
+{
+	requestRecPermission = rec;
+}
+
+bool getRequestRecordingPermission()
+{
+	return requestRecPermission;
+}
+
+bool hasRecordingPermission()
+{
+#if defined(LOVE_ANDROID)
+	return love::android::hasRecordingPermission();
+#else
+	// Always available(?)
+	return true;
+#endif
+}
+
+void requestRecordingPermission()
+{
+#ifdef LOVE_ANDROID
+	love::android::requestRecordingPermission();
+#endif
+}
+
+void showRecordingPermissionMissingDialog()
+{
+#ifdef LOVE_ANDROID
+	love::android::showRecordingPermissionMissingDialog();
+#endif
+}
+
 bool Audio::setMixWithSystem(bool mix)
 bool Audio::setMixWithSystem(bool mix)
 {
 {
 #ifdef LOVE_IOS
 #ifdef LOVE_IOS

+ 28 - 0
src/modules/audio/Audio.h

@@ -45,6 +45,34 @@ class SoundData;
 namespace audio
 namespace audio
 {
 {
 
 
+/*
+ * In some platforms (notably Android), recording from mic
+ * requires user permission. This function sets whetever to
+ * request the permission later or not.
+ */
+void setRequestRecordingPermission(bool rec);
+
+/*
+ * Gets whetever recording permission will be requested.
+ */
+bool getRequestRecordingPermission();
+
+/*
+ * Gets whetever recording permission is granted.
+ */
+bool hasRecordingPermission();
+
+/*
+ * Request recording permission. This is blocking function.
+ */
+void requestRecordingPermission();
+
+/*
+ * In case recording permission is not granted, this
+ * function shows the dialog about the recording permission.
+ */
+void showRecordingPermissionMissingDialog();
+
 /**
 /**
  * The Audio module is responsible for playing back raw sound samples.
  * The Audio module is responsible for playing back raw sound samples.
  **/
  **/

+ 18 - 0
src/modules/audio/openal/Audio.cpp

@@ -101,6 +101,15 @@ Audio::Audio()
 	love::thread::disableSignals();
 	love::thread::disableSignals();
 #endif
 #endif
 
 
+	// Before opening new device, check if recording
+	// is requested.
+	if (getRequestRecordingPermission())
+	{
+		if (!hasRecordingPermission())
+			// Request recording permission on some OSes.
+			requestRecordingPermission();
+	}
+
 	// Passing null for default device.
 	// Passing null for default device.
 	device = alcOpenDevice(nullptr);
 	device = alcOpenDevice(nullptr);
 
 
@@ -402,6 +411,15 @@ const std::vector<love::audio::RecordingDevice*> &Audio::getRecordingDevices()
 	std::vector<std::string> devnames;
 	std::vector<std::string> devnames;
 	std::vector<love::audio::RecordingDevice*> devices;
 	std::vector<love::audio::RecordingDevice*> devices;
 
 
+	// If recording permission is not granted, inform user about it
+	// and return empty list.
+	if (!hasRecordingPermission() && getRequestRecordingPermission())
+	{
+		showRecordingPermissionMissingDialog();
+		capture.clear();
+		return capture;
+	}
+
 	std::string defaultname(alcGetString(NULL, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER));
 	std::string defaultname(alcGetString(NULL, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER));
 
 
 	//no device name obtained from AL, fallback to reading from device
 	//no device name obtained from AL, fallback to reading from device

+ 10 - 0
src/modules/love/love.cpp

@@ -335,6 +335,14 @@ static int w__setAudioMixWithSystem(lua_State *L)
 	return 1;
 	return 1;
 }
 }
 
 
+static int w__requestRecordingPermission(lua_State *L)
+{
+#ifdef LOVE_ENABLE_AUDIO
+	love::audio::setRequestRecordingPermission((bool) lua_toboolean(L, 1));
+#endif
+	return 0;
+}
+
 static int w_love_setDeprecationOutput(lua_State *L)
 static int w_love_setDeprecationOutput(lua_State *L)
 {
 {
 	bool enable = love::luax_checkboolean(L, 1);
 	bool enable = love::luax_checkboolean(L, 1);
@@ -396,6 +404,8 @@ int luaopen_love(lua_State *L)
 	// module is initialized.
 	// module is initialized.
 	lua_pushcfunction(L, w__setAudioMixWithSystem);
 	lua_pushcfunction(L, w__setAudioMixWithSystem);
 	lua_setfield(L, -2, "_setAudioMixWithSystem");
 	lua_setfield(L, -2, "_setAudioMixWithSystem");
+	lua_pushcfunction(L, w__requestRecordingPermission);
+	lua_setfield(L, -2, "_requestRecordingPermission");
 
 
 	lua_newtable(L);
 	lua_newtable(L);
 
 

+ 9 - 2
src/scripts/boot.lua

@@ -425,6 +425,7 @@ function love.init()
 		},
 		},
 		audio = {
 		audio = {
 			mixwithsystem = true, -- Only relevant for Android / iOS.
 			mixwithsystem = true, -- Only relevant for Android / iOS.
+			mic = false, -- Only relevant for Android.
 		},
 		},
 		console = false, -- Only relevant for windows.
 		console = false, -- Only relevant for windows.
 		identity = false,
 		identity = false,
@@ -469,8 +470,14 @@ function love.init()
 		love._setGammaCorrect(c.gammacorrect)
 		love._setGammaCorrect(c.gammacorrect)
 	end
 	end
 
 
-	if love._setAudioMixWithSystem and c.audio then
-		love._setAudioMixWithSystem(c.audio.mixwithsystem)
+	if love._setAudioMixWithSystem then
+		if c.audio and c.audio.mixwithsystem ~= nil then
+			love._setAudioMixWithSystem(c.audio.mixwithsystem)
+		end
+	end
+
+	if love._requestRecordingPermission then
+		love._requestRecordingPermission(c.audio and c.audio.mic)
 	end
 	end
 
 
 	-- Gets desired modules.
 	-- Gets desired modules.

+ 20 - 5
src/scripts/boot.lua.h

@@ -841,6 +841,9 @@ const unsigned char boot_lua[] =
 	0x20, 0x74, 0x72, 0x75, 0x65, 0x2c, 0x20, 0x2d, 0x2d, 0x20, 0x4f, 0x6e, 0x6c, 0x79, 0x20, 0x72, 0x65, 0x6c, 
 	0x20, 0x74, 0x72, 0x75, 0x65, 0x2c, 0x20, 0x2d, 0x2d, 0x20, 0x4f, 0x6e, 0x6c, 0x79, 0x20, 0x72, 0x65, 0x6c, 
 	0x65, 0x76, 0x61, 0x6e, 0x74, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x41, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x20, 
 	0x65, 0x76, 0x61, 0x6e, 0x74, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x41, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x20, 
 	0x2f, 0x20, 0x69, 0x4f, 0x53, 0x2e, 0x0a,
 	0x2f, 0x20, 0x69, 0x4f, 0x53, 0x2e, 0x0a,
+	0x09, 0x09, 0x09, 0x6d, 0x69, 0x63, 0x20, 0x3d, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x2c, 0x20, 0x2d, 0x2d, 
+	0x20, 0x4f, 0x6e, 0x6c, 0x79, 0x20, 0x72, 0x65, 0x6c, 0x65, 0x76, 0x61, 0x6e, 0x74, 0x20, 0x66, 0x6f, 0x72, 
+	0x20, 0x41, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2e, 0x0a,
 	0x09, 0x09, 0x7d, 0x2c, 0x0a,
 	0x09, 0x09, 0x7d, 0x2c, 0x0a,
 	0x09, 0x09, 0x63, 0x6f, 0x6e, 0x73, 0x6f, 0x6c, 0x65, 0x20, 0x3d, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x2c, 
 	0x09, 0x09, 0x63, 0x6f, 0x6e, 0x73, 0x6f, 0x6c, 0x65, 0x20, 0x3d, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x2c, 
 	0x20, 0x2d, 0x2d, 0x20, 0x4f, 0x6e, 0x6c, 0x79, 0x20, 0x72, 0x65, 0x6c, 0x65, 0x76, 0x61, 0x6e, 0x74, 0x20, 
 	0x20, 0x2d, 0x2d, 0x20, 0x4f, 0x6e, 0x6c, 0x79, 0x20, 0x72, 0x65, 0x6c, 0x65, 0x76, 0x61, 0x6e, 0x74, 0x20, 
@@ -944,11 +947,23 @@ const unsigned char boot_lua[] =
 	0x09, 0x65, 0x6e, 0x64, 0x0a,
 	0x09, 0x65, 0x6e, 0x64, 0x0a,
 	0x0a,
 	0x0a,
 	0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x5f, 0x73, 0x65, 0x74, 0x41, 0x75, 0x64, 0x69, 0x6f, 
 	0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x5f, 0x73, 0x65, 0x74, 0x41, 0x75, 0x64, 0x69, 0x6f, 
-	0x4d, 0x69, 0x78, 0x57, 0x69, 0x74, 0x68, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x20, 0x61, 0x6e, 0x64, 0x20, 
-	0x63, 0x2e, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a,
-	0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x5f, 0x73, 0x65, 0x74, 0x41, 0x75, 0x64, 0x69, 0x6f, 0x4d, 0x69, 
-	0x78, 0x57, 0x69, 0x74, 0x68, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x28, 0x63, 0x2e, 0x61, 0x75, 0x64, 0x69, 
-	0x6f, 0x2e, 0x6d, 0x69, 0x78, 0x77, 0x69, 0x74, 0x68, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x29, 0x0a,
+	0x4d, 0x69, 0x78, 0x57, 0x69, 0x74, 0x68, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a,
+	0x09, 0x09, 0x69, 0x66, 0x20, 0x63, 0x2e, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x63, 
+	0x2e, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2e, 0x6d, 0x69, 0x78, 0x77, 0x69, 0x74, 0x68, 0x73, 0x79, 0x73, 0x74, 
+	0x65, 0x6d, 0x20, 0x7e, 0x3d, 0x20, 0x6e, 0x69, 0x6c, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a,
+	0x09, 0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x5f, 0x73, 0x65, 0x74, 0x41, 0x75, 0x64, 0x69, 0x6f, 0x4d, 
+	0x69, 0x78, 0x57, 0x69, 0x74, 0x68, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x28, 0x63, 0x2e, 0x61, 0x75, 0x64, 
+	0x69, 0x6f, 0x2e, 0x6d, 0x69, 0x78, 0x77, 0x69, 0x74, 0x68, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x29, 0x0a,
+	0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a,
+	0x09, 0x65, 0x6e, 0x64, 0x0a,
+	0x0a,
+	0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 
+	0x65, 0x63, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 
+	0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a,
+	0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x65, 0x63, 
+	0x6f, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x28, 0x63, 
+	0x2e, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x63, 0x2e, 0x61, 0x75, 0x64, 0x69, 0x6f, 
+	0x2e, 0x6d, 0x69, 0x63, 0x29, 0x0a,
 	0x09, 0x65, 0x6e, 0x64, 0x0a,
 	0x09, 0x65, 0x6e, 0x64, 0x0a,
 	0x0a,
 	0x0a,
 	0x09, 0x2d, 0x2d, 0x20, 0x47, 0x65, 0x74, 0x73, 0x20, 0x64, 0x65, 0x73, 0x69, 0x72, 0x65, 0x64, 0x20, 0x6d, 
 	0x09, 0x2d, 0x2d, 0x20, 0x47, 0x65, 0x74, 0x73, 0x20, 0x64, 0x65, 0x73, 0x69, 0x72, 0x65, 0x64, 0x20, 0x6d,