-
-
Notifications
You must be signed in to change notification settings - Fork 647
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Play audio from local file in web app #187
Comments
I assume you are aware of the file system restrictions in web apps. If it is not working, would you be interested in helping by creating a pull request? Some relevant information is below: https://w3c.github.io/FileAPI/ I would have expected a file selected via a picker should work in just_audio, although I haven't tested it. |
Closing due to no response, but comment below if you'd like me to re-open it. |
Thanks for the reply and sorry for the late response. I have never done any web development before, so I had to play around a bit first. I use the file_picker package to select a file, but as you pointed out, the file is not available via the path. I can get the raw byte data of the file, but now I am stuck when it comes to actually using it. From what I understand just_audio can not play directly from memory (yet), so I have to provide it some file. I tried writing to an in-memory file, but get error 4: "Failed to load URL."
Do you have an idea why this wouldn't work? |
Is it because just_audio looks for the URI in the actual file system and not the in-memory one? Can I somehow pass the file directly to the player? |
Hi and sorry for the delay. I have just created a new branch called Let me know how it goes for you, and I might consider adding more convenience methods such as: setStream(Stream<List<int>> stream)
setBytes(List<int> bytes) |
Looks promising, but I don't fully understand it yet. I write my on StreamAudioSource: class MyAudioSource extends StreamAudioSource {
Uint8List _buffer;
MyAudioSource(this._buffer) : super("Bla");
@override
Stream<List<int>> read([int start, int end]) {
return Stream.value(_buffer.skip(start).take(end - start));
}
@override
int get lengthInBytes {
return _buffer.length;
}
} And then I try to set that audio source: await player.setAudioSource(MyAudioSource(buffer)); However, I get a Is there some setup required? |
Hmm, are you able to get a stack trace? |
The error is: And this is the call stack. I used VS Code, activated breaking on exceptions and copied the call stack. Please let me know if you need more info and I'll try my best to help.
|
You can also run the whole thing yourself by checking out the "proxy" branch of this repo. You just need to change the path to your local just_audio version in the pubspec.yml and run the app in the example folder. Click the note symbol in the upper right corner of the app and choose "From file". |
Thanks for the reproduction case! I will take a look. |
Sorry to cause more trouble for you but I just changed the |
I have implemented an audio source using the new API, but I still get the same null pointer exception inside the _setup function (line 1909). I have pushed the changes to the branch I mentioned for you to reproduce. Thanks for your effort and let me know if you need help or additional information! |
Ah yes, of course. The proxy is disabled for web because |
Thank you for your efforts! It looks like you at least have a solution to directly stream from a buffer on other platforms, which is nice. Unfortunately, that's a show stopper for me for the time being. |
If you can find a Javascript app that works, I may be able to implement it's solution. Does this work for you? |
I'm currently working on #288 which might lead to a solution for this issue as well. |
I have tried the HTML player you linked in both Firefox and Chrome, but it doesn't show me anything after loading a file. I subscribed to #288 and will give it a spin as soon as you think it should work. |
This should all be implemented in the latest commit. Your existing code should theoretically work but please do let me know if it does! |
Hmm, the request function gets passed null as start and end. |
This is my request function @override
Future<StreamAudioResponse> request([int start, int end]) {
print(_buffer.length);
print("Start:" + start.toString());
print("End:" + end.toString());
return Future.value(
StreamAudioResponse(
sourceLength: _buffer.length,
contentLength: end - start,
offset: start,
contentType: 'audio/mpeg3',
stream: Stream.value(_buffer.skip(start).take(end - start)),
),
);
} which prints
|
Yes that is possible. If those parameters are null, you should return the entire file. |
Sorry, I overlooked that. I had to cast my buffer from uint8 to int, but now it works! |
Great to hear. This is now published in 0.6.9. |
Hi @Mr-Pepe , please can you post the updated code which worked for you? |
Sure, here is my audio source code: import 'dart:typed_data';
import 'package:just_audio/just_audio.dart';
class BufferAudioSource extends StreamAudioSource {
Uint8List _buffer;
BufferAudioSource(this._buffer) : super("Bla");
@override
Future<StreamAudioResponse> request([int start, int end]) {
start = start ?? 0;
end = end ?? _buffer.length;
return Future.value(
StreamAudioResponse(
sourceLength: _buffer.length,
contentLength: end - start,
offset: start,
contentType: 'audio/mpeg',
stream:
Stream.value(List<int>.from(_buffer.skip(start).take(end - start))),
),
);
}
}
|
@Mr-Pepe been struggling with this for a while. Could you help regarding how to cast the Uint8List to make your code work? |
It's in the last line of the code I posted: List<int>.from(_buffer.skip(start).take(end - start)) _buffer is the Uint8List that I take the desired bytes from and Where exactly do you get the error? Did you manage to load the file properly? I use file_picker to load a file final audioFile = await FilePicker.platform.pickFiles(); and pass the content to the audio source BufferAudioSource(audioFile.files.first.bytes); Does that help you? |
Hi! Sorry for the slow response. |
Hi @Mr-Pepe and @ryanheise, thanks a lot for this issue and your progress on it. The When setting the AudioSource I receive an This is how the network traffic tab looks like the Byte range requests are failing: Any idea how to work around this? The |
I don't think that would be it, this is implemented internally as a base64 data URL so it doesn't contact any servers. It may mean either that data URLs are not supported in Safari or that maybe the data is too long. Can you confirm whether or not the example works on Safari? The last item in the playlist is an asset so it would be loaded using the same mechanism internally. |
@ryanheise I checked out the just_audio repository and tried to launch the web version by switching to That resulted in a log message:
So I assume I am doing the wrong thing 😬 Meanwhile some more info about the safari issue: When I use a really short wav-file, the web inspector isn't crashing, when opening the details of the request. Yet it seems that Safari is doing byte-range requests on the data url request (which seems a bit odd..?): Even though Safari tries to fetch the Byte Rande 0-1 it receives the full data url. Does that ring any bell? 🙃 By the way: also images are (successfully) transmitted via data urls in Safari (you can see it in the same screenshot). So I think we can assume that this isn't the issue. But maybe you are right on size of the data urls. |
You can test the example by switching to the main |
Hrmpf, obviously I tried the main directory first but forgot to switch to the Although I see one failing network request (the image isn't loaded due to cors on safari and chrome) the sound files are playing. The Byte-range headers look exactly the same (also saying they were failing but obviously aren't). The only difference I see is that you use audio/mpeg instead of audio/wav. I will dig deeper into your example code as well as trying different files. |
@ryanheise I can confirm that it works with another mp3-file for all browsers and iOS (app). So it seems to be an issue with the encoding or format of my file. Thanks a lot for your fast help 👍 |
Glad to know you got to the bottom of it! |
Is there a way we can return small chunks of the byte array from the StreamAudioSource? Right now I am working with web and android versions, in both of them, the start and end values are coming in as null in the request method and it is taking almost 30 seconds for the song to load in web and around 5 seconds in mobile. This performance is not acceptable. In the web I am able to download the song in few seconds, but the player stays for a long time in loading state. I tried to return only 1kb at a time, by setting the end value to 1024, but the player fails with an error "Unable to load the url" Please help me to improve the performance. And load fast in small chunks. |
If you would like |
This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs, or use StackOverflow if you need help with just_audio. |
Is your feature request related to a problem? Please describe.
Playing audio from a local file doesn't work in a web app.
Describe the solution you'd like
Support out of the box for playing audio from local files in a web app.
Is there a roadmap for this feature?
The text was updated successfully, but these errors were encountered: