filoe / cscore

An advanced audio library, written in C#. Provides tons of features. From playing/recording audio to decoding/encoding audio streams/files to processing audio data in realtime (e.g. applying custom effects during playback, create visualizations,...). The possibilities are nearly unlimited.
Other
2.19k stars 454 forks source link

MP3's on a NAS take a long time to play in branch 1.1. #68

Open digimezzo opened 8 years ago

digimezzo commented 8 years ago

I've been using CSCore 1.0.0.2 for a long time in my audio player. A few weeks ago I decided to use a version compiled from the latest code on the 1.1 branch in my player.

Now a user complains that since the CSCore update, it takes more than 20 seconds before an MP3 file (which is located on the NAS) starts playing. However when the file is on a local disk, it plays fine.

I tested this with MP3's and M4A files and I can confirm this behaviour for MP3's, when they are located on a NAS. M4A files however always start playing instantly (it doesn't matter where they are located).

Did the loading of MP3's change in version 1.1? Should I load them in a different way to avoid this behaviour? Below is a sample of how I'm loading audio files in CSCore:

Private Function GetSoundOut() As ISoundOut

            Select Case Me.mOutputDevice
                Case OutputDevices.DirectSound
                    Return New DirectSoundOut(Me.mLatency)
                Case OutputDevices.WASAPI
                    Return New WasapiOut(Me.mEventSync, Me.mAudioClientShareMode, Me.mLatency)
                Case Else
                    Return New DirectSoundOut(Me.mLatency)
            End Select
        End Function

Public Sub InitializeSoundOut()

    ' Contains the sound to play
    Dim soundSource As IWaveSource = CodecFactory.Instance.GetCodec(Me.mPlayingPath)

    ' SoundOut implementation which plays the sound
    mSoundOut = GetSoundOut()

    ' Initialize the soundOut 
    mNotificationSource = New SingleBlockNotificationStream(soundSource.ToSampleSource)
     mSoundOut.Initialize(Me.mNotificationSource.ToWaveSource(16))

    ' Create the FFT provider
    mFftProvider = New FftProvider(mSoundOut.WaveSource.WaveFormat.Channels, FftSize.Fft2048)

    AddHandler mNotificationSource.SingleBlockRead, AddressOf Me.inputStream_Sample
    AddHandler mSoundOut.Stopped, AddressOf Me.SoundOutStoppedHandler

    mSoundOut.Volume = mVolume
End Sub

Public Sub Play(iUri As String)
    mPlayingPath = iUri
    Me.InitializeSoundOut()
    mSoundOut.Play()
End Sub
filoe commented 8 years ago

Your previous version was using the MediaFoundationDecoder as the default MP3 decoder. Now it is using the DmoMp3Decoder since it is more accurate what position and length concerns. I've added buffered reading now, but I've got no NAS,... to test whether it has an impact on the performance. Don't know whether you can test it. I would say, it should have an impact on the performance(I've checked it with a profiler but my envrionment is not perfect for testing it). As an alternative you can switch back to the MediaFoundationDecoder. I don't know how the MediaFoundationDecoder works internally, but I see no possible solution than parsing the whole file.

digimezzo commented 8 years ago

Thanks for looking into this. Good to know this is caused by a switch in decoder. Buffered reading doesn't solve the issue however. It still takes as long to open an MP3 from a NAS. I'd be glad to do further testing on my NAS if it helps you. Let me know when you need more testing. For switching back to MediaFoundationDecoder, I guess it is this part that I have to modify in CodecFactory:

 Register("mp3", new CodecFactoryEntry(s =>
            {
                try
                {
                    return new DmoMp3Decoder(s);
                }
                catch (Exception)
                {
                    if (Mp3MediafoundationDecoder.IsSupported)
                        return new Mp3MediafoundationDecoder(s);
                    throw;
                }
            },

and modify return new DmoMp3Decoder(s); by return new Mp3MediafoundationDecoder(s);?

filoe commented 8 years ago

It is, but bad to hear that buffering did not solve the problem. The problem is that parsing all mp3 frames (not decoding, just searching the for the headers) consumes quite a lot time. I've got little to no experience in NAS systems. Does these io streams support seeking? PS: I would guess FLAC-files got the same problem?

digimezzo commented 8 years ago

I did tests with a few file formats right now. This is the result:

MP3: not OK (+-30 seconds to play) FLAC: not OK (+-10 seconds to play) OGG: not OK (+-5 seconds to play) WMA: OK (plays instantly) M4A: OK (plays instantly)

As for NAS IO streams. I'm afraid I don't know much about streaming and seeking. I used some sample code found here (http://www.dotnetperls.com/seek) to do the following for an MP3 on the NAS:

using (BinaryReader b = new BinaryReader(File.Open(@"Z:\Temp\Music from NAS test\MP3\Broods - Evergreen (2014)\04 Bridges.mp3",
                                   FileMode.Open)))
        {
            // 2.
            // Important variables:
            int length = (int)b.BaseStream.Length;
            int pos = 50000;
            int required = 2000;
            int count = 0;

            // 3.
            // Seek the required index.
            b.BaseStream.Seek(pos, SeekOrigin.Begin);

            // 4.
            // Slow loop through the bytes.
            while (pos < length && count < required)
            {
                byte y = b.ReadByte();
                // 5.
                // Increment the variables.
                Console.WriteLine("pos = " + pos);
                Console.WriteLine("count = " + count);
                pos++;
                count++;
            }
        }

Not sure if that's an answer to your question, but it didn't throw any exceptions.

filoe commented 8 years ago

Could you please provide an mp3 file of your nas which works fine with mediafoundationdecoder?

digimezzo commented 8 years ago

I've put 2 files here: https://www.dropbox.com/sh/wr36rjx0u1u2aeo/AADnfLBQZ2oJXEIgWyRQHSOZa?dl=0

filoe commented 8 years ago

I'm sorry, it seems like this won't be part of CSCore 1.2. But it's still in focus.