Flutter音频流播放插件audio_streamer的使用

发布于 1周前 作者 yuanlaile 来自 Flutter

Flutter音频流播放插件audio_streamer的使用

描述

audio_streamer 是一个用于从Android和iOS流式传输脉冲编码调制(PCM)音频的Flutter插件,支持自定义采样率。

权限设置

使用此插件需要获取访问麦克风的权限。请求此权限不是插件的一部分,应该由应用程序处理。为了使应用程序能够访问麦克风,您需要在Android和iOS上分别添加以下权限:

Android

AndroidManifest.xml 文件中添加录音权限:

<uses-permission android:name="android.permission.RECORD_AUDIO" />

iOS

  1. 使用XCode启用以下功能:
    • 功能 > 后台模式 > 音频、AirPlay 和画中画
  2. 编辑 Info.plist 文件,添加以下条目以提供麦克风使用说明:
<key>NSMicrophoneUsageDescription</key>
<string>YOUR DESCRIPTION</string>
<key>UIBackgroundModes</key>
<array>
  <string>audio</string>
</array>
  1. 编辑 Podfile 文件,为麦克风添加权限:
post_install do |installer|
  installer.pods_project.targets.each do |target|
    flutter_additional_ios_build_settings(target)

    target.build_configurations.each do |config|
      config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= [
        '$(inherited)',
        'PERMISSION_MICROPHONE=1',
      ]
    end
  end
end

使用插件

该插件作为单例工作,并提供一个简单的 audioStream 供监听。

AudioStreamer().audioStream.listen(
  (List<double> buffer) {
    print('Max amp: ${buffer.reduce(max)}');
    print('Min amp: ${buffer.reduce(min)}');
  },
  onError: (Object error) {
    print(error);
  },
  cancelOnError: true,
);

可以通过 samplingRateactualSampleRate 属性设置和读取采样率。

// 设置采样率。必须在监听 audioStream 之前完成。
AudioStreamer().sampleRate = 22100;

// 获取实际采样率 - 可能与请求的采样率不同。
int sampleRate = await AudioStreamer().actualSampleRate;

示例代码

下面是一个完整的示例代码,展示了如何使用 audio_streamer 插件以及如何请求麦克风权限。

import 'dart:math';
import 'dart:async';

import 'package:flutter/material.dart';
import 'package:audio_streamer/audio_streamer.dart';
import 'package:permission_handler/permission_handler.dart';

void main() => runApp(AudioStreamingApp());

class AudioStreamingApp extends StatefulWidget {
  @override
  AudioStreamingAppState createState() => AudioStreamingAppState();
}

class AudioStreamingAppState extends State<AudioStreamingApp> {
  int? sampleRate;
  bool isRecording = false;
  List<double> audio = [];
  List<double>? latestBuffer;
  double? recordingTime;
  StreamSubscription<List<double>>? audioSubscription;

  /// 检查是否已授予麦克风权限。
  Future<bool> checkPermission() async => await Permission.microphone.isGranted;

  /// 请求麦克风权限。
  Future<void> requestPermission() async =>
      await Permission.microphone.request();

  /// 音频样本回调。
  void onAudio(List<double> buffer) async {
    audio.addAll(buffer);

    // 如果还不知道实际采样率,则获取它。
    sampleRate ??= await AudioStreamer().actualSampleRate;
    recordingTime = audio.length / sampleRate!;

    setState(() => latestBuffer = buffer);
  }

  /// 错误回调。
  void handleError(Object error) {
    setState(() => isRecording = false);
    print(error);
  }

