Flutter音频录制插件flutter_audio_rec的使用

Flutter音频录制插件flutter_audio_rec的使用

flutter_audio_rec

Flutter Audio Rec插件支持录制、暂停、恢复和停止操作,并提供了访问音频电平计量属性(如平均功率和峰值功率)的功能。

支持平台

该插件支持Android和iOS平台。

演示

安装

pubspec.yaml文件中添加flutter_audio_rec依赖:

dependencies:
  flutter_audio_rec: ^版本号

运行flutter pub get以获取依赖项。

iOS权限配置

  1. 在Info.plist文件中添加麦克风使用描述:

    <key>NSMicrophoneUsageDescription</key>
    <string>可以使用您的麦克风吗?</string>
    
  2. 使用hasPermission API请求用户权限:

    bool hasPermission = await FlutterAudioRec.hasPermissions;
    

Android权限配置

  1. ./android/app/src/main/AndroidManifest.xml中添加权限:

    <uses-permission android:name="android.permission.RECORD_AUDIO"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    
  2. 使用hasPermission API请求用户权限:

    bool hasPermission = await FlutterAudioRec.hasPermissions;
    

配置

iOS部署目标

iOS部署目标应为8.0以上。

Android配置

  • 如果使用AndroidX,请使用最新版本(0.5.x
  • 如果使用旧版Android,请使用旧版本(0.4.9

使用

推荐API使用顺序:hasPermission => init => start -> (pause <-> resume) * n -> stop。每次开始新的录制前请重新调用init

检查权限

bool hasPermission = await FlutterAudioRec.hasPermissions;

初始化

var recorder = FlutterAudioRec("file_path.mp4"); // .wav .aac .m4a
await recorder.initialized;

或者指定格式:

var recorder = FlutterAudioRec("file_path", audioFormat: AudioFormat.AAC); // 或者 AudioFormat.WAV
await recorder.initialized;

设置采样率

var recorder = FlutterAudioRec("file_path", audioFormat: AudioFormat.AAC, sampleRate: 22000); // 默认采样率为16000
await recorder.initialized;

录制音频

await recorder.start();
var recording = await recorder.current(channel: 0);

获取录制详情

var current = await recording.current(channel: 0);
// print(current.status);

使用定时器访问详细信息

new Timer.periodic(tick, (Timer t) async {
  var current = await recording.current(channel: 0);
  // print(current.status);
  setState(() {});
});

录制对象属性

属性名 描述
path String
extension String
duration Duration
audioFormat AudioFormat
metering AudioMetering
status RecordingStatus

录制电平计量对象属性

属性名 描述
peakPower double
averagePower double
isMeteringEnabled bool

录制状态

状态 描述
Unset 未设置
Initialized 已初始化
Recording 正在录制
Paused 暂停
Stopped 停止

暂停录制

await recorder.pause();

恢复录制

await recorder.resume();

停止录制

var result = await recorder.stop();
File file = widget.localFileSystem.file(result.path);

示例

以下是一个完整的示例,展示了如何使用flutter_audio_rec插件进行音频录制:

import 'dart:async';
import 'dart:io' as io;

import 'package:audioplayers/audioplayers.dart';
import 'package:file/file.dart';
import 'package:file/local.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_audio_rec/flutter_audio_rec.dart';
import 'package:path_provider/path_provider.dart';

void main() {
  WidgetsFlutterBinding.ensureInitialized();
  SystemChrome.setEnabledSystemUIOverlays([]);
  return runApp(const MyApp());
}

class MyApp extends StatefulWidget {
  const MyApp({Key? key}) : super(key: key);

  [@override](/user/override)
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  [@override](/user/override)
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: Scaffold(
        body: SafeArea(
          child: RecorderExample(),
        ),
      ),
    );
  }
}

class RecorderExample extends StatefulWidget {
  final LocalFileSystem localFileSystem;

  const RecorderExample({Key? key, localFileSystem})
      : localFileSystem = localFileSystem ?? const LocalFileSystem(),
        super(key: key);

  [@override](/user/override)
  State<StatefulWidget> createState() => RecorderExampleState();
}

class RecorderExampleState extends State<RecorderExample> {
  FlutterAudioRec? _recorder;
  Recording? _current;
  RecordingStatus _currentStatus = RecordingStatus.Unset;

  [@override](/user/override)
  void initState() {
    super.initState();
    _init();
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Center(
      child: Padding(
        padding: const EdgeInsets.all(8.0),
        child: Column(mainAxisAlignment: MainAxisAlignment.spaceAround, children: <Widget>[
          Row(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              Padding(
                padding: const EdgeInsets.all(8.0),
                child: TextButton(
                  onPressed: () {
                    switch (_currentStatus) {
                      case RecordingStatus.Initialized:
                        {
                          _start();
                          break;
                        }
                      case RecordingStatus.Recording:
                        {
                          _pause();
                          break;
                        }
                      case RecordingStatus.Paused:
                        {
                          _resume();
                          break;
                        }
                      case RecordingStatus.Stopped:
                        {
                          _init();
                          break;
                        }
                      default:
                        break;
                    }
                  },
                  child: _buildText(_currentStatus),
                  style: ButtonStyle(
                      backgroundColor: MaterialStateProperty.all<Color>(
                    Colors.lightBlue,
                  )),
                ),
              ),
              TextButton(
                onPressed: _currentStatus != RecordingStatus.Unset ? _stop : null,
                child: const Text("Stop", style: TextStyle(color: Colors.white)),
                style: ButtonStyle(
                    backgroundColor: MaterialStateProperty.all<Color>(
                  Colors.blueAccent.withOpacity(0.5),
                )),
              ),
              const SizedBox(
                width: 8,
              ),
              TextButton(
                onPressed: onPlayAudio,
                child: const Text("Play", style: TextStyle(color: Colors.white)),
                style: ButtonStyle(
                    backgroundColor: MaterialStateProperty.all<Color>(
                  Colors.blueAccent.withOpacity(0.5),
                )),
              ),
            ],
          ),
          Text("Status : $_currentStatus"),
          Text('Avg Power: ${_current?.metering?.averagePower}'),
          Text('Peak Power: ${_current?.metering?.peakPower}'),
          Text("File path of the record: ${_current?.path}"),
          Text("Format: ${_current?.audioFormat}"),
          Text("isMeteringEnabled: ${_current?.metering?.isMeteringEnabled}"),
          Text("Extension : ${_current?.extension}"),
          Text("Audio recording duration : ${_current?.duration.toString()}")
        ]),
      ),
    );
  }

  _init() async {
    try {
      bool hasPermission = await FlutterAudioRec.hasPermissions ?? false;

      if (hasPermission) {
        String customPath = '/flutter_audio_recorder_';
        io.Directory appDocDirectory;
        if (io.Platform.isIOS) {
          appDocDirectory = await getApplicationDocumentsDirectory();
        } else {
          appDocDirectory = (await getExternalStorageDirectory())!;
        }

        customPath = appDocDirectory.path +
            customPath +
            DateTime.now().millisecondsSinceEpoch.toString();

        _recorder = FlutterAudioRec(customPath, audioFormat: AudioFormat.WAV);

        await _recorder!.initialized;
        var current = await _recorder!.current(channel: 0);
        if (kDebugMode) {
          print(current);
        }

        setState(() {
          _current = current;
          _currentStatus = current!.status!;
          if (kDebugMode) {
            print(_currentStatus);
          }
        });
      } else {
        ScaffoldMessenger.of(context).showSnackBar(
            const SnackBar(content: Text("您必须接受权限")));
      }
    } catch (e) {
      if (kDebugMode) {
        print(e);
      }
    }
  }

  _start() async {
    try {
      await _recorder!.start();
      var recording = await _recorder!.current(channel: 0);
      setState(() {
        _current = recording;
      });

      const tick = Duration(milliseconds: 50);
      Timer.periodic(tick, (Timer t) async {
        if (_currentStatus == RecordingStatus.Stopped) {
          t.cancel();
        }

        var current = await _recorder!.current(channel: 0);
        setState(() {
          _current = current;
          _currentStatus = _current!.status!;
        });
      });
    } catch (e) {
      if (kDebugMode) {
        print(e);
      }
    }
  }

  _resume() async {
    await _recorder!.resume();
    setState(() {});
  }

  _pause() async {
    await _recorder!.pause();
    setState(() {});
  }

  _stop() async {
    var result = await _recorder!.stop();
    if (kDebugMode) {
      print("停止录制: ${result!.path}");
      print("停止录制: ${result.duration}");
    }

    File file = widget.localFileSystem.file(result?.path);
    if (kDebugMode) {
      print("文件长度: ${await file.length()}");
    }

    setState(() {
      _current = result;
      _currentStatus = _current!.status!;
    });
  }

  Widget _buildText(RecordingStatus status) {
    var text = "";
    switch (_currentStatus) {
      case RecordingStatus.Initialized:
        {
          text = '开始';
          break;
        }
      case RecordingStatus.Recording:
        {
          text = '暂停';
          break;
        }
      case RecordingStatus.Paused:
        {
          text = '继续';
          break;
        }
      case RecordingStatus.Stopped:
        {
          text = '初始化';
          break;
        }
      default:
        break;
    }
    return Text(text, style: const TextStyle(color: Colors.white));
  }

  void onPlayAudio() async {
    AudioPlayer audioPlayer = AudioPlayer();
    await audioPlayer.play(_current!.path!, isLocal: true);
  }
}

