BASS.NET API for the Un4seen BASS Audio Library

DOWNLOADPROC Delegate

BASS.NET API for the Un4seen BASS Audio Library
Internet stream download callback function (to be used with BASS_StreamCreateURL(String, Int32, BASSFlag, DOWNLOADPROC, IntPtr)).

Namespace:  Un4seen.Bass
Assembly:  Bass.Net (in Bass.Net.dll) Version: 2.4.17.5
Syntax

public delegate void DOWNLOADPROC(
	IntPtr buffer,
	int length,
	IntPtr user
)

Parameters

buffer
Type: SystemIntPtr
The pointer to the buffer containing the downloaded data... Zero = finished downloading.
length
Type: SystemInt32
The number of bytes in the buffer... 0 = HTTP or ICY tags.
user
Type: SystemIntPtr
The user instance data given when BASS_StreamCreateURL(String, Int32, BASSFlag, DOWNLOADPROC, IntPtr) was called.
Remarks

The callback will be called before the BASS_StreamCreateURL(String, Int32, BASSFlag, DOWNLOADPROC, IntPtr) call returns (if it's successful), with the initial downloaded data. So any initialization (eg. creating the file if writing to disk) needs to be done either before the call, or in the callback function.

When the BASS_STREAM_STATUS flag is specified in the BASS_StreamCreateURL(String, Int32, BASSFlag, DOWNLOADPROC, IntPtr) call, HTTP and ICY tags may be passed to the callback during connection, before any stream data is received. The tags are given exactly as would be returned by BASS_ChannelGetTags(Int32, BASSTag). You can destinguish between HTTP and ICY tags by checking what the first string starts with ("HTTP" or "ICY").

A download callback function could be used in conjunction with a BASS_SYNC_META sync set via BASS_ChannelSetSync(Int32, BASSSync, Int64, SYNCPROC, IntPtr), to save individual tracks to disk from a Shoutcast stream.

NOTE: When you pass an instance of a callback delegate to one of the BASS functions, this delegate object will not be reference counted. This means .NET would not know, that it might still being used by BASS. The Garbage Collector might (re)move the delegate instance, if the variable holding the delegate is not declared as global. So make sure to always keep your delegate instance in a variable which lives as long as BASS needs it, e.g. use a global variable or member.

Examples

Stream an MP3 file, and save a local copy:
private FileStream _fs = null;
private DOWNLOADPROC _myDownloadProc;
private byte[] _data; // local data buffer
...
_myDownloadProc = new DOWNLOADPROC(MyDownload);
int stream = Bass.BASS_StreamCreateURL("http://www.asite.com/afile.mp3", 0, 
                  BASSFlag.BASS_DEFAULT, _myDownloadProc, IntPtr.Zero);
...
private void MyDownload(IntPtr buffer, int length, IntPtr user)
{
  if (_fs == null) 
  {
    // create the file
    _fs = File.OpenWrite( "output.mp3" );
  }
  if (buffer == IntPtr.Zero)
  {
    // finished downloading
    _fs.Flush();
    _fs.Close();
  }
  else
  {
    // increase the data buffer as needed
    if (_data == null || _data.Length < length)
      _data = new byte[length];
    // copy from managed to unmanaged memory
    Marshal.Copy(buffer, _data, 0, length);
    // write to file
    _fs.Write( _data, 0, length );
  }
}
Note: If you are into C# the above example can also make use of usafe code blocks using native pointers to read the data from BASS and to write it to a file:
C#
// within your download callback method...
// assuming you have created a: BinaryWriter bw = new BinaryWriter(_fs);
unsafe
{
  // simply cast the given IntPtr to a native pointer to short values
  // assuming you receive 16-bit sample data here
  short *data = (short*)buffer;
  for (int a = 0; a < length/2; a++)
  {
    // write the received sample data to a local file
    bw.Write( data[a] );
  }
}
See Also

Reference