Compare commits

..

No commits in common. "c47ad5c4358bff3c7836fa08e890a41b02966ebc" and "5c9a8ea6e6921cdd838d7efd3a2b57b9b8b661ad" have entirely different histories.

35 changed files with 6816 additions and 100 deletions

View File

@ -0,0 +1,31 @@
Extension Discovery Cache
=========================
This folder is used by `package:extension_discovery` to cache lists of
packages that contains extensions for other packages.
DO NOT USE THIS FOLDER
----------------------
* Do not read (or rely) the contents of this folder.
* Do write to this folder.
If you're interested in the lists of extensions stored in this folder use the
API offered by package `extension_discovery` to get this information.
If this package doesn't work for your use-case, then don't try to read the
contents of this folder. It may change, and will not remain stable.
Use package `extension_discovery`
---------------------------------
If you want to access information from this folder.
Feel free to delete this folder
-------------------------------
Files in this folder act as a cache, and the cache is discarded if the files
are older than the modification time of `.dart_tool/package_config.json`.
Hence, it should never be necessary to clear this cache manually, if you find a
need to do please file a bug.

View File

@ -0,0 +1 @@
{"version":2,"entries":[{"package":"yx_asr","rootUri":"../","packageUri":"lib/"}]}

View File

@ -0,0 +1 @@
{"version":2,"entries":[{"package":"yx_asr","rootUri":"../","packageUri":"lib/"}]}

View File

@ -0,0 +1,32 @@
//
// Generated file. Do not edit.
// This file is generated from template in file `flutter_tools/lib/src/flutter_plugins.dart`.
//
// @dart = 3.0
import 'dart:io'; // flutter_ignore: dart_io_import.
import 'package:record_linux/record_linux.dart';
@pragma('vm:entry-point')
class _PluginRegistrant {
@pragma('vm:entry-point')
static void register() {
if (Platform.isAndroid) {
} else if (Platform.isIOS) {
} else if (Platform.isLinux) {
try {
RecordLinux.registerWith();
} catch (err) {
print(
'`record_linux` threw an error: $err. '
'The app may not function as expected until you remove this plugin from pubspec.yaml'
);
}
} else if (Platform.isMacOS) {
} else if (Platform.isWindows) {
}
}
}

View File

@ -252,8 +252,8 @@ file:///Users/max/.pub-cache/hosted/pub.flutter-io.cn/xdg_directories-1.1.0/
file:///Users/max/.pub-cache/hosted/pub.flutter-io.cn/xdg_directories-1.1.0/lib/ file:///Users/max/.pub-cache/hosted/pub.flutter-io.cn/xdg_directories-1.1.0/lib/
yx_asr yx_asr
3.0 3.0
file:///Users/max/SourceCode/yuanxuan/yx_speech_to_text_flutter/ file:///Users/max/SourceCode/yuanxuan/yx_asr/
file:///Users/max/SourceCode/yuanxuan/yx_speech_to_text_flutter/lib/ file:///Users/max/SourceCode/yuanxuan/yx_asr/lib/
sky_engine sky_engine
3.7 3.7
file:///Users/max/fvm/versions/3.32.0/bin/cache/pkg/sky_engine/ file:///Users/max/fvm/versions/3.32.0/bin/cache/pkg/sky_engine/

View File

@ -88,18 +88,6 @@
"vm_service" "vm_service"
] ]
}, },
{
"name": "path_provider",
"version": "2.1.5",
"dependencies": [
"flutter",
"path_provider_android",
"path_provider_foundation",
"path_provider_linux",
"path_provider_platform_interface",
"path_provider_windows"
]
},
{ {
"name": "record", "name": "record",
"version": "6.1.1", "version": "6.1.1",
@ -373,52 +361,6 @@
"webdriver" "webdriver"
] ]
}, },
{
"name": "path_provider_windows",
"version": "2.3.0",
"dependencies": [
"ffi",
"flutter",
"path",
"path_provider_platform_interface"
]
},
{
"name": "path_provider_platform_interface",
"version": "2.1.2",
"dependencies": [
"flutter",
"platform",
"plugin_platform_interface"
]
},
{
"name": "path_provider_linux",
"version": "2.2.1",
"dependencies": [
"ffi",
"flutter",
"path",
"path_provider_platform_interface",
"xdg_directories"
]
},
{
"name": "path_provider_foundation",
"version": "2.4.2",
"dependencies": [
"flutter",
"path_provider_platform_interface"
]
},
{
"name": "path_provider_android",
"version": "2.2.17",
"dependencies": [
"flutter",
"path_provider_platform_interface"
]
},
{ {
"name": "record_macos", "name": "record_macos",
"version": "1.1.1", "version": "1.1.1",
@ -601,21 +543,6 @@
"vm_service" "vm_service"
] ]
}, },
{
"name": "plugin_platform_interface",
"version": "2.1.8",
"dependencies": [
"meta"
]
},
{
"name": "xdg_directories",
"version": "1.1.0",
"dependencies": [
"meta",
"path"
]
},
{ {
"name": "web", "name": "web",
"version": "1.1.1", "version": "1.1.1",
@ -633,6 +560,13 @@
"vector_math" "vector_math"
] ]
}, },
{
"name": "plugin_platform_interface",
"version": "2.1.8",
"dependencies": [
"meta"
]
},
{ {
"name": "fixnum", "name": "fixnum",
"version": "1.1.1", "version": "1.1.1",
@ -656,6 +590,72 @@
"dependencies": [ "dependencies": [
"collection" "collection"
] ]
},
{
"name": "path_provider",
"version": "2.1.5",
"dependencies": [
"flutter",
"path_provider_android",
"path_provider_foundation",
"path_provider_linux",
"path_provider_platform_interface",
"path_provider_windows"
]
},
{
"name": "path_provider_linux",
"version": "2.2.1",
"dependencies": [
"ffi",
"flutter",
"path",
"path_provider_platform_interface",
"xdg_directories"
]
},
{
"name": "path_provider_windows",
"version": "2.3.0",
"dependencies": [
"ffi",
"flutter",
"path",
"path_provider_platform_interface"
]
},
{
"name": "path_provider_platform_interface",
"version": "2.1.2",
"dependencies": [
"flutter",
"platform",
"plugin_platform_interface"
]
},
{
"name": "path_provider_foundation",
"version": "2.4.2",
"dependencies": [
"flutter",
"path_provider_platform_interface"
]
},
{
"name": "xdg_directories",
"version": "1.1.0",
"dependencies": [
"meta",
"path"
]
},
{
"name": "path_provider_android",
"version": "2.2.17",
"dependencies": [
"flutter",
"path_provider_platform_interface"
]
} }
], ],
"configVersion": 1 "configVersion": 1

