Reputation: 487
I am using the flutter_sound package to record and play audio. On Flutter Web, on stopping the recording the recorder returns a path/URL of this type: blob:http://localhost:63986/b60f31ce-b94d-48c8-8a4a-2d939effe6d8
I want to upload the audio recording to Firebase Storage but dart.io can't be used for flutter-web so can't use the File method. Even after searching, I didn't find a way to achieve it. I don't know how to proceed. How can I write the audio to file and upload it to firebase?
My Code:
import 'dart:html' as html;
import 'dart:io' as io;
final recorder = FlutterSoundRecorder();
final player = FlutterSoundPlayer();
String fileName;
@override
void initState() {
super.initState();
initRecorder();
}
@override
void dispose() {
recorder.closeRecorder();
player.closePlayer();
super.dispose();
}
Future<void> initRecorder() async {
if (!kIsWeb) {
final status = await Permission.microphone.request();
if (status != PermissionStatus.granted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Grant Permission form mic first!')),
);
}
}
await recorder.openRecorder();
await player.openPlayer();
recorder.setSubscriptionDuration(Duration(milliseconds: 500));
}
Future<void> record() async {
fileName = DateTime.now().toString();
await recorder.startRecorder(toFile: fileName);
}
Future<void> stop() async {
path = await recorder.stopRecorder();
if (kIsWeb) {
if (path == null) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Grant Permission for mic first!')),
);
} else {
// Get File from path and upload it to Firebase
print(path);
// not working for Web
// final audioFile = io.File(path);
// html.File() doesn't take path/Url as parameter but
// File(List<Object> fileBits, String fileName,[Map? options])
/*
await FirebaseStorage.instance
.ref()
.child('users/uploads/$fileName.mp3')
.putData(file!.bytes!);*/
}
} else if (!kIsWeb) {
if (path == null) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Grant Permission for mic first!')),
);
} else {
//final audioFile = io.File(path);
// await FirebaseStorage.instance
// .ref()
// .child('users/uploads/$fileName.mp3')
// .putFile(audioFile);
}
}
}
Upvotes: 4
Views: 4479
Reputation: 39
If someone has the same problem in 2024 :)
I was recording an audio and then uploaded it to FirebaseStorage. The recording part was done with flutter_sound.
Hope it helps :)
void uploadAudio() async {
if (_mplaybackReady && _mPath != null) {
try {
Uint8List? fileData;
if (kIsWeb) {
final String? blobUri = html.window.sessionStorage[_mPath];
if (blobUri == null) {
throw Exception('No recorded audio found in sessionStorage.');
}
final Uri uri = Uri.parse(blobUri);
final http.Response response = await http.get(uri);
if (response.statusCode != 200) {
throw Exception(
'Failed to fetch recorded audio data. Status code: ${response.statusCode}');
}
fileData = response.bodyBytes;
} else {
// For Mobile/Desktop: Read the recorded file from disk
final file = File(_mPath);
if (!file.existsSync()) {
throw Exception('Recording file does not exist.');
}
fileData = await file.readAsBytes();
}
if (fileData == null || fileData.isEmpty) {
throw Exception('No valid audio data to upload.');
}
final user = FirebaseAuth.instance.currentUser;
if (user == null) {
throw Exception('No user is authenticated.');
}
// Define the correct Content-Type (MIME type)
final metadata = SettableMetadata(
contentType: 'audio/webm', // Update based on the recording format
);
// Firebase Storage path
final fileName = '${DateTime.now().millisecondsSinceEpoch}.webm';
final storageRef = FirebaseStorage.instanceFor(
bucket: 'gs://YOUR_BUCKET_ADRESS',
).ref().child('users/${user.uid}/$fileName');
// Upload the file data to Firebase Storage
final uploadTask = storageRef.putData(fileData, metadata);
// Get the download URL
final snapshot = await uploadTask;
final downloadUrl = await snapshot.ref.getDownloadURL();
// Save metadata in Firestore
final firestore = FirebaseFirestore.instance;
await firestore
.collection('YOUR_COLLECTION_NAME')
.doc(user.uid)
.collection('recordings')
.add({
'fileName': fileName,
'downloadUrl': downloadUrl,
'uploadedAt': FieldValue.serverTimestamp(),
});
print('Audio uploaded successfully: $downloadUrl');
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Audio uploaded successfully: $downloadUrl')),
);
} catch (e) {
print('Error uploading audio: $e');
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Error uploading audio.')));
}
} else {
print('No audio data to upload.');
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Please record audio before uploading.')),
);
}
}
Upvotes: 0
Reputation: 701
This worked for me.
http.Response response = await http.get(
'blob:http://localhost:63986/b60f31ce-b94d-48c8-8a4a-2d939effe6d8',
);
response.bodyBytes //data in bytes
Note: Verified in local machine & firebase hosting.
Upvotes: 3
Reputation: 143
I've been working on this for days, and I finally figured it out!
When you call startRecorder(toFile: audioLocation)
, audioLocation
will be the location of the file after you call stopRecorder()
, stored in html.window.sessionStorage
(html
as in import 'dart:html' as html;
).
So you need to add import 'package:http/http.dart' as http;
, create a fileName
(whatever you want the file to be called in Firebase Storage), and then insert the following piece of code.
var ref = await storage.ref().child('path/to/file/$fileName');
Uri blobUri = Uri.parse(html.window.sessionStorage[audioFile]!);
http.Response response = await http.get(blobUri);
await ref.putData(response.bodyBytes, SettableMetadata(contentType: 'video/mp4'));
This might not be the best way, but it is the way I finally got it to work! Good luck!!
Upvotes: 9