Sumit_VE
Sumit_VE

Reputation: 487

Record Audio and upload file to firebase storage Flutter Web

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

Answers (3)

Aleja Duque-Torres
Aleja Duque-Torres

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

Soorya
Soorya

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

Anderillo
Anderillo

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

Related Questions