19 May '13 - 18:55 *
Welcome, Guest. Please login or register.
Did you miss your activation email?

Login with username, password and session length
 
   Home   Help Search Login Register  
Pages: [1]
  Reply  |  Print  
Author Topic: Netradio Initial Playback Issue (Delphi)  (Read 1532 times)
Orry Verducci
Posts: 9


« on: 12 Apr '09 - 12:15 »
Reply with quoteQuote

I've got a problem in Delphi with both the original netradio application and the application I am basing off it. The first time I try to load any stream, it sits there for some time trying to connect, and then throws up an error with Error Code 0. However, after that when I try to load any stream again, it works perfectly. Is there any way to overcome this?
Logged
Ian @ un4seen
Administrator
Posts: 15244


« Reply #1 on: 13 Apr '09 - 14:49 »
Reply with quoteQuote

Please try to reproduce the problem with the pre-compiled NETRADIO.EXE example (in C\BIN directory). I think the Delphi version of the NETRADIO example is a little buggy when it comes to reporting the error code, as it appears to check the error code in a different thread (the error code is thread-specific).
Logged
Orry Verducci
Posts: 9


« Reply #2 on: 13 Apr '09 - 15:11 »
Reply with quoteQuote

The precompiled version shows the same problem, with Error Code 40.

EDIT: Just tried in on an XP machine, and there was no issue, so it would seem this is some sort of problem with Vista.
« Last Edit: 13 Apr '09 - 17:32 by Orry Verducci » Logged
Chris
Posts: 1503


« Reply #3 on: 13 Apr '09 - 17:51 »
Reply with quoteQuote

@Ian here is a fast Fix for the Delphi example that the Bass_ErrorGetCode will catched in the right Thread

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls, Bass, ExtCtrls;

const
  WM_INFO_UPDATE = WM_USER + 101;

type
 
  TForm1 = class(TForm)
    Panel1: TPanel;
    GroupBox1: TGroupBox;
    Label1: TLabel;
    Label2: TLabel;
    Button1: TButton;
    Button2: TButton;
    Button3: TButton;
    Button4: TButton;
    Button5: TButton;
    Button6: TButton;
    Button7: TButton;
    Button8: TButton;
    Button9: TButton;
    Button10: TButton;
    GroupBox2: TGroupBox;
    Label3: TLabel;
    Label4: TLabel;
    Label5: TLabel;
    GroupBox3: TGroupBox;
    Label6: TLabel;
    ed_ProxyServer: TEdit;
    cbDirectConnection: TCheckBox;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure cbDirectConnectionClick(Sender: TObject);
  private
    { Private declarations }

  public
    { Public declarations }
    procedure WndProc(var Msg: TMessage); override;


  end;

var
  Form1: TForm1;
  Proxy: array [0..99] of char; //proxy server

  cthread: DWORD = 0;
  chan: HSTREAM = 0;
  win: hwnd;
implementation

const
  urls: array[0..9] of string = ( // preset stream URLs
'http://www.radioparadise.com/musiclinks/rp_128-9.m3u','http://www.radioparadise.com/musiclinks/rp_32.m3u',
'http://www.sky.fm/mp3/classical.pls','http://www.sky.fm/mp3/classical_low.pls',
'http://www.sky.fm/mp3/the80s.pls','http://www.sky.fm/mp3/the80s_low.pls',
'http://somafm.com/tags.pls','http://somafm.com/tags32.pls',
'http://somafm.com/secretagent.pls','http://somafm.com/secretagent24.pls'
    );

{$R *.dfm}

  { display error messages }

procedure Error(es: string);
begin
  MessageBox(win, PChar(es + #13#10 + '(error code: ' + IntToStr(BASS_ErrorGetCode) +
    ')'), nil, 0);
end;

{ update stream title from metadata }

procedure DoMeta();
var
  meta: PChar;
  p: Integer;
begin
  meta := BASS_ChannelGetTags(chan, BASS_TAG_META);
  if (meta <> nil) then
  begin
    p := Pos('StreamTitle=', meta);
    if (p = 0) then
      Exit;
    p := p + 13;
    SendMessage(win, WM_INFO_UPDATE, 7, DWORD(PChar(Copy(meta, p, Pos(';', meta) - p - 1))));
  end;
