Can't load sound files LibGdx

半世苍凉 提交于 2019-12-09 13:26:21

问题


I would like to load files directly from expansion OBB file by using AssetManager. I implemented my own FileHandleResolver

public class CustomFileHandleResolver implements FileHandleResolver
{
    @Override
    public FileHandle resolve(String fileName) {
        return new CustomFileHandle(fileName);
    }
}

I set it to my AssetManager. I created my own FileHandle and I override read() function

@Override
public InputStream read()
{
    InputStream input = null;

    try {           
        input = GameInfo.expansionFile.getInputStream(file.getPath().replace('\\', '/'));
    } catch (IOException e) {
        e.printStackTrace();
    }   

    return input;
}

It loads all the files like .PNG, .PACK, .FNT, except .OGG files, so I guess that all sound files won't be loaded. I'm getting this error:

com.badlogic.gdx.utils.GdxRuntimeException: com.badlogic.gdx.utils.GdxRuntimeException: Couldn't load dependencies of asset: SFx/button_click.ogg

And this error:

com.badlogic.gdx.utils.GdxRuntimeException: java.lang.ClassCastException: com.solidgamesstudio.threedefendersn.framework.CustomFileHandle cannot be cast to com.badlogic.gdx.backends.android.AndroidFileHandle

I read that zip can not be compressed. In 7zip I selected compression to "Store" so that it's not compressed at all, but still this problem occurs.

I traversed what is happening when files are being loaded and I found that AssetManager calls my CustomFileHandleResolver which creates CustomFileHandle. For every file that is not .OGG it calls InputStream read(). In this function it loads the file from the zip and it's fine. But as I said when it comes to loading .OGG it doesn't call this function. So it's not even trying yet to get the file from the zip. Question is, why .OGG file doesn't call InputStream read() in CustomFileHandle()?

UPDATE

I traversed more and I found out that it won't call InputStream read() because it can't create a Sound from FileHandle somehow. Clue to this is

CustomFileHandle cannot be cast to AndroidFileHandle

While to create a sound you need to pass fileHandle.

public Sound newSound (FileHandle fileHandle);

This is called from SoundLoader

@Override
public void loadAsync (AssetManager manager, String fileName, FileHandle file, SoundParameter parameter) {
    sound = Gdx.audio.newSound(file);
}

And that soundLoader uses my CustomFileHandleResolver. I don't know if Sounds are handled differently then other types of files. But by default AssetManager uses

public class InternalFileHandleResolver implements FileHandleResolver {
    @Override
    public FileHandle resolve (String fileName) {
        return Gdx.files.internal(fileName);
    }
}

I can't get into Gdx.files.internal to see if there are any special handling for Sounds.

UPDATE

Further analysis give me clue that the main problem is this as mentioned before.

CustomFileHandle cannot be cast to AndroidFileHandle

I don't know why it's casting my FileHandle to AndroidFileHandle while loading OGG file. If it loads fine other type of files, that probably means it doesn't do casting for them. That means that OGG is special and it needs casting. Any clues?


回答1:


I have not found a way to load sound files from the zip file. Problem is that AssetManager loads sound files differently than other file types. Problem was that it is casting FileHandle to AndroidFileHandle, and since CustomFileHandle extends FileHandle it's impossible to cast it to AndroidFileHandle. I found no way to go around this, because it's deeply rooted.

CustomFileHandle cannot be cast to AndroidFileHandle

In this situation I had to take out all sound files from the OBB file and put them together with the app. I created another instance of AssetManager just for loading sounds. So, sounds are loaded normally as you would with AssetManager and for any other type of file I used AssetManager that uses my own FileHandlerResolver which uses my own FileHandle class that returns a file from the zip. The only problem with this approach is that you are limited to having sounds files only up to 50 MB.




回答2:


I solved this problem extracting the zip to a specific folder, and then reading from that external folder.

