audioplayers icon indicating copy to clipboard operation
audioplayers copied to clipboard

Add headers parameters in audio playerscontroller.play() function to GET the url with the good headers (authorization )

Open bulgarian-beast opened this issue 2 years ago • 3 comments

There is no possibility to add headers in the play() function. I love this project but without it I am getting 403 errors from because the JWT Authorization cannot be sent.

It would be great to have a headers parameters in the play function, because there is a lot of APIs that request headers like authorization application-type, ...

This is the error shown by your your package :

	I/MediaHTTPConnection(24565): response code = 403
	E/MediaHTTPConnection(24565): java.io.IOException
	E/MediaHTTPConnection(24565):   at android.media.MediaHTTPConnection.seekTo(MediaHTTPConnection.java:389)
	E/MediaHTTPConnection(24565):   at android.media.MediaHTTPConnection.getMIMEType(MediaHTTPConnection.java:499)
	E/MediaHTTPConnection(24565):   at 		android.media.IMediaHTTPConnection$Stub.onTransact(IMediaHTTPConnection.java:161)
	E/MediaHTTPConnection(24565):   at android.os.Binder.execTransactInternal(Binder.java:1220)
	E/MediaHTTPConnection(24565):   at android.os.Binder.execTransact(Binder.java:1179)
	W/MediaHTTPConnection(24565): request failed with error => 403
	V/MediaPlayerNative(24565): message received msg=100, ext1=1, ext2=-1005
	E/MediaPlayerNative(24565): error (1, -1005)
	E/MediaPlayer(24565): Error (1,-1005)

The package received this error because the server expect to receive in the request the headers:

	{
		...
		"Authorization": jwtString
		...
	}

You should add an optional <Map>headers parameter to your play() function, and add the headers map when you make the get url request.

Example:

	AudioPlayer audioPlayer = AudioPlayer();

	audioPlayer
		.play(
			widget.msg.content["url"],
			isLocal: false,
			headers: {},
		),
	.onError((error, stackTrace) {
        	print(error);
        	return 0;
	});
	audioPlayer.onPlayerCompletion.listen((event) {
        	audioPlayer.dispose();
	});

This should be implemented in each platform because it's an easy fix (headers is always propose with get, post ... requests), and other people will need it. But it my case it's only Android, Web and iOS.

I hope you will be able to add this little fix because this headers parameter is mandatory for us and we cannot use your package without it. Take care.

bulgarian-beast avatar Jun 11 '22 14:06 bulgarian-beast

For people who need the headers, I have created a temporary solution to wait for this urgent feature. But you have to cache the file to give it to the audio player as a file, but it is not nice to do it this way. I don't recommend using this feature in production because of the file saved on the user's phone.

When you start the audio player, add this:

AudioPlayer? audioPlayer = null;
    File? tempFile = null;

    @override
    void initState() {
      print("init state");
      super.initState();
      audioPlayer = AudioPlayer();
      if (audioPlayer != null && url != null && url != "") {
        cacheVoc(widget.msg.content["url"]);
        // CANNOT USE THE FOLLOWING BECAUSE NO HEADERS PARAMETER CAN BE GIVEN
        // widget.audioPlayer
        //     .play(widget.msg.content["url"], isLocal: false)
        //     .onError((error, stackTrace) {
        //		print(error);
        //		return 0;
        //	});
      }
    }

Then define the cache function:

  void cacheVoc(String url) async {
    get(Uri.parse(url), headers: await getHttpHeader()).then((Response response) {
      Uint8List bytes = response.bodyBytes;
      tempFile = File("${widget.appDirectory?.path}/${appname}/audio/temp/${DateTime.now().microsecondsSinceEpoch}.wav");

      if (response.statusCode == 200 && tempFile != null) {
        tempFile!.create(recursive: true).then((File createdFileDescriptor) {
          tempFile = createdFileDescriptor;
          if (tempFile != null) {
            tempFile!.writeAsBytes(bytes).then((_) {
              if (mounted) {
                widget.audioPlayer.play(tempFile!.path, isLocal: true)
                .onError((error, stackTrace) {
                  print(error);
                  return 0;
                });
              }
            });
          }
        });
      }
    });
  }

And delete the file when it is no more needed:

 @override
  void dispose() {
    if (tempFile != null && tempFile!.existsSync()) {
      tempFile?.delete();
    }
    super.dispose();
  }

bulgarian-beast avatar Jun 11 '22 15:06 bulgarian-beast

For an urgent production repair, consider migrating => just_audio From just_audio README

var duration = await player.setUrl(
    "https://foo.com/bar.mp3",
    headers: {
        "header1": "value1",
        "header2": "value2"
    }
);

bulgarian-beast avatar Jun 11 '22 15:06 bulgarian-beast

It's an open source project. Feel free to fork and try to implement it :) I think it's a very special use case, which is not high priority :/

Gustl22 avatar Jun 25 '22 13:06 Gustl22

See #129

Gustl22 avatar Nov 23 '22 20:11 Gustl22