You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

128 lines
3.8 KiB

import 'dart:async';
import 'dart:typed_data';
import 'package:flutter/services.dart';
/// Opus 音频格式的应用类型
class OpusApplicationType {
/// 通用音频编码 (OPUS_APPLICATION_AUDIO)
static const int audio = 2048;
/// 语音编码 (OPUS_APPLICATION_VOIP)
static const int voip = 2048;
/// 低延迟编码 (OPUS_APPLICATION_RESTRICTED_LOWDELAY)
static const int restrictedLowDelay = 2051;
}
/// Opus 编解码插件,提供对 Opus 音频格式的编码和解码功能
class Opus {
static const MethodChannel _channel = MethodChannel('com.yunqiinnovation.opus');
/// 创建 Opus 编码器实例
///
/// [sampleRate] 采样率 (Hz),常用值:8000, 16000, 24000, 48000
/// [channels] 声道数,1=单声道,2=立体声
/// [application] 应用类型,默认为音频编码 [OpusApplicationType.audio]
/// [complexity] 复杂度 (0-10),数值越高质量越好,但CPU占用也更高
/// [frameSize] 编码帧大小,常用值:120, 240, 480, 960, 2880
///
/// 返回创建是否成功
static Future<bool> createEncoder({
int sampleRate = 48000,
int channels = 2,
int application = OpusApplicationType.audio,
int complexity = 10,
int frameSize = 960,
}) async {
try {
final bool? success = await _channel.invokeMethod<bool>('createEncoder', {
'sampleRate': sampleRate,
'channels': channels,
'application': application,
'complexity': complexity,
'frameSize': frameSize,
});
return success ?? false;
} on PlatformException catch (e) {
print('Failed to create Opus encoder: ${e.message}');
return false;
}
}
/// 创建 Opus 解码器实例
///
/// [sampleRate] 采样率 (Hz),常用值:8000, 16000, 24000, 48000
/// [channels] 声道数,1=单声道,2=立体声
///
/// 返回创建是否成功
static Future<bool> createDecoder({
int sampleRate = 48000,
int channels = 2,
}) async {
try {
final bool? success = await _channel.invokeMethod<bool>('createDecoder', {
'sampleRate': sampleRate,
'channels': channels,
});
return success ?? false;
} on PlatformException catch (e) {
print('Failed to create Opus decoder: ${e.message}');
return false;
}
}
/// 编码 PCM 数据为 Opus 格式
///
/// [pcmData] 16位 PCM 音频数据
///
/// 返回编码后的 Opus 数据,如果失败返回 null
static Future<Uint8List?> encodeData(Uint8List pcmData) async {
try {
final result = await _channel.invokeMethod<Uint8List>('encodeData', {
'input': pcmData,
});
return result;
} on PlatformException catch (e) {
print('Failed to encode data: ${e.message}');
return null;
}
}
/// 解码 Opus 数据为 PCM 格式
///
/// [opusData] Opus 编码数据
/// [frameSize] 解码帧大小,需要与编码时使用的帧大小匹配
///
/// 返回解码后的 PCM 数据,如果失败返回 null
static Future<Uint8List?> decodeData(Uint8List opusData, {int frameSize = 960}) async {
try {
final result = await _channel.invokeMethod<Uint8List>('decodeData', {
'input': opusData,
'frameSize': frameSize,
});
return result;
} on PlatformException catch (e) {
print('Failed to decode data: ${e.message}');
return null;
}
}
/// 释放编码器资源
static Future<void> disposeEncoder() async {
try {
await _channel.invokeMethod<void>('disposeEncoder');
} on PlatformException catch (e) {
print('Failed to dispose encoder: ${e.message}');
}
}
/// 释放解码器资源
static Future<void> disposeDecoder() async {
try {
await _channel.invokeMethod<void>('disposeDecoder');
} on PlatformException catch (e) {
print('Failed to dispose decoder: ${e.message}');
}
}
}