I am working on an app targeting Windows, built in Unity.
All the audio files are in streamingAssets so the client can replace them and customize the app.
I have the following code loading the audio files into Audio Sources and it's working fine on Windows.
void SetAudioFromStreamingAssets()
{
if (string.IsNullOrEmpty(StreamingAssetFilePath)) return;
string fullpath = Application.streamingAssetsPath + "/" + StreamingAssetFilePath;
if (!File.Exists(fullpath)) return;
StartCoroutine(SetAudioClipFromFile(source,fullpath));
}
IEnumerator SetAudioClipFromFile(AudioSource audioSource, string path)
{
using (UnityWebRequest www = UnityWebRequestMultimedia.GetAudioClip(path, AudioType.UNKNOWN))
{
yield return www.SendWebRequest();
if (www.isNetworkError)
{
VisDebug.AppendTxt("ERROR. Could not load music file: " + www.error, true);
}
else
{
AudioClip myClip = DownloadHandlerAudioClip.GetContent(www);
audioSource.clip = myClip;
}
}
}
A colleage of mine is trying to work on the project but he only has a mac. And the audio is not loading on his mac.
The code is reaching this line..
VisDebug.AppendTxt("ERROR. Could not load music file: " + www.error, true);
So File.Exists is true, and also www.isNetworkError is true.
and the www.error is...
Cannot connect to destination host
EDIT
The answer below is correct and just fyi here is an example of what the path needs to look like on macos.
file:///Users/spoopy/Documents/GitHub/Thing/Assets/StreamingAssets/GameLoad.wav
You have to prefix your path with file:// on MacOS and Linux.
You could put something like this after your variable definition.
#if UNITY_STANDALONE_OSX || UNITY_EDITOR_OSX
fullpath ="file://" + path);
#endif
Source
Related
Platform: Unity 2020.1.0f1
I have a weird problem while creating a little game that is meant to download videos from a remote URL to Application.PersistentDataPath and play them in the Unity3D-VideoPlayer using the "RenderTexture"-way by pressing a button for a specific video.
In the editor EVERYTHING works fine...
On IOS EVERYTHING works fine...
On Android (no matter which version) only the video from the asset folder is played properly. Accessing a downloaded file from Application.persistentDataPath is simply showing nothing on Android...
Things I checked (in addition to simple blindness):
"External Write Permission" > forced everything on "internal"... not working
Using Path.Combine() and/or "string filepath = ..."
"Different Video Formats" > nope... the asset video is playing properly without transcoding (it is h.264 AVC, 650x650px, 30fps - AAC Audio, 44,1kHz, Bps 32)
Sample code below, the test scene can also be downloaded here:
http://weristaxel.de/upload/Videotest.unity
http://weristaxel.de/upload/VideotestController.cs
Video in Unity asset folder:
https://corolympics.azurewebsites.net/assets/game1howto.mov
What am I missing?
public void PlayFromPersistent()
{
// NOT WORKING ON ANDROID
VideoPlayer VideoHowTo = VideotestCanvas.transform.Find("VideoPlayer").GetComponent<VideoPlayer>();
string filePath = Application.persistentDataPath + "/game2howto.mov";
VideoHowTo.Stop();
VideoHowTo.url = filePath;
VideoHowTo.source = VideoSource.Url;
DebugText.text = "VideoHowTo.url = " + filePath;
VideoHowTo.Prepare();
VideoHowTo.Play();
}
public void PlayFromAssets()
{
// WORKING ON ANDROID
VideoPlayer VideoHowTo = VideotestCanvas.transform.Find("VideoPlayer").GetComponent<VideoPlayer>();
VideoHowTo.Stop();
VideoHowTo.clip = assetVideo;
VideoHowTo.source = VideoSource.VideoClip;
DebugText.text = "VideoHowTo.clip set - original path " + assetVideo.originalPath;
VideoHowTo.Play();
}
public void DownloadVideo()
{
// THIS DOWNLOADS A TEST VIDEO TO "persistentDataPath"...
string url = "https://corolympics.azurewebsites.net/assets/game2howto.mov";
Debug.Log("Downloading " + url);
var uwr = new UnityWebRequest(url, UnityWebRequest.kHttpVerbGET);
string filename = url.Split('/').Last();
string path = Path.Combine(Application.persistentDataPath , filename);
uwr.downloadHandler = new DownloadHandlerFile(path);
uwr.SendWebRequest();
DebugText.text = "Download to " + path + " finished";
}
public void AddListener()
{
// NOT WORKING ON ANDROID - THIS ADDS A LISTENER TO AN EMPTY BUTTON TO EMULATE THE TARGET BEHAVIOUR
Button button = VideotestCanvas.transform.Find("FromPersistentListenerButton").GetComponent<Button>();
Color blueColor = new Color32(52, 152, 219, 255);
button.GetComponent<Image>().color = blueColor;
button.onClick.AddListener(() =>
{
VideoPlayer VideoHowTo = VideotestCanvas.transform.Find("VideoPlayer").GetComponent<VideoPlayer>();
string filePath = Application.persistentDataPath + "/game2howto.mov";
VideoHowTo.Stop();
VideoHowTo.url = filePath;
VideoHowTo.source = VideoSource.Url;
DebugText.text = "VideoHowTo.url = " + filePath;
VideoHowTo.Play();
});
}
If you're still stuck i would try creating an independant function for when you add the listener event. So it would be something like 'button.onClick.AddListener(() => IndFunction())' instead of creating a new instance each time. I was stuck on something similar a while back and i created an editable script for each button to store the info for each one and set each according to a list of image links and image names.
I'm trying to use Unity to upload a .png file to a specific web folder. The issue could be 1 of 3 things.
1) I couldn't locate a php.ini file on godaddy. So could it be that the folder isn't configured for upload?
2) I've never done this in Unity before so it could be an issue with my code there. (it does return the message that my file couldn't be uploaded, so it is pinging the .php file)
3) It could also be the php code I have, not sure if I adapted the example properly.
I've read other examples but I'm just not sure where my issue even lies for what I should be fixing. Any advice would be awesome.
Unity:
public IEnumerator UploadTicketImage()
{
byte[] FileUpload = File.ReadAllBytes(Path.Combine(Application.persistentDataPath
+ "/TicketInformation/", "Pic001.png"));
WWWForm TextureForm = new WWWForm();
//TextureForm.AddBinaryData(PlayerPrefs.GetString("ImageName"), FileUpload);
TextureForm.AddBinaryData("TotalTest", FileUpload, Path.Combine(Application.persistentDataPath
+ "/TicketInformation/", "Pic001.png"),"image/png");
UnityWebRequest wwwimageupload = UnityWebRequest.Post(StaticVars.IPAddress+ "/UploadTicketsImage.php?", TextureForm);
wwwimageupload.uploadHandler = (UploadHandler)new UploadHandlerRaw(FileUpload);
//wwwimageupload.chunkedTransfer = false;
yield return wwwimageupload.SendWebRequest();
Debug.Log(wwwimageupload.downloadHandler.text);
}
PHP
<?php
$target_dir = "PhotoDeposit/";
$target_file = $target_dir . basename($_FILES["fileToUpload"]["name"]);
$uploadOk = 1;
$imageFileType = strtolower(pathinfo($target_file,PATHINFO_EXTENSION));
// Check if image file is a actual image or fake image
if(isset($_POST["submit"])) {
$check = getimagesize($_FILES["fileToUpload"]["tmp_name"]);
if($check !== false) {
echo "File is an image - " . $check["mime"] . ".";
$uploadOk = 1;
} else {
echo "File is not an image.";
$uploadOk = 0;
}
}
if (move_uploaded_file($_FILES["fileToUpload"]["tmp_name"], $target_file)) {
echo "The file ". basename( $_FILES["fileToUpload"]["name"]). " has been uploaded.";
} else {
echo "Sorry, there was an error uploading your file.";
}
?>
I would already expect it to not find the image file you want to upload correctly.
Path.Combine(Application.persistentDataPath + "/TicketInformation/", "Pic001.png")
results in a path like
| |
v v
C:\path\to\project\/TicketInformation/\Pic001.png
on windows or
| |
v v
/path/to/project//TicketInformation//Pic001.png
on linux or android.
It should rather be used like
Path.Combine(Application.persistentDataPath, "TicketInformation", "Pic001.png")
and
Path.Combine(Application.persistentDataPath, "TicketInformation")
The next point is: Why are you even using an UploadHandlerRaw when you already added the data to the WWWForm so this seems to make not much sense to me.
You should remove the line
wwwimageupload.uploadHandler = (UploadHandler)new UploadHandlerRaw(FileUpload);
Also note that File.ReadAllBytes only works on Windows platforms so depending on your build target you might have to change the way you read the file. You could use a UnityWebRequestTexture.GetTexture also to read local files. Something like
public IEnumerator UploadTicketImage()
{
var folderPath = Path.Combine(Application.persistentDataPath, "TicketInformation");
var filepath = Path.Combine(folderPath, "Pic001.png");
byte[] FileUpload = null;
using (var www = UnityWebRequestTexture.GetTexture(filepath))
{
yield return www.SendWebRequest();
if (www.isNetworkError || www.isHttpError)
{
Debug.LogErrorFormat(this, "File loading failed with {0} - {1}", www.responseCode, www.error);
Debug.LogErrorFormat(this, "Couldn't read file at {0}", filepath);
yield break;
}
else
{
// file data successfully loaded
FileUpload = www.downloadHandler.data;
}
}
var form = new WWWForm();
// here you want the name the file should have on the server
// not a complete system path to file on your local device
// |
// |
// |
// And this is the field you will have |
// to access in php |
// | |
// v v
form.AddBinaryData("TotalTest", FileUpload, "Pic001.png", "image/png");
using (var www = UnityWebRequest.Post("https://111.111.111.1" + "/UploadTicketsImage.php?", form))
{
yield return www.SendWebRequest();
if (www.isNetworkError || www.isHttpError)
{
Debug.LogError(www.error);
}
else
{
Debug.Log(www.downloadHandler.text);
}
}
}
Finally I am no PHP expert by afaik you will then have to access the submitted field like
$_FILES['TotalTest']
sicne you call the field TotalTest in form.AddBinaryData.
Also the
if(isset($_POST["submit"]))
is probably never true since you didn't set it in the WWWForm (I might be wrong and it is set automatically whenever a request is sent).
Note: Typed on smartphone so no warranty but I hope the idea gets clear.
Specs
Unity editor version: 2018.2.8f1
Firebase Unity SDK version: 5.5.0
Additional SDKs: SimpleFirebaseUnity
Developing on: Mac
Export Platform: Android
Issue
I'm having troubles setting up a system to download pictures from storage. I'm not an expert in databases, but I wanted to give it try, just to learn how it is done.
I found Firebase very useful to store metadata on the real-time database and easy to approach even for an entry level programmer like me.
The problem is that I'm trying to download a .png file from a folder in storage, but I can't manage to find if the file is actually downloaded or if it's just lost in the process. I don't get any errors in the console, but when I open the folder in which the files should be, it's empty.
Code
private SimpleFirebaseUnity.Firebase firebaseDatabase;
private FirebaseQueue firebaseQueue;
private FirebaseStorage firebaseStorage;
private StorageReference m_storage_ref;
// Setup refernece to database and storage
void SetupReferences()
{
// Get a reference to the database service, using SimpleFirebase plugin
firebaseDatabase = SimpleFirebaseUnity.Firebase.CreateNew(FIREBASE_LINK, FIREBASE_SECRET);
// Get a reference to the storage service, using the default Firebase App
firebaseStorage = FirebaseStorage.DefaultInstance;
// Create a storage reference from our storage service
m_storage_ref = firebaseStorage.GetReferenceFromUrl(STORAGE_LINK);
// Create a queue, using SimpleFirebase
firebaseQueue = new FirebaseQueue(true, 3, 1f);
}
// ...
IEnumerator DownloadImage(string address, string fileName)
{
var local_path = Application.persistentDataPath + THUMBNAILS_PATH;
var content_ref = m_storage_ref.Child(THUMBNAILS_PATH + fileName + ".png");
content_ref.GetFileAsync(local_path).ContinueWith(task => {
if (!task.IsFaulted && !task.IsCanceled)
{
Debug.Log("File downloaded.");
}
});
yield return null;
}
There can be many reason for why this is not working for you including:
security rules are not setup properly
paths to files are not correct
you are testing it on wrong platform (Firebase is not working well in the editor)
your device is blocking the connection
etc...
In order to get error messages you need to log them:
IEnumerator DownloadImage(string address, string fileName)
{
var local_path = Application.persistentDataPath + THUMBNAILS_PATH;
var content_ref = m_storage_ref.Child(THUMBNAILS_PATH + fileName + ".png");
content_ref.GetFileAsync(local_path).ContinueWith(task => {
if (!task.IsFaulted && !task.IsCanceled)
{
Debug.Log("File downloaded.");
}
else
{
Debug.Log(task.Exception.ToString());
}
});
yield return null;
}
Keep in mind testing it in the editor may not work.
I'll start with the errors themselves. The first is : Assertion failed on expression: 'm_UncompressedBlocksOffsets[blockInd] <= from + dstPos && m_UncompressedBlocksOffsets[blockInd] + uncompressedBlockSize >= from + dstPos' UnityEngine.AssetBundle:LoadFromFile(String)
Followed by : Failed to decompress data for the AssetBundle 'D:/Unity/projects/PQv0.10/Assets/AssetBundles/spritesbundle'. UnityEngine.AssetBundle:LoadFromFile(String)
I've always just used the resources folder for my projects but my current project has outgrown what that method can accommodate. So I'm trying to offload assets (in this case 5000 or so sprites)into an assetbundle and load them as needed at runtime. I figured I could just get a reference to the assetbundle and then call assetbundle.LoadAsset(assetname), substituting my old Resources.Load calls. Here's my attempt at making the assetbundle reference that keeps erroring:
AssetBundle sprites;
void loadSprites()
{
sprites = AssetBundle.LoadFromFile(Application.dataPath + "/AssetBundles/spritesbundle"); // " + bundleName);
if (!sprites) {
Debug.Log("failed to load assetbundle");
}
}
For due diligence, here's also the code I used to create that assetbundle. It simple searches my project for png's and packs them into the assetbundle:
public static void SaveSpecificAssets()
{
AssetBundleBuild build = new AssetBundleBuild();
build.assetBundleName = "spritesBundle";
string[] files = AssetDatabase.GetAllAssetPaths();
List<string> validFiles = new List<string>();
foreach (string file in files)
{
if (file.EndsWith(".png")) validFiles.Add(file);
}
build.assetNames = validFiles.ToArray();
BuildPipeline.BuildAssetBundles("Assets/AssetBundles", new AssetBundleBuild[1] { build }, BuildAssetBundleOptions.None, BuildTarget.StandaloneWindows);
}
The assetbundle builds without errors and appears in the directory where it should be. I have no indication that it's faulty other than the errors I get when trying to load it. The manifest it generates contains appropriate items so I think it's working as intended at least.If I'm missing any relevant information, please point it out and I'll try to provide it.
this is the test coroutine I used in place of loadSprites() for testing if it made a difference:
IEnumerator testLoader()
{
WWW www = WWW.LoadFromCacheOrDownload("file:///" + Application.dataPath + "/AssetBundles/spritesbundle", 1);
yield return www;
sprites = www.assetBundle;
}
Try this, for all the PNG's in your project folder, select them all and add them to an AssetBundle via the Editor, Then just build using
BuildPipeline.BuildAssetBundles("Assets/AssetBundles",BuildAssetBundleOptions.None, BuildTarget.StandaloneWindows);
Then try to load the bundles and see if it shows an error.
Also, look into the Manifest to see if all the files you intended are listed
I'm trying to write a basic UWP app to stream media over a LAN via DLNA. I have three PC's on the same LAN, all running W10 Pro, a Homegroup set up, Media streaming switched on and configured on all of them but when I run the method below, passing in a remote folder all I get in folders back and no files, even though I know the folders contain files.
async private void LoadMediaFiles(StorageFolder mediaServerFolder)
{
try
{
MediaFolders = await mediaServerFolder.GetFoldersAsync();
MediaList.Items.Clear();
if (MediaFolders.Count > 0)
{
MediaList.Items.Clear();
foreach (StorageFolder folder in MediaFolders)
{
MediaList.Items.Add(" + " + folder.DisplayName);
}
MediaTitle.Text = "Media folders retrieved";
}
var queryOptions = new QueryOptions();
var options = new QueryOptions();
options.FileTypeFilter.Add(".avi");
options.FileTypeFilter.Add(".mp4");
options.FileTypeFilter.Add(".mkv");
options.FileTypeFilter.Add(".wmv");
options.FolderDepth = FolderDepth.Deep;
var queryFolder = mediaServerFolder.CreateFileQueryWithOptions(queryOptions);
MediaFiles = await queryFolder.GetFilesAsync();
if (MediaFiles.Count > 0)
{
foreach (StorageFile file in MediaFiles)
{
MediaList.Items.Add(file.DisplayName);
}
MediaTitle.Text = "Media files retrieved";
}
else
MediaTitle.Text = "No files found";
}
catch (Exception ex)
{
MediaTitle.Text = "Error locating media files " + ex.Message;
}
}
To get the known DLNA servers I use:
IReadOnlyList<StorageFolder> MediaServers = await KnownFolders.MediaServerDevices.GetFoldersAsync();
and then list the folders from the selected server. When the user taps on any folder it calls the above method but I never get files, only folders.
I can stream between each of the PC's no problem using WMP or VLC etc, it's only trying to get media files via UWP to stream that it doesn't work... I just get "No files found" on every folder.