更多关于Flutter音频录制插件flutter_audio_rec的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter音频录制插件flutter_audio_rec的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是如何在Flutter项目中使用flutter_audio_rec插件进行音频录制的示例代码。这个插件允许你轻松地在Flutter应用中实现音频录制功能。

首先,你需要在你的pubspec.yaml文件中添加flutter_audio_rec依赖:

dependencies:
  flutter:
    sdk: flutter
  flutter_audio_rec: ^x.y.z  # 请替换为最新版本号

然后,运行flutter pub get来安装依赖。

接下来,是一个简单的Flutter应用示例,展示如何使用flutter_audio_rec进行音频录制:

import 'package:flutter/material.dart';
import 'package:flutter_audio_rec/flutter_audio_rec.dart';
import 'package:path_provider/path_provider.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: AudioRecorderScreen(),
    );
  }
}

class AudioRecorderScreen extends StatefulWidget {
  @override
  _AudioRecorderScreenState createState() => _AudioRecorderScreenState();
}

class _AudioRecorderScreenState extends State<AudioRecorderScreen> {
  late FlutterAudioRec audioRecorder;
  String? recordedAudioPath;
  bool isRecording = false;

  @override
  void initState() {
    super.initState();
    audioRecorder = FlutterAudioRec();
    audioRecorder.config = AudioRecorderConfig(
      audioFormat: AudioFormat.AAC,
      channelConfig: ChannelConfig.STEREO,
      encoder: AudioEncoder.AAC,
      bitRate: BitRate.BIT_RATE_128K,
      sampleRate: SampleRate.SAMPLE_RATE_44100,
    );
  }

  Future<void> startRecording() async {
    if (isRecording) return;

    Directory appDocDir = await getApplicationDocumentsDirectory();
    String appDocPath = appDocDir.path;
    String filePath = "${appDocPath}/audio_file.aac";

    recordedAudioPath = filePath;

    setState(() {
      isRecording = true;
    });

    try {
      await audioRecorder.start(path: filePath);
    } catch (e) {
      print("Error starting recording: $e");
    }
  }

  Future<void> stopRecording() async {
    if (!isRecording) return;

    try {
      await audioRecorder.stop();
    } catch (e) {
      print("Error stopping recording: $e");
    }

    setState(() {
      isRecording = false;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Audio Recorder"),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            ElevatedButton(
              onPressed: startRecording,
              child: Text("Start Recording"),
              style: ButtonStyle(
                backgroundColor: MaterialStateProperty.all(
                  isRecording ? Colors.red : Colors.green
                ),
              ),
            ),
            SizedBox(height: 20),
            ElevatedButton(
              onPressed: stopRecording,
              child: Text("Stop Recording"),
              style: ButtonStyle(
                backgroundColor: MaterialStateProperty.all(Colors.blue),
              ),
            ),
            SizedBox(height: 20),
            if (recordedAudioPath != null)
              Text("Recorded Audio Path: $recordedAudioPath"),
          ],
        ),
      ),
    );
  }
}

在这个示例中:

  1. 我们首先导入了必要的包,包括flutter/material.dartflutter_audio_rec
  2. 然后在MyApp类中定义了我们的主应用。
  3. AudioRecorderScreen是一个有状态的组件,用于处理音频录制逻辑。
  4. initState方法中,我们初始化了FlutterAudioRec实例并配置了音频录制参数。
  5. startRecording方法用于开始录音,stopRecording方法用于停止录音。
  6. build方法中,我们创建了一个简单的UI,包含两个按钮用于开始和停止录音,以及一个文本控件用于显示录制的音频路径(如果有的话)。

确保在实际使用时处理异常和权限请求(如录音权限),并根据需要调整UI和逻辑。

回到顶部