I tried the plugins example and indeed it does return the correct length! So it must either be a problem with my code, or with BASS .NET, I guess? Here is my StreamPlayer class in it's entirety:
internal class StreamPlayer : IDisposable
{
#region Fields
private int bassStream;
private BASS_FILEPROCS fileProcs;
private Stream inStream;
private long inStreamLength;
private long inStreamPosition;
#endregion Fields
#region Constructors
public StreamPlayer(string email, string key)
{
BassNet.Registration(email, key);
if (Bass.BASS_Init(-1, 44100, BASSInit.BASS_DEVICE_DEFAULT, IntPtr.Zero) == false)
throw new Exception("BASS failed to initialise");
this.bassStream = -1;
this.fileProcs = new BASS_FILEPROCS(this.Bass_StreamClose, this.Bass_StreamLength, this.Bass_StreamRead, this.Bass_StreamSeek);
this.inStream = null;
this.inStreamLength = -1;
this.inStreamPosition = -1;
}
#endregion Constructors
#region IDisposable Methods
public void Dispose()
{
this.ReleaseStream();
Bass.BASS_Free();
}
#endregion IDisposable Methods
#region Methods
public void SetStream(Stream s, long length)
{
// Release the current stream, if one exists
this.ReleaseStream();
// Set the input stream
this.inStream = s;
this.inStreamLength = length;
this.inStreamPosition = 0;
// Create the new stream
this.bassStream = Bass.BASS_StreamCreateFileUser(BASSStreamSystem.STREAMFILE_BUFFER,
BASSFlag.BASS_DEFAULT, this.fileProcs, IntPtr.Zero);
}
public bool Play()
{
if (this.bassStream != -1)
return Bass.BASS_ChannelPlay(this.bassStream, false);
else
return false;
}
public bool Pause()
{
if (this.bassStream != -1)
return Bass.BASS_ChannelPause(this.bassStream);
else
return false;
}
public bool Stop()
{
if (this.bassStream != -1)
{
this.inStream.Close();
Bass.BASS_ChannelStop(this.bassStream);
this.bassStream = -1;
return true;
}
else
{
return false;
}
}
public long GetBufferPosition()
{
return this.inStreamPosition;
}
public long GetChannelPosition()
{
if (this.bassStream != -1)
return Bass.BASS_ChannelGetPosition(this.bassStream, BASSMode.BASS_POS_BYTES);
else
return -1L;
}
public long GetChannelLength()
{
if (this.bassStream != -1)
return Bass.BASS_ChannelGetLength(this.bassStream, BASSMode.BASS_POS_BYTES);
else
return -1L;
}
public double GetEstimatedPositionSeconds()
{
if (this.bassStream != -1)
return Bass.BASS_ChannelBytes2Seconds(this.bassStream, Bass.BASS_ChannelGetPosition(this.bassStream));
else
return -1.0;
}
public double GetEstimatedDurationSeconds()
{
if (this.bassStream != -1)
return Bass.BASS_ChannelBytes2Seconds(this.bassStream, Bass.BASS_ChannelGetLength(this.bassStream));
else
return -1.0;
}
private void ReleaseStream()
{
if (this.bassStream != -1)
{
Bass.BASS_ChannelStop(this.bassStream);
Bass.BASS_StreamFree(this.bassStream);
}
}
#endregion Methods
#region Bass Stream Callbacks
private int Bass_StreamSeek(long offset, IntPtr user)
{
return (int)this.inStream.Seek(offset, SeekOrigin.Begin);
}
private int Bass_StreamRead(IntPtr buffer, int length, IntPtr user)
{
byte[] readBuffer = new byte[length];
int bytesRead = this.inStream.Read(readBuffer, 0, length);
if (bytesRead > 0)
{
this.inStreamPosition += bytesRead;
Marshal.Copy(readBuffer, 0, buffer, bytesRead);
}
return bytesRead;
}
private int Bass_StreamLength(IntPtr user)
{
return (int)this.inStreamLength;
}
private void Bass_StreamClose(IntPtr user)
{
this.inStream.Close();
}
#endregion Bass Stream Callbacks
}