How to play downloaded sounds in CocosSharp?

SomeProgrammerSomeProgrammer USMember

Hello. Playing with CocosSharp for just a few weeks and have been pulling my hair out with a couple of things.

  • How can I play an audio file that's not installed with the app (i.e. part of the binary and 'content' path)? [Android/iOS/etc.]

Is it using some path evaluating algorithm to find the file? If so.....

  • How do I specify an absolute path?

Someone must have done this right? Not all games use only embedded resources, right? What about an app that records the user and plays back the audio? Maybe there are some other techniques?

Basically...

I want to download extra sounds from the Internet, store them in my local SQLite database and play the binary data but I couldn't figure out how to play binary data so I started with copying the binary data to some place where I could write and then I couldn't play the file from there.

  • How can I play a stream of bytes? It can be whatever format required -- the point is that it's in my local database.

So, I figured out a few little tricks (which might help others)...

-- you can't play MP3s with CCSimpleAudioEngine.SharedEngine.PlayEffect() -- the file needs to be Mono and .WAV -- maybe other types too but not MP3

-- CCSimpleAudioEngine.SharedEngine.PlayBackgroundMusic() will play MP3s but not PlayEffect()

-- you don't have access to write many places -- System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal) worked for me and that equates to /data/data/{MyApp.MyApp}/files (on Android). Need to do something different for WinPhone and iOS.


I dug around in the implementation of CCSimpleAudioEngine.SharedEngine and it seems that it's using...

// MonoGame - Copyright (C) The MonoGame Team
// This file is subject to the terms and conditions defined in
// file 'LICENSE.txt', which is part of this source code package.

namespace Microsoft.Xna.Framework.Media
{
public static partial class MediaPlayer

From there it's Xna???


These 2 posts looked to be useful but didn't answer my questions.

Thanks in advance....

PS The best way that I've found to learn is to look at the 'tests' project on GitHub -- that's of course after Going Bananas.

Posts

  • RamiTabbaraRamiTabbara AUMember, Xamarin Team Xamurai
    edited December 2014

    Hi,

    I understand you're frustration - we'll look at this a bit more. Unfortunately, there's a few limitations within MonoGame that we have to wrestle with, so it's not a straight-forward enhancement to implement.

    In the meantime, I've opened up an enhancement proposal here which should allow a user to load effects via a Stream, and hence allow you to load effects from an absolute file path.

    A few caveats:

    • As you've highlighted currently effect files cannot be mp3's
    • At initialisation, sound effects have their entire byte stream loaded into memory, so it's best to keep the size of these files as small as possible.
  • Thanks! Your comments helped enhance my understanding (a lot) but in the meantime I'm wondering if there are any work-arounds?
    [I did play with this for another 6 hours this Christmas Eve but still don't have a work-around.]

    My understanding is effects and music are implemented using Microsoft.Xna.Framework.Audio and Microsoft.Xna.Framework.Media respectively. Specifically, SoundEffect and MediaPlayer.

    Any WORK-AROUND ideas?

    HACK Attempt#1.

    I could make everything work with my hack of copying my raw bytes into files and then playing those raw files.

    The problem is that I can't get CCSimpleAudioEngine.SharedEngine.PlayEffect or CCSimpleAudioEngine.SharedEngine.PlayBackgroundMusic to play files from the directory where I can write to.

    It appears that everything goes through CCContentManager.SharedContentManager.Load()

    And this guy doesn't seem to support absolute paths.

    HACK Attempt#2.

    I tried adding my directory to the search path so that it would find my files.. NOTE: my files are copied to /data/data/{com.myapp}/files

    application.ContentSearchPaths.Add("..");
    application.ContentSearchPaths.Add("../..");
    application.ContentSearchPaths.Add("../../files");
    application.ContentSearchPaths.Add("../files");
    application.ContentSearchPaths.Add("files");

    But no luck.

    What am I doing wrong? Should this approach work?

    HACK Attemp#3???

    ???? No idea what to try next....

    Maybe the only solution is to start compiling my own version of CococsSharp -- I guess that I'll need to figure out how to do that anyway in order to test any fixes without waiting for an official build.

    Do I need to build my own MonoGame.Framework and Lidgren as well?

  • MichaelBluesteinMichaelBluestein USInsider, University, Developer Group Leader ✭✭✭

    You can always fall back to the native APIs as well from CocosSharp if there isn't a cross-platform abstraction that does what you need (of course, you'd need to implement it for each platform in that case). For example, you could leverage Core Audio on iOS to stream audio. I whipped up a quick example here that does this.

    The audio streaming is implemented in a class I called AudioStreamer (I assumed mp3 in the example but you could change/extend that as needed).

    To use it I created an instance of AudioStreamer in the GameLayer and called Play:

        // stream audio from web
        audio = new AudioStreamer ("http://vprclassical.streamguys.net/vprclassical128.mp3");
        audio.Play ();
    

    Hope that helps :)

  • Thank you Michael. Yes, that does help a bit.

    For effects, I solved it as follows:

    byte[] abyAudioData = GetWaveDataBytes(....);
    MemoryStream ms = new MemoryStream(abyAudioData);
    Microsoft.Xna.Framework.Audio.SoundEffect effect = Microsoft.Xna.Framework.Audio.SoundEffect.FromStream(ms);
    effect.Play();

    I did have one little problem in that sending the buffer directly caused there to be some distortion/clicks at the end. I played with that through all the different interfaces, specifying length, not specifying length, data without header, data with header, etc. I don't know why it works sending the stream but that's fine with me.

    I haven't yet found an interface that will work for MP3 files -- one where I can send an array of buffer or stream.

    AudioFileStream is iOS only, right?

    **Is there a cross platform way (like XNA) that you might suggest for playing an MP3 file that I have in memory?**

Sign In or Register to comment.