4

I'm able to load audio using UnityWebRequestMultimedia.GetAudioClip in the Unity Editor with the following code but when I run it on Android I am unable to load any files from the user's device.

void Start() {
    audio = GetComponent<AudioSource>();
    string fullPath = Path.Combine("file://" + previewSong);
    StartCoroutine(GetAudioClip(fullPath));
}

IEnumerator GetAudioClip(string fullPath)
{
    using (var uwr = UnityWebRequestMultimedia.GetAudioClip(fullPath, AudioType.MPEG))
    {
        ((DownloadHandlerAudioClip)uwr.downloadHandler).streamAudio = true;

        yield return uwr.SendWebRequest();

        if (uwr.isNetworkError || uwr.isHttpError)
        {
            debugSongPath2.text = uwr.error;
            yield break;
        }

        DownloadHandlerAudioClip dlHandler = (DownloadHandlerAudioClip)uwr.downloadHandler;

        if (dlHandler.isDone)
        {
            audio.clip = dlHandler.audioClip;

            if (audio.clip != null)
            {
                audio.clip = DownloadHandlerAudioClip.GetContent(uwr);

                Debug.Log("Playing song using Audio Source!");
            }
            else
            {
                Debug.Log("Couldn't find a valid AudioClip.");
            }
        }
        else
        {
            Debug.Log("The download process is not completely finished.");
        }
    }
}

The errors I experience vary depending on how I form the start of the URL.

Path.Combine("file:/" + previewSong);
malformed URL

Path.Combine("file://" + previewSong); 
http:/1.1 404 not found

Path.Combine("file:///" + previewSong);
unknown error

Path.Combine("file:////" + previewSong);
unknown error

When I output the URLs on my phone they look correct. Here's an example path:

file:///storage/emulated/0/Music/Deorro/Deorro - Five Hours.mp3

I was previously loading audio from this URL successfully with WWW.GetAudioClip but that's obsolete. This leads me to believe the URL is correct. I've tried building with and without Development Mode. Not sure what else to try. I'd like to get this working with UnityWebRequestMultimedia but if there is an alternative, more effective way of loading local files I'm open to it.

Tim Troiano
  • 449
  • 1
  • 7
  • 25
  • Can you print fullPath and check if its okay? – Saad Anees Nov 23 '20 at 06:59
  • @SaadAnees When I print fullPath on Android it returns a valid URL, file:///storage/emulated/0/Music/Deorro/Deorro - Five Hours.mp3. – Tim Troiano Nov 23 '20 at 07:03
  • What happens if you put the audio clip you're trying to play in your StreamingAssets and pass the streaming assets url + filename as filepath, does it load then? If so then it might be an access rights issues to the storage folder. https://docs.unity3d.com/Manual/StreamingAssets.html – Remy Nov 26 '20 at 14:37
  • @Remy I'm able to load from StreamingAssets (and files anywhere else on my PC) from the Unity Editor using the GetAudioClip coroutine. I am not able to load files from StreamingAssets or any other files on my Android device using the GetAudioClip coroutine. I think this means my permissions are OK but my coroutine isn't working properly? – Tim Troiano Nov 30 '20 at 07:32
  • Oh note btw that your `Path.Combine` makes not much sense since you give a single string into it .. – derHugo Dec 01 '20 at 07:11

3 Answers3

1

The issue was with the new Android 11 scoped storage which disables READ_EXTERNAL_STORAGE. I had to add the following to my AndroidManifest.xml:

<manifest ... >
<!-- This attribute is "false" by default on apps targeting Android 10 or higher. -->
  <application android:requestLegacyExternalStorage="true" ... >
    ...
  </application>
</manifest>

https://developer.android.com/training/data-storage/use-cases#opt-out-scoped-storage

Tim Troiano
  • 449
  • 1
  • 7
  • 25
0

Change your build settings to give write access to external sd card. I am using below code to get audio from specified location in android. I tried your code but somehow its not working.

IEnumerator GetAudioClip2(string fullPath)
{
    debugSongPath2.text = previewSong;
    using (UnityWebRequest www = UnityWebRequestMultimedia.GetAudioClip(fullPath, AudioType.MPEG))
    {
        yield return www.SendWebRequest();

        if (www.isNetworkError || www.isHttpError)
        {
            Debug.Log(www.error);
        }
        else
        {
            AudioClip myClip = DownloadHandlerAudioClip.GetContent(www);
            audioSource.clip = myClip;
            audioSource.Play();
        }
    }
}

My full path was "file:///storage/emulated/0/Samsung/Music/Over the Horizon.mp3"

Saad Anees
  • 1,255
  • 1
  • 15
  • 32
  • I changed Write Access from Internal to External (SD Card) in my Player Settings and I tried out your code instead of mine. This works for me in the Unity Editor but still gives me a 404 error on Android. My full path reads "file:///storage/emulated/0/Music/Sublime/06 Santeria.mp3". – Tim Troiano Nov 24 '20 at 05:12
  • My unity version is 2019.4.0f1 and using embedded android sdk by unity – Saad Anees Nov 24 '20 at 06:07
  • I am on 2020.1.0f1 with the Android Studio SDK. I'm trying to troubleshoot this now to see if that's the issue. – Tim Troiano Nov 24 '20 at 06:58
  • I can't downgrade to 2019.4.0f1 without rebuilding the entire project but I did try using the embedded Android SDK and I'm running into the same error, "http:/1.1 404 not found". The path is definitely correct. I have android.permission.READ_EXTERNAL_STORAGE and android.permission.WRITE_EXTERNAL_STORAGE in my AndroidManifest.xml. If I can't figure out a solution soon I can try setting up a minified example in 2019.4.0f1 and see if my Unity version is the issue. – Tim Troiano Nov 24 '20 at 07:58
  • Not sure why this was downvoted .. that is definitely the best way to get a local audio file loaded into Unity on runtime – derHugo Nov 30 '20 at 18:21
  • @derHugo I didn't downvote but the solution didn't work. Looks like the main difference between this GetAudioClip and mine is running the request through DownloadHandlerAudioClip. I don't think that is causing the issue though. – Tim Troiano Dec 01 '20 at 04:21
0
async void GetAudioClip(string audioURL, GameObject itemMedia)
    {
        try
        {
            audioPlayer.clip = await UnityHttpClient.GetAudioClip(audioURL);

            panelLoading.SetActive(false);
            timeEndAudio.GetComponent<Text>().text = Helper.FormatTime(audioPlayer.clip.length);
            sliderControlAudio.GetComponent<Slider>().maxValue = audioPlayer.clip.length;
            btnControlAudio.interactable = true;
            btnExitAudio.interactable = true;
            IsPlayingAudio = true;
            ControlAudio(IsPlayingAudio);
        }
        catch (Exception exception)
        {
            SetUIErrorNetwork(itemMedia);
            Toast.ShowCommonToast(exception.Message, APIUrlConfig.SERVER_ERROR_RESPONSE_CODE);
        }
    }
RusArtM
  • 1,116
  • 3
  • 15
  • 22