Tonejs / Tone.js

A Web Audio framework for making interactive music in the browser.
https://tonejs.github.io
MIT License
13.52k stars 983 forks source link

Tone and Cordova, I can use a file remotely but not locally, what am I wrong? is this a bag? #1015

Closed UbyXsofT closed 2 years ago

UbyXsofT commented 2 years ago

Hi, I created a "default cordova hello world app", and added the "cordova-plugin-file" plugin. I can't understand why, I can process a remote file and play it, but the same file locally, I can't play it, what am I wrong ?.

is this a bag? ... I expect that if it works with a remote file, why not with a local one, how can I bypass this problem?

I removed all the "Content-Security-Policy" from my index.html ... I changed the permissions in the Config.xml file as follows:

 <preference name = "AndroidPersistentFileLocation" value = "Internal" />
     <access origin = "cdvfile: //*" />
     <access origin = "*" />
     <allow-intent href = "cdvfile: //*/*" />
     <allow-intent href = "http: //*/*" />
     <allow-intent href = "https: //*/*" />

Then in the deviceready, if I switch to Tone.js Player, the external url works, with the local url no, where am I wrong?

//Local NO!: "cdvfile://localhost/persistent/1_Hat.mp3"
//Remote OK!: "https://vivo-vivendo-musica.com/sample/1_Hat.mp3"
//nativeURL NO!:'file:///data/user/0/com.example.hello/files/files/1_Hat.mp3'

//attach a click listener to a play button
document.querySelector('#deviceready').addEventListener('click', async () => {
    await Tone.start()
    console.log('audio is ready');

  window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, function (fs) {
    console.log('file system open: ' + fs.name);
    fs.root.getFile("1_Hat.mp3", {  exclusive: false }, function (fileEntry) {
       console.log("fileEntry is file? " + fileEntry.isFile.toString());
       console.log(fileEntry);
       fileEntry.file(function (file) {
        var nativeURL = fileEntry.nativeURL;
        var localURL=  file.localURL;
         console.log("localURL: " + localURL);
         console.log("nativeURL: " + nativeURL);
         player = new Tone.Player(localURL).toDestination();
         // play as soon as the buffer is loaded
          player.autostart = true;
       });
     }, console.log("getFile") );
   }, console.log("onErrorLoadFs") );  

})

I think it's almost certainly a security issue, but I don't understand what's missing, I've tried all sorts of ways to get to this file, which is present in the www folder.

I have tried to solve in a thousand ways, before writing here, but I cannot understand what is not working. I have developed a web application, and I'd like to port it to mobile devices, via cordova ... everything else about Tone works fine for me, and I'd like not to have to forcibly download files remotely, but to keep them locally. Thanks in advance, for any help possible.

UbyXsofT commented 2 years ago

Finally I managed to solve in this way, I don't know if it is the best way, or if it is the only way, but in this way I can get to the resources, present in the www / directory. It hasn't been easy for me, and I think this can help someone else.

Although I believe that Tone, a fantastic framework, should allow easier access to local resources. I don't know if already, there is an easier way, otherwise it could be implemented, it would make many people happy I think.

//attach a click listener to a play button
document.querySelector('#Play').addEventListener('click', async () => {
    await Tone.start()
    console.log('audio is ready');
  play();
})

function play() {
    var xhr = new XMLHttpRequest();
    xhr.open("GET", "1_Hat.mp3", true);
    xhr.responseType = 'blob';
    xhr.onload = function(){
        var blob = URL.createObjectURL(this.response);
        console.log('pressed');
        var player = new Tone.Player().toDestination();
        player.load(blob);
        player.autostart = true;
    };
    xhr.send();
}

Thanks for this! great help: https://github.com/Tonejs/Tone.js/issues/628#issuecomment-599031271

tambien commented 2 years ago

Thanks @UbySoft, we've gotten quite a few questions about Tone and Cordova in the past.

Does anyone have an interest in create a wiki page on the various gotchas that Web Audio + Cordova has?

vycoder commented 2 years ago

Finally I managed to solve in this way, I don't know if it is the best way, or if it is the only way, but in this way I can get to the resources, present in the www / directory. It hasn't been easy for me, and I think this can help someone else.

Although I believe that Tone, a fantastic framework, should allow easier access to local resources. I don't know if already, there is an easier way, otherwise it could be implemented, it would make many people happy I think.

//attach a click listener to a play button
document.querySelector('#Play').addEventListener('click', async () => {
  await Tone.start()
  console.log('audio is ready');
  play();
})

function play() {
  var xhr = new XMLHttpRequest();
  xhr.open("GET", "1_Hat.mp3", true);
  xhr.responseType = 'blob';
  xhr.onload = function(){
      var blob = URL.createObjectURL(this.response);
      console.log('pressed');
      var player = new Tone.Player().toDestination();
      player.load(blob);
      player.autostart = true;
  };
  xhr.send();
}

Thanks for this! great help: #628 (comment)

Can't seem to make this work. I'm getting an InvalidStateError: The object is in an invalid state. on the xhr.send. Using capacitor running on iOS. Anybody got any idea what could be causing this issue?

I'm downloading the files to Documents.Data, the device's native directory, that I was using later when the user is offline. I had a hunch that there lies the issue. I just can't figure it out. I'm able to play the sound if I use the generated local file path and directly put it in an audio src element, it. plays alright. This means the file itself is being saved properly locally. Playing it on Tone.js is what's giving me issues.