# MicYou
> MicYou 将 Android 设备转变为 PC 的高质量麦克风,支持 Wi-Fi、USB 多种连接模式,提供专业音频处理功能。
URL: https://micyou.top
---
# 简体中文
---
# 更新日志 - MicYou 版本历史
URL: https://micyou.top/changelog
Description: MicYou 更新日志,查看所有版本的新功能、改进和修复内容。
---
# faq
URL: https://micyou.top/docs/faq
---
title: 常见问题 - MicYou 故障排除
description: MicYou 常见问题解答,包括设备连接问题、防火墙设置、ADB 配置和音频输出故障排除等。
keywords: MicYou常见问题,MicYou故障排除,MicYou无法连接,防火墙设置,ADB问题,音频问题
---
# 常见问题
## 无法连接设备
### Wi-Fi 模式
1. **确认防火墙设置**
Windows 防火墙可能会拦截入站连接。请按照以下方法手动放行端口:
1. 按下 `Win+R`,输入 `powershell`,同时按住 `Ctrl+Shift`,点击「确定」以管理员身份运行 PowerShell。
2. 输入以下命令:
```powershell
New-NetFirewallRule -DisplayName "MicYou-6000-TCP" -Direction Inbound -LocalPort 6000 -Protocol TCP -Action Allow
New-NetFirewallRule -DisplayName "MicYou-6001-UDP" -Direction Inbound -LocalPort 6001 -Protocol UDP -Action Allow
```
> MicYou 默认使用 TCP 端口 `6000`(控制通道)和 UDP 端口 `6001`(音频数据)。如已修改端口号,请将命令中的端口号替换为实际值。
若未出现任何错误提示,表示操作成功,可以重新尝试连接。
2. **检查设备是否在同一子网**
- 确保 Android 手机和 PC 连接的是**同一个**路由器的 Wi-Fi
- 确保路由器已关闭 **AP 隔离** 或 **网络设备隔离** 功能(详情请参阅路由器说明书)
> [!TIP]
> 高级用户可尝试使用 Nmap 或 ping 等工具检查连接性。
### USB (ADB) 模式
1. **开启开发者选项**
> 此处列出的步骤可能不适用于所有设备,**建议使用搜索引擎**查找适用于您设备的 ADB 教程。
- 在手机设置中找到"关于本机",连续点击 7 次"系统版本号"开启开发者选项
- 进入开发者选项,开启 **USB 调试**
2. **确认 ADB 连接**
> 电脑端需要安装 ADB 工具(参见第 1 步:下载 ADB)。
运行以下命令,确认有且仅有一个设备已连接:
```bash
adb devices
```
如果列出了多个设备,则需要指定目标设备进行端口转发:
```bash
adb -s <设备序列号> reverse tcp:6000 tcp:6000
```
> 设备序列号可在 `adb devices` 的输出中找到。
## 连接设备后无声音输出
请确保 VB-Audio 驱动已正确安装,且以下设备均**未被禁用**:
- **输出设备**:CABLE Input (VB-Audio Virtual Cable)
- **输入设备**:CABLE Output (VB-Audio Virtual Cable)
检查方式:打开「设置」> 「声音」,验证两个设备均为**已启用**状态:


