Flutter音频录制插件system_audio_recorder的使用

system_audio_recorder是一个简单的 Flutter 插件,用于录制 Android 系统播放的音频。

功能

requestRecord

此函数用于请求系统权限以录制播放的音频。调用此函数时,系统会显示提示。点击“允许”返回 true,点击“拒绝”返回 false。(虽然此函数可以接受参数,但无需传递任何参数)

startRecord

调用此函数开始录制系统播放的音频。在调用此函数之前,必须先调用 requestRecord 请求权限。目前仅支持 PCM16 编码

参数名 类型 描述 默认值
sampleRate int 采样率 16000
bufferSize int 缓冲区大小(字节数) 640
toStream bool 是否将录制的音频作为流接收 true
toFile bool 是否将录制的音频保存到文件中 false
filePath String 录制音频保存的文件路径 null

stopRecord

此函数用于停止录制。如果 toFiletrue,它返回文件路径;否则返回 ""

示例

权限配置

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

<manifest xmlns:android="http://schemas.android.com/apk/res/android">
    <application
        ...
        >
        
        <!-- 添加服务开始 -->
        <service
            android:name="com.foregroundservice.ForegroundService"
            android:foregroundServiceType="mediaProjection">
        </service>
        <!-- 添加服务结束 -->

        ...
    </application>

    ...
    
    <!-- 添加权限开始 -->
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WRITE_INTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PROJECTION" />
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION" />
    <uses-permission android:name="android.permission.WAKE_LOCK" />
    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PROJECTION" />
    <!-- 添加权限结束 -->
    
</manifest>

开始录制

bool isConfirmed = await SystemAudioRecorder.requestRecord(
    titleNotification: "titleNotification",
    messageNotification: "messageNotification",
);
bool toStream = true;
bool toFile = true;
String? path;    // path can not be null when toFile is true
if (isConfirmed) {
    audioData.clear();
    if (toFile){ // 如果录制到文件,获取文件路径
        var tempDir = await getExternalStorageDirectory();

        path = '${tempDir?.parent.path}/record.mp3';
        var outputFile = File(path);
        if (outputFile.existsSync()) {
            await outputFile.delete();
        }
    }
    bool isStart = await SystemAudioRecorder.startRecord(toStream: toStream, toFile: toFile, filePath: path);
    if (toStream){  // 如果录制到流,设置流监听器
        _audioSubscription ??=
            SystemAudioRecorder.audioStream.receiveBroadcastStream({}).listen((data) {
            audioData.addAll(List<int>.from(data));   // data.length = bufferSize * 2
        });
    }

}

停止录制

String path = await SystemAudioRecorder.stopRecord();
if (_audioSubscription != null) {   // 如果录制到流,停止时取消订阅
    _audioSubscription?.cancel();
    _audioSubscription = null;
}

完整示例代码

import 'dart:io';

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'dart:async';

import 'package:flutter/services.dart';
import 'package:system_audio_recorder/system_audio_recorder.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:flutter_sound/flutter_sound.dart';
import 'package:path_provider/path_provider.dart';

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

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

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

class _MyAppState extends State<MyApp> {
  String _platformVersion = 'Unknown';
  final _systemAudioRecorderPlugin = SystemAudioRecorder();
  StreamSubscription? _audioSubscription;
  List<int> audioData = List.empty(growable: true);
  Uint8List? udata;
  FlutterSoundPlayer player = FlutterSoundPlayer();

  requestPermissions() async {
    if (!kIsWeb) {
      if (await Permission.storage.request().isDenied) {
        await Permission.storage.request();
      }
    }
  }

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

