mirror of
https://github.com/InstanceBrick/nightcap.git
synced 2026-10-25 15:14:40 +01:00
Maybe fix vc
This commit is contained in:
1 parent
92c7d7b12b
commit
b71873f2a5
7 files changed
+1004
-8
No files matched your search
@@ -1,8 +1,10 @@
|
||||
#include "mocktail/audio/webrtc_jni_audio_bridge.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <atomic>
|
||||
#include <cmath>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
@@ -11,6 +13,7 @@
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
@@ -26,6 +29,7 @@ struct CaptureSession {
|
||||
jnivm::WebRtcAudioRecordDataCallback data_callback = nullptr;
|
||||
void* data_context = nullptr;
|
||||
std::unique_ptr<AudioCapture> capture;
|
||||
std::shared_ptr<std::atomic<bool>> microphone_muted;
|
||||
};
|
||||
|
||||
struct PlayoutSession {
|
||||
@@ -46,6 +50,9 @@ struct PlayoutSession {
|
||||
|
||||
struct WebRtcJniAudioBridgeContext {
|
||||
std::mutex mutex;
|
||||
std::unordered_set<const void*> initialized_managers;
|
||||
std::shared_ptr<std::atomic<bool>> microphone_muted =
|
||||
std::make_shared<std::atomic<bool>>(false);
|
||||
std::unordered_map<const void*, std::shared_ptr<CaptureSession>>
|
||||
capture_sessions;
|
||||
std::unordered_map<const void*, std::shared_ptr<PlayoutSession>>
|
||||
@@ -54,9 +61,71 @@ struct WebRtcJniAudioBridgeContext {
|
||||
bool shutting_down = false;
|
||||
};
|
||||
|
||||
bool GetManagerParameters(void* opaque_context,
|
||||
jnivm::WebRtcAudioManagerParameters* parameters) {
|
||||
auto* context = static_cast<WebRtcJniAudioBridgeContext*>(opaque_context);
|
||||
if (context == nullptr || parameters == nullptr) return false;
|
||||
std::lock_guard<std::mutex> lock(context->mutex);
|
||||
if (context->shutting_down) return false;
|
||||
// SDL converts between this WebRTC-facing format and the actual device.
|
||||
// Match WebRtcAudioManager's default mono input/output and 10 ms frames.
|
||||
// Advertising the format never opens a capture device, including when the
|
||||
// microphone is disabled. Recording init remains the permission boundary.
|
||||
*parameters = {};
|
||||
parameters->sample_rate_hz = 48000;
|
||||
parameters->output_channels = 1;
|
||||
parameters->input_channels = 1;
|
||||
parameters->output_buffer_size_frames = 480;
|
||||
parameters->input_buffer_size_frames = 480;
|
||||
// Android hardware effects, low-latency paths and AAudio are not emulated;
|
||||
// WebRTC must retain its software processing and Java audio transport.
|
||||
return true;
|
||||
}
|
||||
|
||||
bool InitManager(void* opaque_context, const void* identity) {
|
||||
auto* context = static_cast<WebRtcJniAudioBridgeContext*>(opaque_context);
|
||||
if (context == nullptr || identity == nullptr) return false;
|
||||
bool inserted = false;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(context->mutex);
|
||||
if (context->shutting_down) return false;
|
||||
inserted = context->initialized_managers.insert(identity).second;
|
||||
}
|
||||
if (inserted) {
|
||||
std::cout << " [mocktail][audio] WebRTC audio manager initialized\n"
|
||||
<< std::flush;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void DisposeManager(void* opaque_context, const void* identity) {
|
||||
auto* context = static_cast<WebRtcJniAudioBridgeContext*>(opaque_context);
|
||||
if (context == nullptr) return;
|
||||
std::lock_guard<std::mutex> lock(context->mutex);
|
||||
if (context->initialized_managers.erase(identity) != 0) {
|
||||
std::cout << " [mocktail][audio] WebRTC audio manager disposed\n"
|
||||
<< std::flush;
|
||||
}
|
||||
// Record/track objects own their streams and stop them independently.
|
||||
}
|
||||
|
||||
void SetMicrophoneMute(void* opaque_context, bool muted) {
|
||||
auto* context = static_cast<WebRtcJniAudioBridgeContext*>(opaque_context);
|
||||
if (context == nullptr) return;
|
||||
context->microphone_muted->store(muted, std::memory_order_release);
|
||||
}
|
||||
|
||||
void OnCapturedAudio(void* opaque_session, std::size_t size_bytes) {
|
||||
auto* session = static_cast<CaptureSession*>(opaque_session);
|
||||
if (session != nullptr && session->data_callback != nullptr) {
|
||||
if (session->microphone_muted != nullptr &&
|
||||
session->microphone_muted->load(std::memory_order_acquire)) {
|
||||
if (session->capture == nullptr ||
|
||||
size_bytes > session->capture->buffer_size_bytes()) {
|
||||
return;
|
||||
}
|
||||
std::memset(session->capture->buffer_data(), 0, size_bytes);
|
||||
}
|
||||
session->data_callback(session->data_context, session->identity,
|
||||
size_bytes);
|
||||
}
|
||||
@@ -104,6 +173,7 @@ int Init(void* opaque_context, const void* identity, int sample_rate_hz,
|
||||
session->identity = identity;
|
||||
session->data_callback = data_callback;
|
||||
session->data_context = data_context;
|
||||
session->microphone_muted = context->microphone_muted;
|
||||
|
||||
SdlAudioCaptureOptions options;
|
||||
options.output_spec.sample_rate_hz = sample_rate_hz;
|
||||
@@ -480,6 +550,7 @@ void Shutdown(void* opaque_context) {
|
||||
std::lock_guard<std::mutex> lock(context->mutex);
|
||||
context->recording_enabled = false;
|
||||
context->shutting_down = true;
|
||||
context->initialized_managers.clear();
|
||||
capture_sessions.swap(context->capture_sessions);
|
||||
playout_sessions.swap(context->playout_sessions);
|
||||
}
|
||||
@@ -544,6 +615,13 @@ Status InstallWebRtcJniAudioBridge(jnivm::VM* vm) {
|
||||
record_callbacks.shutdown = &Shutdown;
|
||||
vm->SetWebRtcAudioRecordCallbacks(context, record_callbacks);
|
||||
|
||||
jnivm::WebRtcAudioManagerCallbacks manager_callbacks;
|
||||
manager_callbacks.get_parameters = &GetManagerParameters;
|
||||
manager_callbacks.init = &InitManager;
|
||||
manager_callbacks.dispose = &DisposeManager;
|
||||
manager_callbacks.set_microphone_mute = &SetMicrophoneMute;
|
||||
vm->SetWebRtcAudioManagerCallbacks(context, manager_callbacks);
|
||||
|
||||
jnivm::WebRtcAudioTrackCallbacks track_callbacks;
|
||||
track_callbacks.init = &InitPlayout;
|
||||
track_callbacks.buffer_size_frames = &PlayoutBufferSizeFrames;
|
||||
@@ -561,6 +639,7 @@ Status ShutdownWebRtcJniAudioBridge(jnivm::VM* vm) {
|
||||
}
|
||||
// Drop dispatch first, then let the recording binding's shared context stop
|
||||
// both playout workers and capture streams.
|
||||
vm->ClearWebRtcAudioManagerCallbacks();
|
||||
vm->ClearWebRtcAudioTrackCallbacks();
|
||||
vm->ClearWebRtcAudioRecordCallbacks();
|
||||
return Status::Ok();
|
||||
|
||||
+267
-2
@@ -2944,6 +2944,78 @@ bool IsFmodAudioDeviceMethod(jobject obj, jmethodID method_id,
|
||||
ObjectClassName(obj) == "org/fmod/AudioDevice";
|
||||
}
|
||||
|
||||
bool IsWebRtcAudioManagerMethod(jobject obj, jmethodID method_id,
|
||||
const char* name, const char* signature) {
|
||||
return obj != nullptr && method_id != nullptr &&
|
||||
std::strcmp(MethodName(method_id), name) == 0 &&
|
||||
std::strcmp(MethodSignature(method_id), signature) == 0 &&
|
||||
ObjectClassName(obj) == "org/webrtc/voiceengine/WebRtcAudioManager";
|
||||
}
|
||||
|
||||
bool HandleWebRtcAudioManagerBooleanMethod(jobject obj, jmethodID method_id,
|
||||
jboolean* result) {
|
||||
VM* vm = CurrentVM();
|
||||
if (IsWebRtcAudioManagerMethod(obj, method_id, "init", "()Z")) {
|
||||
*result = vm != nullptr && vm->DispatchWebRtcAudioManagerInit(obj)
|
||||
? JNI_TRUE
|
||||
: JNI_FALSE;
|
||||
} else if (IsWebRtcAudioManagerMethod(obj, method_id,
|
||||
"isDeviceBlacklistedForOpenSLESUsage",
|
||||
"()Z")) {
|
||||
// Host recording is provided by AudioRecord JNI, not Android OpenSL ES.
|
||||
*result = JNI_TRUE;
|
||||
} else if (IsWebRtcAudioManagerMethod(obj, method_id,
|
||||
"isCommunicationModeEnabled", "()Z")) {
|
||||
*result = BooleanFieldValue(obj, "initialized");
|
||||
} else if (IsWebRtcAudioManagerMethod(obj, method_id,
|
||||
"isLowLatencyOutputSupported", "()Z")) {
|
||||
*result = BooleanFieldValue(obj, "lowLatencyOutput");
|
||||
} else if (IsWebRtcAudioManagerMethod(obj, method_id,
|
||||
"isLowLatencyInputSupported", "()Z")) {
|
||||
*result = BooleanFieldValue(obj, "lowLatencyInput");
|
||||
} else if (IsWebRtcAudioManagerMethod(obj, method_id, "isProAudioSupported",
|
||||
"()Z")) {
|
||||
*result = BooleanFieldValue(obj, "proAudio");
|
||||
} else if (IsWebRtcAudioManagerMethod(obj, method_id, "isAAudioSupported",
|
||||
"()Z")) {
|
||||
*result = BooleanFieldValue(obj, "aAudio");
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HandleWebRtcAudioManagerVoidMethodV(jobject obj, jmethodID method_id,
|
||||
va_list args) {
|
||||
VM* vm = CurrentVM();
|
||||
if (IsWebRtcAudioManagerMethod(obj, method_id, "dispose", "()V")) {
|
||||
if (vm != nullptr) vm->DispatchWebRtcAudioManagerDispose(obj);
|
||||
} else if (IsWebRtcAudioManagerMethod(obj, method_id, "setMicrophoneMute",
|
||||
"(Z)V")) {
|
||||
const bool muted = va_arg(args, jint) != JNI_FALSE;
|
||||
if (vm != nullptr) vm->DispatchWebRtcAudioManagerMicrophoneMute(obj, muted);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HandleWebRtcAudioManagerVoidMethodA(jobject obj, jmethodID method_id,
|
||||
const jvalue* args) {
|
||||
VM* vm = CurrentVM();
|
||||
if (IsWebRtcAudioManagerMethod(obj, method_id, "dispose", "()V")) {
|
||||
if (vm != nullptr) vm->DispatchWebRtcAudioManagerDispose(obj);
|
||||
} else if (IsWebRtcAudioManagerMethod(obj, method_id, "setMicrophoneMute",
|
||||
"(Z)V")) {
|
||||
if (vm != nullptr && args != nullptr) {
|
||||
vm->DispatchWebRtcAudioManagerMicrophoneMute(obj, args[0].z != JNI_FALSE);
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IsWebRtcAudioRecordMethod(jobject obj, jmethodID method_id,
|
||||
const char *name, const char *signature) {
|
||||
return obj != nullptr && method_id != nullptr &&
|
||||
@@ -4463,6 +4535,7 @@ void JNICALL CallVoidMethod(JNIEnv * /*env*/, jobject obj, jmethodID methodID,
|
||||
va_list args;
|
||||
va_start(args, methodID);
|
||||
if (!HandleRobloxExperienceLifecycleVoidMethod(obj, methodID) &&
|
||||
!HandleWebRtcAudioManagerVoidMethodV(obj, methodID, args) &&
|
||||
!HandleRobloxOpenWebActivityMethodV(obj, methodID, args) &&
|
||||
!HandleRobloxTextInputInstanceVoidMethodV(obj, methodID, args) &&
|
||||
!HandleFmodAudioDeviceVoidMethodV(obj, methodID, args) &&
|
||||
@@ -4493,8 +4566,11 @@ jboolean JNICALL CallBooleanMethod(JNIEnv* /*env*/, jobject obj,
|
||||
va_list args;
|
||||
va_start(args, methodID);
|
||||
jboolean result = JNI_FALSE;
|
||||
bool handled =
|
||||
HandleWebRtcAudioRecordBooleanMethodV(obj, methodID, args, &result);
|
||||
bool handled = HandleWebRtcAudioManagerBooleanMethod(obj, methodID, &result);
|
||||
if (!handled) {
|
||||
handled =
|
||||
HandleWebRtcAudioRecordBooleanMethodV(obj, methodID, args, &result);
|
||||
}
|
||||
if (!handled) {
|
||||
handled =
|
||||
HandleWebRtcAudioTrackBooleanMethodV(obj, methodID, args, &result);
|
||||
@@ -4566,6 +4642,14 @@ jobject ConstructObjectV(jclass clazz, jmethodID methodID, va_list args) {
|
||||
std::strcmp(MethodName(methodID), "<init>") == 0 &&
|
||||
std::strcmp(MethodSignature(methodID), "(J)V") == 0) {
|
||||
SetLongFieldRaw(object, "ref", va_arg(args, jlong));
|
||||
} else if (object_class->GetName() ==
|
||||
"org/webrtc/voiceengine/WebRtcAudioManager" &&
|
||||
std::strcmp(MethodName(methodID), "<init>") == 0 &&
|
||||
std::strcmp(MethodSignature(methodID), "(J)V") == 0) {
|
||||
const jlong native_audio_manager = va_arg(args, jlong);
|
||||
if (VM* vm = CurrentVM()) {
|
||||
vm->DispatchWebRtcAudioManagerConstruct(object, native_audio_manager);
|
||||
}
|
||||
} else if (object_class->GetName() ==
|
||||
"org/webrtc/voiceengine/WebRtcAudioRecord" &&
|
||||
std::strcmp(MethodName(methodID), "<init>") == 0 &&
|
||||
@@ -4648,6 +4732,13 @@ jobject ConstructObjectA(jclass clazz, jmethodID methodID, const jvalue *args) {
|
||||
std::strcmp(MethodName(methodID), "<init>") == 0 &&
|
||||
std::strcmp(MethodSignature(methodID), "(J)V") == 0) {
|
||||
SetLongFieldRaw(object, "ref", args[0].j);
|
||||
} else if (object_class->GetName() ==
|
||||
"org/webrtc/voiceengine/WebRtcAudioManager" &&
|
||||
std::strcmp(MethodName(methodID), "<init>") == 0 &&
|
||||
std::strcmp(MethodSignature(methodID), "(J)V") == 0) {
|
||||
if (VM* vm = CurrentVM()) {
|
||||
vm->DispatchWebRtcAudioManagerConstruct(object, args[0].j);
|
||||
}
|
||||
} else if (object_class->GetName() ==
|
||||
"org/webrtc/voiceengine/WebRtcAudioRecord" &&
|
||||
std::strcmp(MethodName(methodID), "<init>") == 0 &&
|
||||
@@ -4853,6 +4944,7 @@ VM::~VM() {
|
||||
ClearRobloxCredentialProvider();
|
||||
ClearRobloxTextInputCallbacks();
|
||||
ClearAndroidWindowCallbacks();
|
||||
ClearWebRtcAudioManagerCallbacks();
|
||||
ClearWebRtcAudioTrackCallbacks();
|
||||
ClearWebRtcAudioRecordCallbacks();
|
||||
ClearFmodAudioDeviceCallbacks();
|
||||
@@ -5472,6 +5564,163 @@ void OnWebRtcAudioRecordData(void *context, const void *identity,
|
||||
|
||||
} // namespace
|
||||
|
||||
void VM::SetWebRtcAudioManagerCallbacks(
|
||||
std::shared_ptr<void> context,
|
||||
const WebRtcAudioManagerCallbacks& callbacks) {
|
||||
WebRtcAudioManagerBinding previous;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(webrtc_audio_manager_mutex_);
|
||||
previous = std::move(webrtc_audio_manager_binding_);
|
||||
webrtc_audio_manager_binding_ = {std::move(context), callbacks};
|
||||
}
|
||||
}
|
||||
|
||||
void VM::ClearWebRtcAudioManagerCallbacks() {
|
||||
WebRtcAudioManagerBinding previous;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(webrtc_audio_manager_mutex_);
|
||||
previous = std::move(webrtc_audio_manager_binding_);
|
||||
webrtc_audio_manager_binding_ = {};
|
||||
}
|
||||
}
|
||||
|
||||
void VM::RegisterWebRtcAudioManagerNative(const char* name,
|
||||
const char* signature,
|
||||
void* function) {
|
||||
if (name == nullptr || signature == nullptr || function == nullptr ||
|
||||
std::strcmp(name, "nativeCacheAudioParameters") != 0 ||
|
||||
std::strcmp(signature, "(IIIZZZZZZZIIJ)V") != 0) {
|
||||
return;
|
||||
}
|
||||
std::lock_guard<std::mutex> lock(webrtc_audio_manager_mutex_);
|
||||
webrtc_cache_audio_parameters_native_ = function;
|
||||
}
|
||||
|
||||
bool VM::DispatchWebRtcAudioManagerConstruct(jobject manager,
|
||||
jlong native_audio_manager) {
|
||||
const auto fail = [](const char* reason) {
|
||||
std::cerr << " [mocktail][audio] WebRTC audio manager parameters_failed "
|
||||
<< "reason=" << reason << '\n';
|
||||
return false;
|
||||
};
|
||||
if (ObjectClassName(manager) != "org/webrtc/voiceengine/WebRtcAudioManager") {
|
||||
return fail("invalid receiver");
|
||||
}
|
||||
SetLongFieldRaw(manager, "nativeAudioManager", native_audio_manager);
|
||||
SetBooleanFieldRaw(manager, "initialized", JNI_FALSE);
|
||||
SetBooleanFieldRaw(manager, "mocktailAudioParametersCached", JNI_FALSE);
|
||||
WebRtcAudioManagerBinding binding;
|
||||
void* native = nullptr;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(webrtc_audio_manager_mutex_);
|
||||
binding = webrtc_audio_manager_binding_;
|
||||
native = webrtc_cache_audio_parameters_native_;
|
||||
}
|
||||
if (native == nullptr || native_audio_manager == 0) {
|
||||
return fail("missing nativeCacheAudioParameters or native handle");
|
||||
}
|
||||
WebRtcAudioManagerParameters parameters;
|
||||
if (binding.context == nullptr ||
|
||||
binding.callbacks.get_parameters == nullptr ||
|
||||
!binding.callbacks.get_parameters(binding.context.get(), ¶meters)) {
|
||||
return fail("host audio manager unavailable");
|
||||
}
|
||||
if (parameters.sample_rate_hz <= 0 || parameters.output_channels < 1 ||
|
||||
parameters.output_channels > 2 || parameters.input_channels < 1 ||
|
||||
parameters.input_channels > 2 ||
|
||||
parameters.output_buffer_size_frames <= 0 ||
|
||||
parameters.input_buffer_size_frames <= 0) {
|
||||
return fail("invalid host PCM parameters");
|
||||
}
|
||||
SetIntFieldRaw(manager, "sampleRate", parameters.sample_rate_hz);
|
||||
SetIntFieldRaw(manager, "outputChannels", parameters.output_channels);
|
||||
SetIntFieldRaw(manager, "inputChannels", parameters.input_channels);
|
||||
SetIntFieldRaw(manager, "outputBufferSize",
|
||||
parameters.output_buffer_size_frames);
|
||||
SetIntFieldRaw(manager, "inputBufferSize",
|
||||
parameters.input_buffer_size_frames);
|
||||
SetBooleanFieldRaw(manager, "lowLatencyOutput",
|
||||
parameters.low_latency_output);
|
||||
SetBooleanFieldRaw(manager, "lowLatencyInput", parameters.low_latency_input);
|
||||
SetBooleanFieldRaw(manager, "proAudio", parameters.pro_audio);
|
||||
SetBooleanFieldRaw(manager, "aAudio", parameters.aaudio);
|
||||
|
||||
// Execute the constructor's Java -> native callback before returning the
|
||||
// object. The guest needs these formats even before it calls init(). No VM
|
||||
// locks are held here: the native callback may make nested JNI calls.
|
||||
using CacheAudioParameters = void(JNICALL*)(
|
||||
JNIEnv*, jobject, jint, jint, jint, jboolean, jboolean, jboolean,
|
||||
jboolean, jboolean, jboolean, jboolean, jint, jint, jlong);
|
||||
reinterpret_cast<CacheAudioParameters>(native)(
|
||||
GetJNIEnv(), manager, parameters.sample_rate_hz,
|
||||
parameters.output_channels, parameters.input_channels,
|
||||
parameters.hardware_aec, parameters.hardware_agc, parameters.hardware_ns,
|
||||
parameters.low_latency_output, parameters.low_latency_input,
|
||||
parameters.pro_audio, parameters.aaudio,
|
||||
parameters.output_buffer_size_frames, parameters.input_buffer_size_frames,
|
||||
native_audio_manager);
|
||||
SetBooleanFieldRaw(manager, "mocktailAudioParametersCached", JNI_TRUE);
|
||||
std::cout << " [mocktail][audio] WebRTC audio manager parameters "
|
||||
<< "sample_rate_hz=" << parameters.sample_rate_hz
|
||||
<< " output_channels=" << parameters.output_channels
|
||||
<< " input_channels=" << parameters.input_channels << '\n'
|
||||
<< std::flush;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VM::DispatchWebRtcAudioManagerInit(jobject manager) {
|
||||
WebRtcAudioManagerBinding binding;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(webrtc_audio_manager_mutex_);
|
||||
binding = webrtc_audio_manager_binding_;
|
||||
}
|
||||
const bool initialized =
|
||||
ObjectClassName(manager) == "org/webrtc/voiceengine/WebRtcAudioManager" &&
|
||||
BooleanFieldValue(manager, "mocktailAudioParametersCached") == JNI_TRUE &&
|
||||
binding.context != nullptr && binding.callbacks.init != nullptr &&
|
||||
(BooleanFieldValue(manager, "initialized") == JNI_TRUE ||
|
||||
binding.callbacks.init(binding.context.get(), manager));
|
||||
SetBooleanFieldRaw(manager, "initialized",
|
||||
initialized ? JNI_TRUE : JNI_FALSE);
|
||||
if (!initialized) {
|
||||
std::cerr << " [mocktail][audio] WebRTC audio manager init_failed "
|
||||
"reason=parameters or host manager unavailable\n";
|
||||
}
|
||||
return initialized;
|
||||
}
|
||||
|
||||
void VM::DispatchWebRtcAudioManagerDispose(jobject manager) {
|
||||
if (ObjectClassName(manager) != "org/webrtc/voiceengine/WebRtcAudioManager" ||
|
||||
BooleanFieldValue(manager, "initialized") != JNI_TRUE) {
|
||||
return;
|
||||
}
|
||||
SetBooleanFieldRaw(manager, "initialized", JNI_FALSE);
|
||||
WebRtcAudioManagerBinding binding;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(webrtc_audio_manager_mutex_);
|
||||
binding = webrtc_audio_manager_binding_;
|
||||
}
|
||||
if (binding.context != nullptr && binding.callbacks.dispose != nullptr) {
|
||||
binding.callbacks.dispose(binding.context.get(), manager);
|
||||
}
|
||||
}
|
||||
|
||||
void VM::DispatchWebRtcAudioManagerMicrophoneMute(jobject manager, bool muted) {
|
||||
if (ObjectClassName(manager) != "org/webrtc/voiceengine/WebRtcAudioManager" ||
|
||||
BooleanFieldValue(manager, "mocktailAudioParametersCached") != JNI_TRUE) {
|
||||
return;
|
||||
}
|
||||
WebRtcAudioManagerBinding binding;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(webrtc_audio_manager_mutex_);
|
||||
binding = webrtc_audio_manager_binding_;
|
||||
}
|
||||
if (binding.context != nullptr &&
|
||||
binding.callbacks.set_microphone_mute != nullptr) {
|
||||
binding.callbacks.set_microphone_mute(binding.context.get(), muted);
|
||||
}
|
||||
}
|
||||
|
||||
void VM::SetWebRtcAudioRecordCallbacks(
|
||||
std::shared_ptr<void> context,
|
||||
const WebRtcAudioRecordCallbacks &callbacks) {
|
||||
@@ -6232,6 +6481,14 @@ void VM::InitJNIFunctionTables() {
|
||||
} else if (std::strcmp(name, "onTrimMemoryNative") == 0) {
|
||||
mocktail_gameactivity_on_trim_memory_native = methods[i].fnPtr;
|
||||
}
|
||||
if (cls != nullptr &&
|
||||
cls->GetName() ==
|
||||
"org/webrtc/voiceengine/WebRtcAudioManager") {
|
||||
if (VM* vm = CurrentVM()) {
|
||||
vm->RegisterWebRtcAudioManagerNative(
|
||||
methods[i].name, methods[i].signature, methods[i].fnPtr);
|
||||
}
|
||||
}
|
||||
if (cls != nullptr &&
|
||||
cls->GetName() ==
|
||||
"org/webrtc/voiceengine/WebRtcAudioRecord") {
|
||||
@@ -6578,6 +6835,7 @@ void VM::InitJNIFunctionTables() {
|
||||
std::cout << " [JNI] CallVoidMethodV: " << MethodName(methodID) << '\n';
|
||||
}
|
||||
if (!HandleRobloxExperienceLifecycleVoidMethod(obj, methodID) &&
|
||||
!HandleWebRtcAudioManagerVoidMethodV(obj, methodID, args) &&
|
||||
!HandleRobloxOpenWebActivityMethodV(obj, methodID, args) &&
|
||||
!HandleRobloxTextInputInstanceVoidMethodV(obj, methodID, args) &&
|
||||
!HandleFmodAudioDeviceVoidMethodV(obj, methodID, args) &&
|
||||
@@ -6594,6 +6852,7 @@ void VM::InitJNIFunctionTables() {
|
||||
std::cout << " [JNI] CallVoidMethodA: " << MethodName(methodID) << '\n';
|
||||
}
|
||||
if (!HandleRobloxExperienceLifecycleVoidMethod(obj, methodID) &&
|
||||
!HandleWebRtcAudioManagerVoidMethodA(obj, methodID, args) &&
|
||||
!HandleRobloxOpenWebActivityMethodA(obj, methodID, args) &&
|
||||
!HandleRobloxTextInputInstanceVoidMethodA(obj, methodID, args) &&
|
||||
!HandleFmodAudioDeviceVoidMethodA(obj, methodID, args) &&
|
||||
@@ -6669,6 +6928,9 @@ void VM::InitJNIFunctionTables() {
|
||||
std::cout << " [JNI] CallBooleanMethodV: " << MethodName(methodID) << '\n';
|
||||
}
|
||||
jboolean result = JNI_FALSE;
|
||||
if (HandleWebRtcAudioManagerBooleanMethod(obj, methodID, &result)) {
|
||||
return result;
|
||||
}
|
||||
if (HandleWebRtcAudioRecordBooleanMethodV(obj, methodID, args, &result)) {
|
||||
return result;
|
||||
}
|
||||
@@ -6698,6 +6960,9 @@ void VM::InitJNIFunctionTables() {
|
||||
std::cout << " [JNI] CallBooleanMethodA: " << MethodName(methodID) << '\n';
|
||||
}
|
||||
jboolean result = JNI_FALSE;
|
||||
if (HandleWebRtcAudioManagerBooleanMethod(obj, methodID, &result)) {
|
||||
return result;
|
||||
}
|
||||
if (HandleWebRtcAudioRecordBooleanMethodA(obj, methodID, args, &result)) {
|
||||
return result;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user