The extraction of the zip is done by these methods:

    public void extract(){
    String packageName = getPackageName();
    File root = Environment.getExternalStorageDirectory();
    File expPath = new File(root.toString() + "/Android/obb/" + packageName);

    if (expPath.exists()) {
        String strMainPath = null;
        try {
            strMainPath = expPath + File.separator + "main."
                    + getPackageManager().getPackageInfo(
                            getPackageName(), 0).versionCode + "."
                            + packageName + ".obb";


            Log.e("Extract File path", "===>"+strMainPath);

            File f=new File(strMainPath);
            if(f.exists()){
                Log.e("Extract From File path", "===> not exist");
            }
            else
            {
                Log.e("Extract From File path", "===> exist");
            }

            String pathToExtract = Environment.getExternalStorageDirectory()+"/"+Cons.FOLDERNAME;
            Log.e("Extract to path", "===>"+pathToExtract);
            flag = extractZip(strMainPath,pathToExtract);

            Log.e("After Extract Zip", "===>"+flag);
        } catch (NameNotFoundException e) {
            e.printStackTrace();
        }

    }

}


private boolean extractZip(String pathOfZip,String pathToExtract)
{
    int BUFFER_SIZE = 1024;
    int size;
    byte[] buffer = new byte[BUFFER_SIZE];


    try {
        File f = new File(pathToExtract);
        if(!f.isDirectory()) {
            f.mkdirs();
        }
        ZipInputStream zin = new ZipInputStream(new BufferedInputStream(new FileInputStream(pathOfZip), BUFFER_SIZE));
        fileNum=0;
        try {
            ZipEntry ze = null;
            while ((ze = zin.getNextEntry()) != null) {
                String path = pathToExtract  +"/"+ ze.getName();

                if (ze.isDirectory()) {
                    File unzipFile = new File(path);
                    if(!unzipFile.isDirectory()) {
                        unzipFile.mkdirs();
                    }
                }
                else {
                    updateFileNum();
                    FileOutputStream out = new FileOutputStream(path, false);
                    BufferedOutputStream fout = new BufferedOutputStream(out, BUFFER_SIZE);
                    try {
                        while ( (size = zin.read(buffer, 0, BUFFER_SIZE)) != -1 ) {
                            fout.write(buffer, 0, size);
                        }

                        zin.closeEntry();
                    }catch (Exception e) {
                        Log.e("Exception", "Unzip exception 1:" + e.toString());
                    }
                    finally {
                        fout.flush();
                        fout.close();
                    }
                }
            }
        }catch (Exception e) {
            Log.e("Exception", "Unzip exception2 :" + e.toString());
        }
        finally {
            zin.close();
        }
        return true;
    }
    catch (Exception e) {
        Log.e("Exception", "Unzip exception :" + e.toString());
    }
    return false;

}

Note: Extract it to .Android folder, otherwhise users will have direct acces to the assets. For example they will see the images in the Gallery app.




回答3:


Well, I'm doing this currently. Whenever you need to get a real FileHandle in order for the sound loading mechanism to work (or in any other case were the casting to AndroidFileHandle is bothering you), unzip that file to a local directory and reuse it if needed:

    public static FileHandle getRealFileHandle(String zipEntryPath, ZipFile zipFile) {
    if (Gdx.files.local(zipEntryPath).exists()) {
        return Gdx.files.local(zipEntryPath);
    } else {
        Gdx.app.log(TAG, "Unzipping file '" + zipEntryPath + "'...");
        try {
            FileHandle unzippedFile;
            ZipEntry entry = zipFile.getEntry(zipEntryPath);
            if (entry != null) {
                unzippedFile = Gdx.files.local(zipEntryPath);
                InputStream is = zipFile.getInputStream(entry);
                byte[] buffer = new byte[65536];
                int readLength;
                while ((readLength = is.read(buffer)) >= 0) {
                    unzippedFile.writeBytes(buffer, 0, readLength, true);
                }
                return unzippedFile;
            } else {
                Gdx.app.error(TAG, "Entry '" + zipEntryPath + "' not found inside zip file.");
            }
        } catch (IOException ioe) {
            Gdx.app.error(TAG, "A problem occurred while writing to the local file.");
        }
    }
    return null;
}


来源:https://stackoverflow.com/questions/23388946/cant-load-sound-files-libgdx

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!