  /// 开始音频采样。
  void start() async {
    // 检查是否已授予麦克风权限。
    if (!(await checkPermission())) {
      await requestPermission();
    }

    // 设置采样率 - 仅适用于Android。
    AudioStreamer().sampleRate = 22100;

    // 开始监听音频流。
    audioSubscription =
        AudioStreamer().audioStream.listen(onAudio, onError: handleError);

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

  /// 停止音频采样。
  void stop() async {
    audioSubscription?.cancel();
    setState(() => isRecording = false);
  }

  @override
  Widget build(BuildContext context) => MaterialApp(
        home: Scaffold(
          body: Center(
              child: Column(
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: <Widget>[
                Container(
                    margin: EdgeInsets.all(25),
                    child: Column(children: [
                      Container(
                        child: Text(isRecording ? "Mic: ON" : "Mic: OFF",
                            style: TextStyle(fontSize: 25, color: Colors.blue)),
                        margin: EdgeInsets.only(top: 20),
                      ),
                      Text(''),
                      Text('Max amp: ${latestBuffer?.reduce(max)}'),
                      Text('Min amp: ${latestBuffer?.reduce(min)}'),
                      Text('${recordingTime?.toStringAsFixed(2)} seconds recorded.'),
                    ])),
              ])),
          floatingActionButton: FloatingActionButton(
            backgroundColor: isRecording ? Colors.red : Colors.green,
            child: isRecording ? Icon(Icons.stop) : Icon(Icons.mic),
            onPressed: isRecording ? stop : start,
          ),
        ),
      );
}

这个示例应用展示了如何请求麦克风权限、开始和停止音频流的录制,并实时显示录制状态及音频的最大和最小振幅。请注意,在iOS上,采样率可能不会改变,因为只有设置首选项的选项。


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

1 回复

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


当然,以下是一个关于如何在Flutter中使用audio_streamer插件来播放音频流的示例代码。这个插件允许你流式播放网络上的音频内容。

首先,确保你的Flutter项目中已经添加了audio_streamer依赖。在你的pubspec.yaml文件中添加以下依赖:

dependencies:
  flutter:
    sdk: flutter
  audio_streamer: ^0.2.7  # 请注意版本号,根据实际情况更新到最新版本

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

接下来,我们创建一个简单的Flutter应用来演示如何使用audio_streamer播放音频流。

main.dart

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

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Audio Streamer Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: AudioStreamerScreen(),
    );
  }
}

class AudioStreamerScreen extends StatefulWidget {
  @override
  _AudioStreamerScreenState createState() => _AudioStreamerScreenState();
}

class _AudioStreamerScreenState extends State<AudioStreamerScreen> {
  AudioStreamer? _audioStreamer;
  String _status = "Not Playing";

  @override
  void initState() {
    super.initState();
    _audioStreamer = AudioStreamer.withUrl(
      'http://your-audio-stream-url.com/stream', // 替换为你的音频流URL
      autoPlay: false,
    );

    _audioStreamer!.onAudioPositionChanged = (position) {
      print("Current position: ${position.inMilliseconds}");
    };

    _audioStreamer!.onCompletion = () {
      setState(() {
        _status = "Stream Completed";
      });
    };

    _audioStreamer!.onError = (code, message) {
      print("Error: $code, $message");
      setState(() {
        _status = "Error: $message";
      });
    };
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Audio Streamer Demo'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'Status: $_status',
              style: TextStyle(fontSize: 20),
            ),
            SizedBox(height: 20),
            ElevatedButton(
              onPressed: () {
                setState(() {
                  if (_audioStreamer!.isPlaying) {
                    _audioStreamer!.pause();
                    _status = "Paused";
                  } else {
                    _audioStreamer!.play();
                    _status = "Playing";
                  }
                });
              },
              child: Text(_audioStreamer!.isPlaying ? 'Pause' : 'Play'),
            ),
            SizedBox(height: 20),
            ElevatedButton(
              onPressed: () {
                setState(() {
                  _audioStreamer!.stop();
                  _status = "Stopped";
                });
              },
              child: Text('Stop'),
            ),
          ],
        ),
      ),
    );
  }

  @override
  void dispose() {
    _audioStreamer?.dispose();
    super.dispose();
  }
}

说明

  1. 依赖安装:确保在pubspec.yaml中添加了audio_streamer依赖,并运行flutter pub get

  2. 初始化AudioStreamer:在initState方法中,我们创建了一个AudioStreamer实例,并传入音频流的URL。你可以将URL替换为你自己的音频流地址。

  3. 事件监听:我们为AudioStreamer实例添加了三个事件监听器:onAudioPositionChangedonCompletiononError。这些监听器分别用于处理音频位置变化、播放完成和播放错误的情况。

  4. 播放控制:在UI中,我们提供了播放、暂停和停止按钮来控制音频流的播放状态。点击按钮时,会调用相应的AudioStreamer方法,并更新状态文本。

  5. 资源释放:在dispose方法中,我们调用_audioStreamer?.dispose()来释放资源,防止内存泄漏。

将上述代码复制到你的Flutter项目中,并替换音频流URL后,即可运行应用并测试音频流的播放功能。

回到顶部