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.

214 lines
5.0 KiB

import 'dart:async';
import 'dart:typed_data';
import 'package:flutter/services.dart';
/// OPUS解码参数选项
class OpusOption {
/// 是否具有协议头
final bool hasHeader;
/// 通道数。取值范围:[1, 2]
final int channel;
/// 采样率。参考值:{8000, 16000, 24000, 32000, 44100, 48000}
final int sampleRate;
/// 数据包长度。仅hasHeader = false时生效。
final int packetSize;
/// 构造函数
OpusOption({
this.hasHeader = false,
this.channel = 1,
this.sampleRate = 16000,
this.packetSize = 40,
});
/// 转换为参数Map
Map<String, dynamic> toMap() {
return {
'hasHeader': hasHeader,
'channel': channel,
'sampleRate': sampleRate,
'packetSize': packetSize,
};
}
}
/// 杰理OPUS编解码器事件
class OpusEvent {
/// 事件类型
final String event;
/// 数据类型 (file或stream)
final String? type;
/// 解码后的数据 (仅在流解码时有效)
final Uint8List? data;
/// 输出文件路径 (仅在文件解码完成时有效)
final String? filePath;
/// 错误码 (仅在发生错误时有效)
final int? errorCode;
/// 错误信息 (仅在发生错误时有效)
final String? errorMessage;
/// 构造函数
OpusEvent({
required this.event,
this.type,
this.data,
this.filePath,
this.errorCode,
this.errorMessage,
});
/// 从Map构造对象
factory OpusEvent.fromMap(Map<dynamic, dynamic> map) {
return OpusEvent(
event: map['event'],
type: map['type'],
data: map['data'],
filePath: map['filePath'],
errorCode: map['code'],
errorMessage: map['message'],
);
}
}
/// 杰理OPUS编解码插件
class JlOpus {
static const MethodChannel _methodChannel = MethodChannel('com.yunqiinnovation.jl_opus');
static const EventChannel _eventChannel = EventChannel('com.yunqiinnovation.jl_opus/events');
/// 事件流
Stream<OpusEvent>? _eventStream;
/// 获取事件流
Stream<OpusEvent> get eventStream {
_eventStream ??= _eventChannel.receiveBroadcastStream().map((event) {
if (event is Map) {
return OpusEvent.fromMap(event);
}
throw PlatformException(
code: 'INVALID_EVENT',
message: '无效的事件数据',
);
});
return _eventStream!;
}
/// 解码后的数据流
final StreamController<Uint8List> _decodedDataController = StreamController<Uint8List>.broadcast();
/// 获取解码数据流
Stream<Uint8List> get decodedDataStream => _decodedDataController.stream;
/// 构造函数,设置事件监听
JlOpus() {
_setupEventListener();
}
/// 设置事件监听
void _setupEventListener() {
eventStream.listen((event) {
if (event.event == 'onDecodeStream' && event.data != null) {
_decodedDataController.add(event.data!);
}
});
}
/// 初始化OPUS解码器
Future<bool> initOpusDecoder() async {
try {
final result = await _methodChannel.invokeMethod<bool>('initOpusDecoder');
return result ?? false;
} catch (e) {
return false;
}
}
/// 解码OPUS文件
///
/// [inPath] 输入文件路径
/// [outPath] 输出文件路径
/// [option] 解码参数
Future<String?> decodeOpusFile(String inPath, String outPath, OpusOption option) async {
try {
final result = await _methodChannel.invokeMethod<String>(
'decodeOpusFile',
{
'inPath': inPath,
'outPath': outPath,
...option.toMap(),
},
);
return result;
} catch (e) {
rethrow;
}
}
/// 开始解码OPUS数据流
///
/// [option] 解码参数
Future<bool> startDecodeStream(OpusOption option) async {
try {
final result = await _methodChannel.invokeMethod<bool>(
'startDecodeStream',
option.toMap(),
);
return result ?? false;
} catch (e) {
rethrow;
}
}
/// 停止解码OPUS数据流
Future<bool> stopDecodeStream() async {
try {
final result = await _methodChannel.invokeMethod<bool>('stopDecodeStream');
return result ?? false;
} catch (e) {
return false;
}
}
/// 写入OPUS音频数据进行解码
///
/// [data] OPUS音频数据
Future<bool> writeAudioStream(Uint8List data) async {
try {
final result = await _methodChannel.invokeMethod<bool>(
'writeAudioStream',
{'data': data},
);
return result ?? false;
} catch (e) {
rethrow;
}
}
/// 判断是否正在解码
Future<bool> isDecoding() async {
try {
final result = await _methodChannel.invokeMethod<bool>('isDecoding');
return result ?? false;
} catch (e) {
return false;
}
}
/// 释放资源
Future<bool> dispose() async {
try {
_decodedDataController.close();
final result = await _methodChannel.invokeMethod<bool>('dispose');
return result ?? false;
} catch (e) {
return false;
}
}
}