From 3ed93930b068d0328d55429c53380274639a3890 Mon Sep 17 00:00:00 2001 From: Andrew nuark G Date: Mon, 4 May 2026 14:04:35 +0700 Subject: [PATCH] feat: (for now android only!) codec configuration and retrieval methods --- .../LiblinphoneFlutterPlugin.kt | 15 +++++ .../liblinphone_flutter/LinphoneBridge.kt | 57 +++++++++++++++++++ lib/liblinphone_flutter.dart | 7 +++ lib/liblinphone_flutter_method_channel.dart | 19 +++++++ ...iblinphone_flutter_platform_interface.dart | 9 +++ lib/models/lp_codec.dart | 10 ++++ 6 files changed, 117 insertions(+) create mode 100644 lib/models/lp_codec.dart diff --git a/android/src/main/kotlin/xyz/nuark/liblinphone_flutter/LiblinphoneFlutterPlugin.kt b/android/src/main/kotlin/xyz/nuark/liblinphone_flutter/LiblinphoneFlutterPlugin.kt index 24260a3..677aa1d 100644 --- a/android/src/main/kotlin/xyz/nuark/liblinphone_flutter/LiblinphoneFlutterPlugin.kt +++ b/android/src/main/kotlin/xyz/nuark/liblinphone_flutter/LiblinphoneFlutterPlugin.kt @@ -263,6 +263,21 @@ class LiblinphoneFlutterPlugin : FlutterPlugin, ActivityAware, MethodCallHandler result.success(linphoneBridge.getCurrentCallStats()?.toMap()) } + "getAvailableAudioCodecs" -> { + result.success(linphoneBridge.getAvailableAudioCodecs()) + } + + "setAudioCodec" -> { + try { + val mime = call.argument("mime")!! + val clockRate = call.argument("clockRate")!! + result.success(linphoneBridge.setAudioCodec(mime, clockRate)) + } catch (e: Exception) { + Log.e(TAG, "setAudioCodec: ${e.message}") + result.error("error", e.message, e) + } + } + else -> { result.notImplemented() } diff --git a/android/src/main/kotlin/xyz/nuark/liblinphone_flutter/LinphoneBridge.kt b/android/src/main/kotlin/xyz/nuark/liblinphone_flutter/LinphoneBridge.kt index 02010ab..ed197d9 100644 --- a/android/src/main/kotlin/xyz/nuark/liblinphone_flutter/LinphoneBridge.kt +++ b/android/src/main/kotlin/xyz/nuark/liblinphone_flutter/LinphoneBridge.kt @@ -549,4 +549,61 @@ class LinphoneBridge( isZrtpKeyAgreementAlgoPostQuantum = stats.isZrtpKeyAgreementAlgoPostQuantum(), ) } + + data class LPCodec( + val mimeType: String, + val clockRate: Int, + val enabled: Boolean, + ) { + fun toMap(): Map { + return mapOf( + "mimeType" to mimeType, + "clockRate" to clockRate, + "enabled" to enabled, + ); + } + } + + fun getAvailableAudioCodecs(): List> { + return core.audioPayloadTypes.map { + LPCodec( + mimeType = it.mimeType.lowercase(), + clockRate = it.clockRate, + enabled = it.enabled() + ).toMap() + } + } + + fun setAudioCodec(mime: String, clockRate: Int): Boolean { + var codecFound = false + var ok = false + core.audioPayloadTypes.forEach { pt: PayloadType -> + val ptMime = pt.mimeType.lowercase() + val ptClockRate = pt.clockRate + val enable = ptMime == mime && ptClockRate == clockRate + if (enable) { + ok = pt.enable(enable) == 0 + codecFound = true + Log.i( + LiblinphoneFlutterPlugin.TAG, + "setAudioCodec: preferred codec found ($ptMime @ $clockRate) switch: $ok" + ) + } else { + val switchedOk = pt.enable(enable) == 0 + Log.i( + LiblinphoneFlutterPlugin.TAG, + "setAudioCodec: $ptMime @ $clockRate switch: $switchedOk" + ) + } + } + + if (!codecFound) { + Log.i( + LiblinphoneFlutterPlugin.TAG, + "setAudioCodec: could not find codec with parans $mime @ $clockRate" + ) + } + + return ok + } } diff --git a/lib/liblinphone_flutter.dart b/lib/liblinphone_flutter.dart index dcb6b6a..8af2d8f 100644 --- a/lib/liblinphone_flutter.dart +++ b/lib/liblinphone_flutter.dart @@ -4,6 +4,7 @@ import 'liblinphone_flutter_platform_interface.dart'; import 'models/call_stats.dart'; import 'models/call_type.dart'; import 'models/dscp_values.dart'; +import 'models/lp_codec.dart'; import 'models/registration_state.dart'; import 'models/call_state.dart'; @@ -117,4 +118,10 @@ class LiblinphoneFlutter { Future getCurrentCallStats() async => LiblinphoneFlutterPlatform.instance.getCurrentCallStats(); + + Future> getAvailableAudioCodecs() async => + LiblinphoneFlutterPlatform.instance.getAvailableAudioCodecs(); + + Future setAudioCodec(String mime, int clockRate) async => + LiblinphoneFlutterPlatform.instance.setAudioCodec(mime, clockRate); } diff --git a/lib/liblinphone_flutter_method_channel.dart b/lib/liblinphone_flutter_method_channel.dart index 1e3a70a..7b51cdb 100644 --- a/lib/liblinphone_flutter_method_channel.dart +++ b/lib/liblinphone_flutter_method_channel.dart @@ -5,6 +5,7 @@ import 'liblinphone_flutter_platform_interface.dart'; import 'models/call_stats.dart'; import 'models/call_type.dart'; import 'models/dscp_values.dart'; +import 'models/lp_codec.dart'; /// An implementation of [LiblinphoneFlutterPlatform] that uses method channels. class MethodChannelLiblinphoneFlutter extends LiblinphoneFlutterPlatform { @@ -175,4 +176,22 @@ class MethodChannelLiblinphoneFlutter extends LiblinphoneFlutterPlatform { final values = CallStats.fromJson(data); return values; } + + @override + Future> getAvailableAudioCodecs() async { + final data = (await methodChannel.invokeMethod>( + 'getAvailableAudioCodecs', + ))!.cast>(); + + final values = data.map(LPCodec.fromJson).toList(growable: true); + return values; + } + + @override + Future setAudioCodec(String mime, int clockRate) async { + return (await methodChannel.invokeMethod( + 'setAudioCodec', + {'mime': mime, 'clockRate': clockRate}, + ))!; + } } diff --git a/lib/liblinphone_flutter_platform_interface.dart b/lib/liblinphone_flutter_platform_interface.dart index a23daaa..99a28b9 100644 --- a/lib/liblinphone_flutter_platform_interface.dart +++ b/lib/liblinphone_flutter_platform_interface.dart @@ -4,6 +4,7 @@ import 'package:plugin_platform_interface/plugin_platform_interface.dart'; import 'liblinphone_flutter_method_channel.dart'; import 'models/call_stats.dart'; import 'models/dscp_values.dart'; +import 'models/lp_codec.dart'; abstract class LiblinphoneFlutterPlatform extends PlatformInterface { /// Constructs a LiblinphoneFlutterPlatform. @@ -139,4 +140,12 @@ abstract class LiblinphoneFlutterPlatform extends PlatformInterface { Future getCurrentCallStats() async { throw UnimplementedError('getCurrentCallStats() has not been implemented.'); } + + Future> getAvailableAudioCodecs() async { + throw UnimplementedError('getCurrentCallStats() has not been implemented.'); + } + + Future setAudioCodec(String mime, int clockRate) async { + throw UnimplementedError('getCurrentCallStats() has not been implemented.'); + } } diff --git a/lib/models/lp_codec.dart b/lib/models/lp_codec.dart new file mode 100644 index 0000000..511fc7a --- /dev/null +++ b/lib/models/lp_codec.dart @@ -0,0 +1,10 @@ +final class LPCodec { + final String mimeType; + final int clockRate; + final bool enabled; + + const LPCodec(this.mimeType, this.clockRate, this.enabled); + + factory LPCodec.fromJson(Map json) => + LPCodec(json["mimeType"], json["clockRate"], json["enabled"]); +}