|
- import 'dart:convert';
-
- import 'package:crypto/crypto.dart';
- import 'package:demo001/plugin/xunfei/audiototext/result_test.dart';
- import 'package:intl/intl.dart';
- import 'package:web_socket_channel/web_socket_channel.dart';
-
- typedef ResponseCallback = void Function(
- Xunfei_AudioToText_Result_Text_Item text);
-
- class Xunfei_AudioToText {
- static const int STATUS_FIRST_FRAME = 0;
- static const int STATUS_CONTINUE_FRAME = 1;
- static const int STATUS_LAST_FRAME = 2;
-
- final String appId;
- final String apiKey;
- final String apiSecret;
- final String host = "iat-api.xfyun.cn";
- final String requestUri = "/v2/iat";
- WebSocketChannel? _channel;
-
- final ResponseCallback onResponse; // 回调函数类型
- late Xunfei_AudioToText_Result_Text currtext;
- // 静态变量保存唯一实例
- static Xunfei_AudioToText? _instance;
- Xunfei_AudioToText._internal({
- required this.appId,
- required this.apiKey,
- required this.apiSecret,
- required this.onResponse, // 在构造函数中传递回调
- });
- // 工厂构造函数
- factory Xunfei_AudioToText({
- required String appId,
- required String apiKey,
- required String apiSecret,
- required ResponseCallback onResponse,
- }) {
- _instance ??= Xunfei_AudioToText._internal(
- appId: appId,
- apiKey: apiKey,
- apiSecret: apiSecret,
- onResponse: onResponse,
- );
- return _instance!;
- }
-
- // 创建 WebSocket URL
- String _createUrl() {
- final now = DateTime.now();
- final date =
- DateFormat("EEE, dd MMM yyyy HH:mm:ss 'GMT'").format(now.toUtc());
- final signatureOrigin =
- "host: $host\ndate: $date\nGET $requestUri HTTP/1.1";
-
- // 使用 HmacUtil 计算 HMAC-SHA256 签名
- final signature = _hmacSha256(apiSecret, signatureOrigin);
-
- final authorization = base64.encode(utf8.encode(
- "hmac username=\"$apiKey\", algorithm=\"hmac-sha256\", headers=\"host date request-line\", signature=\"$signature\""));
-
- final queryParams = {
- "host": host,
- "date": date,
- "authorization": authorization,
- };
-
- final wsUri =
- 'ws://$host$requestUri?${Uri(queryParameters: queryParams).query}';
- return wsUri;
- }
-
- //测试sdk
- Future<void> start() async {
- String wsUrl = _createUrl();
- await _connect(wsUrl);
- await Future.delayed(const Duration(seconds: 3));
- return;
- }
-
- // 上传音频
- Future<void> pushaudio(Stream<List<int>> audioStream) async {
- int frameSize = 1280; // 每一帧的音频大小
- double interval = 0.04; // 发送音频间隔(单位:s)
- int status = STATUS_FIRST_FRAME; // 音频的状态信息,标识音频是第一帧,还是中间帧、最后一帧
- currtext = Xunfei_AudioToText_Result_Text();
- int index = 0;
- List<int> buffer = [];
- try {
- await for (List<int> frame in audioStream) {
- // 将音频数据添加到 buffer
- buffer.addAll(frame);
- while (buffer.length >= frameSize) {
- List<int> sendFrame = buffer.sublist(0, frameSize);
- buffer = buffer.sublist(frameSize);
-
- // 判断是否读取到足够的帧
- if (index + frameSize <= buffer.length) {
- frame = buffer.sublist(index, index + frameSize);
- index += frameSize;
- } else {
- frame = buffer.sublist(index);
- index = buffer.length; // 结束
- }
-
- // 第一帧处理
- if (status == STATUS_FIRST_FRAME) {
- final param = {
- "common": {
- "app_id": appId,
- },
- "business": {
- "language": "zh_cn",
- "domain": "iat",
- "accent": "mandarin",
- },
- "data": {
- "status": status,
- "format": "audio/L16;rate=16000",
- "audio": base64Encode(sendFrame),
- "encoding": "raw",
- }
- };
- String data = json.encode(param);
- _channel?.sink.add(data);
- // print('第一帧已发送...' + data);
- status = STATUS_CONTINUE_FRAME;
- }
- // 中间帧处理
- else if (status == STATUS_CONTINUE_FRAME) {
- final param = {
- "data": {
- "status": status,
- "format": "audio/L16;rate=16000",
- "audio": base64Encode(sendFrame),
- "encoding": "raw",
- }
- };
- String data = json.encode(param);
- _channel?.sink.add(data);
- // print('中间帧已发送...');
- }
- // 最后一帧处理
- else if (status == STATUS_LAST_FRAME) {
- final param = {
- "data": {
- "status": status,
- "format": "audio/L16;rate=16000",
- "audio": base64Encode(sendFrame),
- "encoding": "raw",
- }
- };
- // print('最后一帧已发送...');
- String data = json.encode(param);
- _channel?.sink.add(data);
- break;
- }
- // 模拟音频采样间隔
- await Future.delayed(
- Duration(milliseconds: (interval * 1000).toInt()));
- }
- }
- status = STATUS_LAST_FRAME;
- String data = json.encode({
- "data": {
- "status": status,
- "format": "audio/L16;rate=16000",
- "audio": base64Encode([]),
- "encoding": "raw",
- }
- });
- _channel?.sink.add(data);
- } catch (e) {
- print("push msg: $e");
- }
-
- print('音频处理完成');
- }
-
- // 创建WebSocket连接
- Future<void> _connect(String url) async {
- _channel = WebSocketChannel.connect(Uri.parse(url));
- _channel?.stream.listen(
- (message) {
- onMessage(message);
- },
- onError: (error) {
- print('连接失败: $error');
- },
- onDone: () {
- print('WebSocket 连接已关闭');
- },
- cancelOnError: true,
- );
- Future.delayed(const Duration(seconds: 1));
- }
-
- Future<void> onMessage(String message) async {}
-
- // 使用SHA-256算法计算HMAC
- String _hmacSha256(String key, String message) {
- var keyBytes = utf8.encode(key); // 将密钥转为字节数组
- var messageBytes = utf8.encode(message); // 将消息转为字节数组
- var hmac = Hmac(sha256, keyBytes); // 创建 HMAC 对象,指定哈希算法和密钥
- var digest = hmac.convert(messageBytes); // 计算消息的哈希
- return base64.encode(digest.bytes); // 返回 base64 编码的哈希值
- }
- }
|