Author Topic: [SOLVED] CallBack related to BASS_ChannelSetSync in Linux causes SIGSEGV  (Read 344 times)

jpt

  • Posts: 104
Hello everybody,

I've searched the forum with the word BASS_ChannelSetSync but found nothing related to my problem, so I ask here :

Programming with FreePascal/Lazarus (more or less = Delphi), I'm trying to detect when the currently playing song stops at the end of file (= end of data ?).
Starting with the snippet found here, http://www.un4seen.com/forum/?topic=17382.msg121948#msg121948, I've played with
Code: [Select]
procedure EndSyncProc(handle: HSYNC; channel, data: DWORD; user: Pointer); {$IFDEF MSWINDOWS} stdcall; {$ELSE} cdecl; {$ENDIF}
begin
  // do something at the end here
  ShowMessage('Here');
end;

procedure TMainForm.Button1Click(Sender: TObject);
begin // http://www.un4seen.com/forum/?topic=17382.msg121948#msg121948
  //str:= BASS_StreamCreateFile(False, pchar('/ian_garbarek-2sec.wav'), 0, 0, BASS_STREAM_AUTOFREE);
  str:= BASS_StreamCreateFile(False, pchar('/ian_garbarek-2sec.wav'), 0, 0, 0);
  BASS_ChannelSetSync(str, BASS_SYNC_END, 0, @EndSyncProc, nil);
  BASS_ChannelPlay(str, false);
end;
but I've never seen the MessageBox "Here", cos' the prog crashes with
Quote
"Le projet project1 a levé une exception de class "External: SIGSEGV".
 à l'adresse B793FF45"

when reaching the end of file.
Tried with other songs = same problem, tried the song with 3 different players found in my machine = no problem.

At the time of crash, assembly Window poping up says :
Code: [Select]
...
B793FEE3 e938e2ffff               jmp    0xb793e120
B793FEE8 8d832c79feff             lea    -0x186d4(%ebx),%eax
B793FEEE 89442408                 mov    %eax,0x8(%esp)
B793FEF2 8d83787ffeff             lea    -0x18088(%ebx),%eax
B793FEF8 89442404                 mov    %eax,0x4(%esp)
B793FEFC 8d836b55fcff             lea    -0x3aa95(%ebx),%eax
B793FF02 890424                   mov    %eax,(%esp)
B793FF05 e8e690faff               call   0xb78e8ff0
B793FF0A 8b5c2410                 mov    0x10(%esp),%ebx
B793FF0E 8b742414                 mov    0x14(%esp),%esi
B793FF12 8b7c2418                 mov    0x18(%esp),%edi
B793FF16 83c41c                   add    $0x1c,%esp
B793FF19 c3                       ret   
B793FF1A 8db600000000             lea    0x0(%esi),%esi
B793FF20 56                       push   %esi
B793FF21 53                       push   %ebx
B793FF22 83ec74                   sub    $0x74,%esp
B793FF25 8b8c2480000000           mov    0x80(%esp),%ecx
B793FF2C e8aaa5faff               call   0xb78ea4db
B793FF31 81c3b7300400             add    $0x430b7,%ebx
B793FF37 8bb42484000000           mov    0x84(%esp),%esi
B793FF3E 8b942488000000           mov    0x88(%esp),%edx
B793FF45 f6415030                 testb  $0x30,0x50(%ecx)  <<<  crash here
B793FF49 750b                     jne    0xb793ff56
B793FF4B 0fb64148                 movzbl 0x48(%ecx),%eax
B793FF4F 83e0fb                   and    $0xfffffffb,%eax
B793FF52 3c02                     cmp    $0x2,%al
B793FF54 750a                     jne    0xb793ff60
B793FF56 83c474                   add    $0x74,%esp
B793FF59 5b                       pop    %ebx
B793FF5A 5e                       pop    %esi
B793FF5B c3                       ret   
...
HTH but, sorry, I don't speak assembly's language...

Same behaviour with
Code: [Select]
  BASS_ChannelSetSync(str, BASS_SYNC_END, 0, @EndSyncProc, Self);or
Code: [Select]
  BASS_ChannelSetSync(str, BASS_SYNC_END, 0, @EndSyncProc, pointer(0));
I test on an old machine with Linux Debian 7 32 bits, an old Lazarus 1.4.0 and BASS 2.4.15.1, and I have the same problem with a brand new machine running Linux Debian 10.6 64 bits, a last Lazarus 2.0.12 and BASS 2.4.16.7.
And there is no problem if I comment out that line.

