Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions lib/open_earable_flutter.dart
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ export 'src/models/capabilities/jingle_player.dart';
export 'src/models/capabilities/audio_player_controls.dart';
export 'src/models/capabilities/storage_path_audio_player.dart';
export 'src/models/capabilities/audio_mode_manager.dart';
export 'src/models/capabilities/microphone_gain_manager.dart';
export 'src/models/capabilities/microphone_manager.dart';
export 'src/models/capabilities/power_saving_mode_manager.dart';
export 'src/models/capabilities/stereo_device.dart';
Expand Down
70 changes: 70 additions & 0 deletions lib/src/models/capabilities/microphone_gain_manager.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
abstract class MicrophoneGainManager {
Future<MicrophoneGain> getMicrophoneGain();

Future<void> setMicrophoneGain(MicrophoneGain gain);
}

class MicrophoneGain {
static const int maxGainRegister = 0x00;
static const int zeroDbRegister = 0x40;
static const int minGainRegister = 0xFE;
static const int muteRegister = 0xFF;
static const int defaultRegister = 0x20;
static const double stepDb = 0.375;
static const double maxGainDb = 24.0;
static const double minGainDb = -71.25;

final int leftRegister;
final int rightRegister;

const MicrophoneGain({
required this.leftRegister,
required this.rightRegister,
}) : assert(leftRegister >= 0 && leftRegister <= muteRegister),
assert(rightRegister >= 0 && rightRegister <= muteRegister);

const MicrophoneGain.stereo(int register)
: this(leftRegister: register, rightRegister: register);

const MicrophoneGain.muted()
: this.stereo(muteRegister);

bool get isMuted =>
leftRegister == muteRegister && rightRegister == muteRegister;

double? get leftDb => registerToDb(leftRegister);

double? get rightDb => registerToDb(rightRegister);

MicrophoneGain copyWith({
int? leftRegister,
int? rightRegister,
}) {
return MicrophoneGain(
leftRegister: leftRegister ?? this.leftRegister,
rightRegister: rightRegister ?? this.rightRegister,
);
}

static double? registerToDb(int register) {
_validateRegister(register);
if (register == muteRegister) {
return null;
}
return maxGainDb - (register * stepDb);
}

static int dbToRegister(double db) {
final clampedDb = db.clamp(minGainDb, maxGainDb).toDouble();
return ((maxGainDb - clampedDb) / stepDb)
.round()
.clamp(maxGainRegister, minGainRegister)
.toInt();
}

static void _validateRegister(int register) {
if (register < 0 || register > muteRegister) {
throw RangeError.range(register, 0, muteRegister, 'register');
}
}
}
35 changes: 35 additions & 0 deletions lib/src/models/devices/open_earable_v2.dart
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ const String _micSelectCharacteristicUuid =
"0x1410df97-5f68-4ebb-a7c7-5e0fb9ae7557";
const String _audioModeCharacteristicUuid =
"0x1410df96-5f68-4ebb-a7c7-5e0fb9ae7557";
const String _dmicGainCharacteristicUuid =
"1410df99-5f68-4ebb-a7c7-5e0fb9ae7557";

const String _buttonServiceUuid = "29c10bdc-4773-11ee-be56-0242ac120002";
const String _buttonCharacteristicUuid = "29c10f38-4773-11ee-be56-0242ac120002";
Expand Down Expand Up @@ -76,6 +78,7 @@ class OpenEarableV2 extends BluetoothWearable
DeviceFirmwareVersion,
DeviceHardwareVersion,
MicrophoneManager<OpenEarableV2Mic>,
MicrophoneGainManager,
AudioModeManager,
EdgeRecorderManager,
ButtonManager,
Expand Down Expand Up @@ -460,6 +463,38 @@ class OpenEarableV2 extends BluetoothWearable
return availableMicrophones.firstWhere((mic) => mic.id == microphoneId);
}

// MARK: MicrophoneGainManager

@override
Future<MicrophoneGain> getMicrophoneGain() async {
final gainBytes = await bleManager.read(
deviceId: deviceId,
serviceId: _audioConfigServiceUuid,
characteristicId: _dmicGainCharacteristicUuid,
);

if (gainBytes.length != 2) {
throw StateError(
'Microphone gain characteristic expected 2 values, but got ${gainBytes.length}',
);
}

return MicrophoneGain(
leftRegister: gainBytes[0],
rightRegister: gainBytes[1],
);
}

@override
Future<void> setMicrophoneGain(MicrophoneGain gain) {
return bleManager.write(
deviceId: deviceId,
serviceId: _audioConfigServiceUuid,
characteristicId: _dmicGainCharacteristicUuid,
byteData: [gain.leftRegister, gain.rightRegister],
);
}

// MARK: AudioModeManager

@override
Expand Down
Loading