File diff suppressed because one or more lines are too long

View File

@ -2,14 +2,14 @@ group 'com.yuanxuan.yx_asr'
version '1.0.0' version '1.0.0'
buildscript { buildscript {
ext.kotlin_version = '1.8.22' ext.kotlin_version = '1.7.10'
repositories { repositories {
google() google()
mavenCentral() mavenCentral()
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:8.1.0' classpath 'com.android.tools.build:gradle:7.3.0'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
} }
} }
@ -25,7 +25,6 @@ apply plugin: 'com.android.library'
apply plugin: 'kotlin-android' apply plugin: 'kotlin-android'
android { android {
namespace 'com.yuanxuan.yx_asr'
compileSdkVersion 33 compileSdkVersion 33
compileOptions { compileOptions {

View File

@ -81,9 +81,7 @@ class YxAsrPlugin: FlutterPlugin, MethodCallHandler, ActivityAware, PluginRegist
override fun onMethodCall(call: MethodCall, result: Result) { override fun onMethodCall(call: MethodCall, result: Result) {
when (call.method) { when (call.method) {
"isAvailable" -> { "isAvailable" -> {
context?.let { result.success(SpeechRecognizer.isRecognitionAvailable(context))
result.success(SpeechRecognizer.isRecognitionAvailable(it))
} ?: result.success(false)
} }
"hasPermission" -> { "hasPermission" -> {
result.success(hasPermission()) result.success(hasPermission())

View File

@ -0,0 +1 @@
{"format-version":[1,0,0],"native-assets":{}}

View File

@ -0,0 +1 @@
assets/models/README.md  assetassets/models/README.md.assets/models/decoder-epoch-99-avg-1.int8.onnx  asset.assets/models/decoder-epoch-99-avg-1.int8.onnx.assets/models/encoder-epoch-99-avg-1.int8.onnx  asset.assets/models/encoder-epoch-99-avg-1.int8.onnx-assets/models/joiner-epoch-99-avg-1.int8.onnx  asset-assets/models/joiner-epoch-99-avg-1.int8.onnxassets/models/tokens.txt  assetassets/models/tokens.txt7packages/record_web/assets/js/record.fixwebmduration.js  asset7packages/record_web/assets/js/record.fixwebmduration.js/packages/record_web/assets/js/record.worklet.js  asset/packages/record_web/assets/js/record.worklet.js

View File

@ -0,0 +1 @@
{"assets/models/README.md":["assets/models/README.md"],"assets/models/decoder-epoch-99-avg-1.int8.onnx":["assets/models/decoder-epoch-99-avg-1.int8.onnx"],"assets/models/encoder-epoch-99-avg-1.int8.onnx":["assets/models/encoder-epoch-99-avg-1.int8.onnx"],"assets/models/joiner-epoch-99-avg-1.int8.onnx":["assets/models/joiner-epoch-99-avg-1.int8.onnx"],"assets/models/tokens.txt":["assets/models/tokens.txt"],"packages/record_web/assets/js/record.fixwebmduration.js":["packages/record_web/assets/js/record.fixwebmduration.js"],"packages/record_web/assets/js/record.worklet.js":["packages/record_web/assets/js/record.worklet.js"]}

View File

@ -0,0 +1 @@
[]

Binary file not shown.

View File

@ -0,0 +1 @@
{"format-version":[1,0,0],"native-assets":{}}

View File

@ -0,0 +1,56 @@
# 语音识别模型文件
这个目录包含了 sherpa_onnx 语音识别所需的模型文件。
## 模型结构
```
assets/models/
├── zh-cn/ # 中文模型
│ ├── encoder.onnx # 编码器模型
│ ├── decoder.onnx # 解码器模型
│ ├── joiner.onnx # 连接器模型
│ └── tokens.txt # 词汇表
├── en-us/ # 英文模型
│ ├── encoder.onnx
│ ├── decoder.onnx
│ ├── joiner.onnx
│ └── tokens.txt
└── multilingual/ # 多语言模型
├── encoder.onnx
├── decoder.onnx
├── joiner.onnx
└── tokens.txt
```
## 模型下载
由于模型文件较大,请从以下地址下载对应的模型文件:
### 中文模型 (推荐)
- 模型名称: sherpa-onnx-streaming-zipformer-bilingual-zh-en-2023-02-20
- 下载地址: https://github.com/k2-fsa/sherpa-onnx/releases/
- 大小: ~40MB
### 英文模型
- 模型名称: sherpa-onnx-streaming-zipformer-en-2023-02-21
- 下载地址: https://github.com/k2-fsa/sherpa-onnx/releases/
- 大小: ~40MB
### 多语言模型
- 模型名称: sherpa-onnx-streaming-zipformer-multilingual-2023-02-20
- 下载地址: https://github.com/k2-fsa/sherpa-onnx/releases/
- 大小: ~60MB
## 使用说明
1. 下载对应的模型文件
2. 解压到对应的语言目录
3. 确保文件名和路径正确
4. 重新构建应用
## 注意事项
- 模型文件会增加应用包大小
- 建议根据需要只包含必要的语言模型
- 模型文件支持热更新,可以在运行时下载

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,507 @@
(function (name, definition) {
window.jsFixWebmDuration = definition();
})('fix-webm-duration', function () {
/*
* This is the list of possible WEBM file sections by their IDs.
* Possible types: Container, Binary, Uint, Int, String, Float, Date
*/
var sections = {
0xa45dfa3: { name: 'EBML', type: 'Container' },
0x286: { name: 'EBMLVersion', type: 'Uint' },
0x2f7: { name: 'EBMLReadVersion', type: 'Uint' },
0x2f2: { name: 'EBMLMaxIDLength', type: 'Uint' },
0x2f3: { name: 'EBMLMaxSizeLength', type: 'Uint' },
0x282: { name: 'DocType', type: 'String' },
0x287: { name: 'DocTypeVersion', type: 'Uint' },
0x285: { name: 'DocTypeReadVersion', type: 'Uint' },
0x6c: { name: 'Void', type: 'Binary' },
0x3f: { name: 'CRC-32', type: 'Binary' },
0xb538667: { name: 'SignatureSlot', type: 'Container' },
0x3e8a: { name: 'SignatureAlgo', type: 'Uint' },
0x3e9a: { name: 'SignatureHash', type: 'Uint' },
0x3ea5: { name: 'SignaturePublicKey', type: 'Binary' },
0x3eb5: { name: 'Signature', type: 'Binary' },
0x3e5b: { name: 'SignatureElements', type: 'Container' },
0x3e7b: { name: 'SignatureElementList', type: 'Container' },
0x2532: { name: 'SignedElement', type: 'Binary' },
0x8538067: { name: 'Segment', type: 'Container' },
0x14d9b74: { name: 'SeekHead', type: 'Container' },
0xdbb: { name: 'Seek', type: 'Container' },
0x13ab: { name: 'SeekID', type: 'Binary' },
0x13ac: { name: 'SeekPosition', type: 'Uint' },
0x549a966: { name: 'Info', type: 'Container' },
0x33a4: { name: 'SegmentUID', type: 'Binary' },
0x3384: { name: 'SegmentFilename', type: 'String' },
0x1cb923: { name: 'PrevUID', type: 'Binary' },
0x1c83ab: { name: 'PrevFilename', type: 'String' },
0x1eb923: { name: 'NextUID', type: 'Binary' },
0x1e83bb: { name: 'NextFilename', type: 'String' },
0x444: { name: 'SegmentFamily', type: 'Binary' },
0x2924: { name: 'ChapterTranslate', type: 'Container' },
0x29fc: { name: 'ChapterTranslateEditionUID', type: 'Uint' },
0x29bf: { name: 'ChapterTranslateCodec', type: 'Uint' },
0x29a5: { name: 'ChapterTranslateID', type: 'Binary' },
0xad7b1: { name: 'TimecodeScale', type: 'Uint' },
0x489: { name: 'Duration', type: 'Float' },
0x461: { name: 'DateUTC', type: 'Date' },
0x3ba9: { name: 'Title', type: 'String' },
0xd80: { name: 'MuxingApp', type: 'String' },
0x1741: { name: 'WritingApp', type: 'String' },
// 0xf43b675: { name: 'Cluster', type: 'Container' },
0x67: { name: 'Timecode', type: 'Uint' },
0x1854: { name: 'SilentTracks', type: 'Container' },
0x18d7: { name: 'SilentTrackNumber', type: 'Uint' },
0x27: { name: 'Position', type: 'Uint' },
0x2b: { name: 'PrevSize', type: 'Uint' },
0x23: { name: 'SimpleBlock', type: 'Binary' },
0x20: { name: 'BlockGroup', type: 'Container' },
0x21: { name: 'Block', type: 'Binary' },
0x22: { name: 'BlockVirtual', type: 'Binary' },
0x35a1: { name: 'BlockAdditions', type: 'Container' },
0x26: { name: 'BlockMore', type: 'Container' },
0x6e: { name: 'BlockAddID', type: 'Uint' },
0x25: { name: 'BlockAdditional', type: 'Binary' },
0x1b: { name: 'BlockDuration', type: 'Uint' },
0x7a: { name: 'ReferencePriority', type: 'Uint' },
0x7b: { name: 'ReferenceBlock', type: 'Int' },
0x7d: { name: 'ReferenceVirtual', type: 'Int' },
0x24: { name: 'CodecState', type: 'Binary' },
0x35a2: { name: 'DiscardPadding', type: 'Int' },
0xe: { name: 'Slices', type: 'Container' },
0x68: { name: 'TimeSlice', type: 'Container' },
0x4c: { name: 'LaceNumber', type: 'Uint' },
0x4d: { name: 'FrameNumber', type: 'Uint' },
0x4b: { name: 'BlockAdditionID', type: 'Uint' },
0x4e: { name: 'Delay', type: 'Uint' },
0x4f: { name: 'SliceDuration', type: 'Uint' },
0x48: { name: 'ReferenceFrame', type: 'Container' },
0x49: { name: 'ReferenceOffset', type: 'Uint' },
0x4a: { name: 'ReferenceTimeCode', type: 'Uint' },
0x2f: { name: 'EncryptedBlock', type: 'Binary' },
0x654ae6b: { name: 'Tracks', type: 'Container' },
0x2e: { name: 'TrackEntry', type: 'Container' },
0x57: { name: 'TrackNumber', type: 'Uint' },
0x33c5: { name: 'TrackUID', type: 'Uint' },
0x3: { name: 'TrackType', type: 'Uint' },
0x39: { name: 'FlagEnabled', type: 'Uint' },
0x8: { name: 'FlagDefault', type: 'Uint' },
0x15aa: { name: 'FlagForced', type: 'Uint' },
0x1c: { name: 'FlagLacing', type: 'Uint' },
0x2de7: { name: 'MinCache', type: 'Uint' },
0x2df8: { name: 'MaxCache', type: 'Uint' },
0x3e383: { name: 'DefaultDuration', type: 'Uint' },
0x34e7a: { name: 'DefaultDecodedFieldDuration', type: 'Uint' },
0x3314f: { name: 'TrackTimecodeScale', type: 'Float' },
0x137f: { name: 'TrackOffset', type: 'Int' },
0x15ee: { name: 'MaxBlockAdditionID', type: 'Uint' },
0x136e: { name: 'Name', type: 'String' },
0x2b59c: { name: 'Language', type: 'String' },
0x6: { name: 'CodecID', type: 'String' },
0x23a2: { name: 'CodecPrivate', type: 'Binary' },
0x58688: { name: 'CodecName', type: 'String' },
0x3446: { name: 'AttachmentLink', type: 'Uint' },
0x1a9697: { name: 'CodecSettings', type: 'String' },
0x1b4040: { name: 'CodecInfoURL', type: 'String' },
0x6b240: { name: 'CodecDownloadURL', type: 'String' },
0x2a: { name: 'CodecDecodeAll', type: 'Uint' },
0x2fab: { name: 'TrackOverlay', type: 'Uint' },
0x16aa: { name: 'CodecDelay', type: 'Uint' },
0x16bb: { name: 'SeekPreRoll', type: 'Uint' },
0x2624: { name: 'TrackTranslate', type: 'Container' },
0x26fc: { name: 'TrackTranslateEditionUID', type: 'Uint' },
0x26bf: { name: 'TrackTranslateCodec', type: 'Uint' },
0x26a5: { name: 'TrackTranslateTrackID', type: 'Binary' },
0x60: { name: 'Video', type: 'Container' },
0x1a: { name: 'FlagInterlaced', type: 'Uint' },
0x13b8: { name: 'StereoMode', type: 'Uint' },
0x13c0: { name: 'AlphaMode', type: 'Uint' },
0x13b9: { name: 'OldStereoMode', type: 'Uint' },
0x30: { name: 'PixelWidth', type: 'Uint' },
0x3a: { name: 'PixelHeight', type: 'Uint' },
0x14aa: { name: 'PixelCropBottom', type: 'Uint' },
0x14bb: { name: 'PixelCropTop', type: 'Uint' },
0x14cc: { name: 'PixelCropLeft', type: 'Uint' },
0x14dd: { name: 'PixelCropRight', type: 'Uint' },
0x14b0: { name: 'DisplayWidth', type: 'Uint' },
0x14ba: { name: 'DisplayHeight', type: 'Uint' },
0x14b2: { name: 'DisplayUnit', type: 'Uint' },
0x14b3: { name: 'AspectRatioType', type: 'Uint' },
0xeb524: { name: 'ColourSpace', type: 'Binary' },
0xfb523: { name: 'GammaValue', type: 'Float' },
0x383e3: { name: 'FrameRate', type: 'Float' },
0x61: { name: 'Audio', type: 'Container' },
0x35: { name: 'SamplingFrequency', type: 'Float' },
0x38b5: { name: 'OutputSamplingFrequency', type: 'Float' },
0x1f: { name: 'Channels', type: 'Uint' },
0x3d7b: { name: 'ChannelPositions', type: 'Binary' },
0x2264: { name: 'BitDepth', type: 'Uint' },
0x62: { name: 'TrackOperation', type: 'Container' },
0x63: { name: 'TrackCombinePlanes', type: 'Container' },
0x64: { name: 'TrackPlane', type: 'Container' },
0x65: { name: 'TrackPlaneUID', type: 'Uint' },
0x66: { name: 'TrackPlaneType', type: 'Uint' },
0x69: { name: 'TrackJoinBlocks', type: 'Container' },
0x6d: { name: 'TrackJoinUID', type: 'Uint' },
0x40: { name: 'TrickTrackUID', type: 'Uint' },
0x41: { name: 'TrickTrackSegmentUID', type: 'Binary' },
0x46: { name: 'TrickTrackFlag', type: 'Uint' },
0x47: { name: 'TrickMasterTrackUID', type: 'Uint' },
0x44: { name: 'TrickMasterTrackSegmentUID', type: 'Binary' },
0x2d80: { name: 'ContentEncodings', type: 'Container' },
0x2240: { name: 'ContentEncoding', type: 'Container' },
0x1031: { name: 'ContentEncodingOrder', type: 'Uint' },
0x1032: { name: 'ContentEncodingScope', type: 'Uint' },
0x1033: { name: 'ContentEncodingType', type: 'Uint' },
0x1034: { name: 'ContentCompression', type: 'Container' },
0x254: { name: 'ContentCompAlgo', type: 'Uint' },
0x255: { name: 'ContentCompSettings', type: 'Binary' },
0x1035: { name: 'ContentEncryption', type: 'Container' },
0x7e1: { name: 'ContentEncAlgo', type: 'Uint' },
0x7e2: { name: 'ContentEncKeyID', type: 'Binary' },
0x7e3: { name: 'ContentSignature', type: 'Binary' },
0x7e4: { name: 'ContentSigKeyID', type: 'Binary' },
0x7e5: { name: 'ContentSigAlgo', type: 'Uint' },
0x7e6: { name: 'ContentSigHashAlgo', type: 'Uint' },
0xc53bb6b: { name: 'Cues', type: 'Container' },
0x3b: { name: 'CuePoint', type: 'Container' },
0x33: { name: 'CueTime', type: 'Uint' },
0x37: { name: 'CueTrackPositions', type: 'Container' },
0x77: { name: 'CueTrack', type: 'Uint' },
0x71: { name: 'CueClusterPosition', type: 'Uint' },
0x70: { name: 'CueRelativePosition', type: 'Uint' },
0x32: { name: 'CueDuration', type: 'Uint' },
0x1378: { name: 'CueBlockNumber', type: 'Uint' },
0x6a: { name: 'CueCodecState', type: 'Uint' },
0x5b: { name: 'CueReference', type: 'Container' },
0x16: { name: 'CueRefTime', type: 'Uint' },
0x17: { name: 'CueRefCluster', type: 'Uint' },
0x135f: { name: 'CueRefNumber', type: 'Uint' },
0x6b: { name: 'CueRefCodecState', type: 'Uint' },
0x941a469: { name: 'Attachments', type: 'Container' },
0x21a7: { name: 'AttachedFile', type: 'Container' },
0x67e: { name: 'FileDescription', type: 'String' },
0x66e: { name: 'FileName', type: 'String' },
0x660: { name: 'FileMimeType', type: 'String' },
0x65c: { name: 'FileData', type: 'Binary' },
0x6ae: { name: 'FileUID', type: 'Uint' },
0x675: { name: 'FileReferral', type: 'Binary' },
0x661: { name: 'FileUsedStartTime', type: 'Uint' },
0x662: { name: 'FileUsedEndTime', type: 'Uint' },
0x43a770: { name: 'Chapters', type: 'Container' },
0x5b9: { name: 'EditionEntry', type: 'Container' },
0x5bc: { name: 'EditionUID', type: 'Uint' },
0x5bd: { name: 'EditionFlagHidden', type: 'Uint' },
0x5db: { name: 'EditionFlagDefault', type: 'Uint' },
0x5dd: { name: 'EditionFlagOrdered', type: 'Uint' },
0x36: { name: 'ChapterAtom', type: 'Container' },
0x33c4: { name: 'ChapterUID', type: 'Uint' },
0x1654: { name: 'ChapterStringUID', type: 'String' },
0x11: { name: 'ChapterTimeStart', type: 'Uint' },
0x12: { name: 'ChapterTimeEnd', type: 'Uint' },
0x18: { name: 'ChapterFlagHidden', type: 'Uint' },
0x598: { name: 'ChapterFlagEnabled', type: 'Uint' },
0x2e67: { name: 'ChapterSegmentUID', type: 'Binary' },
0x2ebc: { name: 'ChapterSegmentEditionUID', type: 'Uint' },
0x23c3: { name: 'ChapterPhysicalEquiv', type: 'Uint' },
0xf: { name: 'ChapterTrack', type: 'Container' },
0x9: { name: 'ChapterTrackNumber', type: 'Uint' },
0x0: { name: 'ChapterDisplay', type: 'Container' },
0x5: { name: 'ChapString', type: 'String' },
0x37c: { name: 'ChapLanguage', type: 'String' },
0x37e: { name: 'ChapCountry', type: 'String' },
0x2944: { name: 'ChapProcess', type: 'Container' },
0x2955: { name: 'ChapProcessCodecID', type: 'Uint' },
0x50d: { name: 'ChapProcessPrivate', type: 'Binary' },
0x2911: { name: 'ChapProcessCommand', type: 'Container' },
0x2922: { name: 'ChapProcessTime', type: 'Uint' },
0x2933: { name: 'ChapProcessData', type: 'Binary' },
0x254c367: { name: 'Tags', type: 'Container' },
0x3373: { name: 'Tag', type: 'Container' },
0x23c0: { name: 'Targets', type: 'Container' },
0x28ca: { name: 'TargetTypeValue', type: 'Uint' },
0x23ca: { name: 'TargetType', type: 'String' },
0x23c5: { name: 'TagTrackUID', type: 'Uint' },
0x23c9: { name: 'TagEditionUID', type: 'Uint' },
0x23c4: { name: 'TagChapterUID', type: 'Uint' },
0x23c6: { name: 'TagAttachmentUID', type: 'Uint' },
0x27c8: { name: 'SimpleTag', type: 'Container' },
0x5a3: { name: 'TagName', type: 'String' },
0x47a: { name: 'TagLanguage', type: 'String' },
0x484: { name: 'TagDefault', type: 'Uint' },
0x487: { name: 'TagString', type: 'String' },
0x485: { name: 'TagBinary', type: 'Binary' }
};
function doInherit(newClass, baseClass) {
newClass.prototype = Object.create(baseClass.prototype);
newClass.prototype.constructor = newClass;
}
function WebmBase(name, type) {
this.name = name || 'Unknown';
this.type = type || 'Unknown';
}
WebmBase.prototype.updateBySource = function () { };
WebmBase.prototype.setSource = function (source) {
this.source = source;
this.updateBySource();
};
WebmBase.prototype.updateByData = function () { };
WebmBase.prototype.setData = function (data) {
this.data = data;
this.updateByData();
};
function WebmUint(name, type) {
WebmBase.call(this, name, type || 'Uint');
}
doInherit(WebmUint, WebmBase);
function padHex(hex) {
return hex.length % 2 === 1 ? '0' + hex : hex;
}
WebmUint.prototype.updateBySource = function () {
// use hex representation of a number instead of number value
this.data = '';
for (var i = 0; i < this.source.length; i++) {
var hex = this.source[i].toString(16);
this.data += padHex(hex);
}
};
WebmUint.prototype.updateByData = function () {
var length = this.data.length / 2;
this.source = new Uint8Array(length);
for (var i = 0; i < length; i++) {
var hex = this.data.substr(i * 2, 2);
this.source[i] = parseInt(hex, 16);
}
};
WebmUint.prototype.getValue = function () {
return parseInt(this.data, 16);
};
WebmUint.prototype.setValue = function (value) {
this.setData(padHex(value.toString(16)));
};
function WebmFloat(name, type) {
WebmBase.call(this, name, type || 'Float');
}
doInherit(WebmFloat, WebmBase);
WebmFloat.prototype.getFloatArrayType = function () {
return this.source && this.source.length === 4 ? Float32Array : Float64Array;
};
WebmFloat.prototype.updateBySource = function () {
var byteArray = this.source.reverse();
var floatArrayType = this.getFloatArrayType();
var floatArray = new floatArrayType(byteArray.buffer);
this.data = floatArray[0];
};
WebmFloat.prototype.updateByData = function () {
var floatArrayType = this.getFloatArrayType();
var floatArray = new floatArrayType([this.data]);
var byteArray = new Uint8Array(floatArray.buffer);
this.source = byteArray.reverse();
};
WebmFloat.prototype.getValue = function () {
return this.data;
};
WebmFloat.prototype.setValue = function (value) {
this.setData(value);
};
function WebmContainer(name, type) {
WebmBase.call(this, name, type || 'Container');
}
doInherit(WebmContainer, WebmBase);
WebmContainer.prototype.readByte = function () {
return this.source[this.offset++];
};
WebmContainer.prototype.readUint = function () {
var firstByte = this.readByte();
var bytes = 8 - firstByte.toString(2).length;
var value = firstByte - (1 << (7 - bytes));
for (var i = 0; i < bytes; i++) {
// don't use bit operators to support x86
value *= 256;
value += this.readByte();
}
return value;
};
WebmContainer.prototype.updateBySource = function () {
this.data = [];
for (this.offset = 0; this.offset < this.source.length; this.offset = end) {
var id = this.readUint();
var len = this.readUint();
var end = Math.min(this.offset + len, this.source.length);
var data = this.source.slice(this.offset, end);
var info = sections[id] || { name: 'Unknown', type: 'Unknown' };
var ctr = WebmBase;
switch (info.type) {
case 'Container':
ctr = WebmContainer;
break;
case 'Uint':
ctr = WebmUint;
break;
case 'Float':
ctr = WebmFloat;
break;
}
var section = new ctr(info.name, info.type);
section.setSource(data);
this.data.push({
id: id,
idHex: id.toString(16),
data: section
});
}
};
WebmContainer.prototype.writeUint = function (x, draft) {
for (var bytes = 1, flag = 0x80; x >= flag && bytes < 8; bytes++, flag *= 0x80) { }
if (!draft) {
var value = flag + x;
for (var i = bytes - 1; i >= 0; i--) {
// don't use bit operators to support x86
var c = value % 256;
this.source[this.offset + i] = c;
value = (value - c) / 256;
}
}
this.offset += bytes;
};
WebmContainer.prototype.writeSections = function (draft) {
this.offset = 0;
for (var i = 0; i < this.data.length; i++) {
var section = this.data[i],
content = section.data.source,
contentLength = content.length;
this.writeUint(section.id, draft);
this.writeUint(contentLength, draft);
if (!draft) {
this.source.set(content, this.offset);
}
this.offset += contentLength;
}
return this.offset;
};
WebmContainer.prototype.updateByData = function () {
// run without accessing this.source to determine total length - need to know it to create Uint8Array
var length = this.writeSections('draft');
this.source = new Uint8Array(length);
// now really write data
this.writeSections();
};
WebmContainer.prototype.getSectionById = function (id) {
for (var i = 0; i < this.data.length; i++) {
var section = this.data[i];
if (section.id === id) {
return section.data;
}
}
return null;
};
function WebmFile(source) {
WebmContainer.call(this, 'File', 'File');
this.setSource(source);
}
doInherit(WebmFile, WebmContainer);
WebmFile.prototype.fixDuration = function (duration, options) {
var logger = options && options.logger;
if (logger === undefined) {
logger = function (message) {
console.log(message);
};
} else if (!logger) {
logger = function () { };
}
var segmentSection = this.getSectionById(0x8538067);
if (!segmentSection) {
logger('[fix-webm-duration] Segment section is missing');
return false;
}
var infoSection = segmentSection.getSectionById(0x549a966);
if (!infoSection) {
logger('[fix-webm-duration] Info section is missing');
return false;
}
var timeScaleSection = infoSection.getSectionById(0xad7b1);
if (!timeScaleSection) {
logger('[fix-webm-duration] TimecodeScale section is missing');
return false;
}
var durationSection = infoSection.getSectionById(0x489);
if (durationSection) {
if (durationSection.getValue() <= 0) {
logger('[fix-webm-duration] Duration section is present, but the value is empty. Applying ' + duration.toLocaleString() + ' ms.');
durationSection.setValue(duration);
} else {
logger('[fix-webm-duration] Duration section is present');
return false;
}
} else {
logger('[fix-webm-duration] Duration section is missing. Applying ' + duration.toLocaleString() + ' ms.');
// append Duration section
durationSection = new WebmFloat('Duration', 'Float');
durationSection.setValue(duration);
infoSection.data.push({
id: 0x489,
data: durationSection
});
}
// set default time scale to 1 millisecond (1000000 nanoseconds)
timeScaleSection.setValue(1000000);
infoSection.updateByData();
segmentSection.updateByData();
this.updateByData();
return true;
};
WebmFile.prototype.toBlob = function (mimeType) {
return new Blob([this.source.buffer], { type: mimeType || 'audio/webm' });
};
function fixWebmDuration(blob, duration, callback, options) {
// The callback may be omitted - then the third argument is options
if (typeof callback === "object") {
options = callback;
callback = undefined;
}
if (!callback) {
return new Promise(function (resolve) {
fixWebmDuration(blob, duration, resolve, options);
});
}
try {
var reader = new FileReader();
reader.onloadend = function () {
try {
var file = new WebmFile(new Uint8Array(reader.result));
if (file.fixDuration(duration, options)) {
blob = file.toBlob(blob.type);
}
} catch (ex) {
// ignore
}
callback(blob);
};
reader.readAsArrayBuffer(blob);
} catch (ex) {
callback(blob);
}
}
// Support AMD import default
fixWebmDuration.default = fixWebmDuration;
return fixWebmDuration;
});

View File

@ -0,0 +1,407 @@
class RecorderProcessor extends AudioWorkletProcessor {
static get parameterDescriptors() {
return [
{
name: 'numChannels',
defaultValue: 1,
minValue: 1,
maxValue: 16
},
{
name: 'sampleRate',
defaultValue: 48000,
minValue: 8000,
maxValue: 96000
},
{
name: 'streamBufferSize',
defaultValue: 2048,
minValue: 256,
maxValue: 8192
}
];
}
// Buffer size compromise between size and process call frequency
_bufferSize = 2048
// The current buffer fill level
_bytesWritten = 0
// Buffer per channel
_buffers = []
// Resampler (passthrough, down or up)
_resampler = null
// Config
_numChannels = 1
_sampleRate = 48000
constructor(options) {
super(options)
this._numChannels = options.parameterData.numChannels
this._sampleRate = options.parameterData.sampleRate
this._bufferSize = options.parameterData.streamBufferSize
// Resampler(current context sample rate, desired sample rate, num channels, buffer size)
// num channels is always 1 since we resample after interleaving channels
this._resampler = new Resampler(sampleRate, this._sampleRate, 1, this._bufferSize * this._numChannels)
this.initBuffers()
}
initBuffers() {
this._bytesWritten = 0
this._buffers = []
for (let channel = 0; channel < this._numChannels; channel++) {
this._buffers[channel] = []
}
}
/**
* @returns {boolean}
*/
isBufferEmpty() {
return this._bytesWritten === 0
}
/**
* @returns {boolean}
*/
isBufferFull() {
return this._bytesWritten >= this._bufferSize
}
/**
* @param {Float32Array[][]} inputs
* @returns {boolean}
*/
process(inputs) {
if (this.isBufferFull()) {
this.flush()
}
const input = inputs[0]
if (input.length == 0) {
// Sometimes, Firefox doesn't give any input. Skip this frame to not fail.
return true
}
for (let channel = 0; channel < this._numChannels; channel++) {
// Push a copy of the array.
// The underlying implementation may reuse it which will break the recording.
this._buffers[channel].push([...input[channel % input.length]])
}
this._bytesWritten += input[0].length
return true
}
flush() {
let channels = []
for (let channel = 0; channel < this._numChannels; channel++) {
channels.push(this.mergeFloat32Arrays(this._buffers[channel], this._bytesWritten))
}
let interleaved = this.interleave(channels)
let resampled = this._resampler.resample(interleaved)
this.port.postMessage(this.floatTo16BitPCM(resampled))
this.initBuffers()
}
mergeFloat32Arrays(arrays, bytesWritten) {
let result = new Float32Array(bytesWritten)
var offset = 0
for (let i = 0; i < arrays.length; i++) {
result.set(arrays[i], offset)
offset += arrays[i].length
}
return result
}
// Interleave data from channels from LLLLRRRR to LRLRLRLR
interleave(channels) {
if (channels === 1) {
return channels[0]
}
var length = 0
for (let i = 0; i < channels.length; i++) {
length += channels[i].length
}
let result = new Float32Array(length)
var index = 0
var inputIndex = 0
while (index < length) {
for (let i = 0; i < channels.length; i++) {
result[index] = channels[i][inputIndex]
index++
}
inputIndex++
}
return result
}
floatTo16BitPCM(input) {
let output = new DataView(new ArrayBuffer(input.length * 2))
for (let i = 0; i < input.length; i++) {
let s = Math.max(-1, Math.min(1, input[i]))
let s16 = s < 0 ? s * 0x8000 : s * 0x7FFF
output.setInt16(i * 2, s16, true)
}
return new Int16Array(output.buffer)
}
}
class Resampler {
constructor(fromSampleRate, toSampleRate, channels, inputBufferSize) {
if (!fromSampleRate || !toSampleRate || !channels) {
throw (new Error("Invalid settings specified for the resampler."));
}
this.resampler = null;
this.fromSampleRate = fromSampleRate;
this.toSampleRate = toSampleRate;
this.channels = channels || 0;
this.inputBufferSize = inputBufferSize;
this.initialize()
}
initialize() {
if (this.fromSampleRate == this.toSampleRate) {
// Setup resampler bypass - Resampler just returns what was passed through
this.resampler = (buffer) => {
return buffer
};
this.ratioWeight = 1;
} else {
if (this.fromSampleRate < this.toSampleRate) {
// Use generic linear interpolation if upsampling,
// as linear interpolation produces a gradient that we want
// and works fine with two input sample points per output in this case.
this.linearInterpolation();
this.lastWeight = 1;
} else {
// Custom resampler I wrote that doesn't skip samples
// like standard linear interpolation in high downsampling.
// This is more accurate than linear interpolation on downsampling.
this.multiTap();
this.tailExists = false;
this.lastWeight = 0;
}
// Initialize the internal buffer:
this.initializeBuffers();
this.ratioWeight = this.fromSampleRate / this.toSampleRate;
}
}
bufferSlice(sliceAmount) {
//Typed array and normal array buffer section referencing:
try {
return this.outputBuffer.subarray(0, sliceAmount);
}
catch (error) {
try {
//Regular array pass:
this.outputBuffer.length = sliceAmount;
return this.outputBuffer;
}
catch (error) {
//Nightly Firefox 4 used to have the subarray function named as slice:
return this.outputBuffer.slice(0, sliceAmount);
}
}
}
initializeBuffers() {
this.outputBufferSize = (Math.ceil(this.inputBufferSize * this.toSampleRate / this.fromSampleRate / this.channels * 1.000000476837158203125) + this.channels) + this.channels;
try {
this.outputBuffer = new Float32Array(this.outputBufferSize);
this.lastOutput = new Float32Array(this.channels);
}
catch (error) {
this.outputBuffer = [];
this.lastOutput = [];
}
}
linearInterpolation() {
this.resampler = (buffer) => {
let bufferLength = buffer.length,
channels = this.channels,
outLength,
ratioWeight,
weight,
firstWeight,
secondWeight,
sourceOffset,
outputOffset,
outputBuffer,
channel;
if ((bufferLength % channels) !== 0) {
throw (new Error("Buffer was of incorrect sample length."));
}
if (bufferLength <= 0) {
return [];
}
outLength = this.outputBufferSize;
ratioWeight = this.ratioWeight;
weight = this.lastWeight;
firstWeight = 0;
secondWeight = 0;
sourceOffset = 0;
outputOffset = 0;
outputBuffer = this.outputBuffer;
for (; weight < 1; weight += ratioWeight) {
secondWeight = weight % 1;
firstWeight = 1 - secondWeight;
this.lastWeight = weight % 1;
for (channel = 0; channel < this.channels; ++channel) {
outputBuffer[outputOffset++] = (this.lastOutput[channel] * firstWeight) + (buffer[channel] * secondWeight);
}
}
weight -= 1;
for (bufferLength -= channels, sourceOffset = Math.floor(weight) * channels; outputOffset < outLength && sourceOffset < bufferLength;) {
secondWeight = weight % 1;
firstWeight = 1 - secondWeight;
for (channel = 0; channel < this.channels; ++channel) {
outputBuffer[outputOffset++] = (buffer[sourceOffset + ((channel > 0) ? (channel) : 0)] * firstWeight) + (buffer[sourceOffset + (channels + channel)] * secondWeight);
}
weight += ratioWeight;
sourceOffset = Math.floor(weight) * channels;
}
for (channel = 0; channel < channels; ++channel) {
this.lastOutput[channel] = buffer[sourceOffset++];
}
return this.bufferSlice(outputOffset);
};
}
multiTap() {
this.resampler = (buffer) => {
let bufferLength = buffer.length,
outLength,
output_variable_list,
channels = this.channels,
ratioWeight,
weight,
channel,
actualPosition,
amountToNext,
alreadyProcessedTail,
outputBuffer,
outputOffset,
currentPosition;
if ((bufferLength % channels) !== 0) {
throw (new Error("Buffer was of incorrect sample length."));
}
if (bufferLength <= 0) {
return [];
}
outLength = this.outputBufferSize;
output_variable_list = [];
ratioWeight = this.ratioWeight;
weight = 0;
actualPosition = 0;
amountToNext = 0;
alreadyProcessedTail = !this.tailExists;
this.tailExists = false;
outputBuffer = this.outputBuffer;
outputOffset = 0;
currentPosition = 0;
for (channel = 0; channel < channels; ++channel) {
output_variable_list[channel] = 0;
}
do {
if (alreadyProcessedTail) {
weight = ratioWeight;
for (channel = 0; channel < channels; ++channel) {
output_variable_list[channel] = 0;
}
} else {
weight = this.lastWeight;
for (channel = 0; channel < channels; ++channel) {
output_variable_list[channel] = this.lastOutput[channel];
}
alreadyProcessedTail = true;
}
while (weight > 0 && actualPosition < bufferLength) {
amountToNext = 1 + actualPosition - currentPosition;
if (weight >= amountToNext) {
for (channel = 0; channel < channels; ++channel) {
output_variable_list[channel] += buffer[actualPosition++] * amountToNext;
}
currentPosition = actualPosition;
weight -= amountToNext;
} else {
for (channel = 0; channel < channels; ++channel) {
output_variable_list[channel] += buffer[actualPosition + ((channel > 0) ? channel : 0)] * weight;
}
currentPosition += weight;
weight = 0;
break;
}
}
if (weight === 0) {
for (channel = 0; channel < channels; ++channel) {
outputBuffer[outputOffset++] = output_variable_list[channel] / ratioWeight;
}
} else {
this.lastWeight = weight;
for (channel = 0; channel < channels; ++channel) {
this.lastOutput[channel] = output_variable_list[channel];
}
this.tailExists = true;
break;
}
} while (actualPosition < bufferLength && outputOffset < outLength);
return this.bufferSlice(outputOffset);
};
}
resample(buffer) {
if (this.fromSampleRate == this.toSampleRate) {
this.ratioWeight = 1;
} else {
if (this.fromSampleRate < this.toSampleRate) {
this.lastWeight = 1;
} else {
this.tailExists = false;
this.lastWeight = 0;
}
this.initializeBuffers();
this.ratioWeight = this.fromSampleRate / this.toSampleRate;
}
return this.resampler(buffer)
}
}
registerProcessor("recorder.worklet", RecorderProcessor)

Binary file not shown.

View File

@ -0,0 +1,44 @@
plugins {
id("com.android.application")
id("kotlin-android")
// The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins.
id("dev.flutter.flutter-gradle-plugin")
}
android {
namespace = "com.yuanxuan.yx_asr_example"
compileSdk = flutter.compileSdkVersion
ndkVersion = flutter.ndkVersion
compileOptions {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
kotlinOptions {
jvmTarget = JavaVersion.VERSION_11.toString()
}
defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId = "com.yuanxuan.yx_asr_example"
// You can update the following values to match your application needs.
// For more information, see: https://flutter.dev/to/review-gradle-config.
minSdk = flutter.minSdkVersion
targetSdk = flutter.targetSdkVersion
versionCode = flutter.versionCode
versionName = flutter.versionName
}
buildTypes {
release {
// TODO: Add your own signing config for the release build.
// Signing with the debug keys for now, so `flutter run --release` works.
signingConfig = signingConfigs.getByName("debug")
}
}
}
flutter {
source = "../.."
}

View File

@ -0,0 +1,21 @@
allprojects {
repositories {
google()
mavenCentral()
}
}
val newBuildDir: Directory = rootProject.layout.buildDirectory.dir("../../build").get()
rootProject.layout.buildDirectory.value(newBuildDir)
subprojects {
val newSubprojectBuildDir: Directory = newBuildDir.dir(project.name)
project.layout.buildDirectory.value(newSubprojectBuildDir)
}
subprojects {
project.evaluationDependsOn(":app")
}
tasks.register<Delete>("clean") {
delete(rootProject.layout.buildDirectory)
}

File diff suppressed because one or more lines are too long

View File

@ -1,3 +1,3 @@
org.gradle.jvmargs=-Xmx4g -XX:MaxMetaspaceSize=1g org.gradle.jvmargs=-Xmx1536M
android.useAndroidX=true android.useAndroidX=true
android.enableJetifier=true android.enableJetifier=true

View File

@ -0,0 +1,25 @@
pluginManagement {
val flutterSdkPath = run {
val properties = java.util.Properties()
file("local.properties").inputStream().use { properties.load(it) }
val flutterSdkPath = properties.getProperty("flutter.sdk")
require(flutterSdkPath != null) { "flutter.sdk not set in local.properties" }
flutterSdkPath
}
includeBuild("$flutterSdkPath/packages/flutter_tools/gradle")
repositories {
google()
mavenCentral()
gradlePluginPortal()
}
}
plugins {
id("dev.flutter.flutter-plugin-loader") version "1.0.0"
id("com.android.application") version "8.7.3" apply false
id("org.jetbrains.kotlin.android") version "2.1.0" apply false
}
include(":app")

View File

@ -24,13 +24,3 @@ flutter:
# 配置模型文件 assets # 配置模型文件 assets
assets: assets:
- assets/models/ - assets/models/
- assets/models/sherpa-onnx-streaming-zipformer-zh-14M-2023-02-23/
- assets/models/sherpa-onnx-streaming-zipformer-zh-14M-2023-02-23/encoder-epoch-99-avg-1.int8.onnx
- assets/models/sherpa-onnx-streaming-zipformer-zh-14M-2023-02-23/decoder-epoch-99-avg-1.int8.onnx
- assets/models/sherpa-onnx-streaming-zipformer-zh-14M-2023-02-23/joiner-epoch-99-avg-1.int8.onnx
- assets/models/sherpa-onnx-streaming-zipformer-zh-14M-2023-02-23/tokens.txt
- assets/models/sherpa-onnx-streaming-zipformer-zh-int8-2025-06-30/
- assets/models/sherpa-onnx-streaming-zipformer-zh-int8-2025-06-30/encoder.int8.onnx
- assets/models/sherpa-onnx-streaming-zipformer-zh-int8-2025-06-30/decoder.onnx
- assets/models/sherpa-onnx-streaming-zipformer-zh-int8-2025-06-30/joiner.int8.onnx
- assets/models/sherpa-onnx-streaming-zipformer-zh-int8-2025-06-30/tokens.txt

View File

@ -0,0 +1,14 @@
// This is a generated file; do not edit or check into version control.
FLUTTER_ROOT=/Users/max/fvm/versions/3.32.0
FLUTTER_APPLICATION_PATH=/Users/max/SourceCode/yuanxuan/yx_asr
COCOAPODS_PARALLEL_CODE_SIGN=true
FLUTTER_TARGET=lib/main.dart
FLUTTER_BUILD_DIR=build
FLUTTER_BUILD_NAME=1.0.0
FLUTTER_BUILD_NUMBER=1.0.0
EXCLUDED_ARCHS[sdk=iphonesimulator*]=i386
EXCLUDED_ARCHS[sdk=iphoneos*]=armv7
DART_OBFUSCATION=false
TRACK_WIDGET_CREATION=true
TREE_SHAKE_ICONS=false
PACKAGE_CONFIG=.dart_tool/package_config.json

View File

@ -0,0 +1,32 @@
#
# Generated file, do not edit.
#
import lldb
def handle_new_rx_page(frame: lldb.SBFrame, bp_loc, extra_args, intern_dict):
"""Intercept NOTIFY_DEBUGGER_ABOUT_RX_PAGES and touch the pages."""
base = frame.register["x0"].GetValueAsAddress()
page_len = frame.register["x1"].GetValueAsUnsigned()
# Note: NOTIFY_DEBUGGER_ABOUT_RX_PAGES will check contents of the
# first page to see if handled it correctly. This makes diagnosing
# misconfiguration (e.g. missing breakpoint) easier.
data = bytearray(page_len)
data[0:8] = b'IHELPED!'
error = lldb.SBError()
frame.GetThread().GetProcess().WriteMemory(base, data, error)
if not error.Success():
print(f'Failed to write into {base}[+{page_len}]', error)
return
def __lldb_init_module(debugger: lldb.SBDebugger, _):
target = debugger.GetDummyTarget()
# Caveat: must use BreakpointCreateByRegEx here and not
# BreakpointCreateByName. For some reasons callback function does not
# get carried over from dummy target for the later.
bp = target.BreakpointCreateByRegex("^NOTIFY_DEBUGGER_ABOUT_RX_PAGES$")
bp.SetScriptCallbackFunction('{}.handle_new_rx_page'.format(__name__))
bp.SetAutoContinue(True)
print("-- LLDB integration loaded --")

View File

@ -0,0 +1,5 @@
#
# Generated file, do not edit.
#
command script import --relative-to-command-file flutter_lldb_helper.py

View File

@ -0,0 +1,13 @@
#!/bin/sh
# This is a generated file; do not edit or check into version control.
export "FLUTTER_ROOT=/Users/max/fvm/versions/3.32.0"
export "FLUTTER_APPLICATION_PATH=/Users/max/SourceCode/yuanxuan/yx_asr"
export "COCOAPODS_PARALLEL_CODE_SIGN=true"
export "FLUTTER_TARGET=lib/main.dart"
export "FLUTTER_BUILD_DIR=build"
export "FLUTTER_BUILD_NAME=1.0.0"
export "FLUTTER_BUILD_NUMBER=1.0.0"
export "DART_OBFUSCATION=false"
export "TRACK_WIDGET_CREATION=true"
export "TREE_SHAKE_ICONS=false"
export "PACKAGE_CONFIG=.dart_tool/package_config.json"

View File

@ -24,10 +24,5 @@ dev_dependencies:
flutter_lints: ^3.0.0 flutter_lints: ^3.0.0
flutter: flutter:
plugin: assets:
platforms: - assets/models/
android:
package: com.yuanxuan.yx_asr
pluginClass: YxAsrPlugin
ios:
pluginClass: YxAsrPlugin