* Copyright (c) 2024 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "audio_manager_jni.h"
#include <jni.h>
#include "audio_common_jni.h"
#include "audio_convert_util.h"
#include "audio_errors.h"
#include "inner_api/plugin_utils_inner.h"
#include "log.h"
#include "plugin_utils.h"
using namespace OHOS::AudioStandard;
namespace OHOS::Plugin {
namespace {
const char CLASS_NAME[] = "ohos/ace/plugin/audiomanager/AudioManagerPlugin";
static const JNINativeMethod METHODS[] = {
{ "nativeInit", "()V", reinterpret_cast<void*>(AudioManagerJni::NativeInit) },
{ "nativeOnAudioDeviceChanged", "(Z[Landroid/media/AudioDeviceInfo;)V",
reinterpret_cast<void*>(AudioManagerJni::NativeOnAudioDeviceChanged) },
{ "nativeOnAudioRendererChanged", "(Ljava/util/List;)V",
reinterpret_cast<void*>(AudioManagerJni::NativeOnAudioRendererChanged) },
{ "nativeOnAudioCapturerChanged", "(Ljava/util/List;)V",
reinterpret_cast<void *>(AudioManagerJni::NativeOnAudioCapturerChanged) }
};
struct {
jmethodID getVolume;
jmethodID getMaxVolume;
jmethodID getMinVolume;
jmethodID isStreamMute;
jmethodID getRingerMode;
jmethodID isMicrophoneMute;
jmethodID isVolumeFixed;
jmethodID getSystemVolumeInDb;
jmethodID getAudioScene;
jmethodID getDevices;
jmethodID registerAudioDeviceCallback;
jmethodID unregisterAudioDeviceCallback;
jmethodID getCurrentAudioRendererInfoArray;
jmethodID getCurrentAudioCapturerInfoArray;
jmethodID registerAudioRendererEventListener;
jmethodID unregisterAudioRendererEventListener;
jmethodID registerAudioCapturerEventListener;
jmethodID unregisterAudioCapturerEventListener;
jmethodID setCommunicationDevice;
jmethodID isCommunicationDeviceActive;
jmethodID setDeviceActive;
jmethodID isDeviceActive;
jobject globalRef;
} g_audioManagerPluginClass;
}
bool AudioManagerJni::hasInit_ = false;
std::shared_ptr<AudioCapturerStateChangeCallback> AudioManagerJni::audioCapturerEventCallback_;
std::shared_ptr<AudioRendererStateChangeCallback> AudioManagerJni::audioRendererEventCallback_;
std::map<DeviceFlag, std::shared_ptr<AudioManagerDeviceChangeCallback>> AudioManagerJni::deviceChangeCallbacks_;
bool AudioManagerJni::Register(void* env)
{
LOGI("AudioManagerJni::Register");
if (hasInit_) {
return hasInit_;
}
auto* jniEnv = static_cast<JNIEnv*>(env);
CHECK_NULL_RETURN(jniEnv, false);
jclass cls = jniEnv->FindClass(CLASS_NAME);
CHECK_NULL_RETURN(cls, false);
bool ret = jniEnv->RegisterNatives(cls, METHODS, sizeof(METHODS) / sizeof(METHODS[0])) == 0;
jniEnv->DeleteLocalRef(cls);
if (!ret) {
LOGE("AudioManagerJni JNI: RegisterNatives fail.");
return false;
}
return true;
}
void AudioManagerJni::NativeInit(JNIEnv* env, jobject jobj)
{
LOGI("AudioManagerJni::NativeInit");
CHECK_NULL_VOID(env);
g_audioManagerPluginClass.globalRef = env->NewGlobalRef(jobj);
CHECK_NULL_VOID(g_audioManagerPluginClass.globalRef);
jclass cls = env->GetObjectClass(jobj);
CHECK_NULL_VOID(cls);
g_audioManagerPluginClass.getVolume = env->GetMethodID(cls, "getVolume", "(I)I");
CHECK_NULL_VOID(g_audioManagerPluginClass.getVolume);
g_audioManagerPluginClass.getMaxVolume = env->GetMethodID(cls, "getMaxVolume", "(I)I");
CHECK_NULL_VOID(g_audioManagerPluginClass.getMaxVolume);
g_audioManagerPluginClass.getMinVolume = env->GetMethodID(cls, "getMinVolume", "(I)I");
CHECK_NULL_VOID(g_audioManagerPluginClass.getMinVolume);
g_audioManagerPluginClass.isStreamMute = env->GetMethodID(cls, "isStreamMute", "(I)Z");
CHECK_NULL_VOID(g_audioManagerPluginClass.isStreamMute);
g_audioManagerPluginClass.getRingerMode = env->GetMethodID(cls, "getRingerMode", "()I");
CHECK_NULL_VOID(g_audioManagerPluginClass.getRingerMode);
g_audioManagerPluginClass.isMicrophoneMute = env->GetMethodID(cls, "isMicrophoneMute", "()Z");
CHECK_NULL_VOID(g_audioManagerPluginClass.isMicrophoneMute);
g_audioManagerPluginClass.isVolumeFixed = env->GetMethodID(cls, "isVolumeFixed", "()Z");
CHECK_NULL_VOID(g_audioManagerPluginClass.isVolumeFixed);
g_audioManagerPluginClass.getSystemVolumeInDb = env->GetMethodID(cls, "getSystemVolumeInDb", "(III)F");
CHECK_NULL_VOID(g_audioManagerPluginClass.getSystemVolumeInDb);
g_audioManagerPluginClass.getAudioScene = env->GetMethodID(cls, "getAudioScene", "()I");
CHECK_NULL_VOID(g_audioManagerPluginClass.getAudioScene);
g_audioManagerPluginClass.getDevices = env->GetMethodID(cls, "getDevices", "(I)[Landroid/media/AudioDeviceInfo;");
CHECK_NULL_VOID(g_audioManagerPluginClass.getDevices);
g_audioManagerPluginClass.registerAudioDeviceCallback = env->GetMethodID(cls, "registerAudioDeviceCallback", "()V");
CHECK_NULL_VOID(g_audioManagerPluginClass.registerAudioDeviceCallback);
g_audioManagerPluginClass.unregisterAudioDeviceCallback =
env->GetMethodID(cls, "unregisterAudioDeviceCallback", "()V");
CHECK_NULL_VOID(g_audioManagerPluginClass.unregisterAudioDeviceCallback);
g_audioManagerPluginClass.getCurrentAudioRendererInfoArray =
env->GetMethodID(cls, "getCurrentAudioRendererInfoArray", "()Ljava/util/List;");
CHECK_NULL_VOID(g_audioManagerPluginClass.getCurrentAudioRendererInfoArray);
g_audioManagerPluginClass.getCurrentAudioCapturerInfoArray =
env->GetMethodID(cls, "getCurrentAudioCapturerInfoArray", "()Ljava/util/List;");
CHECK_NULL_VOID(g_audioManagerPluginClass.getCurrentAudioCapturerInfoArray);
g_audioManagerPluginClass.registerAudioRendererEventListener =
env->GetMethodID(cls, "registerAudioRendererEventListener", "()V");
CHECK_NULL_VOID(g_audioManagerPluginClass.registerAudioRendererEventListener);
g_audioManagerPluginClass.unregisterAudioRendererEventListener =
env->GetMethodID(cls, "unregisterAudioRendererEventListener", "()V");
CHECK_NULL_VOID(g_audioManagerPluginClass.unregisterAudioRendererEventListener);
g_audioManagerPluginClass.registerAudioCapturerEventListener =
env->GetMethodID(cls, "registerAudioCapturerEventListener", "()V");
CHECK_NULL_VOID(g_audioManagerPluginClass.registerAudioCapturerEventListener);
g_audioManagerPluginClass.unregisterAudioCapturerEventListener =
env->GetMethodID(cls, "unregisterAudioCapturerEventListener", "()V");
CHECK_NULL_VOID(g_audioManagerPluginClass.unregisterAudioCapturerEventListener);
g_audioManagerPluginClass.setDeviceActive = env->GetMethodID(cls, "setDeviceActive", "(IZ)Z");
CHECK_NULL_VOID(g_audioManagerPluginClass.setDeviceActive);
g_audioManagerPluginClass.isDeviceActive = env->GetMethodID(cls, "isDeviceActive", "(I)Z");
CHECK_NULL_VOID(g_audioManagerPluginClass.isDeviceActive);
env->DeleteLocalRef(cls);
hasInit_ = true;
}
void AudioManagerJni::NativeOnAudioDeviceChanged(
JNIEnv* env, jobject jobj, jboolean jIsAdded, jobjectArray jDeviceInfos)
{
LOGD("AudioRendererJni::NativeOnAudioDeviceChanged, jIsAdded:%{public}d", jIsAdded);
for (const auto& it : deviceChangeCallbacks_) {
DeviceChangeAction deviceChangeInfo;
int32_t deviceCount = env->GetArrayLength(jDeviceInfos);
for (int32_t i = 0; i < deviceCount; i++) {
jobject jDeviceInfo = env->GetObjectArrayElement(jDeviceInfos, i);
AudioDeviceDescriptor deviceInfo = AudioCommonJni::GetDeviceInfo(jDeviceInfo);
env->DeleteLocalRef(jDeviceInfo);
DeviceFlag flag = (deviceInfo.deviceRole_ == INPUT_DEVICE) ? INPUT_DEVICES_FLAG : OUTPUT_DEVICES_FLAG;
if ((flag != it.first) && (it.first != ALL_DEVICES_FLAG)) {
continue;
}
std::shared_ptr<AudioDeviceDescriptor> audioDeviceDescriptor = std::make_shared<AudioDeviceDescriptor>();
CHECK_NULL_VOID(audioDeviceDescriptor);
ConvertDeviceInfoToAudioDeviceDescriptor(audioDeviceDescriptor, deviceInfo);
deviceChangeInfo.deviceDescriptors.push_back(std::move(audioDeviceDescriptor));
}
if (deviceChangeInfo.deviceDescriptors.size() > 0) {
deviceChangeInfo.flag = it.first;
deviceChangeInfo.type = jIsAdded ? CONNECT : DISCONNECT;
it.second->OnDeviceChange(deviceChangeInfo);
}
}
}
void AudioManagerJni::NativeOnAudioRendererChanged(JNIEnv* env, jobject jobj, jobject jRendererConf)
{
auto infos = GetAudioRendererChangeInfo(jRendererConf);
if (audioRendererEventCallback_) {
audioRendererEventCallback_->OnRendererStateChange(infos);
}
}
int32_t AudioManagerJni::GetVolume(AudioVolumeType volumeType)
{
auto env = ARKUI_X_Plugin_GetJniEnv();
CHECK_NULL_RETURN(env, ERROR);
CHECK_NULL_RETURN(g_audioManagerPluginClass.globalRef, ERROR);
CHECK_NULL_RETURN(g_audioManagerPluginClass.getVolume, ERROR);
StreamType type = ConvertVolumeTypeToAn(volumeType);
if (type == STREAM_INVALID) {
LOGE("AudioManagerJni GetVolume: invalid stream type.");
return ERR_INVALID_PARAM;
}
LOGD("AudioManagerJni GetVolume streamType:%{public}d", type);
jint result = env->CallIntMethod(g_audioManagerPluginClass.globalRef, g_audioManagerPluginClass.getVolume, type);
if (env->ExceptionCheck()) {
LOGE("AudioManagerJni JNI: call getVolume has exception");
env->ExceptionDescribe();
env->ExceptionClear();
return ERROR;
}
LOGD("AudioManagerJni::GetVolume Volume:%{public}d", result);
return result;
}
int32_t AudioManagerJni::GetMaxVolume(AudioVolumeType volumeType)
{
auto env = ARKUI_X_Plugin_GetJniEnv();
CHECK_NULL_RETURN(env, ERROR);
CHECK_NULL_RETURN(g_audioManagerPluginClass.globalRef, ERROR);
CHECK_NULL_RETURN(g_audioManagerPluginClass.getMaxVolume, ERROR);
StreamType type = ConvertVolumeTypeToAn(volumeType);
if (type == STREAM_INVALID) {
LOGE("AudioManagerJni GetMaxVolume: invalid stream type.");
return ERR_INVALID_PARAM;
}
LOGD("AudioManagerJni GetMaxVolume streamType:%{public}d", type);
jint result = env->CallIntMethod(g_audioManagerPluginClass.globalRef, g_audioManagerPluginClass.getMaxVolume, type);
if (env->ExceptionCheck()) {
LOGE("AudioManagerJni JNI: call getMaxVolume has exception");
env->ExceptionDescribe();
env->ExceptionClear();
return ERROR;
}
LOGD("AudioManagerJni::GetMaxVolume Volume:%{public}d", result);
return result;
}
int32_t AudioManagerJni::GetMinVolume(AudioVolumeType volumeType)
{
auto env = ARKUI_X_Plugin_GetJniEnv();
CHECK_NULL_RETURN(env, ERROR);
CHECK_NULL_RETURN(g_audioManagerPluginClass.globalRef, ERROR);
CHECK_NULL_RETURN(g_audioManagerPluginClass.getMinVolume, ERROR);
StreamType type = ConvertVolumeTypeToAn(volumeType);
if (type == STREAM_INVALID) {
LOGE("AudioManagerJni GetMinVolume: invalid stream type.");
return ERR_INVALID_PARAM;
}
LOGD("AudioManagerJni GetMinVolume streamType:%{public}d", type);
jint result = env->CallIntMethod(g_audioManagerPluginClass.globalRef, g_audioManagerPluginClass.getMinVolume, type);
if (env->ExceptionCheck()) {
LOGE("AudioManagerJni JNI: call getMinVolume has exception");
env->ExceptionDescribe();
env->ExceptionClear();
return ERROR;
}
if (result < 0) {
return ERROR;
}
LOGD("AudioManagerJni::GetMinVolume Volume:%{public}d", result);
return result;
}
int32_t AudioManagerJni::IsStreamMute(AudioVolumeType volumeType, bool& isMute)
{
auto env = ARKUI_X_Plugin_GetJniEnv();
CHECK_NULL_RETURN(env, ERROR);
CHECK_NULL_RETURN(g_audioManagerPluginClass.globalRef, ERROR);
CHECK_NULL_RETURN(g_audioManagerPluginClass.isStreamMute, ERROR);
StreamType type = ConvertVolumeTypeToAn(volumeType);
if (type == STREAM_INVALID) {
LOGE("AudioManagerJni IsStreamMute: invalid stream type.");
return ERR_INVALID_PARAM;
}
LOGD("AudioManagerJni IsStreamMute streamType:%{public}d", type);
jboolean result =
env->CallBooleanMethod(g_audioManagerPluginClass.globalRef, g_audioManagerPluginClass.isStreamMute, type);
if (env->ExceptionCheck()) {
LOGE("AudioManagerJni JNI: call isStreamMute has exception");
env->ExceptionDescribe();
env->ExceptionClear();
return ERROR;
}
LOGD("AudioManagerJni IsStreamMute result:%{public}d", result);
isMute = result;
return SUCCESS;
}
AudioRingerMode AudioManagerJni::GetRingerMode()
{
auto env = ARKUI_X_Plugin_GetJniEnv();
CHECK_NULL_RETURN(env, AudioRingerMode::RINGER_MODE_NORMAL);
CHECK_NULL_RETURN(g_audioManagerPluginClass.globalRef, AudioRingerMode::RINGER_MODE_NORMAL);
CHECK_NULL_RETURN(g_audioManagerPluginClass.getRingerMode, AudioRingerMode::RINGER_MODE_NORMAL);
jint result = env->CallIntMethod(g_audioManagerPluginClass.globalRef, g_audioManagerPluginClass.getRingerMode);
if (env->ExceptionCheck()) {
LOGE("AudioManagerJni JNI: call getRingerMode has exception");
env->ExceptionDescribe();
env->ExceptionClear();
return AudioRingerMode::RINGER_MODE_NORMAL;
}
AudioRingerMode mode = ConvertRingerModeToOh(static_cast<RingerMode>(result));
return mode;
}
bool AudioManagerJni::IsMicrophoneMute()
{
auto env = ARKUI_X_Plugin_GetJniEnv();
CHECK_NULL_RETURN(env, false);
CHECK_NULL_RETURN(g_audioManagerPluginClass.globalRef, false);
CHECK_NULL_RETURN(g_audioManagerPluginClass.isMicrophoneMute, false);
jboolean result =
env->CallBooleanMethod(g_audioManagerPluginClass.globalRef, g_audioManagerPluginClass.isMicrophoneMute);
if (env->ExceptionCheck()) {
LOGE("AudioManagerJni JNI: call isMicrophoneMute has exception");
env->ExceptionDescribe();
env->ExceptionClear();
return false;
}
return result;
}
bool AudioManagerJni::IsVolumeFixed()
{
auto env = ARKUI_X_Plugin_GetJniEnv();
CHECK_NULL_RETURN(env, false);
CHECK_NULL_RETURN(g_audioManagerPluginClass.globalRef, false);
CHECK_NULL_RETURN(g_audioManagerPluginClass.isVolumeFixed, false);
jboolean result =
env->CallBooleanMethod(g_audioManagerPluginClass.globalRef, g_audioManagerPluginClass.isVolumeFixed);
if (env->ExceptionCheck()) {
LOGE("AudioManagerJni JNI: call isVolumeFixed has exception");
env->ExceptionDescribe();
env->ExceptionClear();
return false;
}
LOGD("AudioManagerJni::IsVolumeFixed result:%{public}d", result);
return result;
}
float AudioManagerJni::GetSystemVolumeInDb(AudioVolumeType volumeType, int32_t volumeLevel, DeviceType deviceType)
{
LOGD("AudioManagerJni::GetSystemVolumeInDb, volumeType:%{public}d, volumeLevel:%{public}d, deviceType:%{public}d",
volumeType, volumeLevel, deviceType);
auto env = ARKUI_X_Plugin_GetJniEnv();
CHECK_NULL_RETURN(env, 0.0f);
CHECK_NULL_RETURN(g_audioManagerPluginClass.globalRef, 0.0f);
CHECK_NULL_RETURN(g_audioManagerPluginClass.getSystemVolumeInDb, 0.0f);
StreamType streamType = ConvertVolumeTypeToAn(volumeType);
if (streamType == STREAM_INVALID) {
LOGE("AudioManagerJni GetSystemVolumeInDb: invalid stream type.");
return 0.0f;
}
AudioDeviceType deviceTypeAn = ConvertDeviceTypeToAn(deviceType);
LOGD("AudioManagerJni GetMinVolume after convert:streamType:%{public}d, deviceType:%{public}d", streamType,
deviceTypeAn);
jfloat result = env->CallFloatMethod(g_audioManagerPluginClass.globalRef,
g_audioManagerPluginClass.getSystemVolumeInDb, streamType, volumeLevel, deviceTypeAn);
if (env->ExceptionCheck()) {
LOGE("AudioManagerJni JNI: call getSystemVolumeInDb has exception");
env->ExceptionDescribe();
env->ExceptionClear();
return 0.0f;
}
LOGD("AudioManagerJni GetSystemVolumeInDb result:%{public}f", result);
return result;
}
AudioScene AudioManagerJni::GetAudioScene()
{
auto env = ARKUI_X_Plugin_GetJniEnv();
CHECK_NULL_RETURN(env, AUDIO_SCENE_INVALID);
CHECK_NULL_RETURN(g_audioManagerPluginClass.globalRef, AUDIO_SCENE_INVALID);
CHECK_NULL_RETURN(g_audioManagerPluginClass.getAudioScene, AUDIO_SCENE_INVALID);
jint result = env->CallIntMethod(g_audioManagerPluginClass.globalRef, g_audioManagerPluginClass.getAudioScene);
if (env->ExceptionCheck()) {
LOGE("AudioManagerJni JNI: call GetAudioScene has exception");
env->ExceptionDescribe();
env->ExceptionClear();
return AUDIO_SCENE_INVALID;
}
AudioScene scene = ConvertSceneToOh(static_cast<AudioMode>(result));
LOGD("AudioManagerJni::GetAudioScene before convert scene:%{public}d, after convert scene:%{public}d",
static_cast<AudioScene>(result), scene);
return scene;
}
int32_t AudioManagerJni::GetDevices(DeviceFlag deviceFlag, std::vector<std::shared_ptr<AudioDeviceDescriptor>>& desc)
{
auto env = ARKUI_X_Plugin_GetJniEnv();
CHECK_NULL_RETURN(env, ERROR);
CHECK_NULL_RETURN(g_audioManagerPluginClass.globalRef, ERROR);
CHECK_NULL_RETURN(g_audioManagerPluginClass.getDevices, ERROR);
AudioDeviceFlags flag = ConvertDeviceFlagToAn(deviceFlag);
if (flag == GET_DEVICES_INVALID) {
LOGE("AudioManagerJni JNI: invalid device flag.");
return ERR_INVALID_PARAM;
}
jobject jDevices =
env->CallObjectMethod(g_audioManagerPluginClass.globalRef, g_audioManagerPluginClass.getDevices, flag);
if (env->ExceptionCheck() || !jDevices) {
LOGE("AudioManagerJni JNI: call getDevices has exception");
env->ExceptionDescribe();
env->ExceptionClear();
return ERROR;
}
int32_t deviceCount = env->GetArrayLength(static_cast<jobjectArray>(jDevices));
for (int32_t i = 0; i < deviceCount; i++) {
jobject jDeviceInfo = env->GetObjectArrayElement(static_cast<jobjectArray>(jDevices), i);
AudioDeviceDescriptor deviceInfo = AudioCommonJni::GetDeviceInfo(jDeviceInfo);
env->DeleteLocalRef(jDeviceInfo);
std::shared_ptr<AudioDeviceDescriptor> audioDeviceDescriptor = std::make_shared<AudioDeviceDescriptor>();
if (!audioDeviceDescriptor) {
env->DeleteLocalRef(jDevices);
LOGE("AudioManagerJni JNI: create AudioDeviceDescriptor failed.");
return ERROR;
}
ConvertDeviceInfoToAudioDeviceDescriptor(audioDeviceDescriptor, deviceInfo);
desc.push_back(std::move(audioDeviceDescriptor));
}
env->DeleteLocalRef(jDevices);
return SUCCESS;
}
void AudioManagerJni::ConvertDeviceInfoToAudioDeviceDescriptor(
std::shared_ptr<AudioDeviceDescriptor> audioDeviceDescriptor, const AudioDeviceDescriptor& deviceInfo)
{
CHECK_NULL_VOID(audioDeviceDescriptor);
audioDeviceDescriptor->deviceRole_ = deviceInfo.deviceRole_;
audioDeviceDescriptor->deviceType_ = deviceInfo.deviceType_;
audioDeviceDescriptor->deviceId_ = deviceInfo.deviceId_;
audioDeviceDescriptor->channelMasks_ = deviceInfo.channelMasks_;
audioDeviceDescriptor->channelIndexMasks_ = deviceInfo.channelIndexMasks_;
audioDeviceDescriptor->deviceName_ = deviceInfo.deviceName_;
audioDeviceDescriptor->macAddress_ = deviceInfo.macAddress_;
audioDeviceDescriptor->interruptGroupId_ = deviceInfo.interruptGroupId_;
audioDeviceDescriptor->volumeGroupId_ = deviceInfo.volumeGroupId_;
audioDeviceDescriptor->networkId_ = deviceInfo.networkId_;
audioDeviceDescriptor->displayName_ = deviceInfo.displayName_;
audioDeviceDescriptor->audioStreamInfo_ = deviceInfo.audioStreamInfo_;
}
int32_t AudioManagerJni::AddDeviceChangeCallback(
const DeviceFlag flag, const std::shared_ptr<AudioManagerDeviceChangeCallback>& callback)
{
LOGD("AudioManagerJni AddDeviceChangeCallback: flag:%{public}d", flag);
AudioDeviceFlags deviceflag = ConvertDeviceFlagToAn(flag);
if (deviceflag == GET_DEVICES_INVALID) {
LOGE("AudioManagerJni JNI: invalid device flag.");
return ERR_INVALID_PARAM;
}
deviceChangeCallbacks_[flag] = callback;
return RegisterAudioDeviceCallback();
}
int32_t AudioManagerJni::RemoveDeviceChangeCallback()
{
deviceChangeCallbacks_.clear();
return UnregisterAudioDeviceCallback();
}
int32_t AudioManagerJni::RegisterAudioDeviceCallback()
{
auto env = ARKUI_X_Plugin_GetJniEnv();
CHECK_NULL_RETURN(env, ERROR);
CHECK_NULL_RETURN(g_audioManagerPluginClass.globalRef, ERROR);
CHECK_NULL_RETURN(g_audioManagerPluginClass.registerAudioDeviceCallback, ERROR);
env->CallVoidMethod(g_audioManagerPluginClass.globalRef, g_audioManagerPluginClass.registerAudioDeviceCallback);
if (env->ExceptionCheck()) {
LOGE("AudioManagerJni JNI: call registerAudioDeviceCallback has exception");
env->ExceptionDescribe();
env->ExceptionClear();
return ERROR;
}
return SUCCESS;
}
int32_t AudioManagerJni::UnregisterAudioDeviceCallback()
{
auto env = ARKUI_X_Plugin_GetJniEnv();
CHECK_NULL_RETURN(env, ERROR);
CHECK_NULL_RETURN(g_audioManagerPluginClass.globalRef, ERROR);
CHECK_NULL_RETURN(g_audioManagerPluginClass.unregisterAudioDeviceCallback, ERROR);
env->CallVoidMethod(g_audioManagerPluginClass.globalRef, g_audioManagerPluginClass.unregisterAudioDeviceCallback);
if (env->ExceptionCheck()) {
LOGE("AudioManagerJni JNI: call unregisterAudioDeviceCallback has exception");
env->ExceptionDescribe();
env->ExceptionClear();
return ERROR;
}
return SUCCESS;
}
void AudioManagerJni::NativeOnAudioCapturerChanged(JNIEnv* env, jobject jobj, jobject jCapturerConf)
{
auto infos = GetAudioCapturerChangeInfo(jCapturerConf);
if (audioCapturerEventCallback_) {
audioCapturerEventCallback_->OnCapturerStateChange(infos);
}
}
std::vector<std::shared_ptr<AudioRendererChangeInfo>> AudioManagerJni::GetAudioRendererChangeInfo(jobject jRendererConf)
{
std::vector<std::shared_ptr<AudioRendererChangeInfo>> infos;
auto env = ARKUI_X_Plugin_GetJniEnv();
CHECK_NULL_RETURN(env, infos);
jclass jListPlaybackConfigurationCls = env->FindClass("java/util/List");
jclass jAudioPlayCfgCls = env->FindClass("android/media/AudioPlaybackConfiguration");
jclass jAttributeCls = env->FindClass("android/media/AudioAttributes");
jmethodID jUsageId = env->GetMethodID(jAttributeCls, "getUsage", "()I");
jmethodID jContentTypeId = env->GetMethodID(jAttributeCls, "getContentType", "()I");
jmethodID sizeMethod = env->GetMethodID(jListPlaybackConfigurationCls, "size", "()I");
jmethodID getMethod = env->GetMethodID(jListPlaybackConfigurationCls, "get", "(I)Ljava/lang/Object;");
jmethodID jAudioID = env->GetMethodID(jAudioPlayCfgCls, "getAudioAttributes", "()Landroid/media/AudioAttributes;");
jmethodID jDevID = env->GetMethodID(jAudioPlayCfgCls, "getAudioDeviceInfo", "()Landroid/media/AudioDeviceInfo;");
if (!jUsageId || !jContentTypeId || !sizeMethod || !getMethod) {
LOGE("The Android version does not support this interface, please use at least Android 12");
return infos;
}
jint size = env->CallIntMethod(jRendererConf, sizeMethod);
env->DeleteLocalRef(jListPlaybackConfigurationCls);
env->DeleteLocalRef(jAudioPlayCfgCls);
env->DeleteLocalRef(jAttributeCls);
for (int i = 0; i < size; i++) {
jobject objRenderer = env->CallObjectMethod(jRendererConf, getMethod, i);
if (objRenderer) {
jobject jAttribute = env->CallObjectMethod(objRenderer, jAudioID);
if (!jAttribute) {
env->DeleteLocalRef(objRenderer);
continue;
}
jint jContentType = env->CallIntMethod(jAttribute, jContentTypeId);
jint jUsage = env->CallIntMethod(jAttribute, jUsageId);
env->DeleteLocalRef(jAttribute);
jobject jDeviceInfo = env->CallObjectMethod(objRenderer, jDevID);
if (!jDeviceInfo) {
env->DeleteLocalRef(objRenderer);
continue;
}
std::shared_ptr<AudioRendererChangeInfo> rendererChangeInfo = std::make_shared<AudioRendererChangeInfo>();
ConvertAudioUsageToOh(static_cast<AudioAttributesUsage>(jUsage),
static_cast<AudioAttributesContenType>(jContentType), rendererChangeInfo->rendererInfo.streamUsage,
rendererChangeInfo->rendererInfo.contentType);
rendererChangeInfo->outputDeviceInfo = AudioCommonJni::GetDeviceInfo(jDeviceInfo);
infos.push_back(std::move(rendererChangeInfo));
rendererChangeInfo = nullptr;
env->DeleteLocalRef(jDeviceInfo);
env->DeleteLocalRef(objRenderer);
}
}
return infos;
}
std::vector<std::shared_ptr<AudioCapturerChangeInfo>> AudioManagerJni::GetAudioCapturerChangeInfo(jobject jCapturerConf)
{
std::vector<std::shared_ptr<AudioCapturerChangeInfo>> infos;
auto env = ARKUI_X_Plugin_GetJniEnv();
CHECK_NULL_RETURN(env, infos);
jclass jListRecordingConfigurationCls = env->FindClass("java/util/List");
jclass jAudioRecordingConfigurationCls = env->FindClass("android/media/AudioRecordingConfiguration");
jmethodID sizeMethod = env->GetMethodID(jListRecordingConfigurationCls, "size", "()I");
jmethodID getMethod = env->GetMethodID(jListRecordingConfigurationCls, "get", "(I)Ljava/lang/Object;");
jmethodID jSessionIdID = env->GetMethodID(jAudioRecordingConfigurationCls, "getClientAudioSessionId", "()I");
jmethodID jSourceTypeID = env->GetMethodID(jAudioRecordingConfigurationCls, "getClientAudioSource", "()I");
jmethodID jDeviceInfoID =
env->GetMethodID(jAudioRecordingConfigurationCls, "getAudioDevice", "()Landroid/media/AudioDeviceInfo;");
jmethodID jMutedID = env->GetMethodID(jAudioRecordingConfigurationCls, "isClientSilenced", "()Z");
if (!jSessionIdID || !jSourceTypeID || !jDeviceInfoID || !jMutedID || !sizeMethod || !getMethod) {
LOGE("The Android version does not support this interface, please use at least Android 12");
return infos;
}
jint size = env->CallIntMethod(jCapturerConf, sizeMethod);
env->DeleteLocalRef(jListRecordingConfigurationCls);
env->DeleteLocalRef(jAudioRecordingConfigurationCls);
for (int i = 0; i < size; i++) {
jobject objCapturer = env->CallObjectMethod(jCapturerConf, getMethod, i);
if (!objCapturer) {
continue;
}
jint jSessionId = env->CallIntMethod(objCapturer, jSessionIdID);
jint jSourceType = env->CallIntMethod(objCapturer, jSourceTypeID);
jobject jDeviceInfo = env->CallObjectMethod(objCapturer, jDeviceInfoID);
jboolean jMuted = env->CallBooleanMethod(objCapturer, jMutedID);
if (!jDeviceInfo) {
env->DeleteLocalRef(objCapturer);
continue;
}
std::shared_ptr<AudioCapturerChangeInfo> capturerChangeInfo = std::make_shared<AudioCapturerChangeInfo>();
capturerChangeInfo->sessionId = static_cast<int32_t>(jSessionId);
capturerChangeInfo->capturerInfo.sourceType = ConvertSourceTypeToOh(static_cast<AudioSourceType>(jSourceType));
capturerChangeInfo->capturerInfo.capturerFlags = 0;
capturerChangeInfo->inputDeviceInfo = AudioCommonJni::GetDeviceInfo(jDeviceInfo);
capturerChangeInfo->muted = jMuted;
infos.push_back(std::move(capturerChangeInfo));
capturerChangeInfo = nullptr;
env->DeleteLocalRef(jDeviceInfo);
env->DeleteLocalRef(objCapturer);
}
return infos;
}
int32_t AudioManagerJni::RegisterAudioRendererEventListener(
const std::shared_ptr<AudioRendererStateChangeCallback>& callback)
{
audioRendererEventCallback_ = callback;
auto env = ARKUI_X_Plugin_GetJniEnv();
CHECK_NULL_RETURN(env, ERROR);
CHECK_NULL_RETURN(g_audioManagerPluginClass.globalRef, ERROR);
CHECK_NULL_RETURN(g_audioManagerPluginClass.registerAudioRendererEventListener, ERROR);
jint result = env->CallIntMethod(
g_audioManagerPluginClass.globalRef, g_audioManagerPluginClass.registerAudioRendererEventListener);
if (env->ExceptionCheck()) {
LOGE("AudioManagerJni JNI: call registerAudioRendererEventListener has exception");
env->ExceptionDescribe();
env->ExceptionClear();
return ERROR;
}
return result != SUCCESS ? ERR_OPERATION_FAILED : SUCCESS;
}
int32_t AudioManagerJni::UnregisterAudioRendererEventListener()
{
audioRendererEventCallback_ = nullptr;
auto env = ARKUI_X_Plugin_GetJniEnv();
CHECK_NULL_RETURN(env, ERROR);
CHECK_NULL_RETURN(g_audioManagerPluginClass.globalRef, ERROR);
CHECK_NULL_RETURN(g_audioManagerPluginClass.unregisterAudioRendererEventListener, ERROR);
jint result = env->CallIntMethod(
g_audioManagerPluginClass.globalRef, g_audioManagerPluginClass.unregisterAudioRendererEventListener);
if (env->ExceptionCheck()) {
LOGE("AudioManagerJni JNI: call unregisterAudioRendererEventListener has exception");
env->ExceptionDescribe();
env->ExceptionClear();
return ERROR;
}
return result != SUCCESS ? ERR_OPERATION_FAILED : SUCCESS;
}
int32_t AudioManagerJni::RegisterAudioCapturerEventListener(
const std::shared_ptr<AudioCapturerStateChangeCallback>& callback)
{
audioCapturerEventCallback_ = callback;
auto env = ARKUI_X_Plugin_GetJniEnv();
CHECK_NULL_RETURN(env, ERROR);
CHECK_NULL_RETURN(g_audioManagerPluginClass.globalRef, ERROR);
CHECK_NULL_RETURN(g_audioManagerPluginClass.registerAudioCapturerEventListener, ERROR);
jint result = env->CallIntMethod(
g_audioManagerPluginClass.globalRef, g_audioManagerPluginClass.registerAudioCapturerEventListener);
if (env->ExceptionCheck()) {
LOGE("AudioManagerJni JNI: call registerAudioCapturerEventListener has exception");
env->ExceptionDescribe();
env->ExceptionClear();
return ERROR;
}
return result != SUCCESS ? ERR_OPERATION_FAILED : SUCCESS;
}
int32_t AudioManagerJni::UnregisterAudioCapturerEventListener()
{
audioCapturerEventCallback_ = nullptr;
auto env = ARKUI_X_Plugin_GetJniEnv();
CHECK_NULL_RETURN(env, ERROR);
CHECK_NULL_RETURN(g_audioManagerPluginClass.globalRef, ERROR);
CHECK_NULL_RETURN(g_audioManagerPluginClass.unregisterAudioCapturerEventListener, ERROR);
jint result = env->CallIntMethod(
g_audioManagerPluginClass.globalRef, g_audioManagerPluginClass.unregisterAudioCapturerEventListener);
if (env->ExceptionCheck()) {
LOGE("AudioManagerJni JNI: call unregisterAudioCapturerEventListener has exception");
env->ExceptionDescribe();
env->ExceptionClear();
return ERROR;
}
return result != SUCCESS ? ERR_OPERATION_FAILED : SUCCESS;
}
int32_t AudioManagerJni::GetCurrentRendererChangeInfos(
std::vector<std::shared_ptr<AudioRendererChangeInfo>>& audioRendererChangeInfos)
{
auto env = ARKUI_X_Plugin_GetJniEnv();
CHECK_NULL_RETURN(env, ERROR);
CHECK_NULL_RETURN(g_audioManagerPluginClass.globalRef, ERROR);
CHECK_NULL_RETURN(g_audioManagerPluginClass.getCurrentAudioRendererInfoArray, ERROR);
jobject jRendererChangeInfos = env->CallObjectMethod(
g_audioManagerPluginClass.globalRef, g_audioManagerPluginClass.getCurrentAudioRendererInfoArray);
if (env->ExceptionCheck()) {
LOGE("AudioManagerJni JNI: call getCurrentAudioRendererInfoArray has exception");
env->ExceptionDescribe();
env->ExceptionClear();
return ERROR;
}
if (!jRendererChangeInfos) {
LOGE("AudioManagerJni JNI: jRendererChangeInfos is null");
return ERR_OPERATION_FAILED;
}
audioRendererChangeInfos = GetAudioRendererChangeInfo(jRendererChangeInfos);
env->DeleteLocalRef(jRendererChangeInfos);
return SUCCESS;
}
int32_t AudioManagerJni::GetCurrentCapturerChangeInfos(
std::vector<std::shared_ptr<AudioCapturerChangeInfo>>& audioCapturerChangeInfos)
{
auto env = ARKUI_X_Plugin_GetJniEnv();
CHECK_NULL_RETURN(env, ERROR);
CHECK_NULL_RETURN(g_audioManagerPluginClass.globalRef, ERROR);
CHECK_NULL_RETURN(g_audioManagerPluginClass.getCurrentAudioCapturerInfoArray, ERROR);
jobject jCapturerChangeInfos = env->CallObjectMethod(
g_audioManagerPluginClass.globalRef, g_audioManagerPluginClass.getCurrentAudioCapturerInfoArray);
if (env->ExceptionCheck()) {
LOGE("AudioManagerJni JNI: call getCurrentAudioCapturerInfoArray has exception");
env->ExceptionDescribe();
env->ExceptionClear();
return ERROR;
}
if (!jCapturerChangeInfos) {
LOGE("AudioManagerJni JNI: jCapturerChangeInfos is null");
return ERR_OPERATION_FAILED;
}
audioCapturerChangeInfos = GetAudioCapturerChangeInfo(jCapturerChangeInfos);
env->DeleteLocalRef(jCapturerChangeInfos);
return SUCCESS;
}
AudioVolumeType GetVolumeTypeFromStreamUsage(StreamUsage streamUsage)
{
switch (streamUsage) {
case STREAM_USAGE_VOICE_MESSAGE:
case STREAM_USAGE_VOICE_COMMUNICATION:
return AudioStreamType::STREAM_VOICE_CALL;
case STREAM_USAGE_RINGTONE:
case STREAM_USAGE_NOTIFICATION:
return AudioStreamType::STREAM_RING;
case STREAM_USAGE_MUSIC:
case STREAM_USAGE_MOVIE:
case STREAM_USAGE_GAME:
case STREAM_USAGE_AUDIOBOOK:
case STREAM_USAGE_NAVIGATION:
return AudioStreamType::STREAM_MUSIC;
case STREAM_USAGE_VOICE_ASSISTANT:
return STREAM_VOICE_ASSISTANT;
case STREAM_USAGE_ALARM:
return AudioStreamType::STREAM_ALARM;
case STREAM_USAGE_ACCESSIBILITY:
return AudioStreamType::STREAM_ACCESSIBILITY;
default:
return AudioStreamType::STREAM_MUSIC;
}
}
bool AudioManagerJni::IsStreamActive(AudioVolumeType volumeType)
{
std::vector<std::shared_ptr<AudioRendererChangeInfo>> audioRendererChangeInfos;
int32_t result = GetCurrentRendererChangeInfos(audioRendererChangeInfos);
if (result != SUCCESS) {
LOGE("GetCurrentRendererChangeInfos failed");
return false;
}
for (const auto& info : audioRendererChangeInfos) {
if ((GetVolumeTypeFromStreamUsage(info->rendererInfo.streamUsage) == volumeType)) {
return true;
}
}
return false;
}
int32_t AudioManagerJni::SetDeviceActive(DeviceType deviceType, bool flag)
{
auto env = ARKUI_X_Plugin_GetJniEnv();
CHECK_NULL_RETURN(env, ERROR);
CHECK_NULL_RETURN(g_audioManagerPluginClass.globalRef, ERROR);
CHECK_NULL_RETURN(g_audioManagerPluginClass.setDeviceActive, ERROR);
jint deviceTypeAn = ConvertActiveDeviceTypeToAn(deviceType);
jboolean result = env->CallBooleanMethod(
g_audioManagerPluginClass.globalRef, g_audioManagerPluginClass.setDeviceActive, deviceTypeAn, flag);
if (env->ExceptionCheck()) {
LOGE("AudioManagerJni JNI: call SetDeviceActive has exception");
env->ExceptionDescribe();
env->ExceptionClear();
return ERROR;
}
return result ? SUCCESS : ERROR;
}
bool AudioManagerJni::IsDeviceActive(DeviceType deviceType)
{
auto env = ARKUI_X_Plugin_GetJniEnv();
CHECK_NULL_RETURN(env, ERROR);
CHECK_NULL_RETURN(g_audioManagerPluginClass.globalRef, ERROR);
CHECK_NULL_RETURN(g_audioManagerPluginClass.isDeviceActive, ERROR);
jint deviceTypeAn = ConvertActiveDeviceTypeToAn(deviceType);
jboolean result = env->CallBooleanMethod(
g_audioManagerPluginClass.globalRef, g_audioManagerPluginClass.isDeviceActive, deviceTypeAn);
if (env->ExceptionCheck()) {
LOGE("AudioManagerJni JNI: call isDeviceActive has exception");
env->ExceptionDescribe();
env->ExceptionClear();
return false;
}
return result;
}
}