msaaudio.cpp 5.85 KB
Newer Older
Andrea Gianarda's avatar
Andrea Gianarda committed
1 2 3
/*
 * Copyright (c) 2010-2019 Belledonne Communications SARL.
 *
4
 * msaaudio.cpp - Android Media plugin for Linphone, based on AAudio APIs.
Andrea Gianarda's avatar
Andrea Gianarda committed
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

#include <mediastreamer2/msjava.h>
#include <mediastreamer2/devices.h>

#include <sys/types.h>
#include <jni.h>
#include <dlfcn.h>

#include <msaaudio/msaaudio.h>

29
static void android_snd_card_device_create(JNIEnv *env, jobject deviceInfo, MSSndCardManager *m);
Andrea Gianarda's avatar
Andrea Gianarda committed
30

31 32
// this global variable is shared among all msaaudio files
int DeviceFavoriteSampleRate = 44100;
Andrea Gianarda's avatar
Andrea Gianarda committed
33

34
static void android_snd_card_detect(MSSndCardManager *m) {
Andrea Gianarda's avatar
Andrea Gianarda committed
35

36
	JNIEnv *env = ms_get_jni_env();
Andrea Gianarda's avatar
Andrea Gianarda committed
37

38
	// Get all devices
39
	jobject devices = ms_android_get_all_devices(env, "all");
Andrea Gianarda's avatar
Andrea Gianarda committed
40

41 42 43 44 45 46 47 48 49
	// extract required information from every device
	jobjectArray deviceArray = (jobjectArray) devices;
	jsize deviceNumber = (int) env->GetArrayLength(deviceArray);

	ms_message("[AAudio] Create soundcards for %0d devices", deviceNumber);

	for (int idx=0; idx < deviceNumber; idx++) {
		jobject deviceInfo = env->GetObjectArrayElement(deviceArray, idx);
		android_snd_card_device_create(env, deviceInfo, m);
Andrea Gianarda's avatar
Andrea Gianarda committed
50 51 52 53
	}
}

static void android_native_snd_card_init(MSSndCard *card) {
54 55
	AAudioContext* context = new AAudioContext();
	card->data = context;
Andrea Gianarda's avatar
Andrea Gianarda committed
56 57 58 59 60
}

static void android_native_snd_card_uninit(MSSndCard *card) {
	AAudioContext *ctx = (AAudioContext*)card->data;
	ms_warning("[AAudio] Deletion of AAudio context [%p]", ctx);
61
	delete ctx;
Andrea Gianarda's avatar
Andrea Gianarda committed
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77
}

MSSndCardDesc android_native_snd_aaudio_card_desc = {
	"AAudio",
	android_snd_card_detect,
	android_native_snd_card_init,
	NULL,
	NULL,
	NULL,
	NULL,
	NULL,
	android_snd_card_create_reader,
	android_snd_card_create_writer,
	android_native_snd_card_uninit
};

78 79
static void android_snd_card_device_create(JNIEnv *env, jobject deviceInfo, MSSndCardManager *m) {

80
	MSSndCardDeviceType type = ms_android_get_device_type(env, deviceInfo);
81 82 83 84 85 86 87 88 89 90 91
	if (
		(type == MSSndCardDeviceType::MS_SND_CARD_DEVICE_TYPE_BLUETOOTH) ||
		(type == MSSndCardDeviceType::MS_SND_CARD_DEVICE_TYPE_EARPIECE) ||
		(type == MSSndCardDeviceType::MS_SND_CARD_DEVICE_TYPE_SPEAKER) ||
		(type == MSSndCardDeviceType::MS_SND_CARD_DEVICE_TYPE_MICROPHONE) ||
		(type == MSSndCardDeviceType::MS_SND_CARD_DEVICE_TYPE_HEADSET) ||
		(type == MSSndCardDeviceType::MS_SND_CARD_DEVICE_TYPE_HEADPHONES) ||
		(type == MSSndCardDeviceType::MS_SND_CARD_DEVICE_TYPE_GENERIC_USB)
	) {
		MSSndCard *card = ms_snd_card_new(&android_native_snd_aaudio_card_desc);

92 93
		card->name = ms_strdup(ms_android_get_device_product_name(env, deviceInfo));
		card->internal_id = ms_android_get_device_id(env, deviceInfo);
94 95 96 97 98 99
		card->device_type = type;

		AAudioContext *card_data = (AAudioContext*)card->data;

		// Card capabilities
		// Assign the value because the default value is MS_SND_CARD_CAP_CAPTURE|MS_SND_CARD_CAP_PLAYBACK
100
		card->capabilities = ms_android_get_device_capabilities(env, deviceInfo);
101 102 103 104 105 106
		MSDevicesInfo *devices = ms_factory_get_devices_info(m->factory);
		SoundDeviceDescription *d = ms_devices_info_get_sound_device_description(devices);
		if (d->flags & DEVICE_HAS_BUILTIN_AEC) {
			card->capabilities |= MS_SND_CARD_CAP_BUILTIN_ECHO_CANCELLER;
			card_data->builtin_aec = true;
		}
Andrea Gianarda's avatar
Andrea Gianarda committed
107

108 109 110 111
		card->latency = d->delay;
		if (d->recommended_rate){
			card_data->samplerate = d->recommended_rate;
		}
Andrea Gianarda's avatar
Andrea Gianarda committed
112

113 114 115 116
		// Take capabilities into account as the same device type may have different components with different capabilities and IDs
		if(!ms_snd_card_is_card_duplicate(m, card, TRUE)) {
			card=ms_snd_card_ref(card);
			ms_snd_card_manager_prepend_card(m, card);
Andrea Gianarda's avatar
Andrea Gianarda committed
117

Sylvain Berfini's avatar
Sylvain Berfini committed
118
			ms_message("[AAudio] Added card with ID: [%s], name: [%s], device ID: [%0d], type: [%s] and capabilities: [%0d]", card->id, card->name, card->internal_id, ms_snd_card_device_type_to_string(card->device_type), card->capabilities);
119 120
		} else {
			free(card);
121
		}
122
	}
123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139

}

static bool loadLib() {
	void *handle;
	const char * libname = "libaaudio.so";

	bool success = false;

	// open library
	if ((handle = dlopen(libname, RTLD_NOW)) == NULL){
		ms_warning("[AAudio] Fail to load %s : %s", libname, dlerror());
		success = false;
	} else {
		dlerror(); // Clear previous message if present
		ms_message("[AAudio] %s successfully loaded", libname);
		success = true;
Andrea Gianarda's avatar
Andrea Gianarda committed
140
	}
141 142

	return success;
Andrea Gianarda's avatar
Andrea Gianarda committed
143 144 145 146 147 148 149 150 151 152 153 154
}

#ifdef _MSC_VER
#define MS_PLUGIN_DECLARE(type) extern "C" __declspec(dllexport) type
#else
#define MS_PLUGIN_DECLARE(type) extern "C" type
#endif

// Called by ms_load_plugins in ms_common.c
MS_PLUGIN_DECLARE(void) libmsaaudio_init(MSFactory* factory) {
	register_aaudio_player(factory);
	register_aaudio_recorder(factory);
155

Andrea Gianarda's avatar
Andrea Gianarda committed
156 157
	ms_message("[AAudio] libmsaaudio plugin loaded");

158
	DeviceFavoriteSampleRate = ms_android_get_preferred_sample_rate();
159 160

	const bool loadOk = loadLib();
Andrea Gianarda's avatar
Andrea Gianarda committed
161

162
	if (loadOk) {
Andrea Gianarda's avatar
Andrea Gianarda committed
163 164 165 166 167 168 169 170 171
		MSDevicesInfo* devices = ms_factory_get_devices_info(factory);
		SoundDeviceDescription* d = ms_devices_info_get_sound_device_description(devices);

		if (d->flags & DEVICE_HAS_CRAPPY_AAUDIO) {
			ms_error("[AAudio] Device is blacklisted, do not create AAudio soundcard");
			return;
		}

		MSSndCardManager *m = ms_factory_get_snd_card_manager(factory);
172 173 174 175

		// Register card manager so that it can be automaticallty initialized
		ms_snd_card_manager_register_desc(m, &android_native_snd_aaudio_card_desc);

Andrea Gianarda's avatar
Andrea Gianarda committed
176 177
		ms_message("[AAudio] Soundcard created");
	} else {
178
		ms_error("[AAudio] Unable to load AAudio plugin shared object");
Andrea Gianarda's avatar
Andrea Gianarda committed
179 180
	}
}