end;

procedure MetaSync(handle: HSYNC; channel, data, user: DWORD); stdcall;
begin
  DoMeta();
end;

procedure StatusProc(buffer: Pointer; len, user: DWORD); stdcall;
begin
  if (buffer <> nil) and (len = 0) then
    SendMessage(win, WM_INFO_UPDATE, 8, DWORD(PChar(buffer)));
end;

function OpenURL(url: PChar): Integer;
var
  icy: PChar;
  Len, Progress: DWORD;
begin
  Result := 0;
  BASS_StreamFree(chan); // close old stream
  progress := 0;
  SendMessage(win, WM_INFO_UPDATE, 0, 0); // reset the Labels and trying connecting

  chan := BASS_StreamCreateURL(url, 0, BASS_STREAM_STATUS, @StatusProc, 0);
  if (chan = 0) then
  begin
    //lets catch the error here inside the Thread
    // and send it to the WndProc
    SendMessage(win, WM_INFO_UPDATE, 1, Bass_ErrorGetCode()); // Oops Error
  end
  else
  begin
    // Progress
    repeat
      len := BASS_StreamGetFilePosition(chan, BASS_FILEPOS_END);
      if (len = DW_Error) then
        break; // something's gone wrong! (eg. BASS_Free called)
      progress := (BASS_StreamGetFilePosition(chan, BASS_FILEPOS_DOWNLOAD) -
        BASS_StreamGetFilePosition(chan, BASS_FILEPOS_CURRENT)) * 100 div len;
      // percentage of buffer filled
      SendMessage(win, WM_INFO_UPDATE, 2, progress); // show the Progess value in the label

    until
      progress > 75;

    // get the broadcast name and bitrate
    icy := BASS_ChannelGetTags(chan, BASS_TAG_ICY);
    if (icy = nil) then
      icy := BASS_ChannelGetTags(chan, BASS_TAG_HTTP); // no ICY tags, try HTTP
    if (icy <> nil) then
      while (icy^ <> #0) do
      begin
        if (Copy(icy, 1, 9) = 'icy-name:') then
          SendMessage(win, WM_INFO_UPDATE, 3, DWORD(PChar(Copy(icy, 10, MaxInt))))

        else if (Copy(icy, 1, 7) = 'icy-br:') then

          SendMessage(win, WM_INFO_UPDATE, 4, DWORD(PChar('bitrate: ' + Copy(icy, 8, MaxInt))));
        icy := icy + Length(icy) + 1;
      end;
    // get the stream title and set sync for subsequent titles
    DoMeta();
    BASS_ChannelSetSync(chan, BASS_SYNC_META, 0, @MetaSync, 0);
    // play it!
    BASS_ChannelPlay(chan, FALSE);
  end;
  cthread := 0;
end;

                     
procedure TForm1.WndProc(var Msg: TMessage);
// to be threadsave we are passing all Canvas Stuff(e.g. Labels) to this messages
begin
  inherited;
  if Msg.Msg = WM_INFO_UPDATE then
    case msg.WParam of
      0:
        begin
          Label4.Caption := 'connecting...';
          Label3.Caption := '';
          Label5.Caption := '';
        end;
      1:
        begin
          Label4.Caption := 'not playing';
          //Error('Can''t play the stream');
         MessageBox(win, PChar('Can''t play the stream' + #13#10 + '(error code: ' +
            IntToStr(msg.LParam)+')'), nil, 0);

        end;
      2: Label4.Caption := Format('buffering... %d%%', [msg.LParam]);
      3: Label4.Caption := PChar(msg.LParam);
      4: Label5.Caption := PChar(msg.LParam);
      5: Label5.Caption := PChar(msg.LParam);
      6: Label3.Caption := PChar(msg.LParam);
      7: Label3.Caption := PChar(msg.LParam);
      8: Label5.Caption := PChar(msg.LParam);
    end;
end;                       

procedure TForm1.FormCreate(Sender: TObject);
begin
  // check the correct BASS was loaded
  win := handle;
  if (HIWORD(BASS_GetVersion) <> BASSVERSION) then
  begin
    MessageBox(0, 'An incorrect version of BASS.DLL was loaded', nil, MB_ICONERROR);
    Halt;
  end;
  if (not BASS_Init(-1, 44100, 0, Handle, nil)) then
  begin
    Error('Can''t initialize device');
    Halt;
  end;
  BASS_SetConfig(BASS_CONFIG_NET_PLAYLIST, 1); // enable playlist processing
  BASS_SetConfig(BASS_CONFIG_NET_PREBUF, 0); // minimize automatic pre-buffering, so we can do it (and display it) instead
  BASS_SetConfigPtr(BASS_CONFIG_NET_PROXY, @proxy[0]); // setup proxy server location

end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  BASS_Free;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  ThreadId: Cardinal;
begin
  StrPCopy(proxy,ed_ProxyServer.Text); // copy the Servertext to the Proxy array
  if (cthread <> 0) then
    MessageBeep(0)
  else
    cthread := BeginThread(nil, 0, @OpenURL, PChar(urls[TButton(Sender).Tag]), 0, ThreadId);
end;

procedure TForm1.cbDirectConnectionClick(Sender: TObject);
begin
  if not TCheckbox(Sender).Checked then
    BASS_SetConfigPtr(BASS_CONFIG_NET_PROXY, @proxy[0]) // enable proxy
  else
    BASS_SetConfigPtr(BASS_CONFIG_NET_PROXY, nil); // disable proxy
end;

end.
Chris



« Last Edit: 13 Apr '09 - 17:57 by Chris » Logged
Ian @ un4seen
Administrator
Posts: 15244


« Reply #4 on: 14 Apr '09 - 16:17 »
Reply with quoteQuote

The precompiled version shows the same problem, with Error Code 40.

EDIT: Just tried in on an XP machine, and there was no issue, so it would seem this is some sort of problem with Vista.

Error code 40 is BASS_ERROR_TIMEOUT, which means that the connection request timed-out. I'm not sure why that would only happen on Vista and only on the 1st connection request. I guess something is delaying the 1st connection request, perhaps a firewall?

@Ian here is a fast Fix for the Delphi example that the Bass_ErrorGetCode will catched in the right Thread

Thanks for that. The updated example is now in the BASS package.
Logged
Orry Verducci
Posts: 9


« Reply #5 on: 14 Apr '09 - 18:55 »
Reply with quoteQuote

Thanks for that, turns out McAfee Personal Firewall was the culprit, so I'll have a look as to why the firewall is only blocking the first connection.
Logged
Orry Verducci
Posts: 9


« Reply #6 on: 16 Apr '09 - 20:50 »
Reply with quoteQuote

If it's of benefit to anyone, turns out McAfee's Smart Recommendation system took longer to figure out the application was safe than BASS likes. Increasting the timeout resolved the problem.

Rather than starting a new thread, I've decided to try out Delphi 2009, which is obviously proving to be a problem with its unicode support. By changing some of the PChar's to PAnsiChar, the app will compile, but it won't work, throwing up Error Code 37. I've tried the same changed in the original netradio app, and it works, although the meta data it displays looks like chinese script. I know putting the BASS_UNICODE flag is meant to help, but where I'm putting it clearly doesn't work. Any suggestions?
« Last Edit: 16 Apr '09 - 21:43 by Orry Verducci » Logged
Ian @ un4seen
Administrator
Posts: 15244


« Reply #7 on: 17 Apr '09 - 14:44 »
Reply with quoteQuote

First, make sure that you're using the latest Delphi API (BASS.PAS), as there were some modifications made for better Delphi 2009 compatibility. Having said that, the Shoutcast tags are still ANSI, so you will have to either tell Delphi that and have it handle the conversion (if possible) or convert it to Unicode yourself. If Delphi doesn't provide its own ANSI/Unicode conversion routines, the MultiByteToWideChar function can be used.
Logged
Orry Verducci
Posts: 9


« Reply #8 on: 17 Apr '09 - 17:54 »
Reply with quoteQuote

I've managed to get the original netradio working perfectly just by changing the PChar's in WndProc to PAnsiChar, and it turns out Error 37 in my application was a result of a bug with my code which showed up in 2009 which told the app to load an invalid device. Thanks a lot for your help Ian, I appreciate it!
Logged
Pages: [1]
  Reply  |  Print  
 
Jump to:  

Powered by SMF 1.1.18 | SMF © 2013, Simple Machines