0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

FlutterのrecordのAudioEncoderのファイル出力タイプごとの特徴をまとめてみた

Last updated at Posted at 2023-02-28

recordとは

Flutterで音声ファイルを出力できるパッケージ
AudioEncoderはrecordで定められているクラス

この記事の注意点

1m秒は1ミリ秒を表しています。

AudioEncoderが対応しているファイルの種類

audio_encoder.dart
/// Audio encoder to be used for recording.
enum AudioEncoder {
  /// MPEG-4 AAC Low complexity
  /// Will output to MPEG_4 format container.
  aacLc,

  /// MPEG-4 AAC Enhanced Low Delay
  /// Will output to MPEG_4 format container.
  aacEld,

  /// MPEG-4 High Efficiency AAC (Version 2 if available)
  /// Will output to MPEG_4 format container.
  aacHe,

  /// The AMR (Adaptive Multi-Rate) narrow band speech.
  /// sampling rate should be set to 8kHz.
  /// Will output to 3GP format container on Android.
  amrNb,

  /// The AMR (Adaptive Multi-Rate) wide band speech.
  /// sampling rate should be set to 16kHz.
  /// Will output to 3GP format container on Android.
  amrWb,

  /// Will output to MPEG_4 format container.
  ///
  /// SDK 29 on Android
  ///
  /// SDK 11 on iOs
  opus,

  /// Ogg Vorbis Audio
  vorbisOgg,

  /// Free Lossless Audio Codec
  flac,

  /// Waveform Audio (pcm16bit with headers)
  wav,

  /// Linear PCM 8 bit per sample
  pcm8bit,

  /// Linear PCM 16 bit per sample
  pcm16bit,
}

サイズの検証方法

約5秒間、無音の音声を録音して、1m秒あたりのサイズを計算します。

aacLc

1m秒あたりのサイズ

12.45 バイト

計算方法

65,090 / 5226

FirebaseStorageに認識されるファイルタイプ

video/mp4

aacEld

1m秒あたりのサイズ

16.35

計算方法

84,224 / 5151

FirebaseStorageに認識されるファイルタイプ

video/mp4

aacHe

1m秒あたりのサイズ

16.45

計算方法

84,966 / 5164

FirebaseStorageに認識されるファイルタイプ

video/mp4

amrNb

1m秒あたりのサイズ

2.17

計算方法

11,616 / 5330

FirebaseStorageに認識されるファイルタイプ

video/3gpp

amrWb

1m秒あたりのサイズ

3.51

計算方法

18,513 / 5272

FirebaseStorageに認識されるファイルタイプ

video/3gpp

opus

1m秒あたりのサイズ

15.9

計算方法

82,668 / 5205

FirebaseStorageに認識されるファイルタイプ

application/ogg

vorbisOgg

1m秒あたりのサイズ

0

FirebaseStorageに認識されるファイルタイプ

application/octet-stream

コメント

なぜか0バイトでした。
詳しい方、教えてください。

flac

コメント

後述するコードでこの形式だけuploadできませんでした。

wav

1m秒あたりのサイズ

176.7

計算方法

935,468 / 5293

FirebaseStorageに認識されるファイルタイプ

audio/x-wav

pcm8bit

1m秒あたりのサイズ

88.67

計算方法

467,712 / 5275

FirebaseStorageに認識されるファイルタイプ

application/octet-stream

pcm16bit

1m秒あたりのサイズ

177.0

計算方法

935,424 / 5283

FirebaseStorageに認識されるファイルタイプ

application/octet-stream

小さい順のランキング

名称 1m秒あたりのサイズ (byte) FirebaseStorageに認識されるファイルタイプ
flac - -
vorbisOgg 0 application/octet-stream
amrNb 2.17 video/3gpp
amrWb 3.51 video/3gpp
aacLc 12.45 video/mp4
opus 15.9 application/ogg
aacEld 16.35 video/mp4
aacHe 16.45 video/mp4
pcm8bit 88.67 application/octet-stream
wav 176.7 audio/x-wav
pcm16bit 177.0 application/octet-stream

検証したソースコード

main.dart
import 'package:firebase_storage/firebase_storage.dart';
import 'package:flutter/material.dart';

import 'dart:async';
import 'dart:io';
import 'package:firebase_core/firebase_core.dart';
import 'package:record/record.dart';
import 'package:record_app/gen/firebase_options.dart';
import 'package:stop_watch_timer/stop_watch_timer.dart';
import 'package:path_provider/path_provider.dart';
void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp(
    options: DefaultFirebaseOptions.currentPlatform
  );
  runApp(const MyApp());
}

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

class RecordPage extends StatefulWidget {
  @override
  _RecordPageState createState() => _RecordPageState();
}

class _RecordPageState extends State<RecordPage> {
  final _encoder = AudioEncoder.pcm16bit; // ここを変化させて、再ビルドし検証する.
  String _path = "";
  Record recorder = Record();
  final _textStyle = const TextStyle(fontSize: 20);
  late File _audioFile;
  final StopWatchTimer _stopWatchTimer = StopWatchTimer();
  void _startMeasure() => _stopWatchTimer.onStartTimer();

  void _stopMeasure() => _stopWatchTimer.onStopTimer();

  void _resetMeasure() => _stopWatchTimer.onResetTimer();

  Future<void> _startRecording() async {
    bool x = await recorder.hasPermission();
    if (x) {
      _startMeasure();
      try {
        final dir = await getApplicationDocumentsDirectory();
        _path = '${dir.path}/${DateTime.now().millisecondsSinceEpoch}.m4a';
        _audioFile = File(_path);
        await recorder.start(path: _path,encoder: _encoder);
      } catch (e) {
        print(e);
      }
    }
  }
  Future<void> _stopRecording() async {
    _stopMeasure();
    await recorder.stop();
  }
  void _resetRecording() {
    recorder = Record();
    _resetMeasure();
  }

  Future<void> _upload(int value) async {
  _resetMeasure();
  if (_audioFile.existsSync()) {
    final storageRef = FirebaseStorage.instance.ref().child("audio").child(_encoder.name).child("$value-millisec");
    try {
      final uploadTask = storageRef.putFile(_audioFile);
      await uploadTask.whenComplete(() => debugPrint("アップロードが完了しました"));
    } catch(e) {
      debugPrint(e.toString());
    }
  } else {
    debugPrint("_audioFileがnullまたは存在しません");
  }
}
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Record Page'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            IconButton(
              iconSize: 50,
              icon: const Icon(Icons.mic),
              onPressed: () => _startRecording(),
            ),
            IconButton(
              iconSize: 50,
              icon: const Icon(Icons.stop),
              onPressed: () => _stopRecording(),
            ),
            IconButton(
              iconSize: 50,
              icon: const Icon(Icons.restart_alt),
              onPressed: _resetRecording,
            ),
            const SizedBox(height: 16),
            Center(
              child: StreamBuilder<int?>(
                stream: _stopWatchTimer.rawTime,
                initialData: _stopWatchTimer.rawTime.value,
                builder: (_,snapshot) {
                  final value = snapshot.data!.toInt();
                  return Text(StopWatchTimer.getDisplayTime(value,milliSecond: false,hours: false,minute: false),style: _textStyle,);
                },
              ),
            ),
            IconButton(
              iconSize: 50,
              icon: const Icon(Icons.upload),
              onPressed: () async => await _upload(_stopWatchTimer.rawTime.value)
            ),
          ],
        ),
      )
    );
  }
}

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?