Flutter音频处理插件win32audio的使用
Flutter音频处理插件win32audio的使用
win32audio
是一个用于在Windows上获取音频设备信息、调整音量等操作的Flutter插件。它不仅可以枚举音频设备,还可以获取和设置主音量或单个应用程序的音量。此外,它还提供了一个实用函数 nativeIconToBytes
,可用于从EXE或DLL文件中提取图标并存储为 Uint8List
。
使用方法
枚举设备
音频设备
要枚举所有音频设备(输入或输出),可以使用以下代码:
var audioDevices = <AudioDevice>[];
audioDevices = await Audio.enumDevices(audioDeviceType) ?? [];
音频混音器
要枚举音频混音器(即当前运行的应用程序及其音量信息),可以使用以下代码:
var mixerList = <ProcessVolume>[];
mixerList = await Audio.enumAudioMixer() ?? [];
默认设备
获取默认设备
要获取当前的默认音频设备,可以使用以下代码:
var defaultDevice = AudioDevice();
defaultDevice = (await Audio.getDefaultDevice(audioDeviceType))!;
设置默认设备
要设置新的默认音频设备,可以使用以下代码:
await Audio.setDefaultDevice(audioDevices[0].id, console: false, multimedia: true, communications: false);
切换到下一个音频设备
要切换到下一个音频设备,可以使用以下代码:
await Audio.switchDefaultDevice(audioDeviceType, console: false, multimedia: true, communications: false);
音量控制
获取音量
要获取当前的音量值,可以使用以下代码:
final volume = await Audio.getVolume(audioDeviceType);
设置音量
要设置音量值(范围是0到1),可以使用以下代码:
final volume = await Audio.setVolume(0.5, audioDeviceType);
设置特定应用的音量
要设置特定应用程序的音量,可以使用以下代码:
await Audio.setAudioMixerVolume(mixerList[0].processId, 0.3);
监听变化
要监听音频设备的变化,可以在 main()
函数中调用 Audio.setupChangeListener()
,并在 initState()
中添加监听器:
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Audio.setupChangeListener();
runApp(const MyApp());
}
class _MyAppState extends State<MyApp> {
@override
void initState() {
super.initState();
Audio.addChangeListener((String type, String id) async {
print(type);
print(id);
});
}
}
提取图标
要从音频设备或应用程序路径中提取图标,可以使用 nativeIconToBytes
函数:
Map<String, Uint8List?> _audioIcons = {};
for (var audioDevice in audioDevices) {
if (_audioIcons[audioDevice.id] == null) {
_audioIcons[audioDevice.id] = await nativeIconToBytes(audioDevice.iconPath, iconID: audioDevice.iconID);
}
}
注意事项
如果使用此插件,可能会收到以下警告消息:
The 'win32audio' channel sent a message from native to Flutter on a non-platform thread. Platform channel messages must be sent on the platform thread. Failure to do so may result in data loss or crashes, and must be fixed in the plugin or application code creating that channel.
这个警告提示来自一个单独的线程,通常不会影响应用的功能,但建议在开发过程中注意这个问题。
示例代码
下面是一个完整的示例代码,展示了如何使用 win32audio
插件来管理和控制音频设备:
import 'package:flutter/material.dart';
import 'dart:async';
import 'dart:typed_data';
import 'package:win32audio/win32audio.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Audio.setupChangeListener();
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
AudioDevice defaultDevice = AudioDevice();
List<AudioDevice> audioDevices = [];
AudioDeviceType audioDeviceType = AudioDeviceType.output;
List<ProcessVolume> mixerList = [];
bool _stateFetchAudioMixerPeak = true;
double __volume = 0.0;
String fetchStatus = "";
Map<String, Uint8List?> _audioIcons = {};
@override
void initState() {
super.initState();
Audio.addChangeListener((String type, String id) async {
print(type);
print(id);
});
fetchAudioDevices();
Timer.periodic(const Duration(milliseconds: 150), (Timer timer) async {
if (_stateFetchAudioMixerPeak) {
mixerList = await Audio.enumAudioMixer() ?? [];
for (ProcessVolume mixer in mixerList) {
if (_audioIcons[mixer.processPath] == null) {
_audioIcons[mixer.processPath] = await WinIcons().extractFileIcon(mixer.processPath);
}
}
setState(() {});
}
});
}
Future<void> fetchAudioDevices() async {
if (!mounted) return;
audioDevices = await Audio.enumDevices(audioDeviceType) ?? [];
__volume = await Audio.getVolume(audioDeviceType);
defaultDevice = (await Audio.getDefaultDevice(audioDeviceType))!;
_audioIcons = {};
for (AudioDevice audioDevice in audioDevices) {
if (_audioIcons[audioDevice.id] == null) {
_audioIcons[audioDevice.id] = await WinIcons().extractFileIcon(audioDevice.iconPath, iconID: audioDevice.iconID);
}
}
mixerList = await Audio.enumAudioMixer() ?? [];
for (ProcessVolume mixer in mixerList) {
if (_audioIcons[mixer.processPath] == null) {
_audioIcons[mixer.processPath] = await WinIcons().extractFileIcon(mixer.processPath);
}
}
setState(() {
fetchStatus = "Get";
});
}
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
appBar: AppBar(
title: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
TextButton(
child: Text(
fetchStatus,
style: const TextStyle(color: Colors.white),
),
onPressed: () async {
setState(() {
fetchStatus = 'Getting...';
});
fetchAudioDevices();
},
),
TextButton(
child: Row(
children: [
Text(
defaultDevice.name,
style: const TextStyle(color: Colors.black),
),
const Icon(Icons.swap_vertical_circle_outlined, color: Colors.black),
],
),
onPressed: () async {
await Audio.switchDefaultDevice(audioDeviceType);
fetchAudioDevices();
setState(() {});
},
),
],
),
),
body: Column(
children: [
DropdownButton<AudioDeviceType>(
value: audioDeviceType,
items: AudioDeviceType.values.map((AudioDeviceType e) {
return DropdownMenuItem<AudioDeviceType>(
value: e,
child: Text(e.toString()),
);
}).toList(),
onChanged: (Object? e) async {
audioDeviceType = e as AudioDeviceType;
fetchStatus = e.toString();
fetchAudioDevices();
setState(() {});
},
),
Flexible(
child: Center(
child: Text(
"Volume:${(__volume * 100).toStringAsFixed(0)}%",
style: const TextStyle(fontSize: 32),
),
),
),
Slider(
value: __volume,
min: 0,
max: 1,
divisions: 25,
onChanged: (double e) async {
await Audio.setVolume(e.toDouble(), audioDeviceType);
__volume = e;
setState(() {});
},
),
Flexible(
child: ListView.builder(
itemCount: audioDevices.length,
itemBuilder: (BuildContext context, int index) {
return ListTile(
leading: (_audioIcons.containsKey(audioDevices[index].id))
? Image.memory(
_audioIcons[audioDevices[index].id] ?? Uint8List(0),
width: 32,
height: 32,
)
: const Icon(Icons.spoke_outlined),
title: Text(audioDevices[index].name),
trailing: IconButton(
icon: Icon(audioDevices[index].isActive ? Icons.check_box_outlined : Icons.check_box_outline_blank),
onPressed: () async {
await Audio.setDefaultDevice(audioDevices[index].id);
fetchAudioDevices();
setState(() {});
},
),
);
},
),
),
const Divider(thickness: 5, height: 10, color: Color.fromARGB(12, 0, 0, 0)),
CheckboxListTile(
title: const Text("Continuously Fetch The Audio Mixer"),
value: _stateFetchAudioMixerPeak,
controlAffinity: ListTileControlAffinity.leading,
onChanged: (bool? e) {
setState(() {
_stateFetchAudioMixerPeak = e!;
});
},
),
Flexible(
child: ListView.builder(
itemCount: mixerList.length,
itemBuilder: (BuildContext context, int index) {
return Column(
children: [
const Divider(height: 6, thickness: 3, color: Color.fromARGB(10, 0, 0, 0), indent: 100, endIndent: 100),
Row(
children: [
Flexible(
child: ListTile(
leading: (_audioIcons.containsKey(mixerList[index].processPath))
? Image.memory(
_audioIcons[mixerList[index].processPath] ?? Uint8List(0),
width: 32,
height: 32,
)
: const Icon(Icons.spoke_outlined),
title: Text(mixerList[index].processPath),
),
),
Flexible(
child: Padding(
padding: const EdgeInsets.only(right: 20),
child: Column(
children: [
Slider(
value: mixerList[index].maxVolume,
min: 0,
max: 1,
divisions: 25,
onChanged: (double e) async {
await Audio.setAudioMixerVolume(mixerList[index].processId, e.toDouble());
mixerList[index].maxVolume = e;
setState(() {});
},
),
// Add your progress bar widget here if needed
],
),
),
),
],
),
],
);
},
),
),
],
),
),
);
}
}
以上代码展示了如何使用 win32audio
插件来管理和控制音频设备,包括枚举设备、设置默认设备、调整音量以及监听设备变化等功能。希望这些内容能帮助你更好地理解和使用 win32audio
插件。
更多关于Flutter音频处理插件win32audio的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter音频处理插件win32audio的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,以下是一个关于如何在Flutter项目中使用win32audio
插件进行音频处理的示例代码。请注意,win32audio
是一个特定于Windows平台的插件,用于处理Windows系统的音频输入和输出。这意味着它只能在Windows设备上运行。
首先,你需要确保你的Flutter开发环境已经设置好,并且你的项目已经创建完毕。然后,你需要添加win32audio
插件到你的pubspec.yaml
文件中:
dependencies:
flutter:
sdk: flutter
win32audio: ^最新版本号 # 请替换为实际可用的最新版本号
然后运行flutter pub get
来安装插件。
接下来是一个简单的示例,展示如何使用win32audio
插件来录制音频并播放:
- 导入必要的包
import 'package:flutter/material.dart';
import 'package:win32audio/win32audio.dart';
- 创建录音和播放功能
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: AudioProcessingScreen(),
);
}
}
class AudioProcessingScreen extends StatefulWidget {
@override
_AudioProcessingScreenState createState() => _AudioProcessingScreenState();
}
class _AudioProcessingScreenState extends State<AudioProcessingScreen> {
late Win32Audio win32Audio;
List<int>? recordedAudioData;
@override
void initState() {
super.initState();
win32Audio = Win32Audio();
}
void startRecording() async {
try {
recordedAudioData = await win32Audio.startRecording(duration: Duration(seconds: 5));
print("Recording completed");
// You can save the recorded data to a file or process it further
} catch (e) {
print("Error recording: $e");
}
}
void playAudio(List<int> audioData) async {
try {
await win32Audio.playAudio(audioData);
} catch (e) {
print("Error playing audio: $e");
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Win32 Audio Processing'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
ElevatedButton(
onPressed: startRecording,
child: Text('Start Recording'),
),
ElevatedButton(
onPressed: () {
if (recordedAudioData != null) {
playAudio(recordedAudioData!);
} else {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('No audio data to play')),
);
}
},
child: Text('Play Audio'),
),
],
),
),
);
}
}
在这个示例中,我们创建了一个Flutter应用,它有两个按钮:一个用于开始录音,另一个用于播放录制的音频。
startRecording
函数调用win32Audio.startRecording
方法开始录音,并指定录音时长为5秒。录音完成后,将录制的音频数据存储在recordedAudioData
变量中。playAudio
函数接受一个包含音频数据的列表,并调用win32Audio.playAudio
方法播放音频。
请注意,这个示例代码是为了演示插件的基本用法,并没有处理所有可能的错误和边界情况。在实际应用中,你可能需要添加更多的错误处理和用户反馈机制。
此外,由于win32audio
是一个特定于Windows的插件,因此在非Windows平台上运行此代码将会失败。确保只在Windows设备上运行和测试你的应用。