Search code examples
c#unity-game-engineaudio-streamingnaudiointernet-radio

Unity with Naudio RadioStreaming


I'm working in a script based on the NAudio Demo modified for streaming a Shoutcast inside my Unity game.

I have tried to remove the original while loop using the update from the MonoBehvaiour class, I only get some noises but not music during the time I'm streaming with this script.

I usually get an error while the execution related with the format

MmException: AcmNotPossible calling acmStreamConvert NAudio.MmException.Try (MmResult result, System.String function) NAudio.Wave.Compression.AcmStreamHeader.Convert (Int32 bytesToConvert, System.Int32& sourceBytesConverted) NAudio.Wave.Compression.AcmStream.Convert (Int32 bytesToConvert, System.Int32& sourceBytesConverted) NAudio.Wave.AcmMp3FrameDecompressor.DecompressFrame (NAudio.Wave.Mp3Frame frame, System.Byte[] dest, Int32 destOffset)

I have tried with different radios online, but I always get that error. I don't know what is happening... Any help?

 public class NAudioStreamer : MonoBehaviour {

    private IWavePlayer mWaveOutDevice;


    private WaveStream  mMainOutputStream;
    private WaveChannel32 mVolumeStream;
    private VolumeWaveProvider16 volumeProvider;



    private string m_Url = "http://37.59.32.115:8122/";


    enum StreamingPlaybackState
    {
        Stopped,
        Playing,
        Buffering,
        Paused
    }

    private volatile StreamingPlaybackState playbackState = StreamingPlaybackState.Stopped;


    private bool fullyDownloaded = false;
    public bool m_Play = false;
    float timer;

    void Update()
    {
        if (m_Play)
        {
            playbackState = StreamingPlaybackState.Buffering;
            StreamMP3(m_Url);
            m_Play = false;
        }

        switch (playbackState)
        {
            case StreamingPlaybackState.Buffering:
            case StreamingPlaybackState.Playing:
                StreamMP3(m_Url);
                break;

            default:        
                break;
        }

    }

    HttpWebRequest webRequest;
    BufferedWaveProvider bufferedWaveProvider = null;
    byte[] buffer = new byte[16384 * 4];


    private void StreamMP3(string lUrl)
    {
        this.fullyDownloaded = false;
        webRequest = (HttpWebRequest)WebRequest.Create(lUrl);

        int metaInt = 0; // blocksize of mp3 data

        webRequest.Headers.Clear();
        webRequest.Headers.Add("GET", "/ HTTP/1.0");

        webRequest.Headers.Add("Icy-MetaData", "1");
        webRequest.UserAgent = "WinampMPEG/5.09";

        HttpWebResponse resp = null;
        try
        {
            resp = (HttpWebResponse)webRequest.GetResponse();
        }
        catch(WebException e)
        {
            if (e.Status != WebExceptionStatus.RequestCanceled)
            {
                Debug.LogError(e.Message);
            }
            return;
        }
         // needs to be big enough to hold a decompressed frame

        try
        {
            // read blocksize to find metadata block
            metaInt = Convert.ToInt32(resp.GetResponseHeader("icy-metaint"));

        }
        catch
        {
        }

        IMp3FrameDecompressor decompressor = null;

        try
        {
            using (var responseStream = resp.GetResponseStream())
            {

                ReadFullyStream readFullyStream = new ReadFullyStream(responseStream);
                //do
                {
                    if (bufferedWaveProvider != null && bufferedWaveProvider.BufferLength - bufferedWaveProvider.BufferedBytes < bufferedWaveProvider.WaveFormat.AverageBytesPerSecond / 4)
                    {
                        Debug.LogError("Buffer getting full, taking a break");
                        Thread.Sleep(500);
                    }
                    else
                    {
                        Mp3Frame frame = null;
                        try
                        {

                            frame = Mp3Frame.LoadFromStream(readFullyStream, true);



                        }
                        catch (EndOfStreamException)
                        {
                            this.fullyDownloaded = true;
                            Debug.LogError("reached the end of the MP3 file / stream");
                            // reached the end of the MP3 file / stream
//                          break;
                        }
                        catch (WebException)
                        {
                            // probably we have aborted download from the GUI thread
//                          break;
                        }
                        if (decompressor == null && frame != null)
                        {
                            // don't think these details matter too much - just help ACM select the right codec
                            // however, the buffered provider doesn't know what sample rate it is working at
                            // until we have a frame
                            WaveFormat waveFormat = new Mp3WaveFormat(frame.SampleRate, frame.ChannelMode == ChannelMode.Mono ? 1 : 2, frame.FrameLength, frame.BitRate);
                            decompressor = new AcmMp3FrameDecompressor(waveFormat);
                            if(bufferedWaveProvider == null)
                            {
                                this.bufferedWaveProvider = new BufferedWaveProvider(decompressor.OutputFormat);
                                this.bufferedWaveProvider.BufferDuration = TimeSpan.FromSeconds(20); // allow us to get well ahead of ourselves
                            }

                        }

                        int decompressed =  decompressor.DecompressFrame(frame, buffer, 0);

                        if(bufferedWaveProvider != null)
                        {
                            bufferedWaveProvider.AddSamples(buffer, 0, decompressed);

                        }
                    }
                } 

                if (this.mWaveOutDevice == null && this.bufferedWaveProvider != null)
                {
                    Debug.Log("Creating WaveOut Device");
                    this.mWaveOutDevice = new  WaveOut();
                    this.volumeProvider = new VolumeWaveProvider16(bufferedWaveProvider);
                    this.volumeProvider.Volume = 100.0f;
                    mWaveOutDevice.Init(volumeProvider);

                }
                else if (bufferedWaveProvider != null)
                {
                    double bufferedSeconds = bufferedWaveProvider.BufferedDuration.TotalSeconds;
                    if(bufferedSeconds > 0.2f && playbackState == StreamingPlaybackState.Buffering)
                    {
                        Debug.Log("PLaying music...");
                        mWaveOutDevice.Play();
                        playbackState = StreamingPlaybackState.Playing;
                    }

                }
            }
        }
        finally
        {
            if (decompressor != null)
            {
                decompressor.Dispose();
            }
        }
    }
}

Solution

  • The ACM error either means there is no ACM MP3 decoder on the machine, or that possibly a corrupt frame has been received (or some album art misinterpreted as a frame). It it's the latter, you can just catch the error and ignore it. If the former, you'll need to install a decoder, or use a different MP3 frame decompressor. (Possibly the NLayer one).