提交 e1f79b8e 作者: 王苏进

feat: 实现完成

上级 67d744f6
...@@ -2,18 +2,26 @@ package com.yourcompany.aivoiceplugin; ...@@ -2,18 +2,26 @@ package com.yourcompany.aivoiceplugin;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import io.flutter.embedding.engine.plugins.FlutterPlugin; import io.flutter.embedding.engine.plugins.FlutterPlugin;
import io.flutter.plugin.common.EventChannel;
import io.flutter.plugin.common.MethodCall; import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel; import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.MethodChannel.MethodCallHandler; import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
import io.flutter.plugin.common.MethodChannel.Result; import io.flutter.plugin.common.MethodChannel.Result;
import java.util.HashMap;
import java.util.Map;
public class AivoicePlugin implements FlutterPlugin, MethodCallHandler { public class AivoicePlugin implements FlutterPlugin, MethodCallHandler, EventChannel.StreamHandler {
private MethodChannel channel; private MethodChannel channel;
private EventChannel eventChannel;
private EventChannel.EventSink eventSink;
@Override @Override
public void onAttachedToEngine(@NonNull FlutterPluginBinding flutterPluginBinding) { public void onAttachedToEngine(@NonNull FlutterPluginBinding flutterPluginBinding) {
channel = new MethodChannel(flutterPluginBinding.getBinaryMessenger(), "aivoice_plugin"); channel = new MethodChannel(flutterPluginBinding.getBinaryMessenger(), "aivoice_plugin");
channel.setMethodCallHandler(this); channel.setMethodCallHandler(this);
eventChannel = new EventChannel(flutterPluginBinding.getBinaryMessenger(), "aivoice_plugin/events");
eventChannel.setStreamHandler(this);
} }
@Override @Override
...@@ -40,5 +48,23 @@ public class AivoicePlugin implements FlutterPlugin, MethodCallHandler { ...@@ -40,5 +48,23 @@ public class AivoicePlugin implements FlutterPlugin, MethodCallHandler {
@Override @Override
public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) { public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) {
channel.setMethodCallHandler(null); channel.setMethodCallHandler(null);
eventChannel.setStreamHandler(null);
}
@Override
public void onListen(Object arguments, EventChannel.EventSink events) {
eventSink = events;
}
@Override
public void onCancel(Object arguments) {
eventSink = null;
}
// 新增的发送 Map<String, dynamic> 方法
private void sendMapToFlutter(Map<String, Object> message) {
if (eventSink != null) {
eventSink.success(message);
}
} }
} }
\ No newline at end of file
...@@ -6,20 +6,17 @@ ...@@ -6,20 +6,17 @@
// For more information about Flutter integration tests, please see // For more information about Flutter integration tests, please see
// https://docs.flutter.dev/cookbook/testing/integration/introduction // https://docs.flutter.dev/cookbook/testing/integration/introduction
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart'; import 'package:integration_test/integration_test.dart';
import 'package:aivoice_plugin/aivoice_plugin.dart';
void main() { void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized(); IntegrationTestWidgetsFlutterBinding.ensureInitialized();
testWidgets('getPlatformVersion test', (WidgetTester tester) async { testWidgets('getPlatformVersion test', (WidgetTester tester) async {
final AivoicePlugin plugin = AivoicePlugin(); // final AivoicePlugin plugin = AivoicePlugin();
final String? version = await plugin.getPlatformVersion(); // final String? version = await plugin.getPlatformVersion();
// The version string depends on the host platform running the test, so // // The version string depends on the host platform running the test, so
// just assert that some non-empty string is returned. // // just assert that some non-empty string is returned.
expect(version?.isNotEmpty, true); // expect(version?.isNotEmpty, true);
}); });
} }
...@@ -97,7 +97,6 @@ ...@@ -97,7 +97,6 @@
E774E85DB7E797F8A4A2605C /* Pods-RunnerTests.release.xcconfig */, E774E85DB7E797F8A4A2605C /* Pods-RunnerTests.release.xcconfig */,
8BDA28280F6BDBDBFE64ACEF /* Pods-RunnerTests.profile.xcconfig */, 8BDA28280F6BDBDBFE64ACEF /* Pods-RunnerTests.profile.xcconfig */,
); );
name = Pods;
path = Pods; path = Pods;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
...@@ -471,7 +470,7 @@ ...@@ -471,7 +470,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = ZTL5A6WMHV; DEVELOPMENT_TEAM = RPKZNKHR3T;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
...@@ -654,7 +653,7 @@ ...@@ -654,7 +653,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = ZTL5A6WMHV; DEVELOPMENT_TEAM = RPKZNKHR3T;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
...@@ -677,7 +676,7 @@ ...@@ -677,7 +676,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = ZTL5A6WMHV; DEVELOPMENT_TEAM = RPKZNKHR3T;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
......
import UIKit import UIKit
import Flutter import Flutter
import aivoice_plugin
@UIApplicationMain @UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate { @objc class AppDelegate: FlutterAppDelegate {
...@@ -8,6 +9,29 @@ import Flutter ...@@ -8,6 +9,29 @@ import Flutter
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool { ) -> Bool {
GeneratedPluginRegistrant.register(with: self) GeneratedPluginRegistrant.register(with: self)
let ret = SpeechEngine.prepareEnvironment();
if ret {
setupResourceManager()
}
return super.application(application, didFinishLaunchingWithOptions: launchOptions) return super.application(application, didFinishLaunchingWithOptions: launchOptions)
} }
func setupResourceManager() {
let ins = SpeechResourceManager.shareInstance()
ins.setAppId(SDEF_APPID)
ins.setAppVersion("1.0.0")
if let documentDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first {
let modelsPath = documentDirectory.appendingPathComponent("models").path
ins.setRootPath(modelsPath)
}
ins.setOnlineModelEnable(true)
ins.setup()
}
} }
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="10117" systemVersion="15F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="BYZ-38-t0r"> <document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="22155" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
<device id="retina6_12" orientation="portrait" appearance="light"/>
<dependencies> <dependencies>
<deployment identifier="iOS"/> <deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10085"/> <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="22131"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies> </dependencies>
<scenes> <scenes>
<!--Flutter View Controller--> <!--Flutter View Controller-->
...@@ -14,13 +16,14 @@ ...@@ -14,13 +16,14 @@
<viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/> <viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
</layoutGuides> </layoutGuides>
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC"> <view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/> <rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/> <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</view> </view>
</viewController> </viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/> <placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
</objects> </objects>
<point key="canvasLocation" x="-16" y="-40"/>
</scene> </scene>
</scenes> </scenes>
</document> </document>
...@@ -45,5 +45,17 @@ ...@@ -45,5 +45,17 @@
<true/> <true/>
<key>UIApplicationSupportsIndirectInputEvents</key> <key>UIApplicationSupportsIndirectInputEvents</key>
<true/> <true/>
<key>UIBackgroundModes</key>
<array>
<string>audio</string>
</array>
<key>NSMicrophoneUsageDescription</key>
<string>Speech demo would like to access your recorder data.</string>
<key>UIFileSharingEnabled</key>
<true/>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>armv7</string>
</array>
</dict> </dict>
</plist> </plist>
import 'package:flutter/material.dart';
import 'dart:async'; import 'dart:async';
import 'package:flutter/services.dart';
import 'package:aivoice_plugin/aivoice_plugin.dart'; import 'package:aivoice_plugin/aivoice_plugin.dart';
import 'package:flutter/material.dart';
void main() { void main() {
runApp(const MyApp()); runApp(const MyApp());
...@@ -16,35 +15,30 @@ class MyApp extends StatefulWidget { ...@@ -16,35 +15,30 @@ class MyApp extends StatefulWidget {
} }
class _MyAppState extends State<MyApp> { class _MyAppState extends State<MyApp> {
String _platformVersion = 'Unknown'; final String _platformVersion = 'Unknown';
final _aivoicePlugin = AivoicePlugin(); final _aivoicePlugin = AivoicePlugin();
String _text = '';
@override @override
void initState() { void initState() {
super.initState(); super.initState();
initPlatformState(); initPlatformState();
_aivoicePlugin.onAsrResultReceived.listen((event) {
setState(() {
_text = event["text"];
});
// print(event["text"]);
});
// _aivoicePlugin.initEngine({});
} }
// Platform messages are asynchronous, so we initialize in an async method. // Platform messages are asynchronous, so we initialize in an async method.
Future<void> initPlatformState() async { Future<void> initPlatformState() async {
String platformVersion;
// Platform messages may fail, so we use a try/catch PlatformException.
// We also handle the message potentially returning null.
try {
platformVersion =
await _aivoicePlugin.getPlatformVersion() ?? 'Unknown platform version';
} on PlatformException {
platformVersion = 'Failed to get platform version.';
}
// If the widget was removed from the tree while the asynchronous platform
// message was in flight, we want to discard the reply rather than calling
// setState to update our non-existent appearance.
if (!mounted) return; if (!mounted) return;
setState(() { setState(() {});
_platformVersion = platformVersion;
});
} }
@override @override
...@@ -55,7 +49,30 @@ class _MyAppState extends State<MyApp> { ...@@ -55,7 +49,30 @@ class _MyAppState extends State<MyApp> {
title: const Text('Plugin example app'), title: const Text('Plugin example app'),
), ),
body: Center( body: Center(
child: Text('Running on: $_platformVersion\n'), child: Row(
children: [
Expanded(child: Text('识别结果是: $_text')),
],
),
),
floatingActionButton: Row(
children: [
TextButton(
onPressed: () {
_aivoicePlugin.initEngine({});
},
child: const Text('init')),
TextButton(
onPressed: () {
_aivoicePlugin.startOrStopEngine(true);
},
child: const Text('start')),
TextButton(
onPressed: () {
_aivoicePlugin.stopEngine();
},
child: const Text('stop')),
],
), ),
), ),
); );
......
#import "AivoicePlugin.h" #import "AivoicePlugin.h"
#import "VoiceAsr.h"
@interface AivoicePlugin () @interface AivoicePlugin () <FlutterStreamHandler, VoiceAsrDelegate>
@property (nonatomic, strong) FlutterEventSink eventSink;
@property(nonatomic, strong)VoiceAsr * voiceAsr;
@end @end
@implementation AivoicePlugin @implementation AivoicePlugin
...@@ -11,26 +14,66 @@ ...@@ -11,26 +14,66 @@
binaryMessenger:[registrar messenger]]; binaryMessenger:[registrar messenger]];
AivoicePlugin* instance = [[AivoicePlugin alloc] init]; AivoicePlugin* instance = [[AivoicePlugin alloc] init];
[registrar addMethodCallDelegate:instance channel:channel]; [registrar addMethodCallDelegate:instance channel:channel];
FlutterEventChannel* eventChannel = [FlutterEventChannel
eventChannelWithName:@"aivoice_plugin/events"
binaryMessenger:[registrar messenger]];
[eventChannel setStreamHandler:instance];
} }
- (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result { - (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result {
// 删除了 getPlatformVersion 方法的实现 // 删除了 getPlatformVersion 方法的实现
if ([@"initEngine" isEqualToString:call.method]) { if ([@"initEngine" isEqualToString:call.method]) {
// 空实现 [self.voiceAsr initEngine];
result(nil); result(nil);
} else if ([@"stopEngine" isEqualToString:call.method]) { } else if ([@"stopEngine" isEqualToString:call.method]) {
// 空实现 [self.voiceAsr stopEngineBtnClicked];
result(nil); result(nil);
} else if ([@"uninitEngine" isEqualToString:call.method]) { } else if ([@"uninitEngine" isEqualToString:call.method]) {
// 空实现 [self.voiceAsr uninitEngine];
result(nil); result(nil);
} else if ([@"startOrStopEngine" isEqualToString:call.method]) { } else if ([@"startOrStopEngine" isEqualToString:call.method]) {
// 空实现
// BOOL arg = [NSNumber numberWithBool:call.arguments];
[self.voiceAsr startEngineBtnClicked];
result(nil); result(nil);
} else { } else {
result(FlutterMethodNotImplemented); result(FlutterMethodNotImplemented);
} }
} }
- (FlutterError* _Nullable)onListenWithArguments:(id _Nullable)arguments eventSink:(FlutterEventSink)events {
self.eventSink = events;
return nil;
}
- (FlutterError* _Nullable)onCancelWithArguments:(id _Nullable)arguments {
self.eventSink = nil;
return nil;
}
// 新增的发送 Map<String, dynamic> 方法
- (void)sendMessageToFlutter:(NSDictionary*)message {
if (self.eventSink) {
self.eventSink(message);
}
}
- (VoiceAsr *)voiceAsr {
if(!_voiceAsr) {
_voiceAsr = [[VoiceAsr alloc] initWithDelegate:self];
}
return _voiceAsr;
}
- (void)onRecieve:(nonnull NSDictionary *)message {
[self sendMessageToFlutter:message];
}
@end @end
...@@ -151,8 +151,20 @@ extern NSString *const SETTING_AU_PROCESS_TIMEOUT; ...@@ -151,8 +151,20 @@ extern NSString *const SETTING_AU_PROCESS_TIMEOUT;
extern NSString *const SETTING_AU_AUDIO_PACKET_DURATION; extern NSString *const SETTING_AU_AUDIO_PACKET_DURATION;
extern NSString *const SETTING_AU_EMPTY_PACKET_INTERVAL; extern NSString *const SETTING_AU_EMPTY_PACKET_INTERVAL;
#pragma mark - SETTING_HELPER #pragma mark - SETTING_HELPER
@interface SettingsHelper : NSObject @interface SettingsHelper : NSObject
@property (strong, nonatomic) Settings* asrSettings;
@property (strong, nonatomic) Settings* asrOfflineSettings;
@property (strong, nonatomic) Settings* captSettings;
@property (strong, nonatomic) Settings* fulllinkSettings;
@property (strong, nonatomic) Settings* ttsSettings;
@property (strong, nonatomic) Settings* voiceCloneSettings;
@property (strong, nonatomic) Settings* voiceConvSettings;
@property (strong, nonatomic) Settings* dialogSettings;
@property (strong, nonatomic) Settings* vadSettings;
@property (strong, nonatomic) Settings* auSettings;
+ (instancetype)shareInstance; + (instancetype)shareInstance;
...@@ -160,4 +172,7 @@ extern NSString *const SETTING_AU_EMPTY_PACKET_INTERVAL; ...@@ -160,4 +172,7 @@ extern NSString *const SETTING_AU_EMPTY_PACKET_INTERVAL;
@end @end
NS_ASSUME_NONNULL_END NS_ASSUME_NONNULL_END
...@@ -12,20 +12,11 @@ ...@@ -12,20 +12,11 @@
#import "SensitiveDefines.h" #import "SensitiveDefines.h"
@interface SettingsHelper() @interface SettingsHelper()
@property (strong, nonatomic) Settings* asrSettings;
@property (strong, nonatomic) Settings* asrOfflineSettings;
@property (strong, nonatomic) Settings* captSettings;
@property (strong, nonatomic) Settings* fulllinkSettings;
@property (strong, nonatomic) Settings* ttsSettings;
@property (strong, nonatomic) Settings* voiceCloneSettings;
@property (strong, nonatomic) Settings* voiceConvSettings;
@property (strong, nonatomic) Settings* dialogSettings;
@property (strong, nonatomic) Settings* vadSettings;
@property (strong, nonatomic) Settings* auSettings;
@end @end
@implementation SettingsHelper @implementation SettingsHelper
#pragma mark - SETTING_KEY #pragma mark - SETTING_KEY
...@@ -515,4 +506,6 @@ static NSArray* SETTING_OPTIONS_AU_ABILITY(void) { ...@@ -515,4 +506,6 @@ static NSArray* SETTING_OPTIONS_AU_ABILITY(void) {
@end @end
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
// //
#import "StreamRecorder.h" #import "StreamRecorder.h"
#import "SettingsHelper.h" //#import "SettingsHelper.h"
#import <AVFoundation/AVFoundation.h> #import <AVFoundation/AVFoundation.h>
#define INPUT_BUS 1 #define INPUT_BUS 1
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
@property (assign, nonatomic) BOOL initted; @property (assign, nonatomic) BOOL initted;
@property (weak, nonatomic) SpeechEngine *curEngine; @property (weak, nonatomic) SpeechEngine *curEngine;
@property (weak, nonatomic) NSString *curViewId; //@property (weak, nonatomic) NSString *curViewId;
@property (assign, atomic) int16_t* packageData; @property (assign, atomic) int16_t* packageData;
@property (assign, nonatomic) int packageSize; // Size in int16_t @property (assign, nonatomic) int packageSize; // Size in int16_t
@property (assign, nonatomic) int packageTotalSize; // Size in int16_t @property (assign, nonatomic) int packageTotalSize; // Size in int16_t
...@@ -56,7 +56,7 @@ AudioUnit audioUnit; ...@@ -56,7 +56,7 @@ AudioUnit audioUnit;
} }
- (void)setSpeechEngine:(NSString *) viewId engine:(SpeechEngine *)engine { - (void)setSpeechEngine:(NSString *) viewId engine:(SpeechEngine *)engine {
self.curViewId = viewId; // self.curViewId = viewId;
self.curEngine = engine; self.curEngine = engine;
} }
...@@ -65,8 +65,8 @@ AudioUnit audioUnit; ...@@ -65,8 +65,8 @@ AudioUnit audioUnit;
return FALSE; return FALSE;
} }
@synchronized (self) { @synchronized (self) {
Settings *settings = [[SettingsHelper shareInstance]getSettings:self.curViewId]; // Settings *settings = [[SettingsHelper shareInstance]getSettings:self.curViewId];
self.packageDuration = [settings getInt:SETTING_STREAM_PACKAGE_DURATION def:DEFAULT_PACKAGE_DURATION]; self.packageDuration = DEFAULT_PACKAGE_DURATION;
self.packageTotalSize = (int)((long) REC_SAMPLE_RATE * REC_CHANNEL * 16 / 8 * self.packageDuration / 1000 / sizeof(int16_t)); self.packageTotalSize = (int)((long) REC_SAMPLE_RATE * REC_CHANNEL * 16 / 8 * self.packageDuration / 1000 / sizeof(int16_t));
self.packageData = (int16_t*) malloc(self.packageTotalSize * sizeof(int16_t)); self.packageData = (int16_t*) malloc(self.packageTotalSize * sizeof(int16_t));
self.packageSize = 0; self.packageSize = 0;
......
...@@ -9,8 +9,26 @@ ...@@ -9,8 +9,26 @@
NS_ASSUME_NONNULL_BEGIN NS_ASSUME_NONNULL_BEGIN
@protocol VoiceAsrDelegate <NSObject>
- (void)onRecieve:(NSDictionary*)message;
@end
@interface VoiceAsr : NSObject @interface VoiceAsr : NSObject
- (instancetype)initWithDelegate:(id<VoiceAsrDelegate>)delegate;
- (void)initEngine;
- (void)uninitEngine;
- (void)startEngineBtnClicked;
- (void)stopEngineBtnClicked;
- (void)startEngineByLongPress:(BOOL)isBegin;
@end @end
NS_ASSUME_NONNULL_END NS_ASSUME_NONNULL_END
...@@ -31,24 +31,44 @@ ...@@ -31,24 +31,44 @@
@property (strong, nonatomic) Settings *settings; @property (strong, nonatomic) Settings *settings;
// APP 层自定义的录音机,在音频来源为 Stream 时使用 // APP 层自定义的录音机,在音频来源为 Stream 时使用
@property (weak, nonatomic) StreamRecorder *streamRecorder; @property (strong, nonatomic) StreamRecorder *streamRecorder;
// 一些用于统计的字段 // 一些用于统计的字段
@property (nonatomic, assign) long talkingFinisheTimestamp; @property (nonatomic, assign) long talkingFinisheTimestamp;
@property (nonatomic, weak) id<VoiceAsrDelegate> delegate;
@end @end
@implementation VoiceAsr @implementation VoiceAsr
- (instancetype)init {
return [self initWithDelegate:nil];
}
- (instancetype)initWithDelegate:(id<VoiceAsrDelegate>)delegate {
self = [super init];
if (self) {
self.delegate = delegate;
self.streamRecorder = [[StreamRecorder alloc] init];
self.settings = [SettingsHelper shareInstance].asrSettings;
}
return self;
}
#pragma mark - UI Actions #pragma mark - UI Actions
- (void)startEngineBtnClicked { - (void)startEngineBtnClicked {
[self setResultText:@""]; [self setResultText:@""];
NSLog(@"配置启动参数"); NSLog(@"配置启动参数");
[self configStartAsrParams]; [self configStartAsrParams];
...@@ -73,7 +93,7 @@ ...@@ -73,7 +93,7 @@
[self.curEngine sendDirective:SEDirectiveStopEngine]; [self.curEngine sendDirective:SEDirectiveStopEngine];
} }
- (void)startEngineByLongPress:(bool)isBegin { - (void)startEngineByLongPress:(BOOL)isBegin {
if (isBegin) { if (isBegin) {
[self setResultText:@""]; [self setResultText:@""];
...@@ -414,6 +434,9 @@ ...@@ -414,6 +434,9 @@
[text appendFormat:@"\nreqid: %@", [jsonResult objectForKey:@"reqid"]]; [text appendFormat:@"\nreqid: %@", [jsonResult objectForKey:@"reqid"]];
[text appendFormat:@"\nresponse_delay: %ld", response_delay]; [text appendFormat:@"\nresponse_delay: %ld", response_delay];
} }
if([self.delegate respondsToSelector:@selector(onRecieve:)]) {
[self.delegate onRecieve:@{@"text" : [text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]], @"isFinal" : @(isFinal)}];
}
[self setResultText:[text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]]; [self setResultText:[text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]];
}); });
} }
...@@ -440,6 +463,7 @@ ...@@ -440,6 +463,7 @@
#pragma mark - Helper #pragma mark - Helper
- (NSString *)getRecorderType { - (NSString *)getRecorderType {
SettingOptions* recorderTypeOptions = [self.settings getOptions:SETTING_RECORD_TYPE]; SettingOptions* recorderTypeOptions = [self.settings getOptions:SETTING_RECORD_TYPE];
switch (recorderTypeOptions.chooseIdx) { switch (recorderTypeOptions.chooseIdx) {
case 0: case 0:
...@@ -451,7 +475,7 @@ ...@@ -451,7 +475,7 @@
default: default:
break; break;
} }
return @""; return SE_RECORDER_TYPE_STREAM;
} }
- (void)setResultText:(NSString *)result { - (void)setResultText:(NSString *)result {
......
import 'package:flutter/services.dart';
import 'aivoice_plugin_platform_interface.dart'; import 'aivoice_plugin_platform_interface.dart';
class AivoicePlugin { class AivoicePlugin {
...@@ -22,4 +24,11 @@ class AivoicePlugin { ...@@ -22,4 +24,11 @@ class AivoicePlugin {
Future<void> startOrStopEngine(bool isBegin) { Future<void> startOrStopEngine(bool isBegin) {
return AivoicePluginPlatform.instance.startOrStopEngine(isBegin); return AivoicePluginPlatform.instance.startOrStopEngine(isBegin);
} }
// 新增的监听方法
static const EventChannel _eventChannel = EventChannel('aivoice_plugin/events');
Stream<Map<String, dynamic>> get onAsrResultReceived {
return _eventChannel.receiveBroadcastStream().map((event) => Map<String, dynamic>.from(event));
}
} }
...@@ -6,11 +6,6 @@ class MethodChannelAivoicePlugin extends AivoicePluginPlatform { ...@@ -6,11 +6,6 @@ class MethodChannelAivoicePlugin extends AivoicePluginPlatform {
final MethodChannel _channel = const MethodChannel('aivoice_plugin'); final MethodChannel _channel = const MethodChannel('aivoice_plugin');
@override @override
Future<String?> getPlatformVersion() {
return _channel.invokeMethod<String>('getPlatformVersion');
}
@override
Future<void> initEngine(Map<String, dynamic> config) { Future<void> initEngine(Map<String, dynamic> config) {
return _channel.invokeMethod<void>('initEngine', config); return _channel.invokeMethod<void>('initEngine', config);
} }
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论