I am trying to load some sounds in OGG format into my game at runtime in a WebGL build. I use a WWW class to fetch the file which has an ".ogg" extension and then I call www.audioClip to get the downloaded file. This works on other platforms but fails in WebGL.
Unity throws up this error message: "Streaming of 'ogg' on this platform is not supported". Strange since I am not trying to stream it, and I have tried explicitly calling GetAudioClip(false, false, AudioType.OGGVORBIS) and got the same result.
I have tried converting my OGG file to AAC (with M4A and MP4 extensions) and loading this with www.audioClip (error that it cannot determine the file type from the URL) and www.GetAudioClip(false, false, AudioType.MPEG) (no error but also no sound). The closest thing to a solution I've seen online is to use MP3 instead but I don't want to do this for licensing reasons.
Is WebGL in Unity restricted to audio assets that are build into the application?
try:
WWW data = new WWW (url); yield return data;
AudioClip ac = data.GetAudioClipCompressed(false, AudioType.AUDIOQUEUE) as AudioClip;
if(ac != null)
{
ac.name = "mySoundFile.ogg";
gameObject.GetComponent<AudioSource> ().clip = ac;
}
else
{
gameObject.GetComponent<AudioSource> ().clip = null;
Debug.Log("no audio found.");
}
works for me with .ogg files.
Related
Under normal circumstances, I load assetbundle like this
WWW www = WWW.LoadFromCacheOrDownload("http://x.x.x.x/player.unity3d", 3);
yield return www;
but I want to load assetbundle by difference file, for example
I have a difference file like: http://x.x.x.x/player.unity3d.diff
I generate the diff by bsdiff (daemonology.net/bsdiff)
My question is; how can I load assetbundle by player.unity3d.diff?
I am trying to google it, but I not found anything.
Unity doesn't support loading bsdiff'ed files, but you could implement it yourself. Example:
// Load asset bundle
WWW www1 = WWW.LoadFromCacheOrDownload("original.bundle");
// Load diff
WWW www2 = WWW.LoadFromCacheOrDownload("updated.bundle.diff");
// Get bytes for both assets
byte[] original = www1.bytes;
byte[] diff = www2.bytes;
// Apply diff
byte[] updated = ApplyBspatch(original, diff);
// You can save updated bundle at this point to a file.
// Finally, create asset bundle
AssetBundle bundle = AssetBundle.CreateFromMemory(updated);
Here's one of bsdiff implementations in C# you could use to do the patching: https://github.com/LogosBible/bsdiff.net
We have our asset bundles stored on an Amazon S3 bucket. When the game starts, it determines which bundles it needs to download new versions of, using WWW.LoadFromCacheOrDownload.
The problem we're running into is the memory iOS reports it has allocated for our app keeps increasing, however the memory Unity reports it's using (through the profiler) always stays the same. We have enough bundles that by the time it has finished downloading everything we need, it has invariably received a memory warning from iOS, and we are shutdown due to memory pressure shortly after.
Common solutions we have in place already: Unloading the assetbundle after the WWW is finished, using assetBundle.unload(), calling Resources.UnloadUnusedAssets(), and calling Dispose() on the WWW. None of it is solving the problem.
Code follows:
private IEnumerator DownloadBundle(DownloadQueueEntry entry, DownloadFinishedCallback callback)
{
while (!entry.finished)
{
// grab bundle off S3
string url = string.Format(BUNDLE_URL_FORMAT, entry.directory, entry.assetName);
WWW www = WWW.LoadFromCacheOrDownload(url, entry.version);
yield return www;
if (string.IsNullOrEmpty(www.error))
{
Debug.Log("[BundleDownloader] Download Completed " + entry.assetName);
entry.finished = true;
entry.downloading = false;
www.assetBundle.Unload (true);
Resources.UnloadUnusedAssets ();
}
else
{
// usually timed out resolving host, just try again for now
Debug.LogError("[BundleDownloader] Download failed: " + url + " Error: " + www.error);
}
www.Dispose();
www = null;
}
if(callback != null)
{
callback ();
}
}
--edit--
A screenshot showing the increasing memory usage is at the link below. Memory usage proceeds like that until it has chewed up around 150MB. This is all in an scene that only has a GameObject for init scripts in it (no art or anything).
https://www.dropbox.com/s/3b6skexz6xhug5g/Screenshot%202014-03-28%2014.54.26.png
As the Unity docs suggest, you should really be encapsulating your usage of the WWW object/caching routines in a "using" statement block.
using System;
using UnityEngine;
using System.Collections;
public class CachingLoadExample : MonoBehaviour {
public string BundleURL;
public string AssetName;
public int version;
void Start() {
StartCoroutine (DownloadAndCache());
}
IEnumerator DownloadAndCache (){
// Wait for the Caching system to be ready
while (!Caching.ready)
yield return null;
// Load the AssetBundle file from Cache if it exists with the same version or download and store it in the cache
using(WWW www = WWW.LoadFromCacheOrDownload (BundleURL, version)){
yield return www;
if (www.error != null)
throw new Exception("WWW download had an error:" + www.error);
AssetBundle bundle = www.assetBundle;
if (AssetName == "")
Instantiate(bundle.mainAsset);
else
Instantiate(bundle.Load(AssetName));
// Unload the AssetBundles compressed contents to conserve memory
bundle.Unload(false);
} // memory is freed from the web stream (www.Dispose() gets called implicitly)
}
}
"using" statements are a C# feature to ensure that "Dispose()" methods work correctly (and in many cases, are called automagically for you).
As stated in MS's docs: http://msdn.microsoft.com/en-us/library/yh598w02.aspx
"[using] Provides a convenient syntax that ensures the correct use of IDisposable objects."
I'm guess your memory leak is due to these functions not performing as intended (possibly due to improper configuration, not sure).
I had similar issues on AssetBundle downloading on iPad. However, in my case;
I was downloading assetbundle from server (without using cache) and loading it later. In one asset bundle, it boosts the memory if the asset bundle has images more than 100 or lets say 200.
This was not UnityDestroyWWWConnection or "using" issue. I was downloading 60MB asset bundle (with using best-compression on asset bundle generation) and it uses about 450MB while downloading.
I checked the result from instrument and saw tons of small malloc while downloading asset bundle. You can check the instrument screenshot from here.
My guess - not sure: Unity extract the information from asset bundle while downloading continues, which gives error on memory. It gets the header info first, and understands that it is unity3d object and because it downloads with www class it prepare for WWW asset bundle.
My solution was:
Compressing assetbundle and putting server as zip.
Downloading asset bundle zip and extracting on iPad (using SharpZipLib)
We ran into a similar issue in our app. We were loading lots of textures from WWW and noticing iOS being the only platform to have a memory leak from it. We eventually found our solution here http://forum.unity3d.com/threads/www-memory-leak-ios.227753/. Basically, there is a known issue in unity 4.3 that leaks the data from www calls. This SHOULD be fixed in unity 4.5. In the meantime, you can follow Alexey's suggestion to modify the code in the generate xcode project or update to 4.5:
4.5 will have the fix.
Essentially you need:
search for
extern "C" void UnityDestroyWWWConnection(void* connection)
in WWWConnection.mm
[delegate.connection cancel];
delegate.connection = nil;
[delegate.data release]; // <-- ADD THIS
[delegate release];
I have a simple mail system developed with G.W.T and i am trying add a feature to play audio and video files if there is a video or audio file comes as an attachment.
I have been trying bst player and HTML video tag to get work , but i can not play some video formats such as .avi, .mpeg ,.mpg and so on.
What else can be done to play those kind of video formats?
On the other hand, i am thinking of converting the video file in a java servlet then giving that url to player, but i do not know if that makes sense.Is that should be the way?
Last thing is; is there a general format (maybe .flv?) that a video file first have to be converted into so it can be playable by VlcPlayerPlugin or another video player? Any other tip will be helpful.
Thank you for your helps.
the html5 video tag can only play certain formats. You can find a list of the supported browser formats here.
I also had some problems with the BST player but at least it worked with the following code:
public YoutubeVideoPopup( String youtubeUrl )
{
// PopupPanel's constructor takes 'auto-hide' as its boolean parameter.
// If this is set, the panel closes itself automatically when the user
// clicks outside of it.
super( true );
this.setAnimationEnabled( true );
Widget player = null;
try
{
player = new YouTubePlayer( youtubeUrl, "500", "375" );
player.setStyleName( "player" );
}
catch ( PluginVersionException e )
{
// catch plugin version exception and alert user to download plugin first.
// An option is to use the utility method in PlayerUtil class.
player = PlayerUtil.getMissingPluginNotice( Plugin.Auto, "Missing Plugin",
"You have to install a flash plaxer first!",
false );
}
catch ( PluginNotFoundException e )
{
// catch PluginNotFoundException and tell user to download plugin, possibly providing
// a link to the plugin download page.
player = new HTML( "You have to install a flash plaxer first!" );
}
setWidget( player );
}
As you can see, we used the youtube player here, which has the positive effect that the vide can be placed at youtube and must not be pished to server every time the GWT app is redeployed.
You also can play flash other formats, simply use the correct Player class in the try block; example for flash:
player = new com.bramosystems.oss.player.core.client.ui.FlashMediaPlayer( GWT.getHostPageBaseURL( ) +
f4vFileName, true, "375", "500" );
player.setWidth( 500 + "px" );
player.setHeight( "100%" );
Sorry for the delay, did not have the chance to reply.Because of VlcPlayer was behaving strange and showing different control buttons on Ubuntu and Windows, i decided to use FlashPlayerPlugin of BstPlayer.I first convert file to flv by using jave is described here in documentation, then it serves the converted video to FlashPlayer, it works without problem now , thank you all for your helps.
AVAudioPlayer seems not to handle some audio files that can be handled if using AudioStreamer (https://github.com/mattgallagher/AudioStreamer) even when played as a local file.
My questions:
1) What type of audio files generate the error code "pty?". NOTE: Audio file plays fine in QuickTime Player.
2) The following code generates the same error using this audio file:
UInt32 size;
OSStatus err = AudioFileGetPropertyInfo([self audioFileID], kAudioFilePropertyChannelLayout, &size, NULL);
But using the stream api on the same audio file this will work (ok different properties are fetched but then the question is why can't channel layout be asked?):
err = AudioFileStreamGetPropertyInfo(inAudioFileStream, kAudioFileStreamProperty_FormatList, &formatListSize, &outWriteable);
I know that if you stream audio you need to use the stream api because only a part of the file is available at the time. But when the complete file is in the filesystem the file audio api should be possible to use (?)
3) Is it recommended to use stream api even if the file is local? Good ideas how to implement it are welcome.
What puzzles me is why AudioFile* api fails were AudioFileStream* works.
No matter what I try (build -> content, NSUrl, filename) I get a 'null exception': file not found when I try to play a .caf sound file in monotouch.
//var path = NSBundle.MainBundle.PathForResource("MatchGame", "caf");
//var gameSong = SystemSound.FromFile( new NSUrl(path, false));
var gameSong = SystemSound.FromFile("MatchGame.caf");
gameSong.PlaySystemSound();
I also try combinations using the folder name "images/MatchGame.caf" and moving MatchGame.caf into the root folder.
What am I missing? Thanks a lot.
Here is a link to a video of adding the sound in monotouch. http://www.screencast.com/t/MmE0ZmFh What is wrong?
Bryan,
From looking at your screencast - you are trying to play a mp3 file and not a caf file. Mp3 files are encoded differently and will not play with the SystemSound class that's there (I can't remember if you can do this in Obj-C or not.)
You'll want to use the AVFoundation Namespace and AVAudioPlayer class.
using Monotouch.AVFoundation;
var mediaFile = NSUrl.FromFilename("myMp3.mp3");
var audioPlayer = AVAudioPlayer.FromUrl(mediaFile);
audioPlayer.FinishedPlaying += delegate { audioPlayer.Dispose(); };
audioPlayer.Play();
You might need to tweak the code above - I don't have MonoDevelop to hand but that should help you a little further.
Cheers,
ChrisNTR
You need the first line:
var path = NSBundle.MainBundle.PathForResource("MatchGame", "caf");
Then make sure that your audio file is included in the application by making sure that your CAF file is flagged as "Content" in the Properties pane, otherwise the file is not copied to the resulting application package (your .app)
You can follow the steps documented here (they are for images, but apply the same to audio files):
http://wiki.monotouch.net/HowTo/Images/Add_an_Image_to_your_Project
Additionally, this is a good resource for where you should store files:
http://wiki.monotouch.net/HowTo/Files/HowTo%3a_Store_Files