搜索插件、代码仓与 APP 分类

waveform_recorder 封面
插件详情v2.0.0

waveform_recorder

一个用于实时波形可视化录音的 Flutter 包,非常适合聊天应用中的语音消息和音频录制功能。

AndroidiOSWebmacOSWindowsLinux
近 30 天下载
1.7万
喜欢数
53
Pub 分数
160

安装插件

flutter pub add waveform_recorder

插件介绍

基于插件公开信息、社区数据与项目使用情况整理的选型参考。

一个 Flutter 包,可实现音频录制并实时显示波形图,专为需要语音消息或音频输入功能的应用程序设计。它支持 Android、iOS、Web、macOS、Windows 和 Linux 多个平台,提供在录制过程中具有视觉反馈的流畅用户体验。该包可无缝集成到聊天或通信应用中,让用户在说话时看到自己的语音波形。基于性能和跨平台一致性而构建,它以最少的设置简化了音频录制功能的实现。

适合场景

  • 聊天应用中的语音消息
  • 音频笔记
  • 实时语音反馈
  • 播客录制接口
  • 基于语音的互动游戏
  • 实时音频流预览

主要特点

  • 实时波形可视化
  • 跨平台支持
  • 简单的 API 用于记录
  • 录制期间的视觉反馈
  • 低延迟音频处理
  • 内置播放控制

适合对象

  • 开发聊天应用的开发者
  • 语音功能工具的创作者
  • 带有音频输入的教育类应用程序
  • 音频录制原型
  • 需要直观音频用户界面的应用程序

使用建议

  • 所有平台都需要麦克风权限
  • Web 支持可能有浏览器限制
  • 大型录音可能会增加内存使用
  • 性能在低端设备上有所不同
  • 波形外观的自定义选项有限
  • 依赖于底层平台的音频API

原始 README

以下为关联源码仓库的 README 原文快照,最新内容请访问源码仓库。

The waveform_recorder package provides a widget to show a waveform as an audio stream is being recorded in the style of recent AI chat packages.

Screenshot of waveform_recorder in
action

Setup

For this package to work, you'll need to set up the underlying record package according to the setup and permission instructions.

Usage

The main entry point for this package is the WaveformRecorder widget, which requires an instance of the WaveformRecorderController to start/stop recording. Here's an example of using the recorder to record audio and then allowing the user to play it back:

import 'dart:async';

import 'package:audioplayers/audioplayers.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:gap/gap.dart';
import 'package:waveform_recorder/waveform_recorder.dart';

void main() => runApp(const MyApp());

class MyApp extends StatefulWidget {
  const MyApp({super.key});

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  final _textController = TextEditingController();
  final _waveController = WaveformRecorderController();

  @override
  void dispose() {
    _textController.dispose();
    _waveController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) => MaterialApp(
        home: Scaffold(
          appBar: AppBar(title: const Text('WaveForm Example')),
          body: ListenableBuilder(
            listenable: _waveController,
            builder: (context, _) => Column(
              children: [
                Expanded(
                  child: Center(
                    child: OutlinedButton(
                      onPressed: !_waveController.isRecording &&
                              _waveController.file != null
                          ? _playRecording
                          : null,
                      child: const Text('Play'),
                    ),
                  ),
                ),
                Padding(
                  padding: const EdgeInsets.all(16),
                  child: Row(
                    children: [
                      Expanded(
                        child: DecoratedBox(
                          decoration: BoxDecoration(
                            border: Border.all(color: Colors.grey),
                            borderRadius: BorderRadius.circular(8),
                          ),
                          child: _waveController.isRecording
                              ? WaveformRecorder(
                                  height: 48,
                                  controller: _waveController,
                                  onRecordingStopped: _onRecordingStopped,
                                )
                              : TextField(
                                  controller: _textController,
                                  maxLines: 1,
                                  decoration: const InputDecoration(
                                    border: InputBorder.none,
                                    contentPadding: EdgeInsets.symmetric(
                                      horizontal: 8,
                                    ),
                                  ),
                                ),
                        ),
                      ),
                      const Gap(8),
                      IconButton(
                        icon: Icon(
                          _waveController.isRecording ? Icons.stop : Icons.mic,
                        ),
                        onPressed: _toggleRecording,
                      ),
                    ],
                  ),
                ),
              ],
            ),
          ),
        ),
      );

  Future<void> _toggleRecording() => switch (_waveController.isRecording) {
        true => _waveController.stopRecording(),
        false => _waveController.startRecording(),
      };

  Future<void> _onRecordingStopped() async {
    final file = _waveController.file;
    if (file == null) return;

    _textController.text = ''
        '${file.name}: '
        '${_waveController.length.inMilliseconds / 1000} seconds';

    debugPrint('XFile properties:');
    debugPrint('  path: ${file.path}');
    debugPrint('  name: ${file.name}');
    debugPrint('  mimeType: ${file.mimeType}');
  }

  Future<void> _playRecording() async {
    final file = _waveController.file;
    if (file == null) return;
    final source = kIsWeb ? UrlSource(file.path) : DeviceFileSource(file.path);
    await AudioPlayer().play(source);
  }
}
Usage Considerations

For all platforms except the web, the output of a record operation is a file on your hard drive; it's your app's responsibility to remove this temp file when it's done with it. When executing on the web, the file (an instance of the XFile type from the cross_file package) of the recorded audio will contain a path to a blob URL but otherwise, it will be a file in the file system. You can get the path to that file from WaveformRecorderController.file.path, e.g.

  Future<void> _deleteRecording() async {
    final file = _waveController.file;
    if (file == null) return;
    if (!kIsWeb) await File(file.path).delete();
  }

Feedback

Your feedback via issues or PRs is welcome!

所属分类

依赖

依赖清单 6 项

源码仓库

使用此插件的项目