  // 平台消息异步初始化
  Future<void> initPlatformState() async {
    String platformVersion;
    // 平台消息可能失败,因此使用 try/catch 捕获 PlatformException。
    // 我们还处理消息可能返回 null 的情况。
    try {
      platformVersion = await _systemAudioRecorderPlugin.getPlatformVersion() ?? 'Unknown platform version';
    } on PlatformException {
      platformVersion = 'Failed to get platform version.';
    }

    // 如果小部件从树中移除时异步平台消息仍在飞行中,则我们希望丢弃回复而不是调用
    // setState 来更新我们的非存在的外观。
    if (!mounted) return;

    setState(() {
      _platformVersion = platformVersion;
    });
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Plugin example app'),
        ),
        body: Column(children: [
          Text('Running on: $_platformVersion\n'),
          TextButton(
              onPressed: () async {
                bool isConfirmed = await SystemAudioRecorder.requestRecord(
                  titleNotification: "titleNotification",
                  messageNotification: "messageNotification",
                );
                bool toStream = true;
                bool toFile = true;
                String? path;    // path can not be null when toFile is true
                if (isConfirmed) {
                  audioData.clear();
                  if (toFile){
                    var tempDir = await getExternalStorageDirectory();

                    path = '${tempDir?.parent.path}/record.mp3';
                    var outputFile = File(path);
                    if (outputFile.existsSync()) {
                      await outputFile.delete();
                    }
                  }
                  bool isStart = await SystemAudioRecorder.startRecord(toStream: toStream, toFile: toFile, filePath: path);
                  if (toStream){
                    _audioSubscription ??=
                        SystemAudioRecorder.audioStream.receiveBroadcastStream({}).listen((data) {
                          audioData.addAll(List<int>.from(data));
                        });
                  }

                }
              },
              child: const Text("开始录制")),
          TextButton(
              onPressed: () async {
                String path = await SystemAudioRecorder.stopRecord();
                if (_audioSubscription != null) {
                  _audioSubscription?.cancel();
                  _audioSubscription = null;
                }
                if(path != "") print(path);
              },
              child: const Text("停止录制")),
          TextButton(onPressed: () async {
            udata = Uint8List.fromList(audioData);
            await player.openPlayer();
            await player.startPlayerFromStream(codec: Codec.pcm16, numChannels: 1, sampleRate: 16000);
            await player.feedFromStream(udata!);
            await player.stopPlayer();

          }, child: const Text("开始播放"))
        ]),
      ),
    );
  }
}

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

1 回复

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


system_audio_recorder 是一个 Flutter 插件,用于录制系统音频。它允许你录制来自系统本身的音频输出,而不是通过麦克风录制外部声音。这在某些场景下非常有用,比如录制音乐、游戏音频或其他系统声音。

安装插件

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

dependencies:
  flutter:
    sdk: flutter
  system_audio_recorder: ^1.0.0  # 请检查最新版本

然后运行 flutter pub get 来安装插件。

使用插件

以下是一个简单的示例,展示如何使用 system_audio_recorder 插件来录制系统音频:

import 'package:flutter/material.dart';
import 'package:system_audio_recorder/system_audio_recorder.dart';

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

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

class AudioRecorderScreen extends StatefulWidget {
  [@override](/user/override)
  _AudioRecorderScreenState createState() => _AudioRecorderScreenState();
}

class _AudioRecorderScreenState extends State<AudioRecorderScreen> {
  SystemAudioRecorder _recorder = SystemAudioRecorder();
  bool _isRecording = false;

  Future<void> _startRecording() async {
    try {
      await _recorder.start();
      setState(() {
        _isRecording = true;
      });
    } catch (e) {
      print("Failed to start recording: $e");
    }
  }

  Future<void> _stopRecording() async {
    try {
      String? filePath = await _recorder.stop();
      setState(() {
        _isRecording = false;
      });
      print("Recording saved to: $filePath");
    } catch (e) {
      print("Failed to stop recording: $e");
    }
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('System Audio Recorder'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            _isRecording
                ? Text("Recording...")
                : Text("Press the button to start recording"),
            SizedBox(height: 20),
            ElevatedButton(
              onPressed: _isRecording ? _stopRecording : _startRecording,
              child: Text(_isRecording ? "Stop Recording" : "Start Recording"),
            ),
          ],
        ),
      ),
    );
  }
}
回到顶部