recordとは
Flutterで音声ファイルを出力できるパッケージ
AudioEncoderはrecordで定められているクラス
この記事の注意点
1m秒は1ミリ秒を表しています。
AudioEncoderが対応しているファイルの種類
/// 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
検証したソースコード
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)
),
],
),
)
);
}
}