Unity Android load local MP3 or WAV as AudioClip

5.7k views Asked by At

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.

3

There are 3 answers

0
Tim Troiano On BEST ANSWER

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

6
Saad Anees On

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"

0
Minh Max On
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);
        }
    }