---
# plugin-api-reference
URL: https://micyou.top/docs/plugin/plugin-api-reference
---
title: MicYou 插件 API 参考
description: MicYou Plugin API 完整接口文档,包含所有类、方法和数据类型的详细说明
keywords: MicYou API,插件接口,PluginContext,PluginHost,音频效果API,Kotlin插件API
---
# MicYou 插件 API 参考
本文档详细描述 MicYou Plugin API 的所有接口、类和方法。
## 目录
- [Plugin](#plugin)
- [PluginManifest](#pluginmanifest)
- [PluginContext](#plugincontext)
- [PluginHost](#pluginhost)
- [PluginDataChannel](#plugindatachannel)
- [PluginInfo](#plugininfo)
- [PluginPlatform](#pluginplatform)
- [PluginUIProvider](#pluginuiprovider)
- [PluginSettingsProvider](#pluginsettingsprovider)
- [AudioEffectProvider](#audioeffectprovider)
- [AudioEffectPlugin](#audioeffectplugin)
- [PluginLocalization](#pluginlocalization)
- [PluginLocalizationProvider](#pluginlocalizationprovider)
- [数据类型](#数据类型)
## Plugin
插件主接口,所有插件必须实现此接口。
```kotlin
interface Plugin {
val manifest: PluginManifest
fun onLoad(context: PluginContext) {}
fun onEnable() {}
fun onDisable() {}
fun onUnload() {}
}
```
### 属性
| 属性 | 类型 | 说明 |
|------|------|------|
| `manifest` | `PluginManifest` | 插件元数据清单,包含插件的基本信息 |
### 方法
#### onLoad
```kotlin
fun onLoad(context: PluginContext)
```
插件加载时调用。这是插件初始化的最佳时机。
**参数:**
- `context` - 插件上下文,提供运行环境访问能力
**调用时机:** 插件包被解析并验证通过后,在插件实例创建后立即调用。
**示例:**
```kotlin
override fun onLoad(context: PluginContext) {
this.context = context
context.log("Plugin ${manifest.name} loaded")
// 访问主机能力
val host = context.host
context.log("Platform: ${host.platform.name}")
}
```
#### onEnable
```kotlin
fun onEnable()
```
插件启用时调用。
**调用时机:** 用户在设置中启用插件时调用。
#### onDisable
```kotlin
fun onDisable()
```
插件禁用时调用。
**调用时机:** 用户在设置中禁用插件时调用。
#### onUnload
```kotlin
fun onUnload()
```
插件卸载时调用。
**调用时机:** 插件被删除或应用关闭时调用。
---
## PluginManifest
插件元数据清单,描述插件的基本信息。
```kotlin
@Serializable
data class PluginManifest(
val id: String,
val name: String,
val version: String,
val author: String,
val description: String = "",
val tags: List = emptyList(),
val platform: PluginPlatform = PluginPlatform.BOTH,
val minApiVersion: String,
val mainClass: String
)
```
### 属性
| 属性 | 类型 | 必需 | 默认值 | 说明 |
|------|------|------|--------|------|
| `id` | `String` | 是 | - | 插件唯一标识符,反向域名格式 |
| `name` | `String` | 是 | - | 插件显示名称 |
| `version` | `String` | 是 | - | 版本号,遵循语义化版本规范 |
| `author` | `String` | 是 | - | 作者名称 |
| `description` | `String` | 否 | `""` | 插件描述 |
| `tags` | `List` | 否 | `emptyList()` | 标签列表 |
| `platform` | `PluginPlatform` | 否 | `BOTH` | 支持的平台 |
| `minApiVersion` | `String` | 是 | - | 最低 API 版本要求 |
| `mainClass` | `String` | 是 | - | 主类全限定名 |
---
## PluginContext
插件运行上下文,提供插件运行环境访问能力。
```kotlin
interface PluginContext {
val pluginId: String
val pluginDataDir: String
val localization: PluginLocalization
val appLocalization: PluginLocalization
val host: PluginHost
// 数据存储
fun getString(key: String, defaultValue: String): String
fun putString(key: String, value: String)
fun getBoolean(key: String, defaultValue: Boolean): Boolean
fun putBoolean(key: String, value: Boolean)
fun getInt(key: String, defaultValue: Int): Int
fun putInt(key: String, value: Int)
fun getFloat(key: String, defaultValue: Float): Float
fun putFloat(key: String, value: Float)
// 日志
fun log(message: String)
fun logError(message: String, throwable: Throwable? = null)
}
```
### 属性
| 属性 | 类型 | 说明 |
|------|------|------|
| `pluginId` | `String` | 插件唯一标识符 |
| `pluginDataDir` | `String` | 插件专属数据目录路径 |
| `localization` | `PluginLocalization` | 插件本地化接口 |
| `appLocalization` | `PluginLocalization` | 应用全局本地化接口 |
| `host` | `PluginHost` | 主机应用访问接口 |
---
## PluginHost
提供对主机应用的访问能力,允许插件与主机交互。
```kotlin
interface PluginHost {
// 状态流
val streamState: StateFlow
val audioLevels: StateFlow
val isMuted: StateFlow
val connectionInfo: StateFlow
val audioConfig: StateFlow
// 音频配置
fun updateAudioConfig(config: AudioConfig)
fun updateAudioConfig(block: AudioConfig.() -> AudioConfig)
// 流控制
suspend fun startStream(ip: String, port: Int, mode: ConnectionMode, isClient: Boolean)
suspend fun stopStream()
suspend fun setMute(muted: Boolean)
fun setMonitoring(enabled: Boolean)
// 音频效果注册
fun registerAudioEffect(effect: AudioEffectProvider, priority: Int = 100)
fun unregisterAudioEffect(effect: AudioEffectProvider)
// 数据通道
fun createDataChannel(id: String, config: DataChannelConfig = DataChannelConfig()): PluginDataChannel
fun getDataChannel(id: String): PluginDataChannel?
fun closeDataChannel(id: String)
// UI 反馈
fun showSnackbar(message: String)
fun showNotification(title: String, message: String)
// 设置访问
fun getSetting(key: String, defaultValue: String): String
fun setSetting(key: String, value: String)
fun getSettingBoolean(key: String, defaultValue: Boolean): Boolean
fun setSettingBoolean(key: String, value: Boolean)
fun getSettingInt(key: String, defaultValue: Int): Int
fun setSettingInt(key: String, value: Int)
fun getSettingFloat(key: String, defaultValue: Float): Float
fun setSettingFloat(key: String, value: Float)
// 平台信息
val platform: PlatformInfo
}
```
### 状态流
| 属性 | 类型 | 说明 |
|------|------|------|
| `streamState` | `StateFlow` | 当前流状态 |
| `audioLevels` | `StateFlow` | 音频电平 |
| `isMuted` | `StateFlow` | 静音状态 |
| `connectionInfo` | `StateFlow` | 连接信息 |
| `audioConfig` | `StateFlow` | 音频配置 |
### 方法
#### updateAudioConfig
```kotlin
fun updateAudioConfig(config: AudioConfig)
fun updateAudioConfig(block: AudioConfig.() -> AudioConfig)
```
更新音频处理配置。
**示例:**
```kotlin
context.host.updateAudioConfig {
copy(enableNS = true, nsType = NoiseReductionType.RNNoise)
}
```
#### startStream / stopStream
```kotlin
suspend fun startStream(ip: String, port: Int, mode: ConnectionMode, isClient: Boolean)
suspend fun stopStream()
```
启动/停止音频流。
#### registerAudioEffect / unregisterAudioEffect
```kotlin
fun registerAudioEffect(effect: AudioEffectProvider, priority: Int = 100)
fun unregisterAudioEffect(effect: AudioEffectProvider)
```
注册/注销自定义音频效果器。优先级数值越小,越先执行。
#### createDataChannel / getDataChannel / closeDataChannel
```kotlin
fun createDataChannel(id: String, config: DataChannelConfig = DataChannelConfig()): PluginDataChannel
fun getDataChannel(id: String): PluginDataChannel?
fun closeDataChannel(id: String)
```
创建/获取/关闭自定义网络数据通道。
**参数:**
- `id` - 通道唯一标识符
- `config` - 通道配置
**示例:**
```kotlin
val channel = context.host.createDataChannel("my-channel")
channel.connect("192.168.1.100", 8080)
// ... 使用通道
context.host.closeDataChannel("my-channel")
```
#### showSnackbar / showNotification
```kotlin
fun showSnackbar(message: String)
fun showNotification(title: String, message: String)
```
显示 UI 反馈。
---
## PluginDataChannel
自定义网络数据通道接口,允许插件建立独立的网络连接。
```kotlin
enum class DataChannelMode {
Tcp, Udp
}
data class DataChannelConfig(
val mode: DataChannelMode = DataChannelMode.Tcp,
val port: Int = 0,
val bufferSize: Int = 8192
)
interface PluginDataChannel {
val id: String
val config: DataChannelConfig
val isConnected: Flow
val localPort: Int
suspend fun connect(host: String, port: Int): Result
suspend fun bind(port: Int = 0): Result
suspend fun send(data: ByteArray): Result
fun receive(): Flow
suspend fun close()
}
```
### DataChannelMode
| 模式 | 说明 |
|------|------|
| `Tcp` | TCP 连接,可靠传输 |
| `Udp` | UDP 连接,低延迟 |
### DataChannelConfig
| 属性 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| `mode` | `DataChannelMode` | `Tcp` | 连接模式 |
| `port` | `Int` | `0` | 本地端口(0 表示自动分配) |
| `bufferSize` | `Int` | `8192` | 接收缓冲区大小 |
### PluginDataChannel 方法
#### connect
```kotlin
suspend fun connect(host: String, port: Int): Result
```
作为客户端连接到远程主机。
**参数:**
- `host` - 远程主机地址
- `port` - 远程端口
**返回:** `Result` 表示连接结果
#### bind
```kotlin
suspend fun bind(port: Int = 0): Result
```
绑定本地端口,作为服务端监听连接。
**参数:**
- `port` - 本地端口,0 表示自动分配
**返回:** `Result` 表示绑定结果
#### send
```kotlin
suspend fun send(data: ByteArray): Result
```
发送数据。
#### receive
```kotlin
fun receive(): Flow
```
接收数据流。
#### close
```kotlin
suspend fun close()
```
关闭通道。
### 使用示例
```kotlin
class CameraStreamPlugin : Plugin {
private lateinit var channel: PluginDataChannel
override fun onEnable() {
channel = context.host.createDataChannel("camera-stream",
DataChannelConfig(mode = DataChannelMode.Udp)
)
scope.launch {
channel.connect("192.168.1.100", 9000)
.onSuccess {
while (true) {
val frame = captureCameraFrame()
channel.send(frame)
delay(33) // ~30fps
}
}
.onFailure { e ->
context.logError("Connection failed: ${e.message}")
}
}
}
override fun onDisable() {
context.host.closeDataChannel("camera-stream")
}
}
```
---
## PluginInfo
插件运行时信息。
```kotlin
data class PluginInfo(
val manifest: PluginManifest,
val isEnabled: Boolean = false,
val isLoaded: Boolean = false,
val installPath: String,
val iconPath: String? = null
)
```
---
## PluginPlatform
插件支持平台枚举。
```kotlin
enum class PluginPlatform {
MOBILE, // 仅移动端
DESKTOP, // 仅桌面端
BOTH // 两端都需要安装
}
```
---
## PluginUIProvider
插件 UI 提供者接口。
```kotlin
enum class MobileUIMode {
Dialog, // 对话框模式
NewScreen // 新页面模式
}
interface PluginUIProvider {
val hasMainWindow: Boolean get() = false
val hasDialog: Boolean get() = false
// 窗口配置(桌面端)
val windowWidth: Dp get() = 600.dp
val windowHeight: Dp get() = 500.dp
val windowTitle: String get() = "Plugin Window"
val windowResizable: Boolean get() = true
// 移动端 UI 模式
val mobileUIMode: MobileUIMode get() = MobileUIMode.Dialog
@Composable
fun MainWindow(onClose: () -> Unit) {}
@Composable
fun DialogContent(onDismiss: () -> Unit) {}
}
```
### 属性
| 属性 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| `hasMainWindow` | `Boolean` | `false` | 是否提供主窗口 |
| `hasDialog` | `Boolean` | `false` | 是否提供对话框 |
| `windowWidth` | `Dp` | `600.dp` | 窗口宽度(桌面端) |
| `windowHeight` | `Dp` | `500.dp` | 窗口高度(桌面端) |
| `windowTitle` | `String` | `"Plugin Window"` | 窗口标题 |
| `windowResizable` | `Boolean` | `true` | 窗口是否可调整大小 |
| `mobileUIMode` | `MobileUIMode` | `Dialog` | 移动端 UI 模式 |
---
## PluginSettingsProvider
插件设置页面提供者接口。
```kotlin
interface PluginSettingsProvider {
@Composable
fun SettingsContent()
}
```
---
## AudioEffectProvider
音频效果提供者接口,用于实现自定义音频处理。
```kotlin
interface AudioEffectProvider {
val id: String
val name: String
val description: String
var isEnabled: Boolean
fun process(input: ShortArray, channelCount: Int, sampleRate: Int): ShortArray
fun reset()
fun release()
fun onConfigChanged(config: AudioConfig) {}
}
```
### 属性
| 属性 | 类型 | 说明 |
|------|------|------|
| `id` | `String` | 效果器唯一标识符 |
| `name` | `String` | 效果器显示名称 |
| `description` | `String` | 效果器描述 |
| `isEnabled` | `Boolean` | 是否启用 |
### 方法
#### process
```kotlin
fun process(input: ShortArray, channelCount: Int, sampleRate: Int): ShortArray
```
处理音频数据。
**参数:**
- `input` - 输入音频采样数据(16-bit PCM)
- `channelCount` - 声道数
- `sampleRate` - 采样率
**返回:** 处理后的音频数据
---
## AudioEffectPlugin
音频效果插件接口,简化音频效果插件的实现。
```kotlin
interface AudioEffectPlugin : Plugin {
val audioEffectProvider: AudioEffectProvider
val effectPriority: Int get() = 100
}
```
---
## 数据类型
### StreamState
```kotlin
enum class StreamState {
Idle, Connecting, Streaming, Error
}
```
### ConnectionMode
```kotlin
enum class ConnectionMode {
Wifi, Usb
}
```
### NoiseReductionType
```kotlin
enum class NoiseReductionType {
Ulunas, RNNoise, Speexdsp, None
}
```
### AudioConfig
```kotlin
data class AudioConfig(
val enableNS: Boolean = false,
val nsType: NoiseReductionType = NoiseReductionType.RNNoise,
val enableAGC: Boolean = false,
val agcTargetLevel: Int = 32000,
val enableVAD: Boolean = false,
val vadThreshold: Int = 10,
val enableDereverb: Boolean = false,
val dereverbLevel: Float = 0.5f,
val amplification: Float = 0.0f
)
```
### ConnectionInfo
```kotlin
data class ConnectionInfo(
val mode: ConnectionMode,
val ipAddress: String,
val port: Int,
val isClient: Boolean
)
```
### PlatformInfo
```kotlin
data class PlatformInfo(
val name: String,
val version: String,
val isDesktop: Boolean,
val isMobile: Boolean
)
```
---
# MicYou 插件开发最佳实践
URL: https://micyou.top/docs/plugin/plugin-best-practices
Description: MicYou 插件开发最佳实践指南,包含项目结构、生命周期管理、音频效果开发和性能优化建议
# MicYou 插件开发最佳实践
本文档提供 MicYou 插件开发的最佳实践和建议。
## 项目结构
### 推荐目录结构
```
my-plugin/
├── build.gradle.kts
├── src/
│ └── main/
│ ├── kotlin/
│ │ └── com/example/myplugin/
│ │ ├── MyPlugin.kt # 主类
│ │ ├── MyPluginUI.kt # UI 组件
│ │ ├── MyPluginSettings.kt # 设置页面
│ │ ├── AudioEffects.kt # 音频效果(可选)
│ │ └── model/ # 数据模型
│ │ └── Config.kt
│ └── resources/
│ └── plugin.json # 清单文件
└── README.md
```
### 代码组织
将不同功能分离到不同文件:
```kotlin
// MyPlugin.kt - 主类
class MyPlugin : Plugin {
override val manifest = PluginManifest(...)
// 生命周期方法
}
// MyPluginUI.kt - UI 组件
class MyPluginUI : PluginUIProvider {
// UI 实现
}
// MyPluginSettings.kt - 设置页面
class MyPluginSettings : PluginSettingsProvider {
// 设置页面实现
}
```
## 生命周期管理
### 正确管理状态
```kotlin
class MyPlugin : Plugin {
private var context: PluginContext? = null
private var isRunning = false
override fun onLoad(context: PluginContext) {
this.context = context
context.log("Plugin loaded")
}
override fun onEnable() {
if (isRunning) return
isRunning = true
startBackgroundTask()
}
override fun onDisable() {
if (!isRunning) return
isRunning = false
stopBackgroundTask()
}
override fun onUnload() {
context = null
releaseAllResources()
}
}
```
### 避免内存泄漏
```kotlin
class MyPlugin : Plugin {
private val jobs = mutableListOf()
override fun onEnable() {
jobs.add(startTask1())
jobs.add(startTask2())
}
override fun onDisable() {
jobs.forEach { it.cancel() }
jobs.clear()
}
}
```
## 访问主机能力
### 监听状态变化
```kotlin
@Composable
override fun MainWindow(onClose: () -> Unit) {
val host = context?.host ?: return
// 监听流状态
val streamState by host.streamState.collectAsState()
// 监听音频电平
val audioLevel by host.audioLevels.collectAsState()
// 监听音频配置
val audioConfig by host.audioConfig.collectAsState()
Column {
Text("Stream: $streamState")
Text("Level: $audioLevel")
Text("NS: ${audioConfig.enableNS}")
}
}
```
### 修改音频配置
```kotlin
class MyPlugin : Plugin {
fun enableNoiseReduction() {
context?.host?.updateAudioConfig { config ->
config.copy(
enableNS = true,
nsType = NoiseReductionType.RNNoise
)
}
}
fun setAmplification(gainDb: Float) {
context?.host?.updateAudioConfig { config ->
config.copy(amplification = gainDb)
}
}
}
```
## 音频效果开发
### 实现自定义降噪
```kotlin
class CustomNoiseReducer : AudioEffectProvider {
override val id = "com.example.custom-ns"
override val name = "Custom Noise Reducer"
override val description = "AI-powered noise reduction"
override var isEnabled = true
private var model: NoiseModel? = null
override fun process(input: ShortArray, channelCount: Int, sampleRate: Int): ShortArray {
if (!isEnabled) return input
// 实现降噪算法
val output = ShortArray(input.size)
for (i in input.indices) {
output[i] = reduceNoise(input[i])
}
return output
}
private fun reduceNoise(sample: Short): Short {
// 降噪逻辑
return sample
}
override fun reset() {
model?.reset()
}
override fun release() {
model?.close()
model = null
}
override fun onConfigChanged(config: AudioConfig) {
// 根据配置调整参数
}
}
```
### 注册音频效果
```kotlin
class MyPlugin : Plugin {
private val noiseReducer = CustomNoiseReducer()
override fun onLoad(context: PluginContext) {
// 注册效果器,优先级 50(数值越小越先执行)
context.host.registerAudioEffect(noiseReducer, priority = 50)
}
override fun onUnload() {
// 注销效果器
context?.host?.unregisterAudioEffect(noiseReducer)
noiseReducer.release()
}
}
```
### 使用 AudioEffectPlugin 简化
```kotlin
class MyPlugin : AudioEffectPlugin {
override val manifest = PluginManifest(...)
override val audioEffectProvider = CustomNoiseReducer()
override val effectPriority = 50
// 生命周期由 AudioEffectPlugin 自动处理
}
```
## 数据存储
### 使用 PluginContext 存储
```kotlin
class MyPlugin : Plugin {
private var context: PluginContext? = null
fun saveConfig(config: Config) {
context?.apply {
putString("serverUrl", config.serverUrl)
putInt("port", config.port)
putBoolean("ssl", config.useSsl)
}
}
fun loadConfig(): Config {
return context?.let {
Config(
serverUrl = it.getString("serverUrl", "localhost"),
port = it.getInt("port", 8080),
useSsl = it.getBoolean("ssl", false)
)
} ?: Config()
}
}
```
### 文件存储
```kotlin
class MyPlugin : Plugin {
private fun saveDataFile(data: String) {
val context = context ?: return
val file = File(context.pluginDataDir, "data.json")
file.writeText(data)
}
private fun loadDataFile(): String? {
val context = context ?: return null
val file = File(context.pluginDataDir, "data.json")
return if (file.exists()) file.readText() else null
}
}
```
## UI 开发
### 响应式 UI
```kotlin
class MyPluginUI : PluginUIProvider {
override val hasMainWindow = true
@Composable
override fun MainWindow(onClose: () -> Unit) {
var data by remember { mutableStateOf(emptyList- ()) }
var loading by remember { mutableStateOf(true) }
LaunchedEffect(Unit) {
data = loadData()
loading = false
}
if (loading) {
Box(Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
CircularProgressIndicator()
}
} else {
LazyColumn {
items(data) { item ->
ItemRow(item)
}
}
}
}
}
```
### 移动端 UI 模式选择
```kotlin
class MyPlugin : Plugin, PluginUIProvider {
// 对于复杂 UI,使用新页面模式
override val mobileUIMode = MobileUIMode.NewScreen
// 对于简单对话框,使用对话框模式
// override val mobileUIMode = MobileUIMode.Dialog
}
```
### 设置页面最佳实践
```kotlin
class MyPluginSettings : PluginSettingsProvider {
@Composable
override fun SettingsContent() {
var serverUrl by remember { mutableStateOf("") }
var port by remember { mutableStateOf(8080) }
Column(Modifier.padding(16.dp).fillMaxWidth()) {
Text("Connection Settings", style = MaterialTheme.typography.titleMedium)
Spacer(Modifier.height(16.dp))
OutlinedTextField(
value = serverUrl,
onValueChange = { serverUrl = it },
label = { Text("Server URL") },
modifier = Modifier.fillMaxWidth(),
singleLine = true
)
Spacer(Modifier.height(8.dp))
OutlinedTextField(
value = port.toString(),
onValueChange = { port = it.toIntOrNull() ?: 8080 },
label = { Text("Port") },
modifier = Modifier.fillMaxWidth(),
singleLine = true
)
Spacer(Modifier.height(16.dp))
Button(
onClick = { saveSettings(serverUrl, port) },
modifier = Modifier.align(Alignment.End)
) {
Text("Save")
}
}
}
}
```
## 通知和反馈
### 显示消息
```kotlin
class MyPlugin : Plugin {
fun showFeedback() {
val host = context?.host ?: return
// 简短消息
host.showSnackbar("Operation completed!")
// 系统通知
host.showNotification(
title = "My Plugin",
message = "Background task finished successfully"
)
}
}
```
## 错误处理
### 优雅处理错误
```kotlin
class MyPlugin : Plugin {
fun performOperation() {
try {
val result = riskyOperation()
context?.log("Operation succeeded: $result")
} catch (e: Exception) {
context?.logError("Operation failed", e)
context?.host?.showSnackbar("Operation failed: ${e.message}")
}
}
}
```
### 验证主机状态
```kotlin
class MyPlugin : Plugin {
fun startStreaming() {
val host = context?.host ?: run {
context?.logError("Host not available")
return
}
if (host.streamState.value != StreamState.Idle) {
host.showSnackbar("Please stop current stream first")
return
}
// 启动流
}
}
```
## 性能优化
### 音频处理优化
```kotlin
class OptimizedEffect : AudioEffectProvider {
private var buffer: ShortArray = ShortArray(0)
override fun process(input: ShortArray, channelCount: Int, sampleRate: Int): ShortArray {
// 重用缓冲区避免分配
if (buffer.size != input.size) {
buffer = ShortArray(input.size)
}
// 使用 SIMD 或其他优化技术
for (i in input.indices) {
buffer[i] = processSample(input[i])
}
return buffer
}
}
```
### 协程使用
```kotlin
class MyPlugin : Plugin {
private val scope = CoroutineScope(Dispatchers.Default)
override fun onEnable() {
scope.launch {
while (isActive) {
performBackgroundTask()
delay(1000)
}
}
}
override fun onDisable() {
scope.cancel()
}
}
```
## 相关文档
- [插件开发指南](./plugin-development-guide)
- [插件 API 参考](./plugin-api-reference)
- [插件包格式规范](./plugin-package-format)
---
# MicYou 插件开发指南
URL: https://micyou.top/docs/plugin/plugin-development-guide
Description: MicYou 插件系统开发快速入门,学习如何创建自定义插件扩展应用功能
# MicYou 插件开发指南
MicYou 插件开发快速开始指南。
## 概述
MicYou 插件系统允许开发者扩展应用功能。插件可以:
- 提供自定义 UI 界面(主窗口、对话框或新页面)
- 提供设置页面
- 访问插件专属存储空间
- 访问主机应用状态和控制能力
- 注册自定义音频效果器(降噪、增益等)
- 修改应用设置和音频配置
## 快速开始
### 1. 创建项目
创建一个新的 Kotlin/JVM Gradle 项目:
```kotlin
// build.gradle.kts
plugins {
kotlin("jvm") version "2.2.20"
kotlin("plugin.serialization") version "2.2.20"
kotlin("plugin.compose") version "2.2.20"
id("org.jetbrains.compose") version "1.7.3"
}
group = "com.example"
version = "1.0.0"
repositories {
mavenCentral()
google()
}
dependencies {
compileOnly(files("path/to/plugin-api-jvm.jar"))
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.0")
// Compose
implementation(compose.runtime)
implementation(compose.foundation)
implementation(compose.material3)
implementation(compose.ui)
}
```
### 2. 实现 Plugin 接口
创建插件主类:
```kotlin
package com.example.myplugin
import com.lanrhyme.micyou.plugin.*
class MyPlugin : Plugin {
override val manifest = PluginManifest(
id = "com.example.myplugin",
name = "My Plugin",
version = "1.0.0",
author = "Your Name",
description = "A sample plugin for MicYou",
minApiVersion = "1.0.0",
mainClass = "com.example.myplugin.MyPlugin"
)
override fun onLoad(context: PluginContext) {
context.log("Plugin loaded!")
// 访问主机能力
val host = context.host
context.log("Platform: ${host.platform.name}")
}
override fun onEnable() {
// 插件启用时调用
}
override fun onDisable() {
// 插件禁用时调用
}
override fun onUnload() {
// 插件卸载时调用
}
}
```
### 3. 创建 plugin.json
在资源目录创建 `plugin.json`:
```json
{
"id": "com.example.myplugin",
"name": "My Plugin",
"version": "1.0.0",
"author": "Your Name",
"description": "A sample plugin for MicYou",
"minApiVersion": "1.0.0",
"mainClass": "com.example.myplugin.MyPlugin"
}
```
### 4. 打包插件
构建 JAR 文件并打包:
```bash
./gradlew jar
# 创建插件包
mkdir -p plugin-package
cp build/libs/my-plugin.jar plugin-package/plugin.jar
cp src/main/resources/plugin.json plugin-package/
cd plugin-package && zip -r ../my-plugin.micyou-plugin.zip .
```
### 5. 安装插件
1. 打开 MicYou 应用
2. 进入设置 → 插件
3. 点击"导入插件"按钮
4. 选择 `.micyou-plugin.zip` 文件
5. 启用插件
## 核心接口
### Plugin
插件主接口,定义生命周期方法:
```kotlin
interface Plugin {
val manifest: PluginManifest
fun onLoad(context: PluginContext) {}
fun onEnable() {}
fun onDisable() {}
fun onUnload() {}
}
```
### PluginContext
提供插件运行环境:
```kotlin
interface PluginContext {
val pluginId: String
val pluginDataDir: String
// 本地化接口
val localization: PluginLocalization
val appLocalization: PluginLocalization
// 数据存储
fun getString(key: String, defaultValue: String): String
fun putString(key: String, value: String)
fun getBoolean(key: String, defaultValue: Boolean): Boolean
fun putBoolean(key: String, value: Boolean)
fun getInt(key: String, defaultValue: Int): Int
fun putInt(key: String, value: Int)
fun getFloat(key: String, defaultValue: Float): Float
fun putFloat(key: String, value: Float)
// 日志
fun log(message: String)
fun logError(message: String, throwable: Throwable? = null)
// 主机能力
val host: PluginHost
}
```
### PluginHost
提供对主机应用的访问能力:
```kotlin
interface PluginHost {
// 状态流
val streamState: StateFlow
val audioLevels: StateFlow
val isMuted: StateFlow
val connectionInfo: StateFlow
val audioConfig: StateFlow
// 音频配置
fun updateAudioConfig(config: AudioConfig)
fun updateAudioConfig(block: AudioConfig.() -> AudioConfig)
// 流控制
suspend fun startStream(ip: String, port: Int, mode: ConnectionMode, isClient: Boolean)
suspend fun stopStream()
suspend fun setMute(muted: Boolean)
fun setMonitoring(enabled: Boolean)
// 音频效果注册
fun registerAudioEffect(effect: AudioEffectProvider, priority: Int = 100)
fun unregisterAudioEffect(effect: AudioEffectProvider)
// UI 反馈
fun showSnackbar(message: String)
fun showNotification(title: String, message: String)
// 设置访问
fun getSetting(key: String, defaultValue: String): String
fun setSetting(key: String, value: String)
// ... 其他设置方法
// 平台信息
val platform: PlatformInfo
}
```
### PluginUIProvider
提供插件 UI 组件:
```kotlin
interface PluginUIProvider {
val hasMainWindow: Boolean get() = false
val hasDialog: Boolean get() = false
// 窗口配置(桌面端)
val windowWidth: Dp get() = 600.dp
val windowHeight: Dp get() = 500.dp
val windowTitle: String get() = "Plugin Window"
val windowResizable: Boolean get() = true
// 移动端 UI 模式
val mobileUIMode: MobileUIMode get() = MobileUIMode.Dialog
@Composable
fun MainWindow(onClose: () -> Unit) {}
@Composable
fun DialogContent(onDismiss: () -> Unit) {}
}
enum class MobileUIMode {
Dialog, // 对话框模式
NewScreen // 新页面模式
}
```
### PluginSettingsProvider
提供插件设置页面:
```kotlin
interface PluginSettingsProvider {
@Composable
fun SettingsContent()
}
```
## 进阶功能
### 访问主机状态
```kotlin
class MyPlugin : Plugin {
private var context: PluginContext? = null
override fun onLoad(context: PluginContext) {
this.context = context
// 获取当前流状态
val state = context.host.streamState.value
context.log("Current stream state: $state")
// 获取音频配置
val config = context.host.audioConfig.value
context.log("NS enabled: ${config.enableNS}")
}
}
```
### 修改音频配置
```kotlin
class MyPlugin : Plugin {
fun enableCustomNoiseReduction() {
context?.host?.updateAudioConfig { config ->
config.copy(
enableNS = true,
nsType = NoiseReductionType.RNNoise
)
}
}
}
```
### 注册自定义音频效果
```kotlin
class MyNoiseReducer : AudioEffectProvider {
override val id = "com.example.myplugin.noise-reducer"
override val name = "My Noise Reducer"
override val description = "Custom noise reduction effect"
override var isEnabled = true
override fun process(input: ShortArray, channelCount: Int, sampleRate: Int): ShortArray {
// 实现降噪算法
return input
}
override fun reset() {
// 重置内部状态
}
override fun release() {
// 释放资源
}
}
class MyPlugin : Plugin, AudioEffectPlugin {
override val audioEffectProvider = MyNoiseReducer()
override val effectPriority = 50 // 较高优先级
override fun onLoad(context: PluginContext) {
// 注册音频效果
context.host.registerAudioEffect(audioEffectProvider, effectPriority)
}
override fun onUnload() {
context?.host?.unregisterAudioEffect(audioEffectProvider)
}
}
```
### 显示通知
```kotlin
class MyPlugin : Plugin {
fun notifyUser() {
context?.host?.showSnackbar("Operation completed!")
context?.host?.showNotification("My Plugin", "Background task finished")
}
}
```
### 读取/修改应用设置
```kotlin
class MyPlugin : Plugin {
fun readAppSettings() {
val host = context?.host ?: return
// 读取应用设置
val theme = host.getSetting("theme", "system")
val autoStart = host.getSettingBoolean("autoStart", false)
// 修改应用设置
host.setSettingBoolean("autoStart", true)
}
}
```
## 本地化
插件支持多语言本地化。在资源目录创建 `i18n/` 文件夹:
```
src/main/resources/
└── i18n/
├── en.json
├── zh-CN.json
└── ja.json
```
JSON 文件格式:
```json
{
"plugin.name": "My Plugin",
"plugin.description": "A sample plugin",
"settings.title": "Settings",
"button.save": "Save"
}
```
在代码中使用本地化:
```kotlin
class MyPlugin : Plugin, PluginLocalizationProvider {
override fun getLocalizedString(languageCode: String, key: String): String? {
return when (languageCode) {
"zh" -> zhStrings[key]
"en" -> enStrings[key]
else -> null
}
}
override fun getSupportedLanguages(): List {
return listOf("zh", "en")
}
}
```
## 完整示例
```kotlin
class MyPlugin : Plugin, PluginUIProvider, PluginSettingsProvider {
private var context: PluginContext? = null
override val manifest = PluginManifest(
id = "com.example.myplugin",
name = "My Plugin",
version = "1.0.0",
author = "Your Name",
description = "A plugin with UI and settings",
minApiVersion = "1.0.0",
mainClass = "com.example.myplugin.MyPlugin"
)
// PluginUIProvider
override val hasMainWindow = true
override val windowWidth = 700.dp
override val windowHeight = 500.dp
override val windowTitle = "My Plugin"
override val mobileUIMode = MobileUIMode.NewScreen
@Composable
override fun MainWindow(onClose: () -> Unit) {
val host = context?.host
val streamState by host?.streamState?.collectAsState()
?: remember { mutableStateOf(StreamState.Idle) }
Column(modifier = Modifier.padding(16.dp)) {
Text("Stream State: $streamState")
Button(onClick = { host?.showSnackbar("Hello!") }) {
Text("Show Message")
}
}
}
// PluginSettingsProvider
@Composable
override fun SettingsContent() {
// 设置页面内容
}
}
```
## 相关文档
- [插件 API 参考](./plugin-api-reference)
- [插件开发最佳实践](./plugin-best-practices)
- [插件包格式规范](./plugin-package-format)
---
# MicYou 插件包格式规范
URL: https://micyou.top/docs/plugin/plugin-package-format
Description: MicYou 插件包结构规范详解,包含 plugin.json 配置、JAR 文件要求和图标规范
# MicYou 插件包格式规范
## 插件包结构
插件包是一个 ZIP 压缩文件,扩展名为 `.micyou-plugin.zip`,包含以下结构:
```
my-plugin.micyou-plugin.zip
├── plugin.json # 必需:插件元数据清单
├── plugin.jar # 必需:插件代码(Kotlin/JVM 编译产物)
├── assets/ # 可选:资源文件目录
│ ├── images/
│ ├── sounds/
│ └── ...
└── icon.png # 可选:插件图标(建议 128x128 PNG)
```
## plugin.json 规范
### JSON Schema
```json
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"required": ["id", "name", "version", "author", "description", "minApiVersion", "mainClass"],
"properties": {
"id": {
"type": "string",
"pattern": "^[a-z][a-z0-9_]*(\\.[a-z][a-z0-9_]*)+$",
"description": "插件唯一标识符,采用反向域名格式,如 com.example.myplugin"
},
"name": {
"type": "string",
"minLength": 1,
"maxLength": 100,
"description": "插件显示名称"
},
"version": {
"type": "string",
"pattern": "^\\d+\\.\\d+\\.\\d+(-[a-zA-Z0-9]+)?$",
"description": "版本号,遵循语义化版本规范,如 1.0.0 或 1.0.0-beta"
},
"author": {
"type": "string",
"minLength": 1,
"maxLength": 100,
"description": "作者名称"
},
"description": {
"type": "string",
"minLength": 1,
"maxLength": 500,
"description": "插件描述"
},
"tags": {
"type": "array",
"items": {
"type": "string",
"enum": ["camera", "streaming", "audio", "video", "utility", "effect", "network", "storage"]
},
"description": "插件标签,用于分类和筛选"
},
"platform": {
"type": "string",
"enum": ["mobile", "desktop", "both"],
"default": "both",
"description": "支持的平台:mobile=仅移动端,desktop=仅桌面端,both=两端都需要安装"
},
"minApiVersion": {
"type": "string",
"pattern": "^\\d+\\.\\d+\\.\\d+$",
"description": "最低 API 版本要求"
},
"mainClass": {
"type": "string",
"description": "插件主类全限定名,必须实现 Plugin 接口"
}
}
}
```
### 字段说明
| 字段 | 必需 | 类型 | 说明 |
|------|------|------|------|
| id | 是 | string | 插件唯一标识符,反向域名格式 |
| name | 是 | string | 插件显示名称,1-100 字符 |
| version | 是 | string | 语义化版本号 |
| author | 是 | string | 作者名称 |
| description | 是 | string | 插件描述,1-500 字符 |
| tags | 否 | string[] | 标签数组,用于分类筛选 |
| platform | 否 | string | 支持平台:mobile/desktop/both,默认 both |
| minApiVersion | 是 | string | 最低 API 版本 |
| mainClass | 是 | string | 主类全限定名 |
## 完整示例
```json
{
"id": "com.example.audio-enhancer",
"name": "Audio Enhancer",
"version": "1.0.0",
"author": "Developer Name",
"description": "A plugin that provides advanced audio enhancement features including custom noise reduction and equalization.",
"tags": ["audio", "effect"],
"platform": "both",
"minApiVersion": "1.0.0",
"mainClass": "com.example.audioenhancer.AudioEnhancerPlugin"
}
```
## plugin.jar 要求
- 必须是有效的 JVM JAR 文件
- 主类必须实现 `com.lanrhyme.micyou.plugin.Plugin` 接口
- 可以包含其他依赖类,但建议使用 shaded JAR 避免冲突
- 文件大小建议不超过 50MB
## 图标规范
- 格式:PNG
- 建议尺寸:128x128 像素
- 支持透明背景
- 文件名必须为 `icon.png`
## 平台说明
| 值 | 说明 |
|------|------|
| `mobile` | 仅 Android 端支持 |
| `desktop` | 仅 JVM Desktop 端支持 |
| `both` | 两端都需要安装,用于跨平台功能 |
## 相关文档
- [插件开发指南](./plugin-development-guide)
- [插件 API 参考](./plugin-api-reference)
- [插件开发最佳实践](./plugin-best-practices)
---
# quick-start
URL: https://micyou.top/docs/quick-start
---
title: 快速开始 - MicYou 安装配置指南
description: MicYou 快速开始指南,详细介绍如何在 Windows、macOS、Linux 和 Android 上安装和配置 MicYou,将手机变成电脑麦克风。
keywords: MicYou安装,MicYou配置,MicYou快速开始,ADB配置,USB调试,Wi-Fi连接
---
# 快速开始
## 1. 下载 ADB
从 [Android Developers](https://developer.android.com/tools/releases/platform-tools?hl=zh_cn) 下载,或使用系统包管理器:
-
-
-
其他平台请参考 [官方文档](https://developer.android.com/tools/releases/platform-tools)
## 2. 启用 USB 调试
以 OneUI 8 为例:
1. 进入「设置」> 「关于手机」
2. 点击「软件信息」,找到「编译编号」,点击 7 次以启用开发者选项
3. 返回「设置」> 「开发者选项」,启用「USB 调试」
## 3. 使用 USB 连接
请使用稳定的数据线,并确保桌面端和 Android 客户端都将连接模式切换为 `USB`。
## 4. 使用 Wi-Fi 连接
请确保 Android 设备与 PC 处于同一网络环境,并且桌面端和 Android 客户端都将连接模式切换为 `Wi-Fi`。
## Android
1. 下载并安装 APK 到您的 Android 设备
2. 确保您的设备与 PC 处于同一网络(Wi-Fi 模式),或通过 USB 连接
## Windows
1. 运行桌面端应用程序
2. 配置连接模式以匹配 Android 应用
## macOS
为了获得更好的使用体验,建议通过 Homebrew 安装以下依赖:
```bash
brew install blackhole-2ch --cask
brew install switchaudio-osx --formulae
```
> **BlackHole** 必须安装(虚拟音频驱动)。若未安装 Homebrew,请前往 https://existential.audio/blackhole/download/ 下载安装程序并安装。
完成后请重启您的 Mac。
在 [社区下载页](https://pan.quark.cn/s/cdda33358113) 下载应用并安装到“应用程序”目录后,首次启动可能会被 Gatekeeper 拦截。
- 若提示「不受信任的开发者」,请前往 **「系统设置」/「系统偏好设置」 > 「隐私与安全」** 允许应用运行。
- 若提示「应用已损坏」,请在终端执行:
```bash
sudo xattr -r -d com.apple.quarantine /Applications/MicYou.app
```
执行时需要输入您的用户账号密码,输入时密码不可见,完成后回车即可。
## Linux
### 使用预编译包(推荐)
预编译包可在 [社区下载页](https://pan.quark.cn/s/cdda33358113) 下载。
**DEB 包(适用于 Debian/Ubuntu/Mint 等发行版):**
```bash
# 从社区下载页获取 .deb 包
sudo dpkg -i MicYou-*.deb
# 如果缺少依赖:
sudo apt install -f
```
**RPM 包(适用于 Fedora/RHEL/openSUSE 等发行版):**
```bash
# 从社区下载页获取 .rpm 包
sudo rpm -i MicYou-*.rpm
# 或者使用 dnf/yum:
sudo dnf install MicYou-*.rpm
```
**AUR 仓库(适用于 Arch Linux 及其衍生发行版):**
```bash
# 克隆 AUR 仓库并自动安装软件包及其依赖
git clone https://aur.archlinux.org/micyou-bin.git
cd micyou-bin
makepkg -si
# 或者使用 paru 等 AUR helpers
paru -S micyou-bin
```
**运行应用:**
```bash
# 安装后可以从应用菜单运行 MicYou
# 或者从终端运行:
MicYou
```
---
# download
URL: https://micyou.top/download
---
layout: page
title: 下载 MicYou - Windows、macOS、Linux、Android
description: 下载 MicYou 客户端,支持 Windows、macOS、Linux 桌面端和 Android 移动端,将手机变成电脑麦克风。
keywords: MicYou下载,MicYou安装,Android麦克风下载,手机麦克风下载,Windows麦克风,Linux麦克风,macOS麦克风
---
---
# video
URL: https://micyou.top/video
---
aside: false
title: 视频教程 - MicYou 使用教程
description: MicYou 视频教程,包含项目简介、更新介绍和使用教程,帮助您快速上手将手机变成电脑麦克风。
keywords: MicYou教程,MicYou视频,MicYou使用教程,手机麦克风教程,Android麦克风教程
---
# 视频教程
项目简介
更新介绍
使用教程 (Bilibili)
使用教程 (YouTube)
---
# English
---
# Changelog - MicYou Version History
URL: https://micyou.top/en/changelog
Description: MicYou changelog with all version updates, new features, improvements and bug fixes.
---
# faq
URL: https://micyou.top/en/docs/faq
---
title: FAQ - MicYou Troubleshooting
description: MicYou frequently asked questions including device connection issues, firewall settings, ADB configuration, and audio output troubleshooting.
keywords: MicYou FAQ,MicYou troubleshooting,MicYou cannot connect,firewall settings,ADB issues,audio issues
---
# FAQ
## Cannot connect to device
### Wi-Fi Mode
1. **Check Firewall Settings**
Windows Firewall may block inbound connections. Please follow these steps to manually allow the ports:
1. Press `Win+R`, type `powershell`, then hold `Ctrl+Shift` and click "OK" to run PowerShell as administrator.
2. Enter the following commands:
```powershell
New-NetFirewallRule -DisplayName "MicYou-6000-TCP" -Direction Inbound -LocalPort 6000 -Protocol TCP -Action Allow
New-NetFirewallRule -DisplayName "MicYou-6001-UDP" -Direction Inbound -LocalPort 6001 -Protocol UDP -Action Allow
```
> MicYou uses TCP port `6000` (control) and UDP port `6001` (audio data) by default. Change the port numbers if you have configured a different port.
If no error appears, the operation was successful. Try connecting again.
2. **Check if devices are on the same subnet**
- Ensure the Android phone and PC are connected to the **same** Wi-Fi router.
- Ensure that **AP Isolation** or **Network Device Isolation** features are disabled in router settings (refer to your router's manual).
> [!TIP]
> Advanced users can try using tools like Nmap or ping to check connectivity.
### USB (ADB) Mode
1. **Enable Developer Options**
> The steps below may vary depending on your device. **Please use a search engine** to find instructions for your specific device.
- Find "About phone" in phone settings, tap "Build number" 7 times to enable Developer Options.
- Enter Developer Options and enable **USB debugging**.
2. **Confirm ADB connection**
> ADB tools must be installed on the computer (see Step 1: Download ADB above).
Run the following command to verify that one and only one device is connected:
```bash
adb devices
```
If multiple devices are listed, specify the target device for port forwarding:
```bash
adb -s reverse tcp:6000 tcp:6000
```
> The device serial number can be found in the output of `adb devices`.
## No audio output after connecting
Please ensure that the VB-Audio driver is correctly installed and that the following devices are **not disabled**:
- **Output Device**: CABLE Input (VB-Audio Virtual Cable)
- **Input Device**: CABLE Output (VB-Audio Virtual Cable)
To check: Open Settings > Sound, and verify both devices are **Enabled**:


---
# plugin-api-reference
URL: https://micyou.top/en/docs/plugin/plugin-api-reference
---
title: MicYou Plugin API Reference
description: Complete MicYou Plugin API documentation with detailed descriptions of all interfaces, classes, methods, and data types
keywords: MicYou API,plugin interface,PluginContext,PluginHost,audio effect API,Kotlin plugin API
---
# MicYou Plugin API Reference
This document describes all interfaces, classes, and methods of the MicYou Plugin API in detail.
## Table of Contents
- [Plugin](#plugin)
- [PluginManifest](#pluginmanifest)
- [PluginContext](#plugincontext)
- [PluginHost](#pluginhost)
- [PluginDataChannel](#plugindatachannel)
- [PluginInfo](#plugininfo)
- [PluginPlatform](#pluginplatform)
- [PluginUIProvider](#pluginuiprovider)
- [PluginSettingsProvider](#pluginsettingsprovider)
- [AudioEffectProvider](#audioeffectprovider)
- [AudioEffectPlugin](#audioeffectplugin)
- [PluginLocalization](#pluginlocalization)
- [PluginLocalizationProvider](#pluginlocalizationprovider)
- [Data Types](#data-types)
## Plugin
Main plugin interface that all plugins must implement.
```kotlin
interface Plugin {
val manifest: PluginManifest
fun onLoad(context: PluginContext) {}
fun onEnable() {}
fun onDisable() {}
fun onUnload() {}
}
```
### Properties
| Property | Type | Description |
|------|------|------|
| `manifest` | `PluginManifest` | Plugin metadata manifest containing basic plugin information |
### Methods
#### onLoad
```kotlin
fun onLoad(context: PluginContext)
```
Called when the plugin is loaded. This is the best time for plugin initialization.
**Parameters:**
- `context` - Plugin context providing runtime environment access
**Timing:** Called immediately after the plugin package is parsed and validated, after the plugin instance is created.
**Example:**
```kotlin
override fun onLoad(context: PluginContext) {
this.context = context
context.log("Plugin ${manifest.name} loaded")
// Access host capabilities
val host = context.host
context.log("Platform: ${host.platform.name}")
}
```
#### onEnable
```kotlin
fun onEnable()
```
Called when the plugin is enabled.
**Timing:** Called when the user enables the plugin in settings.
#### onDisable
```kotlin
fun onDisable()
```
Called when the plugin is disabled.
**Timing:** Called when the user disables the plugin in settings.
#### onUnload
```kotlin
fun onUnload()
```
Called when the plugin is unloaded.
**Timing:** Called when the plugin is deleted or the application closes.
---
## PluginManifest
Plugin metadata manifest describing basic plugin information.
```kotlin
@Serializable
data class PluginManifest(
val id: String,
val name: String,
val version: String,
val author: String,
val description: String = "",
val tags: List = emptyList(),
val platform: PluginPlatform = PluginPlatform.BOTH,
val minApiVersion: String,
val mainClass: String
)
```
### Properties
| Property | Type | Required | Default | Description |
|------|------|------|--------|------|
| `id` | `String` | Yes | - | Plugin unique identifier in reverse domain format |
| `name` | `String` | Yes | - | Plugin display name |
| `version` | `String` | Yes | - | Version number following semantic versioning |
| `author` | `String` | Yes | - | Author name |
| `description` | `String` | No | `""` | Plugin description |
| `tags` | `List` | No | `emptyList()` | Tags list |
| `platform` | `PluginPlatform` | No | `BOTH` | Supported platform |
| `minApiVersion` | `String` | Yes | - | Minimum API version requirement |
| `mainClass` | `String` | Yes | - | Main class fully qualified name |
---
## PluginContext
Plugin runtime context providing plugin runtime environment access.
```kotlin
interface PluginContext {
val pluginId: String
val pluginDataDir: String
val localization: PluginLocalization
val appLocalization: PluginLocalization
val host: PluginHost
// Data storage
fun getString(key: String, defaultValue: String): String
fun putString(key: String, value: String)
fun getBoolean(key: String, defaultValue: Boolean): Boolean
fun putBoolean(key: String, value: Boolean)
fun getInt(key: String, defaultValue: Int): Int
fun putInt(key: String, value: Int)
fun getFloat(key: String, defaultValue: Float): Float
fun putFloat(key: String, value: Float)
// Logging
fun log(message: String)
fun logError(message: String, throwable: Throwable? = null)
}
```
### Properties
| Property | Type | Description |
|------|------|------|
| `pluginId` | `String` | Plugin unique identifier |
| `pluginDataDir` | `String` | Plugin-specific data directory path |
| `localization` | `PluginLocalization` | Plugin localization interface |
| `appLocalization` | `PluginLocalization` | Application global localization interface |
| `host` | `PluginHost` | Host application access interface |
---
## PluginHost
Provides access to host application capabilities, allowing plugins to interact with the host.
```kotlin
interface PluginHost {
// State flows
val streamState: StateFlow
val audioLevels: StateFlow
val isMuted: StateFlow
val connectionInfo: StateFlow
val audioConfig: StateFlow
// Audio configuration
fun updateAudioConfig(config: AudioConfig)
fun updateAudioConfig(block: AudioConfig.() -> AudioConfig)
// Stream control
suspend fun startStream(ip: String, port: Int, mode: ConnectionMode, isClient: Boolean)
suspend fun stopStream()
suspend fun setMute(muted: Boolean)
fun setMonitoring(enabled: Boolean)
// Audio effect registration
fun registerAudioEffect(effect: AudioEffectProvider, priority: Int = 100)
fun unregisterAudioEffect(effect: AudioEffectProvider)
// Data channels
fun createDataChannel(id: String, config: DataChannelConfig = DataChannelConfig()): PluginDataChannel
fun getDataChannel(id: String): PluginDataChannel?
fun closeDataChannel(id: String)
// UI feedback
fun showSnackbar(message: String)
fun showNotification(title: String, message: String)
// Settings access
fun getSetting(key: String, defaultValue: String): String
fun setSetting(key: String, value: String)
fun getSettingBoolean(key: String, defaultValue: Boolean): Boolean
fun setSettingBoolean(key: String, value: Boolean)
fun getSettingInt(key: String, defaultValue: Int): Int
fun setSettingInt(key: String, value: Int)
fun getSettingFloat(key: String, defaultValue: Float): Float
fun setSettingFloat(key: String, value: Float)
// Platform info
val platform: PlatformInfo
}
```
### State Flows
| Property | Type | Description |
|------|------|------|
| `streamState` | `StateFlow` | Current stream state |
| `audioLevels` | `StateFlow` | Audio levels |
| `isMuted` | `StateFlow` | Mute state |
| `connectionInfo` | `StateFlow` | Connection info |
| `audioConfig` | `StateFlow` | Audio configuration |
### Methods
#### updateAudioConfig
```kotlin
fun updateAudioConfig(config: AudioConfig)
fun updateAudioConfig(block: AudioConfig.() -> AudioConfig)
```
Update audio processing configuration.
**Example:**
```kotlin
context.host.updateAudioConfig {
copy(enableNS = true, nsType = NoiseReductionType.RNNoise)
}
```
#### startStream / stopStream
```kotlin
suspend fun startStream(ip: String, port: Int, mode: ConnectionMode, isClient: Boolean)
suspend fun stopStream()
```
Start/stop audio stream.
#### registerAudioEffect / unregisterAudioEffect
```kotlin
fun registerAudioEffect(effect: AudioEffectProvider, priority: Int = 100)
fun unregisterAudioEffect(effect: AudioEffectProvider)
```
Register/unregister custom audio effect provider. Lower priority values execute first.
#### createDataChannel / getDataChannel / closeDataChannel
```kotlin
fun createDataChannel(id: String, config: DataChannelConfig = DataChannelConfig()): PluginDataChannel
fun getDataChannel(id: String): PluginDataChannel?
fun closeDataChannel(id: String)
```
Create/get/close custom network data channel.
**Parameters:**
- `id` - Channel unique identifier
- `config` - Channel configuration
**Example:**
```kotlin
val channel = context.host.createDataChannel("my-channel")
channel.connect("192.168.1.100", 8080)
// ... use channel
context.host.closeDataChannel("my-channel")
```
#### showSnackbar / showNotification
```kotlin
fun showSnackbar(message: String)
fun showNotification(title: String, message: String)
```
Display UI feedback.
---
## PluginDataChannel
Custom network data channel interface allowing plugins to establish independent network connections.
```kotlin
enum class DataChannelMode {
Tcp, Udp
}
data class DataChannelConfig(
val mode: DataChannelMode = DataChannelMode.Tcp,
val port: Int = 0,
val bufferSize: Int = 8192
)
interface PluginDataChannel {
val id: String
val config: DataChannelConfig
val isConnected: Flow
val localPort: Int
suspend fun connect(host: String, port: Int): Result
suspend fun bind(port: Int = 0): Result
suspend fun send(data: ByteArray): Result
fun receive(): Flow
suspend fun close()
}
```
### DataChannelMode
| Mode | Description |
|------|------|
| `Tcp` | TCP connection, reliable transmission |
| `Udp` | UDP connection, low latency |
### DataChannelConfig
| Property | Type | Default | Description |
|------|------|--------|------|
| `mode` | `DataChannelMode` | `Tcp` | Connection mode |
| `port` | `Int` | `0` | Local port (0 for auto assignment) |
| `bufferSize` | `Int` | `8192` | Receive buffer size |
### PluginDataChannel Methods
#### connect
```kotlin
suspend fun connect(host: String, port: Int): Result
```
Connect to remote host as client.
**Parameters:**
- `host` - Remote host address
- `port` - Remote port
**Returns:** `Result` indicating connection result
#### bind
```kotlin
suspend fun bind(port: Int = 0): Result
```
Bind to local port, listen for connections as server.
**Parameters:**
- `port` - Local port, 0 for auto assignment
**Returns:** `Result` indicating binding result
#### send
```kotlin
suspend fun send(data: ByteArray): Result
```
Send data.
#### receive
```kotlin
fun receive(): Flow
```
Receive data stream.
#### close
```kotlin
suspend fun close()
```
Close channel.
### Usage Example
```kotlin
class CameraStreamPlugin : Plugin {
private lateinit var channel: PluginDataChannel
override fun onEnable() {
channel = context.host.createDataChannel("camera-stream",
DataChannelConfig(mode = DataChannelMode.Udp)
)
scope.launch {
channel.connect("192.168.1.100", 9000)
.onSuccess {
while (true) {
val frame = captureCameraFrame()
channel.send(frame)
delay(33) // ~30fps
}
}
.onFailure { e ->
context.logError("Connection failed: ${e.message}")
}
}
}
override fun onDisable() {
context.host.closeDataChannel("camera-stream")
}
}
```
---
## PluginInfo
Plugin runtime information.
```kotlin
data class PluginInfo(
val manifest: PluginManifest,
val isEnabled: Boolean = false,
val isLoaded: Boolean = false,
val installPath: String,
val iconPath: String? = null
)
```
---
## PluginPlatform
Plugin supported platform enumeration.
```kotlin
enum class PluginPlatform {
MOBILE, // Mobile only
DESKTOP, // Desktop only
BOTH // Both need to be installed
}
```
---
## PluginUIProvider
Plugin UI provider interface.
```kotlin
enum class MobileUIMode {
Dialog, // Dialog mode
NewScreen // New screen mode
}
interface PluginUIProvider {
val hasMainWindow: Boolean get() = false
val hasDialog: Boolean get() = false
// Window configuration (desktop)
val windowWidth: Dp get() = 600.dp
val windowHeight: Dp get() = 500.dp
val windowTitle: String get() = "Plugin Window"
val windowResizable: Boolean get() = true
// Mobile UI mode
val mobileUIMode: MobileUIMode get() = MobileUIMode.Dialog
@Composable
fun MainWindow(onClose: () -> Unit) {}
@Composable
fun DialogContent(onDismiss: () -> Unit) {}
}
```
### Properties
| Property | Type | Default | Description |
|------|------|--------|------|
| `hasMainWindow` | `Boolean` | `false` | Whether to provide main window |
| `hasDialog` | `Boolean` | `false` | Whether to provide dialog |
| `windowWidth` | `Dp` | `600.dp` | Window width (desktop) |
| `windowHeight` | `Dp` | `500.dp` | Window height (desktop) |
| `windowTitle` | `String` | `"Plugin Window"` | Window title |
| `windowResizable` | `Boolean` | `true` | Whether window is resizable |
| `mobileUIMode` | `MobileUIMode` | `Dialog` | Mobile UI mode |
---
## PluginSettingsProvider
Plugin settings page provider interface.
```kotlin
interface PluginSettingsProvider {
@Composable
fun SettingsContent()
}
```
---
## AudioEffectProvider
Audio effect provider interface for implementing custom audio processing.
```kotlin
interface AudioEffectProvider {
val id: String
val name: String
val description: String
var isEnabled: Boolean
fun process(input: ShortArray, channelCount: Int, sampleRate: Int): ShortArray
fun reset()
fun release()
fun onConfigChanged(config: AudioConfig) {}
}
```
### Properties
| Property | Type | Description |
|------|------|------|
| `id` | `String` | Effect unique identifier |
| `name` | `String` | Effect display name |
| `description` | `String` | Effect description |
| `isEnabled` | `Boolean` | Whether enabled |
### Methods
#### process
```kotlin
fun process(input: ShortArray, channelCount: Int, sampleRate: Int): ShortArray
```
Process audio data.
**Parameters:**
- `input` - Input audio sample data (16-bit PCM)
- `channelCount` - Number of channels
- `sampleRate` - Sample rate
**Returns:** Processed audio data
---
## AudioEffectPlugin
Audio effect plugin interface simplifying audio effect plugin implementation.
```kotlin
interface AudioEffectPlugin : Plugin {
val audioEffectProvider: AudioEffectProvider
val effectPriority: Int get() = 100
}
```
---
## Data Types
### StreamState
```kotlin
enum class StreamState {
Idle, Connecting, Streaming, Error
}
```
### ConnectionMode
```kotlin
enum class ConnectionMode {
Wifi, Usb
}
```
### NoiseReductionType
```kotlin
enum class NoiseReductionType {
Ulunas, RNNoise, Speexdsp, None
}
```
### AudioConfig
```kotlin
data class AudioConfig(
val enableNS: Boolean = false,
val nsType: NoiseReductionType = NoiseReductionType.RNNoise,
val enableAGC: Boolean = false,
val agcTargetLevel: Int = 32000,
val enableVAD: Boolean = false,
val vadThreshold: Int = 10,
val enableDereverb: Boolean = false,
val dereverbLevel: Float = 0.5f,
val amplification: Float = 0.0f
)
```
### ConnectionInfo
```kotlin
data class ConnectionInfo(
val mode: ConnectionMode,
val ipAddress: String,
val port: Int,
val isClient: Boolean
)
```
### PlatformInfo
```kotlin
data class PlatformInfo(
val name: String,
val version: String,
val isDesktop: Boolean,
val isMobile: Boolean
)
```
---
# MicYou Plugin Development Best Practices
URL: https://micyou.top/en/docs/plugin/plugin-best-practices
Description: Best practices guide for MicYou plugin development including project structure, lifecycle management, audio effect development, and performance optimization
# MicYou Plugin Development Best Practices
This document provides best practices and recommendations for MicYou plugin development.
## Project Structure
### Recommended Directory Structure
```
my-plugin/
├── build.gradle.kts
├── src/
│ └── main/
│ ├── kotlin/
│ │ └── com/example/myplugin/
│ │ ├── MyPlugin.kt # Main class
│ │ ├── MyPluginUI.kt # UI components
│ │ ├── MyPluginSettings.kt # Settings page
│ │ ├── AudioEffects.kt # Audio effects (optional)
│ │ └── model/ # Data models
│ │ └ Config.kt
│ └── resources/
│ └── plugin.json # Manifest file
└── README.md
```
### Code Organization
Separate different functionalities into different files:
```kotlin
// MyPlugin.kt - Main class
class MyPlugin : Plugin {
override val manifest = PluginManifest(...)
// Lifecycle methods
}
// MyPluginUI.kt - UI components
class MyPluginUI : PluginUIProvider {
// UI implementation
}
// MyPluginSettings.kt - Settings page
class MyPluginSettings : PluginSettingsProvider {
// Settings page implementation
}
```
## Lifecycle Management
### Properly Manage State
```kotlin
class MyPlugin : Plugin {
private var context: PluginContext? = null
private var isRunning = false
override fun onLoad(context: PluginContext) {
this.context = context
context.log("Plugin loaded")
}
override fun onEnable() {
if (isRunning) return
isRunning = true
startBackgroundTask()
}
override fun onDisable() {
if (!isRunning) return
isRunning = false
stopBackgroundTask()
}
override fun onUnload() {
context = null
releaseAllResources()
}
}
```
### Avoid Memory Leaks
```kotlin
class MyPlugin : Plugin {
private val jobs = mutableListOf()
override fun onEnable() {
jobs.add(startTask1())
jobs.add(startTask2())
}
override fun onDisable() {
jobs.forEach { it.cancel() }
jobs.clear()
}
}
```
## Accessing Host Capabilities
### Listen to State Changes
```kotlin
@Composable
override fun MainWindow(onClose: () -> Unit) {
val host = context?.host ?: return
// Listen to stream state
val streamState by host.streamState.collectAsState()
// Listen to audio levels
val audioLevel by host.audioLevels.collectAsState()
// Listen to audio configuration
val audioConfig by host.audioConfig.collectAsState()
Column {
Text("Stream: $streamState")
Text("Level: $audioLevel")
Text("NS: ${audioConfig.enableNS}")
}
}
```
### Modify Audio Configuration
```kotlin
class MyPlugin : Plugin {
fun enableNoiseReduction() {
context?.host?.updateAudioConfig { config ->
config.copy(
enableNS = true,
nsType = NoiseReductionType.RNNoise
)
}
}
fun setAmplification(gainDb: Float) {
context?.host?.updateAudioConfig { config ->
config.copy(amplification = gainDb)
}
}
}
```
## Audio Effect Development
### Implement Custom Noise Reduction
```kotlin
class CustomNoiseReducer : AudioEffectProvider {
override val id = "com.example.custom-ns"
override val name = "Custom Noise Reducer"
override val description = "AI-powered noise reduction"
override var isEnabled = true
private var model: NoiseModel? = null
override fun process(input: ShortArray, channelCount: Int, sampleRate: Int): ShortArray {
if (!isEnabled) return input
// Implement noise reduction algorithm
val output = ShortArray(input.size)
for (i in input.indices) {
output[i] = reduceNoise(input[i])
}
return output
}
private fun reduceNoise(sample: Short): Short {
// Noise reduction logic
return sample
}
override fun reset() {
model?.reset()
}
override fun release() {
model?.close()
model = null
}
override fun onConfigChanged(config: AudioConfig) {
// Adjust parameters based on configuration
}
}
```
### Register Audio Effect
```kotlin
class MyPlugin : Plugin {
private val noiseReducer = CustomNoiseReducer()
override fun onLoad(context: PluginContext) {
// Register effect with priority 50 (lower values execute first)
context.host.registerAudioEffect(noiseReducer, priority = 50)
}
override fun onUnload() {
// Unregister effect
context?.host?.unregisterAudioEffect(noiseReducer)
noiseReducer.release()
}
}
```
### Use AudioEffectPlugin for Simplification
```kotlin
class MyPlugin : AudioEffectPlugin {
override val manifest = PluginManifest(...)
override val audioEffectProvider = CustomNoiseReducer()
override val effectPriority = 50
// Lifecycle is handled automatically by AudioEffectPlugin
}
```
## Data Storage
### Use PluginContext for Storage
```kotlin
class MyPlugin : Plugin {
private var context: PluginContext? = null
fun saveConfig(config: Config) {
context?.apply {
putString("serverUrl", config.serverUrl)
putInt("port", config.port)
putBoolean("ssl", config.useSsl)
}
}
fun loadConfig(): Config {
return context?.let {
Config(
serverUrl = it.getString("serverUrl", "localhost"),
port = it.getInt("port", 8080),
useSsl = it.getBoolean("ssl", false)
)
} ?: Config()
}
}
```
### File Storage
```kotlin
class MyPlugin : Plugin {
private fun saveDataFile(data: String) {
val context = context ?: return
val file = File(context.pluginDataDir, "data.json")
file.writeText(data)
}
private fun loadDataFile(): String? {
val context = context ?: return null
val file = File(context.pluginDataDir, "data.json")
return if (file.exists()) file.readText() else null
}
}
```
## UI Development
### Responsive UI
```kotlin
class MyPluginUI : PluginUIProvider {
override val hasMainWindow = true
@Composable
override fun MainWindow(onClose: () -> Unit) {
var data by remember { mutableStateOf(emptyList- ()) }
var loading by remember { mutableStateOf(true) }
LaunchedEffect(Unit) {
data = loadData()
loading = false
}
if (loading) {
Box(Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
CircularProgressIndicator()
}
} else {
LazyColumn {
items(data) { item ->
ItemRow(item)
}
}
}
}
}
```
### Mobile UI Mode Selection
```kotlin
class MyPlugin : Plugin, PluginUIProvider {
// For complex UI, use new screen mode
override val mobileUIMode = MobileUIMode.NewScreen
// For simple dialogs, use dialog mode
// override val mobileUIMode = MobileUIMode.Dialog
}
```
### Settings Page Best Practices
```kotlin
class MyPluginSettings : PluginSettingsProvider {
@Composable
override fun SettingsContent() {
var serverUrl by remember { mutableStateOf("") }
var port by remember { mutableStateOf(8080) }
Column(Modifier.padding(16.dp).fillMaxWidth()) {
Text("Connection Settings", style = MaterialTheme.typography.titleMedium)
Spacer(Modifier.height(16.dp))
OutlinedTextField(
value = serverUrl,
onValueChange = { serverUrl = it },
label = { Text("Server URL") },
modifier = Modifier.fillMaxWidth(),
singleLine = true
)
Spacer(Modifier.height(8.dp))
OutlinedTextField(
value = port.toString(),
onValueChange = { port = it.toIntOrNull() ?: 8080 },
label = { Text("Port") },
modifier = Modifier.fillMaxWidth(),
singleLine = true
)
Spacer(Modifier.height(16.dp))
Button(
onClick = { saveSettings(serverUrl, port) },
modifier = Modifier.align(Alignment.End)
) {
Text("Save")
}
}
}
}
```
## Notifications and Feedback
### Show Messages
```kotlin
class MyPlugin : Plugin {
fun showFeedback() {
val host = context?.host ?: return
// Short message
host.showSnackbar("Operation completed!")
// System notification
host.showNotification(
title = "My Plugin",
message = "Background task finished successfully"
)
}
}
```
## Error Handling
### Handle Errors Gracefully
```kotlin
class MyPlugin : Plugin {
fun performOperation() {
try {
val result = riskyOperation()
context?.log("Operation succeeded: $result")
} catch (e: Exception) {
context?.logError("Operation failed", e)
context?.host?.showSnackbar("Operation failed: ${e.message}")
}
}
}
```
### Validate Host State
```kotlin
class MyPlugin : Plugin {
fun startStreaming() {
val host = context?.host ?: run {
context?.logError("Host not available")
return
}
if (host.streamState.value != StreamState.Idle) {
host.showSnackbar("Please stop current stream first")
return
}
// Start stream
}
}
```
## Performance Optimization
### Audio Processing Optimization
```kotlin
class OptimizedEffect : AudioEffectProvider {
private var buffer: ShortArray = ShortArray(0)
override fun process(input: ShortArray, channelCount: Int, sampleRate: Int): ShortArray {
// Reuse buffer to avoid allocation
if (buffer.size != input.size) {
buffer = ShortArray(input.size)
}
// Use SIMD or other optimization techniques
for (i in input.indices) {
buffer[i] = processSample(input[i])
}
return buffer
}
}
```
### Coroutine Usage
```kotlin
class MyPlugin : Plugin {
private val scope = CoroutineScope(Dispatchers.Default)
override fun onEnable() {
scope.launch {
while (isActive) {
performBackgroundTask()
delay(1000)
}
}
}
override fun onDisable() {
scope.cancel()
}
}
```
## Related Documentation
- [Plugin Development Guide](./plugin-development-guide)
- [Plugin API Reference](./plugin-api-reference)
- [Plugin Package Format Specification](./plugin-package-format)
---
# MicYou Plugin Development Guide
URL: https://micyou.top/en/docs/plugin/plugin-development-guide
Description: Quick start guide for MicYou plugin system development, learn how to create custom plugins to extend app functionality
# MicYou Plugin Development Guide
Quick start guide for MicYou plugin development.
## Overview
The MicYou plugin system allows developers to extend application functionality. Plugins can:
- Provide custom UI interfaces (main window, dialog, or new screen)
- Provide settings pages
- Access plugin-specific storage space
- Access host application state and control capabilities
- Register custom audio effects (noise reduction, gain, etc.)
- Modify application settings and audio configuration
## Quick Start
### 1. Create Project
Create a new Kotlin/JVM Gradle project:
```kotlin
// build.gradle.kts
plugins {
kotlin("jvm") version "2.2.20"
kotlin("plugin.serialization") version "2.2.20"
kotlin("plugin.compose") version "2.2.20"
id("org.jetbrains.compose") version "1.7.3"
}
group = "com.example"
version = "1.0.0"
repositories {
mavenCentral()
google()
}
dependencies {
compileOnly(files("path/to/plugin-api-jvm.jar"))
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.0")
// Compose
implementation(compose.runtime)
implementation(compose.foundation)
implementation(compose.material3)
implementation(compose.ui)
}
```
### 2. Implement Plugin Interface
Create the plugin main class:
```kotlin
package com.example.myplugin
import com.lanrhyme.micyou.plugin.*
class MyPlugin : Plugin {
override val manifest = PluginManifest(
id = "com.example.myplugin",
name = "My Plugin",
version = "1.0.0",
author = "Your Name",
description = "A sample plugin for MicYou",
minApiVersion = "1.0.0",
mainClass = "com.example.myplugin.MyPlugin"
)
override fun onLoad(context: PluginContext) {
context.log("Plugin loaded!")
// Access host capabilities
val host = context.host
context.log("Platform: ${host.platform.name}")
}
override fun onEnable() {
// Called when plugin is enabled
}
override fun onDisable() {
// Called when plugin is disabled
}
override fun onUnload() {
// Called when plugin is unloaded
}
}
```
### 3. Create plugin.json
Create `plugin.json` in the resources directory:
```json
{
"id": "com.example.myplugin",
"name": "My Plugin",
"version": "1.0.0",
"author": "Your Name",
"description": "A sample plugin for MicYou",
"minApiVersion": "1.0.0",
"mainClass": "com.example.myplugin.MyPlugin"
}
```
### 4. Package Plugin
Build JAR file and package:
```bash
./gradlew jar
# Create plugin package
mkdir -p plugin-package
cp build/libs/my-plugin.jar plugin-package/plugin.jar
cp src/main/resources/plugin.json plugin-package/
cd plugin-package && zip -r ../my-plugin.micyou-plugin.zip .
```
### 5. Install Plugin
1. Open MicYou application
2. Go to Settings → Plugins
3. Click "Import Plugin" button
4. Select the `.micyou-plugin.zip` file
5. Enable the plugin
## Core Interfaces
### Plugin
Main plugin interface, defining lifecycle methods:
```kotlin
interface Plugin {
val manifest: PluginManifest
fun onLoad(context: PluginContext) {}
fun onEnable() {}
fun onDisable() {}
fun onUnload() {}
}
```
### PluginContext
Provides plugin runtime environment:
```kotlin
interface PluginContext {
val pluginId: String
val pluginDataDir: String
// Localization interface
val localization: PluginLocalization
val appLocalization: PluginLocalization
// Data storage
fun getString(key: String, defaultValue: String): String
fun putString(key: String, value: String)
fun getBoolean(key: String, defaultValue: Boolean): Boolean
fun putBoolean(key: String, value: Boolean)
fun getInt(key: String, defaultValue: Int): Int
fun putInt(key: String, value: Int)
fun getFloat(key: String, defaultValue: Float): Float
fun putFloat(key: String, value: Float)
// Logging
fun log(message: String)
fun logError(message: String, throwable: Throwable? = null)
// Host capabilities
val host: PluginHost
}
```
### PluginHost
Provides access to host application capabilities:
```kotlin
interface PluginHost {
// State flows
val streamState: StateFlow
val audioLevels: StateFlow
val isMuted: StateFlow
val connectionInfo: StateFlow
val audioConfig: StateFlow
// Audio configuration
fun updateAudioConfig(config: AudioConfig)
fun updateAudioConfig(block: AudioConfig.() -> AudioConfig)
// Stream control
suspend fun startStream(ip: String, port: Int, mode: ConnectionMode, isClient: Boolean)
suspend fun stopStream()
suspend fun setMute(muted: Boolean)
fun setMonitoring(enabled: Boolean)
// Audio effect registration
fun registerAudioEffect(effect: AudioEffectProvider, priority: Int = 100)
fun unregisterAudioEffect(effect: AudioEffectProvider)
// UI feedback
fun showSnackbar(message: String)
fun showNotification(title: String, message: String)
// Settings access
fun getSetting(key: String, defaultValue: String): String
fun setSetting(key: String, value: String)
// ... other settings methods
// Platform info
val platform: PlatformInfo
}
```
### PluginUIProvider
Provides plugin UI components:
```kotlin
interface PluginUIProvider {
val hasMainWindow: Boolean get() = false
val hasDialog: Boolean get() = false
// Window configuration (desktop)
val windowWidth: Dp get() = 600.dp
val windowHeight: Dp get() = 500.dp
val windowTitle: String get() = "Plugin Window"
val windowResizable: Boolean get() = true
// Mobile UI mode
val mobileUIMode: MobileUIMode get() = MobileUIMode.Dialog
@Composable
fun MainWindow(onClose: () -> Unit) {}
@Composable
fun DialogContent(onDismiss: () -> Unit) {}
}
enum class MobileUIMode {
Dialog, // Dialog mode
NewScreen // New screen mode
}
```
### PluginSettingsProvider
Provides plugin settings page:
```kotlin
interface PluginSettingsProvider {
@Composable
fun SettingsContent()
}
```
## Advanced Features
### Access Host State
```kotlin
class MyPlugin : Plugin {
private var context: PluginContext? = null
override fun onLoad(context: PluginContext) {
this.context = context
// Get current stream state
val state = context.host.streamState.value
context.log("Current stream state: $state")
// Get audio configuration
val config = context.host.audioConfig.value
context.log("NS enabled: ${config.enableNS}")
}
}
```
### Modify Audio Configuration
```kotlin
class MyPlugin : Plugin {
fun enableCustomNoiseReduction() {
context?.host?.updateAudioConfig { config ->
config.copy(
enableNS = true,
nsType = NoiseReductionType.RNNoise
)
}
}
}
```
### Register Custom Audio Effect
```kotlin
class MyNoiseReducer : AudioEffectProvider {
override val id = "com.example.myplugin.noise-reducer"
override val name = "My Noise Reducer"
override val description = "Custom noise reduction effect"
override var isEnabled = true
override fun process(input: ShortArray, channelCount: Int, sampleRate: Int): ShortArray {
// Implement noise reduction algorithm
return input
}
override fun reset() {
// Reset internal state
}
override fun release() {
// Release resources
}
}
class MyPlugin : Plugin, AudioEffectPlugin {
override val audioEffectProvider = MyNoiseReducer()
override val effectPriority = 50 // Higher priority
override fun onLoad(context: PluginContext) {
// Register audio effect
context.host.registerAudioEffect(audioEffectProvider, effectPriority)
}
override fun onUnload() {
context?.host?.unregisterAudioEffect(audioEffectProvider)
}
}
```
### Show Notifications
```kotlin
class MyPlugin : Plugin {
fun notifyUser() {
context?.host?.showSnackbar("Operation completed!")
context?.host?.showNotification("My Plugin", "Background task finished")
}
}
```
### Read/Modify Application Settings
```kotlin
class MyPlugin : Plugin {
fun readAppSettings() {
val host = context?.host ?: return
// Read application settings
val theme = host.getSetting("theme", "system")
val autoStart = host.getSettingBoolean("autoStart", false)
// Modify application settings
host.setSettingBoolean("autoStart", true)
}
}
```
## Localization
Plugins support multi-language localization. Create an `i18n/` folder in resources:
```
src/main/resources/
└── i18n/
├── en.json
├── zh-CN.json
└── ja.json
```
JSON file format:
```json
{
"plugin.name": "My Plugin",
"plugin.description": "A sample plugin",
"settings.title": "Settings",
"button.save": "Save"
}
```
Use localization in code:
```kotlin
class MyPlugin : Plugin, PluginLocalizationProvider {
override fun getLocalizedString(languageCode: String, key: String): String? {
return when (languageCode) {
"zh" -> zhStrings[key]
"en" -> enStrings[key]
else -> null
}
}
override fun getSupportedLanguages(): List {
return listOf("zh", "en")
}
}
```
## Complete Example
```kotlin
class MyPlugin : Plugin, PluginUIProvider, PluginSettingsProvider {
private var context: PluginContext? = null
override val manifest = PluginManifest(
id = "com.example.myplugin",
name = "My Plugin",
version = "1.0.0",
author = "Your Name",
description = "A plugin with UI and settings",
minApiVersion = "1.0.0",
mainClass = "com.example.myplugin.MyPlugin"
)
// PluginUIProvider
override val hasMainWindow = true
override val windowWidth = 700.dp
override val windowHeight = 500.dp
override val windowTitle = "My Plugin"
override val mobileUIMode = MobileUIMode.NewScreen
@Composable
override fun MainWindow(onClose: () -> Unit) {
val host = context?.host
val streamState by host?.streamState?.collectAsState()
?: remember { mutableStateOf(StreamState.Idle) }
Column(modifier = Modifier.padding(16.dp)) {
Text("Stream State: $streamState")
Button(onClick = { host?.showSnackbar("Hello!") }) {
Text("Show Message")
}
}
}
// PluginSettingsProvider
@Composable
override fun SettingsContent() {
// Settings page content
}
}
```
## Related Documentation
- [Plugin API Reference](./plugin-api-reference)
- [Plugin Development Best Practices](./plugin-best-practices)
- [Plugin Package Format Specification](./plugin-package-format)
---
# MicYou Plugin Package Format Specification
URL: https://micyou.top/en/docs/plugin/plugin-package-format
Description: Detailed MicYou plugin package structure specification including plugin.json configuration, JAR file requirements, and icon specifications
# MicYou Plugin Package Format Specification
## Plugin Package Structure
A plugin package is a ZIP compressed file with the extension `.micyou-plugin.zip`, containing the following structure:
```
my-plugin.micyou-plugin.zip
├── plugin.json # Required: Plugin metadata manifest
├── plugin.jar # Required: Plugin code (Kotlin/JVM compiled artifact)
├── assets/ # Optional: Resource files directory
│ ├── images/
│ ├── sounds/
│ └── ...
└── icon.png # Optional: Plugin icon (recommended 128x128 PNG)
```
## plugin.json Specification
### JSON Schema
```json
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"required": ["id", "name", "version", "author", "description", "minApiVersion", "mainClass"],
"properties": {
"id": {
"type": "string",
"pattern": "^[a-z][a-z0-9_]*(\\.[a-z][a-z0-9_]*)+$",
"description": "Plugin unique identifier in reverse domain format, e.g. com.example.myplugin"
},
"name": {
"type": "string",
"minLength": 1,
"maxLength": 100,
"description": "Plugin display name"
},
"version": {
"type": "string",
"pattern": "^\\d+\\.\\d+\\.\\d+(-[a-zA-Z0-9]+)?$",
"description": "Version number following semantic versioning, e.g. 1.0.0 or 1.0.0-beta"
},
"author": {
"type": "string",
"minLength": 1,
"maxLength": 100,
"description": "Author name"
},
"description": {
"type": "string",
"minLength": 1,
"maxLength": 500,
"description": "Plugin description"
},
"tags": {
"type": "array",
"items": {
"type": "string",
"enum": ["camera", "streaming", "audio", "video", "utility", "effect", "network", "storage"]
},
"description": "Plugin tags for categorization and filtering"
},
"platform": {
"type": "string",
"enum": ["mobile", "desktop", "both"],
"default": "both",
"description": "Supported platform: mobile=mobile only, desktop=desktop only, both=both platforms required"
},
"minApiVersion": {
"type": "string",
"pattern": "^\\d+\\.\\d+\\.\\d+$",
"description": "Minimum API version requirement"
},
"mainClass": {
"type": "string",
"description": "Plugin main class fully qualified name, must implement Plugin interface"
}
}
}
```
### Field Descriptions
| Field | Required | Type | Description |
|------|------|------|------|
| id | Yes | string | Plugin unique identifier in reverse domain format |
| name | Yes | string | Plugin display name, 1-100 characters |
| version | Yes | string | Semantic version number |
| author | Yes | string | Author name |
| description | Yes | string | Plugin description, 1-500 characters |
| tags | No | string[] | Tags array for categorization and filtering |
| platform | No | string | Supported platform: mobile/desktop/both, default both |
| minApiVersion | Yes | string | Minimum API version |
| mainClass | Yes | string | Main class fully qualified name |
## Complete Example
```json
{
"id": "com.example.audio-enhancer",
"name": "Audio Enhancer",
"version": "1.0.0",
"author": "Developer Name",
"description": "A plugin that provides advanced audio enhancement features including custom noise reduction and equalization.",
"tags": ["audio", "effect"],
"platform": "both",
"minApiVersion": "1.0.0",
"mainClass": "com.example.audioenhancer.AudioEnhancerPlugin"
}
```
## plugin.jar Requirements
- Must be a valid JVM JAR file
- Main class must implement `com.lanrhyme.micyou.plugin.Plugin` interface
- Can contain other dependency classes, but using shaded JAR is recommended to avoid conflicts
- File size should not exceed 50MB
## Icon Specification
- Format: PNG
- Recommended size: 128x128 pixels
- Supports transparent background
- Filename must be `icon.png`
## Platform Description
| Value | Description |
|------|------|
| `mobile` | Android only support |
| `desktop` | JVM Desktop only support |
| `both` | Both platforms need to be installed, used for cross-platform features |
## Related Documentation
- [Plugin Development Guide](./plugin-development-guide)
- [Plugin API Reference](./plugin-api-reference)
- [Plugin Development Best Practices](./plugin-best-practices)
---
# quick-start
URL: https://micyou.top/en/docs/quick-start
---
title: Quick Start - MicYou Installation Guide
description: MicYou quick start guide with detailed instructions on how to install and configure MicYou on Windows, macOS, Linux, and Android to turn your phone into a PC microphone.
keywords: MicYou install,MicYou setup,MicYou quick start,ADB setup,USB debugging,Wi-Fi connection
---
# Quick Start
## 1. Download ADB
Download from [Android Developers](https://developer.android.com/tools/releases/platform-tools?hl=zh_cn), or install via package manager:
-
-
-
Other platforms, please refer to [official documentation](https://developer.android.com/tools/releases/platform-tools)
## 2. Enable USB Debugging
Using OneUI 8 as an example:
1. Go to Settings > About phone
2. Tap Software information, find Build number and tap it 7 times to enable Developer Options
3. Go back to Settings > Developer options, and enable USB debugging
## 3. USB connection
Use a **stable** data cable, and set the connection mode to `USB` on **both** the desktop app and the Android app.
## 4. Wi-Fi connection
Ensure your Android device and PC are on the **same network**, and set the connection mode to `Wi-Fi` on **both** the desktop app and the Android app.
## Android
1. Download and install the APK on your Android device.
2. Ensure your device is on the same network as your PC (for Wi-Fi) or connected via USB.
## Windows
1. Run the desktop application.
2. Configure the connection mode to match the Android app.
## macOS
For the best experience, install the following dependencies via Homebrew:
```bash
brew install blackhole-2ch --cask
brew install switchaudio-osx --formulae
```
> **BlackHole** is required (virtual audio driver). If you do not have Homebrew, go to https://existential.audio/blackhole/download/ to download the installer.
Please restart your Mac after installation.
After downloading the app from the [community download page](https://pan.quark.cn/s/cdda33358113) and installing it in your Applications folder, Gatekeeper may block it during first use:
- If prompted with "Untrusted Developer," navigate to **System Settings/System Preferences > Privacy & Security** to allow the app to run.
- If prompted with "The application is damaged," execute the following command:
```bash
sudo xattr -r -d com.apple.quarantine /Applications/MicYou.app
```
You will need to enter your account password during the process. The password will be hidden while you are entering it. Press Enter after you have finished entering it.
## Linux
### Using pre-built packages (recommended)
Pre-built packages are available on the [community download page](https://pan.quark.cn/s/cdda33358113). Choose the appropriate package for your Linux distribution.
**DEB package (Debian/Ubuntu/Mint etc.):**
```bash
sudo dpkg -i MicYou-*.deb
# If dependencies are missing:
sudo apt install -f
```
**RPM package (Fedora/RHEL/openSUSE etc.):**
```bash
sudo rpm -i MicYou-*.rpm
# Or use dnf/yum:
sudo dnf install MicYou-*.rpm
```
**AUR (Arch Linux and derivatives):**
```bash
git clone https://aur.archlinux.org/micyou-bin.git
cd micyou-bin
makepkg -si
```
Or use an AUR helper like paru:
```bash
paru -S micyou-bin
```
**Run the application:**
From the application menu, or run from terminal:
```bash
MicYou
```
---
# Download MicYou - Windows, macOS, Linux, Android
URL: https://micyou.top/en/download
Description: Download MicYou client for Windows, macOS, Linux desktop and Android mobile to turn your phone into a PC microphone.
---
# Video Tutorials - MicYou Guide
URL: https://micyou.top/en/video
Description: MicYou video tutorials including project introduction, whats new, and usage guides to help you get started turning your phone into a PC microphone.
# Video Tutorials
Introduction
What's New
Tutorial (Bilibili)
Tutorial (YouTube)
---
# 繁體中文
---
# 更新日誌 - MicYou 版本歷史
URL: https://micyou.top/zh-TW/changelog
Description: MicYou 更新日誌,查看所有版本的新功能、改進和修復內容。
---
# faq
URL: https://micyou.top/zh-TW/docs/faq
---
title: 常見問題 - MicYou 故障排除
description: MicYou 常見問題解答,包括裝置連線問題、防火牆設定、ADB 設定和音訊輸出故障排除等。
keywords: MicYou常見問題,MicYou故障排除,MicYou無法連線,防火牆設定,ADB問題,音訊問題
---
# 常見問題
## 無法連線裝置
### Wi-Fi 模式
1. **確認防火牆設定**
Windows 防火牆可能會攔截入站連線。請按照以下步驟手動放行連接埠:
1. 按下 `Win+R`,輸入 `powershell`,同時按住 `Ctrl+Shift`,點選「確定」以系統管理員身分執行 PowerShell。
2. 輸入以下命令:
```powershell
New-NetFirewallRule -DisplayName "MicYou-6000-TCP" -Direction Inbound -LocalPort 6000 -Protocol TCP -Action Allow
New-NetFirewallRule -DisplayName "MicYou-6001-UDP" -Direction Inbound -LocalPort 6001 -Protocol UDP -Action Allow
```
> MicYou 預設使用 TCP 連接埠 `6000`(控制通道)和 UDP 連接埠 `6001`(音訊資料)。如已修改連接埠號,請將命令中的連接埠號替換為實際值。
若未出現任何錯誤訊息,表示操作成功,可嘗試重新連線。
2. **檢查裝置是否在同一子網路**
- 確保 Android 手機與 PC 連接的是**同一個**路由器的 Wi-Fi
- 確保路由器已關閉 **AP 隔離** 或 **網路裝置隔離** 功能(詳情請參考路由器說明書)
> [!TIP]
> 進階使用者可使用 Nmap 或 ping 等工具檢查連線性。
### USB (ADB) 模式
1. **開啟開發者選項**
> 不同裝置的步驟可能不同,**建議使用搜尋引擎**搜尋為您的裝置開啟 ADB 的教學。
- 在手機設定中找到「關於本機」,連續點擊 7 次「系統版本號」以開啟開發者選項
- 進入開發者選項,開啟 **USB 偵錯**
2. **確認 ADB 連線**
> 電腦端需安裝 ADB 工具(參見第 1 步:下載 ADB)。
執行以下命令確認有且僅有一個裝置已連線:
```bash
adb devices
```
若列出多個裝置,需指定目標裝置進行連接埠轉發:
```bash
adb -s <裝置序列號> reverse tcp:6000 tcp:6000
```
> 裝置序列號可在 `adb devices` 的輸出中找到。
## 連線裝置後無聲音輸出
請確保 VB-Audio 驅動已正確安裝,且以下裝置未被停用:
- **輸出裝置**:CABLE Input (VB-Audio Virtual Cable)
- **輸入裝置**:CABLE Output (VB-Audio Virtual Cable)
檢查方式:開啟「設定」> 「聲音」,確保以下兩項均為**已啟用**狀態:


---
# plugin-api-reference
URL: https://micyou.top/zh-TW/docs/plugin/plugin-api-reference
---
title: MicYou 插件 API 參考
description: MicYou Plugin API 完整介面文檔,包含所有類別、方法和資料類型的詳細說明
keywords: MicYou API,插件介面,PluginContext,PluginHost,音訊效果API,Kotlin插件API
---
# MicYou 插件 API 參考
本文檔詳細描述 MicYou Plugin API 的所有介面、類別和方法。
## 目錄
- [Plugin](#plugin)
- [PluginManifest](#pluginmanifest)
- [PluginContext](#plugincontext)
- [PluginHost](#pluginhost)
- [PluginDataChannel](#plugindatachannel)
- [PluginInfo](#plugininfo)
- [PluginPlatform](#pluginplatform)
- [PluginUIProvider](#pluginuiprovider)
- [PluginSettingsProvider](#pluginsettingsprovider)
- [AudioEffectProvider](#audioeffectprovider)
- [AudioEffectPlugin](#audioeffectplugin)
- [PluginLocalization](#pluginlocalization)
- [PluginLocalizationProvider](#pluginlocalizationprovider)
- [資料類型](#資料類型)
## Plugin
插件主介面,所有插件必須實作此介面。
```kotlin
interface Plugin {
val manifest: PluginManifest
fun onLoad(context: PluginContext) {}
fun onEnable() {}
fun onDisable() {}
fun onUnload() {}
}
```
### 屬性
| 属性 | 类型 | 说明 |
|------|------|------|
| `manifest` | `PluginManifest` | 插件元資料清單,包含插件的基本資訊 |
### 方法
#### onLoad
```kotlin
fun onLoad(context: PluginContext)
```
插件載入時呼叫。這是插件初始化的最佳時機。
**參數:**
- `context` - 插件上下文,提供執行環境存取能力
**呼叫時機:** 插件包被解析並驗證通過後,在插件實例建立後立即呼叫。
**範例:**
```kotlin
override fun onLoad(context: PluginContext) {
this.context = context
context.log("Plugin ${manifest.name} loaded")
// 存取主機能力
val host = context.host
context.log("Platform: ${host.platform.name}")
}
```
#### onEnable
```kotlin
fun onEnable()
```
插件啟用時呼叫。
**呼叫時機:** 使用者在設定中啟用插件時呼叫。
#### onDisable
```kotlin
fun onDisable()
```
插件停用時呼叫。
**呼叫時機:** 使用者在設定中停用插件時呼叫。
#### onUnload
```kotlin
fun onUnload()
```
插件卸載時呼叫。
**呼叫時機:** 插件被刪除或應用關閉時呼叫。
---
## PluginManifest
插件元資料清單,描述插件的基本資訊。
```kotlin
@Serializable
data class PluginManifest(
val id: String,
val name: String,
val version: String,
val author: String,
val description: String = "",
val tags: List = emptyList(),
val platform: PluginPlatform = PluginPlatform.BOTH,
val minApiVersion: String,
val mainClass: String
)
```
### 属性
| 属性 | 类型 | 必需 | 預設值 | 说明 |
|------|------|------|--------|------|
| `id` | `String` | 是 | - | 插件唯一識別符,反向域名格式 |
| `name` | `String` | 是 | - | 插件顯示名稱 |
| `version` | `String` | 是 | - | 版本號,遵循語義化版本規範 |
| `author` | `String` | 是 | - | 作者名稱 |
| `description` | `String` | 否 | `""` | 插件描述 |
| `tags` | `List` | 否 | `emptyList()` | 標籤列表 |
| `platform` | `PluginPlatform` | 否 | `BOTH` | 支援的平台 |
| `minApiVersion` | `String` | 是 | - | 最低 API 版本要求 |
| `mainClass` | `String` | 是 | - | 主類別全限定名 |
---
## PluginContext
插件執行上下文,提供插件執行環境存取能力。
```kotlin
interface PluginContext {
val pluginId: String
val pluginDataDir: String
val localization: PluginLocalization
val appLocalization: PluginLocalization
val host: PluginHost
// 資料儲存
fun getString(key: String, defaultValue: String): String
fun putString(key: String, value: String)
fun getBoolean(key: String, defaultValue: Boolean): Boolean
fun putBoolean(key: String, value: Boolean)
fun getInt(key: String, defaultValue: Int): Int
fun putInt(key: String, value: Int)
fun getFloat(key: String, defaultValue: Float): Float
fun putFloat(key: String, value: Float)
// 日誌
fun log(message: String)
fun logError(message: String, throwable: Throwable? = null)
}
```
### 属性
| 属性 | 类型 | 说明 |
|------|------|------|
| `pluginId` | `String` | 插件唯一識別符 |
| `pluginDataDir` | `String` | 插件專屬資料目錄路徑 |
| `localization` | `PluginLocalization` | 插件本地化介面 |
| `appLocalization` | `PluginLocalization` | 應用全域本地化介面 |
| `host` | `PluginHost` | 主機應用存取介面 |
---
## PluginHost
提供對主機應用的存取能力,允許插件與主機互動。
```kotlin
interface PluginHost {
// 狀態流
val streamState: StateFlow
val audioLevels: StateFlow
val isMuted: StateFlow
val connectionInfo: StateFlow
val audioConfig: StateFlow
// 音訊配置
fun updateAudioConfig(config: AudioConfig)
fun updateAudioConfig(block: AudioConfig.() -> AudioConfig)
// 流控制
suspend fun startStream(ip: String, port: Int, mode: ConnectionMode, isClient: Boolean)
suspend fun stopStream()
suspend fun setMute(muted: Boolean)
fun setMonitoring(enabled: Boolean)
// 音訊效果註冊
fun registerAudioEffect(effect: AudioEffectProvider, priority: Int = 100)
fun unregisterAudioEffect(effect: AudioEffectProvider)
// 資料通道
fun createDataChannel(id: String, config: DataChannelConfig = DataChannelConfig()): PluginDataChannel
fun getDataChannel(id: String): PluginDataChannel?
fun closeDataChannel(id: String)
// UI 反饋
fun showSnackbar(message: String)
fun showNotification(title: String, message: String)
// 設定存取
fun getSetting(key: String, defaultValue: String): String
fun setSetting(key: String, value: String)
fun getSettingBoolean(key: String, defaultValue: Boolean): Boolean
fun setSettingBoolean(key: String, value: Boolean)
fun getSettingInt(key: String, defaultValue: Int): Int
fun setSettingInt(key: String, value: Int)
fun getSettingFloat(key: String, defaultValue: Float): Float
fun setSettingFloat(key: String, value: Float)
// 平台資訊
val platform: PlatformInfo
}
```
### 狀態流
| 属性 | 类型 | 说明 |
|------|------|------|
| `streamState` | `StateFlow` | 目前串流狀態 |
| `audioLevels` | `StateFlow` | 音訊電平 |
| `isMuted` | `StateFlow` | 靜音狀態 |
| `connectionInfo` | `StateFlow` | 連線資訊 |
| `audioConfig` | `StateFlow` | 音訊配置 |
### 方法
#### updateAudioConfig
```kotlin
fun updateAudioConfig(config: AudioConfig)
fun updateAudioConfig(block: AudioConfig.() -> AudioConfig)
```
更新音訊處理配置。
**範例:**
```kotlin
context.host.updateAudioConfig {
copy(enableNS = true, nsType = NoiseReductionType.RNNoise)
}
```
#### startStream / stopStream
```kotlin
suspend fun startStream(ip: String, port: Int, mode: ConnectionMode, isClient: Boolean)
suspend fun stopStream()
```
啟動/停止音訊串流。
#### registerAudioEffect / unregisterAudioEffect
```kotlin
fun registerAudioEffect(effect: AudioEffectProvider, priority: Int = 100)
fun unregisterAudioEffect(effect: AudioEffectProvider)
```
註冊/註銷自訂音訊效果器。優先級數值越小,越先執行。
#### createDataChannel / getDataChannel / closeDataChannel
```kotlin
fun createDataChannel(id: String, config: DataChannelConfig = DataChannelConfig()): PluginDataChannel
fun getDataChannel(id: String): PluginDataChannel?
fun closeDataChannel(id: String)
```
建立/取得/關閉自訂網路資料通道。
**參數:**
- `id` - 通道唯一識別符
- `config` - 通道配置
**範例:**
```kotlin
val channel = context.host.createDataChannel("my-channel")
channel.connect("192.168.1.100", 8080)
// ... 使用通道
context.host.closeDataChannel("my-channel")
```
#### showSnackbar / showNotification
```kotlin
fun showSnackbar(message: String)
fun showNotification(title: String, message: String)
```
顯示 UI 反饋。
---
## PluginDataChannel
自訂網路資料通道介面,允許插件建立獨立的網路連線。
```kotlin
enum class DataChannelMode {
Tcp, Udp
}
data class DataChannelConfig(
val mode: DataChannelMode = DataChannelMode.Tcp,
val port: Int = 0,
val bufferSize: Int = 8192
)
interface PluginDataChannel {
val id: String
val config: DataChannelConfig
val isConnected: Flow
val localPort: Int
suspend fun connect(host: String, port: Int): Result
suspend fun bind(port: Int = 0): Result
suspend fun send(data: ByteArray): Result
fun receive(): Flow
suspend fun close()
}
```
### DataChannelMode
| 模式 | 说明 |
|------|------|
| `Tcp` | TCP 連線,可靠傳輸 |
| `Udp` | UDP 連線,低延遲 |
### DataChannelConfig
| 属性 | 类型 | 預設值 | 说明 |
|------|------|--------|------|
| `mode` | `DataChannelMode` | `Tcp` | 連線模式 |
| `port` | `Int` | `0` | 本地埠(0 表示自動分配) |
| `bufferSize` | `Int` | `8192` | 接收緩衝區大小 |
### PluginDataChannel 方法
#### connect
```kotlin
suspend fun connect(host: String, port: Int): Result
```
作為客戶端連線到遠端主機。
**參數:**
- `host` - 遠端主機地址
- `port` - 遠端埠
**返回:** `Result` 表示連線結果
#### bind
```kotlin
suspend fun bind(port: Int = 0): Result
```
綁定本地埠,作為伺服端監聽連線。
**參數:**
- `port` - 本地埠,0 表示自動分配
**返回:** `Result` 表示綁定結果
#### send
```kotlin
suspend fun send(data: ByteArray): Result
```
傳送資料。
#### receive
```kotlin
fun receive(): Flow
```
接收資料流。
#### close
```kotlin
suspend fun close()
```
關閉通道。
### 使用範例
```kotlin
class CameraStreamPlugin : Plugin {
private lateinit var channel: PluginDataChannel
override fun onEnable() {
channel = context.host.createDataChannel("camera-stream",
DataChannelConfig(mode = DataChannelMode.Udp)
)
scope.launch {
channel.connect("192.168.1.100", 9000)
.onSuccess {
while (true) {
val frame = captureCameraFrame()
channel.send(frame)
delay(33) // ~30fps
}
}
.onFailure { e ->
context.logError("Connection failed: ${e.message}")
}
}
}
override fun onDisable() {
context.host.closeDataChannel("camera-stream")
}
}
```
---
## PluginInfo
插件執行時資訊。
```kotlin
data class PluginInfo(
val manifest: PluginManifest,
val isEnabled: Boolean = false,
val isLoaded: Boolean = false,
val installPath: String,
val iconPath: String? = null
)
```
---
## PluginPlatform
插件支援平台枚舉。
```kotlin
enum class PluginPlatform {
MOBILE, // 仅移动端
DESKTOP, // 仅桌面端
BOTH // 两端都需要安装
}
```
---
## PluginUIProvider
插件 UI 提供者介面。
```kotlin
enum class MobileUIMode {
Dialog, // 对话框模式
NewScreen // 新页面模式
}
interface PluginUIProvider {
val hasMainWindow: Boolean get() = false
val hasDialog: Boolean get() = false
// 窗口配置(桌面端)
val windowWidth: Dp get() = 600.dp
val windowHeight: Dp get() = 500.dp
val windowTitle: String get() = "Plugin Window"
val windowResizable: Boolean get() = true
// 移动端 UI 模式
val mobileUIMode: MobileUIMode get() = MobileUIMode.Dialog
@Composable
fun MainWindow(onClose: () -> Unit) {}
@Composable
fun DialogContent(onDismiss: () -> Unit) {}
}
```
### 属性
| 属性 | 类型 | 預設值 | 说明 |
|------|------|--------|------|
| `hasMainWindow` | `Boolean` | `false` | 是否提供主視窗 |
| `hasDialog` | `Boolean` | `false` | 是否提供對話框 |
| `windowWidth` | `Dp` | `600.dp` | 視窗寬度(桌面端) |
| `windowHeight` | `Dp` | `500.dp` | 視窗高度(桌面端) |
| `windowTitle` | `String` | `"Plugin Window"` | 視窗標題 |
| `windowResizable` | `Boolean` | `true` | 視窗是否可調整大小 |
| `mobileUIMode` | `MobileUIMode` | `Dialog` | 行動端 UI 模式 |
---
## PluginSettingsProvider
插件設定頁面提供者介面。
```kotlin
interface PluginSettingsProvider {
@Composable
fun SettingsContent()
}
```
---
## AudioEffectProvider
音訊效果提供者介面,用於實作自訂音訊處理。
```kotlin
interface AudioEffectProvider {
val id: String
val name: String
val description: String
var isEnabled: Boolean
fun process(input: ShortArray, channelCount: Int, sampleRate: Int): ShortArray
fun reset()
fun release()
fun onConfigChanged(config: AudioConfig) {}
}
```
### 属性
| 属性 | 类型 | 说明 |
|------|------|------|
| `id` | `String` | 效果器唯一識別符 |
| `name` | `String` | 效果器顯示名稱 |
| `description` | `String` | 效果器描述 |
| `isEnabled` | `Boolean` | 是否啟用 |
### 方法
#### process
```kotlin
fun process(input: ShortArray, channelCount: Int, sampleRate: Int): ShortArray
```
處理音訊資料。
**參數:**
- `input` - 輸入音訊採樣資料(16-bit PCM)
- `channelCount` - 声道数
- `sampleRate` - 采样率
**返回:** 处理后的音频数据
---
## AudioEffectPlugin
音訊效果插件介面,簡化音訊效果插件的實作。
```kotlin
interface AudioEffectPlugin : Plugin {
val audioEffectProvider: AudioEffectProvider
val effectPriority: Int get() = 100
}
```
---
## 資料類型
### StreamState
```kotlin
enum class StreamState {
Idle, Connecting, Streaming, Error
}
```
### ConnectionMode
```kotlin
enum class ConnectionMode {
Wifi, Usb
}
```
### NoiseReductionType
```kotlin
enum class NoiseReductionType {
Ulunas, RNNoise, Speexdsp, None
}
```
### AudioConfig
```kotlin
data class AudioConfig(
val enableNS: Boolean = false,
val nsType: NoiseReductionType = NoiseReductionType.RNNoise,
val enableAGC: Boolean = false,
val agcTargetLevel: Int = 32000,
val enableVAD: Boolean = false,
val vadThreshold: Int = 10,
val enableDereverb: Boolean = false,
val dereverbLevel: Float = 0.5f,
val amplification: Float = 0.0f
)
```
### ConnectionInfo
```kotlin
data class ConnectionInfo(
val mode: ConnectionMode,
val ipAddress: String,
val port: Int,
val isClient: Boolean
)
```
### PlatformInfo
```kotlin
data class PlatformInfo(
val name: String,
val version: String,
val isDesktop: Boolean,
val isMobile: Boolean
)
```
---
# MicYou 插件開發最佳實踐
URL: https://micyou.top/zh-TW/docs/plugin/plugin-best-practices
Description: MicYou 插件開發最佳實踐指南,包含專案結構、生命週期管理、音訊效果開發和效能優化建議
# MicYou 插件開發最佳實踐
本文檔提供 MicYou 插件開發的最佳實踐和建議。
## 專案結構
### 推薦目錄結構
```
my-plugin/
├── build.gradle.kts
├── src/
│ └── main/
│ ├── kotlin/
│ │ └── com/example/myplugin/
│ │ ├── MyPlugin.kt # 主類別
│ │ ├── MyPluginUI.kt # UI 元件
│ │ ├── MyPluginSettings.kt # 設定頁面
│ │ ├── AudioEffects.kt # 音訊效果(可選)
│ │ └── model/ # 資料模型
│ │ └ Config.kt
│ └── resources/
│ └── plugin.json # 清單檔案
└ README.md
```
### 程式碼組織
將不同功能分離到不同檔案:
```kotlin
// MyPlugin.kt - 主類別
class MyPlugin : Plugin {
override val manifest = PluginManifest(...)
// 生命週期方法
}
// MyPluginUI.kt - UI 元件
class MyPluginUI : PluginUIProvider {
// UI 實作
}
// MyPluginSettings.kt - 設定頁面
class MyPluginSettings : PluginSettingsProvider {
// 設定頁面實作
}
```
## 生命週期管理
### 正確管理狀態
```kotlin
class MyPlugin : Plugin {
private var context: PluginContext? = null
private var isRunning = false
override fun onLoad(context: PluginContext) {
this.context = context
context.log("Plugin loaded")
}
override fun onEnable() {
if (isRunning) return
isRunning = true
startBackgroundTask()
}
override fun onDisable() {
if (!isRunning) return
isRunning = false
stopBackgroundTask()
}
override fun onUnload() {
context = null
releaseAllResources()
}
}
```
### 避免記憶體洩漏
```kotlin
class MyPlugin : Plugin {
private val jobs = mutableListOf()
override fun onEnable() {
jobs.add(startTask1())
jobs.add(startTask2())
}
override fun onDisable() {
jobs.forEach { it.cancel() }
jobs.clear()
}
}
```
## 存取主機能力
### 監聽狀態變化
```kotlin
@Composable
override fun MainWindow(onClose: () -> Unit) {
val host = context?.host ?: return
// 監聽串流狀態
val streamState by host.streamState.collectAsState()
// 監聽音訊電平
val audioLevel by host.audioLevels.collectAsState()
// 監聯音訊配置
val audioConfig by host.audioConfig.collectAsState()
Column {
Text("Stream: $streamState")
Text("Level: $audioLevel")
Text("NS: ${audioConfig.enableNS}")
}
}
```
### 修改音訊配置
```kotlin
class MyPlugin : Plugin {
fun enableNoiseReduction() {
context?.host?.updateAudioConfig { config ->
config.copy(
enableNS = true,
nsType = NoiseReductionType.RNNoise
)
}
}
fun setAmplification(gainDb: Float) {
context?.host?.updateAudioConfig { config ->
config.copy(amplification = gainDb)
}
}
}
```
## 音訊效果開發
### 實作自訂降噪
```kotlin
class CustomNoiseReducer : AudioEffectProvider {
override val id = "com.example.custom-ns"
override val name = "Custom Noise Reducer"
override val description = "AI-powered noise reduction"
override var isEnabled = true
private var model: NoiseModel? = null
override fun process(input: ShortArray, channelCount: Int, sampleRate: Int): ShortArray {
if (!isEnabled) return input
// 實作降噪演算法
val output = ShortArray(input.size)
for (i in input.indices) {
output[i] = reduceNoise(input[i])
}
return output
}
private fun reduceNoise(sample: Short): Short {
// 降噪邏輯
return sample
}
override fun reset() {
model?.reset()
}
override fun release() {
model?.close()
model = null
}
override fun onConfigChanged(config: AudioConfig) {
// 根據配置調整參數
}
}
```
### 註冊音訊效果
```kotlin
class MyPlugin : Plugin {
private val noiseReducer = CustomNoiseReducer()
override fun onLoad(context: PluginContext) {
// 註冊效果器,優先級 50(數值越小越先執行)
context.host.registerAudioEffect(noiseReducer, priority = 50)
}
override fun onUnload() {
// 註銷效果器
context?.host?.unregisterAudioEffect(noiseReducer)
noiseReducer.release()
}
}
```
### 使用 AudioEffectPlugin 簡化
```kotlin
class MyPlugin : AudioEffectPlugin {
override val manifest = PluginManifest(...)
override val audioEffectProvider = CustomNoiseReducer()
override val effectPriority = 50
// 生命週期由 AudioEffectPlugin 自動處理
}
```
## 資料儲存
### 使用 PluginContext 儲存
```kotlin
class MyPlugin : Plugin {
private var context: PluginContext? = null
fun saveConfig(config: Config) {
context?.apply {
putString("serverUrl", config.serverUrl)
putInt("port", config.port)
putBoolean("ssl", config.useSsl)
}
}
fun loadConfig(): Config {
return context?.let {
Config(
serverUrl = it.getString("serverUrl", "localhost"),
port = it.getInt("port", 8080),
useSsl = it.getBoolean("ssl", false)
)
} ?: Config()
}
}
```
### 檔案儲存
```kotlin
class MyPlugin : Plugin {
private fun saveDataFile(data: String) {
val context = context ?: return
val file = File(context.pluginDataDir, "data.json")
file.writeText(data)
}
private fun loadDataFile(): String? {
val context = context ?: return null
val file = File(context.pluginDataDir, "data.json")
return if (file.exists()) file.readText() else null
}
}
```
## UI 開發
### 回應式 UI
```kotlin
class MyPluginUI : PluginUIProvider {
override val hasMainWindow = true
@Composable
override fun MainWindow(onClose: () -> Unit) {
var data by remember { mutableStateOf(emptyList- ()) }
var loading by remember { mutableStateOf(true) }
LaunchedEffect(Unit) {
data = loadData()
loading = false
}
if (loading) {
Box(Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
CircularProgressIndicator()
}
} else {
LazyColumn {
items(data) { item ->
ItemRow(item)
}
}
}
}
}
```
### 行動端 UI 模式選擇
```kotlin
class MyPlugin : Plugin, PluginUIProvider {
// 對於複雜 UI,使用新頁面模式
override val mobileUIMode = MobileUIMode.NewScreen
// 對於簡單對話框,使用對話框模式
// override val mobileUIMode = MobileUIMode.Dialog
}
```
### 設定頁面最佳實踐
```kotlin
class MyPluginSettings : PluginSettingsProvider {
@Composable
override fun SettingsContent() {
var serverUrl by remember { mutableStateOf("") }
var port by remember { mutableStateOf(8080) }
Column(Modifier.padding(16.dp).fillMaxWidth()) {
Text("Connection Settings", style = MaterialTheme.typography.titleMedium)
Spacer(Modifier.height(16.dp))
OutlinedTextField(
value = serverUrl,
onValueChange = { serverUrl = it },
label = { Text("Server URL") },
modifier = Modifier.fillMaxWidth(),
singleLine = true
)
Spacer(Modifier.height(8.dp))
OutlinedTextField(
value = port.toString(),
onValueChange = { port = it.toIntOrNull() ?: 8080 },
label = { Text("Port") },
modifier = Modifier.fillMaxWidth(),
singleLine = true
)
Spacer(Modifier.height(16.dp))
Button(
onClick = { saveSettings(serverUrl, port) },
modifier = Modifier.align(Alignment.End)
) {
Text("Save")
}
}
}
}
```
## 通知和反饋
### 顯示訊息
```kotlin
class MyPlugin : Plugin {
fun showFeedback() {
val host = context?.host ?: return
// 簡短訊息
host.showSnackbar("Operation completed!")
// 系統通知
host.showNotification(
title = "My Plugin",
message = "Background task finished successfully"
)
}
}
```
## 錯誤處理
### 優雅處理錯誤
```kotlin
class MyPlugin : Plugin {
fun performOperation() {
try {
val result = riskyOperation()
context?.log("Operation succeeded: $result")
} catch (e: Exception) {
context?.logError("Operation failed", e)
context?.host?.showSnackbar("Operation failed: ${e.message}")
}
}
}
```
### 驗證主機狀態
```kotlin
class MyPlugin : Plugin {
fun startStreaming() {
val host = context?.host ?: run {
context?.logError("Host not available")
return
}
if (host.streamState.value != StreamState.Idle) {
host.showSnackbar("Please stop current stream first")
return
}
// 啟動串流
}
}
```
## 效能優化
### 音訊處理優化
```kotlin
class OptimizedEffect : AudioEffectProvider {
private var buffer: ShortArray = ShortArray(0)
override fun process(input: ShortArray, channelCount: Int, sampleRate: Int): ShortArray {
// 重用緩衝區避免分配
if (buffer.size != input.size) {
buffer = ShortArray(input.size)
}
// 使用 SIMD 或其他優化技術
for (i in input.indices) {
buffer[i] = processSample(input[i])
}
return buffer
}
}
```
### 協程使用
```kotlin
class MyPlugin : Plugin {
private val scope = CoroutineScope(Dispatchers.Default)
override fun onEnable() {
scope.launch {
while (isActive) {
performBackgroundTask()
delay(1000)
}
}
}
override fun onDisable() {
scope.cancel()
}
}
```
## 相關文檔
- [插件開發指南](./plugin-development-guide)
- [插件 API 參考](./plugin-api-reference)
- [插件包格式規範](./plugin-package-format)
---
# MicYou 插件開發指南
URL: https://micyou.top/zh-TW/docs/plugin/plugin-development-guide
Description: MicYou 插件系統開發快速入門,學習如何建立自訂插件擴充應用功能
# MicYou 插件開發指南
MicYou 插件開發快速開始指南。
## 概述
MicYou 插件系統允許開發者擴充應用功能。插件可以:
- 提供自訂 UI 界面(主視窗、對話框或新頁面)
- 提供設定頁面
- 存取插件專屬儲存空間
- 存取主機應用狀態和控制能力
- 註冊自訂音訊效果器(降噪、增益等)
- 修改應用設定和音訊配置
## 快速開始
### 1. 建立專案
建立一個新的 Kotlin/JVM Gradle 專案:
```kotlin
// build.gradle.kts
plugins {
kotlin("jvm") version "2.2.20"
kotlin("plugin.serialization") version "2.2.20"
kotlin("plugin.compose") version "2.2.20"
id("org.jetbrains.compose") version "1.7.3"
}
group = "com.example"
version = "1.0.0"
repositories {
mavenCentral()
google()
}
dependencies {
compileOnly(files("path/to/plugin-api-jvm.jar"))
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.0")
// Compose
implementation(compose.runtime)
implementation(compose.foundation)
implementation(compose.material3)
implementation(compose.ui)
}
```
### 2. 實作 Plugin 介面
建立插件主類別:
```kotlin
package com.example.myplugin
import com.lanrhyme.micyou.plugin.*
class MyPlugin : Plugin {
override val manifest = PluginManifest(
id = "com.example.myplugin",
name = "My Plugin",
version = "1.0.0",
author = "Your Name",
description = "A sample plugin for MicYou",
minApiVersion = "1.0.0",
mainClass = "com.example.myplugin.MyPlugin"
)
override fun onLoad(context: PluginContext) {
context.log("Plugin loaded!")
// 存取主機能力
val host = context.host
context.log("Platform: ${host.platform.name}")
}
override fun onEnable() {
// 插件啟用時呼叫
}
override fun onDisable() {
// 插件停用時呼叫
}
override fun onUnload() {
// 插件卸載時呼叫
}
}
```
### 3. 建立 plugin.json
在資源目錄建立 `plugin.json`:
```json
{
"id": "com.example.myplugin",
"name": "My Plugin",
"version": "1.0.0",
"author": "Your Name",
"description": "A sample plugin for MicYou",
"minApiVersion": "1.0.0",
"mainClass": "com.example.myplugin.MyPlugin"
}
```
### 4. 打包插件
建置 JAR 檔案並打包:
```bash
./gradlew jar
# 建立插件包
mkdir -p plugin-package
cp build/libs/my-plugin.jar plugin-package/plugin.jar
cp src/main/resources/plugin.json plugin-package/
cd plugin-package && zip -r ../my-plugin.micyou-plugin.zip .
```
### 5. 安裝插件
1. 開啟 MicYou 應用
2. 進入設定 → 插件
3. 點擊「匯入插件」按鈕
4. 選擇 `.micyou-plugin.zip` 檔案
5. 啟用插件
## 核心介面
### Plugin
插件主介面,定義生命周期方法:
```kotlin
interface Plugin {
val manifest: PluginManifest
fun onLoad(context: PluginContext) {}
fun onEnable() {}
fun onDisable() {}
fun onUnload() {}
}
```
### PluginContext
提供插件執行環境:
```kotlin
interface PluginContext {
val pluginId: String
val pluginDataDir: String
// 本地化介面
val localization: PluginLocalization
val appLocalization: PluginLocalization
// 資料儲存
fun getString(key: String, defaultValue: String): String
fun putString(key: String, value: String)
fun getBoolean(key: String, defaultValue: Boolean): Boolean
fun putBoolean(key: String, value: Boolean)
fun getInt(key: String, defaultValue: Int): Int
fun putInt(key: String, value: Int)
fun getFloat(key: String, defaultValue: Float): Float
fun putFloat(key: String, value: Float)
// 日誌
fun log(message: String)
fun logError(message: String, throwable: Throwable? = null)
// 主機能力
val host: PluginHost
}
```
### PluginHost
提供對主機應用的存取能力:
```kotlin
interface PluginHost {
// 狀態流
val streamState: StateFlow
val audioLevels: StateFlow
val isMuted: StateFlow
val connectionInfo: StateFlow
val audioConfig: StateFlow
// 音訊配置
fun updateAudioConfig(config: AudioConfig)
fun updateAudioConfig(block: AudioConfig.() -> AudioConfig)
// 流控制
suspend fun startStream(ip: String, port: Int, mode: ConnectionMode, isClient: Boolean)
suspend fun stopStream()
suspend fun setMute(muted: Boolean)
fun setMonitoring(enabled: Boolean)
// 音訊效果註冊
fun registerAudioEffect(effect: AudioEffectProvider, priority: Int = 100)
fun unregisterAudioEffect(effect: AudioEffectProvider)
// UI 反饋
fun showSnackbar(message: String)
fun showNotification(title: String, message: String)
// 設定存取
fun getSetting(key: String, defaultValue: String): String
fun setSetting(key: String, value: String)
// ... 其他設定方法
// 平台資訊
val platform: PlatformInfo
}
```
### PluginUIProvider
提供插件 UI 元件:
```kotlin
interface PluginUIProvider {
val hasMainWindow: Boolean get() = false
val hasDialog: Boolean get() = false
// 視窗配置(桌面端)
val windowWidth: Dp get() = 600.dp
val windowHeight: Dp get() = 500.dp
val windowTitle: String get() = "Plugin Window"
val windowResizable: Boolean get() = true
// 行動端 UI 模式
val mobileUIMode: MobileUIMode get() = MobileUIMode.Dialog
@Composable
fun MainWindow(onClose: () -> Unit) {}
@Composable
fun DialogContent(onDismiss: () -> Unit) {}
}
enum class MobileUIMode {
Dialog, // 對話框模式
NewScreen // 新頁面模式
}
```
### PluginSettingsProvider
提供插件設定頁面:
```kotlin
interface PluginSettingsProvider {
@Composable
fun SettingsContent()
}
```
## 進階功能
### 存取主機狀態
```kotlin
class MyPlugin : Plugin {
private var context: PluginContext? = null
override fun onLoad(context: PluginContext) {
this.context = context
// 取得目前串流狀態
val state = context.host.streamState.value
context.log("Current stream state: $state")
// 取得音訊配置
val config = context.host.audioConfig.value
context.log("NS enabled: ${config.enableNS}")
}
}
```
### 修改音訊配置
```kotlin
class MyPlugin : Plugin {
fun enableCustomNoiseReduction() {
context?.host?.updateAudioConfig { config ->
config.copy(
enableNS = true,
nsType = NoiseReductionType.RNNoise
)
}
}
}
```
### 註冊自訂音訊效果
```kotlin
class MyNoiseReducer : AudioEffectProvider {
override val id = "com.example.myplugin.noise-reducer"
override val name = "My Noise Reducer"
override val description = "Custom noise reduction effect"
override var isEnabled = true
override fun process(input: ShortArray, channelCount: Int, sampleRate: Int): ShortArray {
// 實作降噪演算法
return input
}
override fun reset() {
// 重置內部狀態
}
override fun release() {
// 釋放資源
}
}
class MyPlugin : Plugin, AudioEffectPlugin {
override val audioEffectProvider = MyNoiseReducer()
override val effectPriority = 50 // 較高優先級
override fun onLoad(context: PluginContext) {
// 註冊音訊效果
context.host.registerAudioEffect(audioEffectProvider, effectPriority)
}
override fun onUnload() {
context?.host?.unregisterAudioEffect(audioEffectProvider)
}
}
```
###顯示通知
```kotlin
class MyPlugin : Plugin {
fun notifyUser() {
context?.host?.showSnackbar("Operation completed!")
context?.host?.showNotification("My Plugin", "Background task finished")
}
}
```
### 讀取/修改應用設定
```kotlin
class MyPlugin : Plugin {
fun readAppSettings() {
val host = context?.host ?: return
// 讀取應用設定
val theme = host.getSetting("theme", "system")
val autoStart = host.getSettingBoolean("autoStart", false)
// 修改應用設定
host.setSettingBoolean("autoStart", true)
}
}
```
## 本地化
插件支援多語言本地化。在資源目錄建立 `i18n/` 資料夾:
```
src/main/resources/
└── i18n/
├── en.json
├── zh-CN.json
└── ja.json
```
JSON 檔案格式:
```json
{
"plugin.name": "My Plugin",
"plugin.description": "A sample plugin",
"settings.title": "Settings",
"button.save": "Save"
}
```
在程式碼中使用本地化:
```kotlin
class MyPlugin : Plugin, PluginLocalizationProvider {
override fun getLocalizedString(languageCode: String, key: String): String? {
return when (languageCode) {
"zh" -> zhStrings[key]
"en" -> enStrings[key]
else -> null
}
}
override fun getSupportedLanguages(): List {
return listOf("zh", "en")
}
}
```
## 完整範例
```kotlin
class MyPlugin : Plugin, PluginUIProvider, PluginSettingsProvider {
private var context: PluginContext? = null
override val manifest = PluginManifest(
id = "com.example.myplugin",
name = "My Plugin",
version = "1.0.0",
author = "Your Name",
description = "A plugin with UI and settings",
minApiVersion = "1.0.0",
mainClass = "com.example.myplugin.MyPlugin"
)
// PluginUIProvider
override val hasMainWindow = true
override val windowWidth = 700.dp
override val windowHeight = 500.dp
override val windowTitle = "My Plugin"
override val mobileUIMode = MobileUIMode.NewScreen
@Composable
override fun MainWindow(onClose: () -> Unit) {
val host = context?.host
val streamState by host?.streamState?.collectAsState()
?: remember { mutableStateOf(StreamState.Idle) }
Column(modifier = Modifier.padding(16.dp)) {
Text("Stream State: $streamState")
Button(onClick = { host?.showSnackbar("Hello!") }) {
Text("Show Message")
}
}
}
// PluginSettingsProvider
@Composable
override fun SettingsContent() {
// 設定頁面內容
}
}
```
## 相關文檔
- [插件 API 參考](./plugin-api-reference)
- [插件開發最佳實踐](./plugin-best-practices)
- [插件包格式規範](./plugin-package-format)
---
# MicYou 插件包格式規範
URL: https://micyou.top/zh-TW/docs/plugin/plugin-package-format
Description: MicYou 插件包結構規範詳解,包含 plugin.json 配置、JAR 檔案要求和圖示規範
# MicYou 插件包格式規範
## 插件包結構
插件包是一個 ZIP 壓縮檔案,副檔名為 `.micyou-plugin.zip`,包含以下結構:
```
my-plugin.micyou-plugin.zip
├── plugin.json # 必需:插件元資料清單
├── plugin.jar # 必需:插件程式碼(Kotlin/JVM 編譯產物)
├── assets/ # 可選:資源檔案目錄
│ ├── images/
│ ├── sounds/
│ └── ...
└── icon.png # 可選:插件圖示(建議 128x128 PNG)
```
## plugin.json 規範
### JSON Schema
```json
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"required": ["id", "name", "version", "author", "description", "minApiVersion", "mainClass"],
"properties": {
"id": {
"type": "string",
"pattern": "^[a-z][a-z0-9_]*(\\.[a-z][a-z0-9_]*)+$",
"description": "插件唯一識別符,採用反向域名格式,如 com.example.myplugin"
},
"name": {
"type": "string",
"minLength": 1,
"maxLength": 100,
"description": "插件顯示名稱"
},
"version": {
"type": "string",
"pattern": "^\\d+\\.\\d+\\.\\d+(-[a-zA-Z0-9]+)?$",
"description": "版本號,遵循語義化版本規範,如 1.0.0 或 1.0.0-beta"
},
"author": {
"type": "string",
"minLength": 1,
"maxLength": 100,
"description": "作者名稱"
},
"description": {
"type": "string",
"minLength": 1,
"maxLength": 500,
"description": "插件描述"
},
"tags": {
"type": "array",
"items": {
"type": "string",
"enum": ["camera", "streaming", "audio", "video", "utility", "effect", "network", "storage"]
},
"description": "插件標籤,用於分類和篩選"
},
"platform": {
"type": "string",
"enum": ["mobile", "desktop", "both"],
"default": "both",
"description": "支援的平台:mobile=僅行動端,desktop=僅桌面端,both=兩端都需要安裝"
},
"minApiVersion": {
"type": "string",
"pattern": "^\\d+\\.\\d+\\.\\d+$",
"description": "最低 API 版本要求"
},
"mainClass": {
"type": "string",
"description": "插件主類別全限定名,必須實作 Plugin 介面"
}
}
}
```
### 欄位說明
| 欄位 | 必需 | 類型 | 說明 |
|------|------|------|------|
| id | 是 | string | 插件唯一識別符,反向域名格式 |
| name | 是 | string | 插件顯示名稱,1-100 字元 |
| version | 是 | string | 語義化版本號 |
| author | 是 | string | 作者名稱 |
| description | 是 | string | 插件描述,1-500 字元 |
| tags | 否 | string[] | 標籤陣列,用於分類篩選 |
| platform | 否 | string | 支援平台:mobile/desktop/both,預設 both |
| minApiVersion | 是 | string | 最低 API 版本 |
| mainClass | 是 | string | 主類別全限定名 |
## 完整範例
```json
{
"id": "com.example.audio-enhancer",
"name": "Audio Enhancer",
"version": "1.0.0",
"author": "Developer Name",
"description": "A plugin that provides advanced audio enhancement features including custom noise reduction and equalization.",
"tags": ["audio", "effect"],
"platform": "both",
"minApiVersion": "1.0.0",
"mainClass": "com.example.audioenhancer.AudioEnhancerPlugin"
}
```
## plugin.jar 要求
- 必須是有效的 JVM JAR 檔案
- 主類別必須實作 `com.lanrhyme.micyou.plugin.Plugin` 介面
- 可以包含其他依賴類別,但建議使用 shaded JAR 避免衝突
- 檔案大小建議不超過 50MB
## 圖示規範
- 格式:PNG
- 建議尺寸:128x128 像素
- 支援透明背景
- 檔案名稱必須為 `icon.png`
## 平台說明
| 值 | 說明 |
|------|------|
| `mobile` | 僅 Android 端支援 |
| `desktop` | 僅 JVM Desktop 端支援 |
| `both` | 兩端都需要安裝,用於跨平台功能 |
## 相關文檔
- [插件開發指南](./plugin-development-guide)
- [插件 API 參考](./plugin-api-reference)
- [插件開發最佳實踐](./plugin-best-practices)
---
# quick-start
URL: https://micyou.top/zh-TW/docs/quick-start
---
title: 快速開始 - MicYou 安裝設定指南
description: MicYou 快速開始指南,詳細介紹如何在 Windows、macOS、Linux 和 Android 上安裝和設定 MicYou,將手機變成電腦麥克風。
keywords: MicYou安裝,MicYou設定,MicYou快速開始,ADB設定,USB偵錯,Wi-Fi連線
---
# 快速開始
## 1. 下載 ADB
從 [Android Developers](https://developer.android.com/tools/releases/platform-tools?hl=zh_cn) 下載,或使用套件管理工具:
-
-
-
其他平台請參考 [官方文檔](https://developer.android.com/tools/releases/platform-tools)
大多數情況下 ADB 會自動加入系統環境變數,如未加入請自行設定。
## 2. 啟用 USB 偵錯
以 OneUI 8 為例:
1. 進入「設定」> 「關於手機」
2. 點選「軟體資訊」,找到「編譯編號」,連點 7 次以啟用開發者選項
3. 返回「設定」> 「開發者選項」,啟用「USB 偵錯」
## 3. 使用 USB 連線
請使用品質穩定的傳輸線,並在桌面端與 Android 應用同時將連線模式切換為 `USB`。
## 4. 使用 Wi‑Fi 連線
請確保 Android 裝置與電腦位於同一網路,並在桌面端與 Android 應用同時切換成 `Wi‑Fi` 模式。
## Android
1. 下載並安裝 APK 到您的 Android 裝置
2. 確保您的裝置與 PC 位於同一網路(Wi-Fi 模式),或透過 USB 連線
## Windows
1. 執行桌面端應用程式
2. 設定連線模式以匹配 Android 應用
## macOS
為了獲得更佳的使用體驗,建議透過 Homebrew 安裝以下套件:
```bash
brew install blackhole-2ch --cask
brew install switchaudio-osx --formulae
```
> **BlackHole** 為必要軟體(虛擬音訊驅動程式)。若未安裝 Homebrew,可至 https://existential.audio/blackhole/download/ 下載安裝程式。
安裝完成後請重新啟動電腦。
從 [社群下載頁](https://pan.quark.cn/s/cdda33358113) 下載並安裝到「應用程式」資料夾。首次開啟可能會被 Gatekeeper 攔截:
- 若顯示「不受信任的開發者」,請至「系統設定」> 「隱私權與安全性」允許應用程式
- 若顯示「應用程式已損毀」,在終端執行:
```bash
sudo xattr -r -d com.apple.quarantine /Applications/MicYou.app
```
執行時需輸入您的使用者帳號密碼,輸入時密碼不可見,完成後回車即可。
## Linux
### 使用預編譯套件(推薦)
預編譯套件可在 [社群下載頁](https://pan.quark.cn/s/cdda33358113) 下載。根據您的 Linux 發行版選擇相應的套件。
**DEB 套件(Debian/Ubuntu/Mint 等):**
```bash
sudo dpkg -i MicYou-*.deb
# 如果缺少依賴:
sudo apt install -f
```
**RPM 套件(Fedora/RHEL/openSUSE 等):**
```bash
sudo rpm -i MicYou-*.rpm
# 或使用 dnf/yum:
sudo dnf install MicYou-*.rpm
```
**AUR(Arch Linux 及衍生發行版):**
```bash
git clone https://aur.archlinux.org/micyou-bin.git
cd micyou-bin
makepkg -si
```
或使用 AUR 輔助程式(如 paru):
```bash
paru -S micyou-bin
```
**執行應用:**
從應用程式選單執行,或在終端執行:
```bash
MicYou
```
---
# 下載 MicYou - Windows、macOS、Linux、Android
URL: https://micyou.top/zh-TW/download
Description: 下載 MicYou 用戶端,支援 Windows、macOS、Linux 桌面端和 Android 行動端,將手機變成電腦麥克風。
---
# 影片教學 - MicYou 使用教學
URL: https://micyou.top/zh-TW/video
Description: MicYou 影片教學,包含專案簡介、更新介紹和使用教學,幫助您快速上手將手機變成電腦麥克風。
# 影片教學
專案簡介
更新介紹
使用教學 (Bilibili)
使用教學 (YouTube)