Help welcome, have a nice day.
--
jp
« Last Edit: 2 Nov '21 - 15:55 by jpt »

Chris

  • Posts: 2050
You are parsing Guistuff through  the Sync. Try to change it to a PostMessage.
and try to change the Sync to
Code: [Select]
BASS_ChannelSetSync(str, BASS_SYNC_END or BASS_SYNC_MIXTIME, 0, @EndSyncProc, pointer(0));
Code: [Select]
const
  WM_Stream_END = WM_USER + 101;
Code: [Select]
procedure TForm1.WndProc(var Msg: TMessage);
begin
  inherited;
  if Msg.Msg = WM_Stream_END then
     ShowMessage('Stream has End'');
    end;
end;

« Last Edit: 2 Nov '21 - 12:13 by Chris »

morknot

  • Posts: 21
Hello. I use Lazarus with an endsyncproc with the same structure as yours (except for {$IFDEF MSWINDOWS} stdcall; {$ELSE} cdecl; {$ENDIF} and don't have any problems.

 But a place to start is your  str:= BASS_StreamCreateFile(False, pchar('/ian_garbarek-2sec.wav'), 0, 0, BASS_STREAM_AUTOFREE).

Is your wav file in the same folder as the Lazarus application?

If it is then try PWideChar( 'ian_garbarek-2sec.wav'), that is with PWideChar instead of pChar and without the '/'.

You can test if the file is being opened by declaring an integer, say x, and putting x:=BASS_ErrorGetCode afterwards. If x=2 then the file is not being opened.


Sorry, that's all I can think of at the moment


jpt

  • Posts: 104
--snip--
Thx for your reply, but you fight aside the target, lol !
Yes, I've forgotten to write that song his well played, that was just the end-of-song that I couldn't detect.

You are parsing Guistuff through the Sync.
Thx also, Chris, yes, I've forgotten that basic rule : no gui action in callback proc !
Anyway, there are some strange behaviour :
Code: [Select]
procedure EndSyncProc(handle: HSYNC; channel, data: DWORD; user: Pointer); {$IFDEF MSWINDOWS} stdcall; {$ELSE} cdecl; {$ENDIF}
begin
  // do something at the end here
//  ShowMessage('Here'); // just for testing, but crash if present
  BASS_ChannelRemoveSync(str, lsync); // remove old sync
  if str <> 0 then BASS_StreamFree(str);
  MainForm.WhatToDoAtEndOfSong;
end;

procedure TMainForm.WhatToDoAtEndOfSong;
var avalue : dword;
begin
  log('end of song');
//  ShowMessage('Here'); // just for testing, crash again
  avalue := BASS_ChannelIsActive(str);
  log('test '+inttostr(avalue));
end;
The "log" proc is
Code: [Select]
procedure TMainForm.log(s:string);begin memo.Lines.Add(s); end;, so a full gui action with TMemo, which works, when the ShowMessage still not...

Try to change it to a PostMessage.
Code: [Select]
const
  WM_Stream_END = WM_USER + 101;
Code: [Select]
procedure TForm1.WndProc(var Msg: TMessage);
begin
  inherited;
  if Msg.Msg = WM_Stream_END then
     ShowMessage('Stream has End'');
    end;
end;
Regarding the WndProc, hard to implement in Lazarus, I've found the following in one of my old projects :
Code: [Select]
const
  LM_Stream_END = LM_USER + 101;

implementation

{$R *.lfm}

procedure TMainForm.DefaultHandler(var Msg); // Méthode qui intercepte TOUS les messages
begin
  inherited DefaultHandler(Msg);
  if TLMessage(Msg).msg = LM_Stream_END then
    ShowMessage('Stream has End');
end;

procedure TMainForm.WhatToDoAtEndOfSong;
var avalue : dword;
begin
  log('end of song');
//  ShowMessage('Here');
  avalue := BASS_ChannelIsActive(str);
  log('4 '+inttostr(avalue));
  PostMessage(Handle, LM_Stream_END, 0, 0); // Nice, I see the ShowMessage. +1 !
end;

Don't forget to add
Code: [Select]
  LCLIntf, LCLType,
  LMessages, Messages,
in the uses section.

and try to change the Sync to
Code: [Select]
BASS_ChannelSetSync(str, BASS_SYNC_END or BASS_SYNC_MIXTIME, 0, @EndSyncProc, pointer(0));[/code]
I've noticed that the line
Code: [Select]
lsync := BASS_ChannelSetSync(str, BASS_SYNC_END {or BASS_SYNC_MIXTIME}, FileLength, @EndSyncProc, pointer(0)); is also good, with
Code: [Select]
FileLength := BASS_ChannelGetLength(str,BASS_POS_BYTE); // stream Bytes
Thanks for the help, [SOLVED]

Chris

  • Posts: 2050
Quote
procedure EndSyncProc(handle: HSYNC; channel, data: DWORD; user: Pointer); {$IFDEF MSWINDOWS} stdcall; {$ELSE} cdecl; {$ENDIF}
begin
  // do something at the end here
//  ShowMessage('Here'); // just for testing, but crash if present
  BASS_ChannelRemoveSync(str, lsync); // remove old sync
  if str <> 0 then BASS_StreamFree(str);
  MainForm.WhatToDoAtEndOfSong;
end;

That make no sense, because
you have in your Bass_StreamCreateFile..... Call set the flag BASS_STREAM_AUTOFREE flag
will mean Bass will self freeing the Stream and freeing the connected Handles from that stream eg (in your Example the sync)

Showing a MessageBox is not the same as setting a label oder a memobox/Listbox
A ShowMessage will create a New Window/Form

and that is with the WaitofEndingsong will crash , you are once more try to passing the Messagebox call through the sync

so make it on this way

Code: [Select]
const
  WM_Stream_END = WM_USER + 101;

Code: [Select]
private
    procedure EndOfSong(var msg: TMessage); message WM_Stream_END;

Code: [Select]
procedure EndSyncProc(handle: HSYNC; channel, data: DWORD; user: Pointer); {$IFDEF MSWINDOWS} stdcall; {$ELSE} cdecl; {$ENDIF}
begin
  PostMessage(Win,WM_Stream_END,0,DWORD(PChar('Stream has end')));
end;


Code: [Select]
procedure TForm1.EndOfSong(var msg: TMessage);
begin
  ShowMessage( PChar(msg.lParam));
end;

Code: [Select]
procedure TForm1.FormCreate(Sender: TObject);
begin
  win := handle;
end;
 



jpt

  • Posts: 104
Hi,

That make no sense, because
you have in your Bass_StreamCreateFile..... Call set the flag BASS_STREAM_AUTOFREE flag
will mean Bass will self freeing the Stream and freeing the connected Handles from that stream eg (in your Example the sync)
Yes, I know -- it's just a typo here (will edit my post).

Showing a MessageBox is not the same as setting a label oder a memobox/Listbox
A ShowMessage will create a New Window/Form
The ShowMessage was here just for a quick test to see if things worked as expected.
IRL, no ShowMessage but action to play next song or loop current song or other stuff, action previously set using CheckBox and RadioButtons.

Thx,
--
jp

jpt

  • Posts: 104
so make it on this way

Code: [Select]
const
  WM_Stream_END = WM_USER + 101;

Code: [Select]
private
    procedure EndOfSong(var msg: TMessage); message WM_Stream_END;

Code: [Select]
procedure EndSyncProc(handle: HSYNC; channel, data: DWORD; user: Pointer); {$IFDEF MSWINDOWS} stdcall; {$ELSE} cdecl; {$ENDIF}
begin
  PostMessage(Win,WM_Stream_END,0,DWORD(PChar('Stream has end')));
end;


Code: [Select]
procedure TForm1.EndOfSong(var msg: TMessage);
begin
  ShowMessage( PChar(msg.lParam));
end;

Code: [Select]
procedure TForm1.FormCreate(Sender: TObject);
begin
  win := handle;
end;


For the Lazarus' boys, at top of main file, after
Code: [Select]
interface

uses
  LMessages, // for LM const
  ...

const
  LM_Stream_END = LM_USER + 101;

type

  { TMainForm }
...

...
var
  MainForm: TMainForm;
  // use "unitname." for working with these var's from another unit
  lsync: HSYNC;    // looping synchronizer handle
  StreamPlay,StreamData: HSTREAM;
  win: THandle;

implementation
...
and all that stuff works fine.

Thanks again, Chris  8)
--
jp
« Last Edit: 2 Nov '21 - 16:49 by jpt »