Flutter音频编解码插件g711_flutter的使用

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

Flutter音频编解码插件g711_flutter的使用

g711_flutter 是一个用于快速进行PCM到G711编码和解码的Flutter插件。它提供了两种实现方式:一种是通过调用C代码实现的(基于 escrichov/G711),另一种是纯Dart代码实现的。

文档

  • NativeG711Codec: 通过调用C代码实现。
  • DartG711Codec: 使用纯Dart代码实现。

性能

以下是处理1MB PCM数据所需的时间:

I/flutter (17001): native.preload: 0:00:00.001007 
I/flutter (17001): dart  .preload: 0:00:00.003305 
I/flutter (17001): native.encode: 0:00:00.001478 
I/flutter (17001): dart  .encode: 0:00:00.017759 
I/flutter (17001): native.decode: 0:00:00.001663 
I/flutter (17001): dart  .decode: 0:00:00.010298 

完整示例Demo

以下是一个完整的示例代码,展示了如何使用 g711_flutter 插件进行PCM到G711的编码和解码操作。

import 'dart:async';
import 'dart:developer';
import 'dart:math' as math;
import 'dart:typed_data';

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:g711_flutter/g711_flutter.dart';
import 'package:g711_flutter_example/sound_button.dart';

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

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

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

class _MyAppState extends State<MyApp> {
  String _platformVersion = 'Unknown';
  late NativeG711Codec g711 = NativeG711Codec.g711u();

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

  // Platform messages are asynchronous, so we initialize in an async method.
  Future<void> initPlatformState() async {
    String platformVersion;
    // Platform messages may fail, so we use a try/catch PlatformException.
    // We also handle the message potentially returning null.
    try {
      platformVersion =
          await NativeG711Codec.platformVersion ?? 'Unknown platform version';
    } on PlatformException {
      platformVersion = 'Failed to get platform version.';
    }

    // If the widget was removed from the tree while the asynchronous platform
    // message was in flight, we want to discard the reply rather than calling
    // setState to update our non-existent appearance.
    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${native_add(1, 2) + native_add_func(3, 4)}'),
            const SoundButton(),
            OutlinedButton(
              onPressed: () {
                final nativeG711u = NativeG711Codec.g711u();
                final nativeG711a = NativeG711Codec.g711a();
                final dartG711u = DartG711Codec.g711u();
                final dartG711a = DartG711Codec.g711a();
                final pcm16 = Uint8List.sublistView(
                    Int16List.fromList([1, -1, 0xffff, 0, 0x7fff, 0x8000]));
                final ulaw1 = nativeG711u.encode(pcm16);
                final ulaw2 = dartG711u.encode(pcm16);
                final pcm1 = nativeG711u.decode(ulaw1);
                final pcm2 = dartG711u.decode(ulaw2);
                final alaw1 = nativeG711a.encode(pcm16);
                final alaw2 = dartG711a.encode(pcm16);
                final pcm11 = nativeG711a.decode(alaw1);
                final pcm12 = dartG711a.decode(alaw2);

                log('''
                  pcm16: $pcm16
                  ulaw1: $ulaw1
                  ulaw2: $ulaw2
                  pcm1: $pcm1
                  pcm2: $pcm2
                  alaw1: $alaw1
                  alaw2: $alaw2
                  pcm11: $pcm11
                  pcm12: $pcm12
                ''');
              },
              child: const Text('检查结果'),
            ),
            OutlinedButton(
              onPressed: () {
                final w = Stopwatch()..start();

                final g1 = NativeG711Codec.g711u();
                final g2 = DartG711Codec.g711u();
                w.printElapsed('native.preload', () => g1.forcePreloadTable());
                w.printElapsed('dart  .preload', () => g2.forcePreloadTable());
                final random = math.Random();
                final pcm16 = Uint8List.fromList(List.generate(
                    1024 * 1024, (index) => random.nextInt(0xff)));

                final ulaw1 =
                    w.printElapsed('native.encode', () => g1.encode(pcm16));
                final ulaw2 =
                    w.printElapsed('dart  .encode', () => g2.encode(pcm16));
                final pcm1 =
                    w.printElapsed('native.decode', () => g1.decode(ulaw1));
                final pcm2 =
                    w.printElapsed('dart  .decode', () => g2.decode(ulaw2));
              },
              child: const Text('性能测试'),
            ),
          ],
        ),
      ),
    );
  }
}

extension StopwatchExt on Stopwatch {
  R printElapsed<R>(String tag, R Function() block, {bool printResult = false}) {
    reset();
    final result = block();
    final elapsed = this.elapsed;

    print('$tag: $elapsed ${printResult ? result : ''}');

    return result;
  }
}

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

1 回复

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


当然,以下是如何在Flutter项目中使用g711_flutter插件进行音频编解码的示例代码。g711_flutter插件允许你使用G.711标准对音频数据进行编码和解码,G.711是一种广泛使用的音频压缩算法,主要用于电话通信。

首先,确保你已经在pubspec.yaml文件中添加了g711_flutter依赖:

dependencies:
  flutter:
    sdk: flutter
  g711_flutter: ^最新版本号  # 替换为当前最新版本号

然后运行flutter pub get来获取依赖。

接下来,在你的Flutter项目中,你可以使用以下代码示例来进行音频数据的编码和解码:

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

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

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  String encodedResult = '';
  String decodedResult = '';

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('G.711 Flutter Demo'),
        ),
        body: Padding(
          padding: const EdgeInsets.all(16.0),
          child: Column(
            children: <Widget>[
              TextField(
                decoration: InputDecoration(labelText: 'Input PCM data (hex string)'),
                onChanged: (value) {
                  // 当输入改变时,进行编码和解码
                  setState(() {
                    try {
                      // 将输入的十六进制字符串转换为Uint8List
                      List<int> pcmData = Uint8List.fromList(
                        value.replaceAll(' ', '').split(',').map(int.parse, radix: 16).toList(),
                      );
                      
                      // 编码为G.711 uLaw
                      List<int> encodedData = G711Flutter.encodeULaw(pcmData);
                      encodedResult = encodedData.map((e) => e.toRadixString(16).padLeft(2, '0')).join(' ');

                      // 解码回PCM
                      List<int> decodedData = G711Flutter.decodeULaw(encodedData);
                      decodedResult = decodedData.map((e) => e.toRadixString(16).padLeft(2, '0')).join(' ');
                    } catch (e) {
                      encodedResult = 'Error: $e';
                      decodedResult = '';
                    }
                  });
                },
              ),
              SizedBox(height: 20),
              Text('Encoded Data (uLaw, hex): $encodedResult'),
              SizedBox(height: 20),
              Text('Decoded Data (PCM, hex): $decodedResult'),
            ],
          ),
        ),
      ),
    );
  }
}

在这个示例中,我们创建了一个简单的Flutter应用,它允许用户输入PCM音频数据的十六进制字符串。当用户输入数据时,应用会:

  1. 将输入的十六进制字符串转换为Uint8List
  2. 使用G711Flutter.encodeULaw方法将PCM数据编码为G.711 uLaw格式。
  3. 使用G711Flutter.decodeULaw方法将编码后的数据解码回PCM格式。
  4. 显示编码和解码后的十六进制字符串结果。

请注意,输入数据应该是十六进制格式的字符串,每个字节之间用逗号分隔(例如:“00,FF,01,FE”)。你也可以根据需要调整输入和输出的显示格式。

这个示例提供了一个基本的框架,你可以根据实际需求进行扩展和修改。

回到顶部