opus_flutter 3.0.2 copy "opus_flutter: ^3.0.2" to clipboard
opus_flutter: ^3.0.2 copied to clipboard

Loads a DynamicLibrary of opus for usage with opus_dart on flutter platforms.


import 'dart:convert';
import 'dart:math' show min;
import 'dart:typed_data';

import 'package:flutter/material.dart';
import 'package:opus_flutter/opus_flutter.dart' as opus_flutter;
import 'package:opus_dart/opus_dart.dart';
import 'package:share_plus/share_plus.dart';
import 'package:platform_info/platform_info.dart';

Future<void> main() async {
  initOpus(await opus_flutter.load());
  runApp(const OpusFlutter());

/// Even if we could load the file as whole, we create a stream out of it
/// to simulate streaming behaviour (e.g. if the stream comes over the network).
Stream<List<int>> exampleRawStream(BuildContext context) async* {
  const int portionSize =
      65535; //equals the usual size you get per list in a network stream
  ByteData data = await DefaultAssetBundle.of(context)
  int i = 0;
  while (i != data.lengthInBytes) {
    int r = min(portionSize, data.lengthInBytes - i);
    yield data.buffer.asUint8List(data.offsetInBytes + i, r);
    i += r;
    await Future.delayed(
        const Duration(milliseconds: 10)); //Simulate network latency

class OpusFlutter extends StatelessWidget {
  const OpusFlutter({super.key});

  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('opus_flutter'),
        body: Center(
            child: Column(
                mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                children: <Widget>[
              Text('Version: ${getOpusVersion()}\n'),
              const OpusExample()

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

  State<OpusExample> createState() => _OpusExampleState();

class _OpusExampleState extends State<OpusExample> {
  bool _processing = false;

  void initState() {

  Widget build(BuildContext context) {
    if (_processing) {
      return const Column(
        crossAxisAlignment: CrossAxisAlignment.center,
        children: <Widget>[CircularProgressIndicator(), Text('Processing...')],
    } else {
      return ElevatedButton(
        onPressed: () {
          setState(() {
            _processing = true;
          example(exampleRawStream(context)).then((Uint8List data) {
            setState(() {
              _processing = false;
        child: const Text('Start'),

/// This is mostly the same example as from the opus_dart package:
/// Get a stream, encode it and decode it, then share it.
/// Add a wav header, so it can be played by any sound app.
Future<Uint8List> example(Stream<List<int>> input) async {
  const int sampleRate = 16000;
  const int channels = 1;
  List<Uint8List> output = [];
  output.add(Uint8List(wavHeaderSize)); //Reserve space for the header
  //Encode and decode using opus
  await input
          floatInput: false,
          frameTime: FrameTime.ms20,
          sampleRate: sampleRate,
          channels: channels,
          application: Application.audio,
          copyOutput: true,
          fillUpLastFrame: true))
          floatOutput: false,
          sampleRate: sampleRate,
          channels: channels,
          copyOutput: true,
          forwardErrorCorrection: false))
  int length = output.fold(0, (int l, Uint8List element) => l + element.length);
  //Write the wav header
  Uint8List header =
      wavHeader(channels: channels, sampleRate: sampleRate, fileSize: length);
  output[0] = header;
  // Merge into a single Uint8List
  Uint8List flat = Uint8List(length);
  int index = 0;
  for (Uint8List element in output) {
    flat.setAll(index, element);
    index += element.length;
  return flat;

const int wavHeaderSize = 44;

Uint8List wavHeader(
    {required int sampleRate, required int channels, required int fileSize}) {
  const int sampleBits = 16; //We know this since we used opus
  const Endian endian = Endian.little;
  final int frameSize = ((sampleBits + 7) ~/ 8) * channels;
  ByteData data = ByteData(wavHeaderSize);
  data.setUint32(4, fileSize - 4, endian);
  data.setUint32(16, 16, endian);
  data.setUint16(20, 1, endian);
  data.setUint16(22, channels, endian);
  data.setUint32(24, sampleRate, endian);
  data.setUint32(28, sampleRate * frameSize, endian);
  data.setUint16(30, frameSize, endian);
  data.setUint16(34, sampleBits, endian);
  data.setUint32(40, fileSize - 44, endian);
  Uint8List bytes = data.buffer.asUint8List();
  bytes.setAll(0, ascii.encode('RIFF'));
  bytes.setAll(8, ascii.encode('WAVE'));
  bytes.setAll(12, ascii.encode('fmt '));
  bytes.setAll(36, ascii.encode('data'));
  return bytes;

void _share(Uint8List data) async {
  String mimeType = 'audio/wav';
  if (Platform.instance.isAndroid) {
    // due to a bug in the share_plus plugin we need only wav
    mimeType = 'wav';
  XFile file = XFile.fromData(
    mimeType: mimeType,
    name: 'output.wav',
    length: data.length,
  await Share.shareXFiles([file]);