{
  Autor: Michael Springwald

  Erstellt: Samstag der 01.März.2008
  Updates:
  -----------------------------------------------------------------------
01- Mittwoch, 26.März.2008         - Freitag, 28.März.2008              -
  -----------------------------------------------------------------------
02- Samstag, 29.März.2008          - Mittwoch, 11.Februar.2009          -
  -----------------------------------------------------------------------
03- Sonntag, 21.März.2010          -                                    -  by Peter During
  -----------------------------------------------------------------------
04-                                -                                    -
  -----------------------------------------------------------------------
05-                                -                                    -
  -----------------------------------------------------------------------
06-                                -                                    -
  -----------------------------------------------------------------------
}

unit plXine;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, xine,xlib;

const
  plSOpen  = 0;
  plSPlay  = 1;
  plSPause = 2;
  plSStop  = 3;

type
  TPLXine = class;
  TPLTestEvent = procedure of Object;

  TMyThread = class(TThread)
    private
      procedure ShowStatus;
    protected
      procedure Execute; override;
    public
      xine:TPLXine;
      TestEvent:TPLTestEvent;
      t:Integer;
      Constructor Create(CreateSuspended : boolean);
    end;

  TOnFINISHED = procedure of Object;

  TXineEvent = procedure(data:Pointer) of object;

  TxineUserData = record
    rect: x11_rectangle_t;
    old_width, old_height : Integer;
    resizeFactor : Double;
    displayRatio : Double;
    Display: PDisplay;
    shmEventId: Integer;

    { event callbacks }
    OnPlaybackFinished: TXineEvent;
    OnChannelChanged: TXineEvent;
    OnSetTitle: TXineEvent;
    OnProgress: TXineEvent;
    OnNumButtons: TXineEvent;
    OnMRLReference: TXineEvent;
  end;

  { TPLXine }

  TPLXine = class
    fOnFINISHED: TXineEvent;
  private
    function GetMusicLenght: Integer;
    function GetPosition: Integer;
    function GetVolume: Integer;

    procedure SetPosition(const AValue: Integer);
    procedure SetVolume(const AValue: Integer);

  protected

  public
    PlayTime, PlayPos, PlayLen:Integer;

    CurrFileName:String;
    myXine : Pxine_t;

    ao_driver:Pxine_ao_driver_t;
    myXStream : Pxine_stream_t;
    queue: Pxine_event_queue_t;
    PlayStatus:Integer;
    UserData : TxineUserData;

    myThread:TMyThread;
    OpenF, NotPlay:Boolean;

    constructor Create(const aAutoInit:Boolean = True);
    destructor Destroy; override;

    procedure init;
    procedure FileOpen(const aFileName:String);
    procedure play;
    procedure Stop;
    procedure Pause;

    procedure Status(var aPos, aTime, aLen:Integer);
    procedure SetInfo;

    function GetLen(const Stunde:boolean = false):String;
    function GetCurrTime(const aCurr2Time:Boolean = False; Stunde:boolean = false):String;

    function GetFileExt:String;
    procedure TestEv;

  published
    property OnFINISHED:TXineEvent read fOnFINISHED write fOnFINISHED;

    property Volume:Integer read GetVolume write SetVolume;
    property Position:Integer read GetPosition write SetPosition;

    property MusicLenght:Integer read GetMusicLenght;

  end; // TPLXine


procedure XineEventCB(user_data:Pointer; event: Pxine_event_t); cdecl;

implementation
{ TPLXine }

procedure XineEventCB(user_data:Pointer; event: Pxine_event_t); cdecl;
var
  data:^TxineUserData;
begin
  if (user_data <> NIL) then begin
    data:=user_data;
    case event^.typ of
      XINE_EVENT_UI_PLAYBACK_FINISHED:
      begin
        if Assigned(data^.OnPlaybackFinished) then
          data^.OnPlaybackFinished(event^.data);
      end;

      XINE_EVENT_UI_CHANNELS_CHANGED:
      begin
      end;

      XINE_EVENT_UI_SET_TITLE:
      begin
      end;

      XINE_EVENT_PROGRESS:
      begin
        writeln('TEST:Progress');
      end;

      XINE_EVENT_UI_NUM_BUTTONS:
      begin
      end;

      XINE_EVENT_MRL_REFERENCE:
      begin
      end
      else
      begin
      end;
   end;
  end
end;

function TPLXine.GetMusicLenght: Integer;
begin

end;

function TPLXine.GetPosition: Integer;
begin
  result:=PlayTime;
end; // TPLXine.GetPosition

function TPLXine.GetVolume: Integer;
begin
  result:=xine_get_param(myXStream, XINE_PARAM_AUDIO_VOLUME);
end; // TPLXine.GetVolume

procedure TPLXine.SetPosition(const AValue: Integer);
begin
  if( xine_get_stream_info( myXStream, XINE_STREAM_INFO_SEEKABLE ) <> 0) then
  begin
    xine_set_param(myXStream, XINE_PARAM_AUDIO_VOLUME, AValue);
   xine_play( myXStream, 0, AValue );
  end;
end; // TPLXine.SetPosition

procedure TPLXine.SetVolume(const AValue: Integer);
begin
  xine_set_param(myXStream, XINE_PARAM_AUDIO_VOLUME, AValue);
end; // TPLXine.SetVolume

constructor TPLXine.Create(const aAutoInit:Boolean = True);
begin
  inherited Create;
  OpenF:=False;
  myThread:=TMyThread.Create(True);
  myThread.TestEvent:=@TestEv;
  myThread.xine:=self;

  if aAutoInit then init;
end; // TPLXine.Create

destructor TPLXine.Destroy;
begin
  inherited Destroy;
end; // TPLXine.Destroy

procedure TPLXine.init;
begin
  myThread.t:=1;
  myThread.Resume;
end; // TPLXine.init

procedure TPLXine.FileOpen(const aFileName: String);
begin
  CurrFileName:=aFileName;
  if xine_open(myXStream,PChar(CurrFileName)) >= 1 then begin
    if not NotPlay then begin
      OpenF:=True;
    end;
  end;
end; // TPLXine.FileOpen

procedure TPLXine.play;
begin
  xine_usec_sleep(1000);
  if (xine_get_param(myXStream,XINE_PARAM_SPEED) <> XINE_SPEED_PAUSE) then
  begin
     xine_play(myXStream,0,0);
  end;
  xine_set_param(myXStream,XINE_PARAM_SPEED,XINE_SPEED_NORMAL);

//  myThread.t:=3;
//  myThread.Resume;
  //writeln('-- Play -- ');

//  myThread.Resume;
end; // TPLXine.play

procedure TPLXine.Stop;
begin
  xine_stop(myXStream);
  xine_close(myXStream);
  OpenF:=False;
end; // TPLXine.Stop

procedure TPLXine.Pause;
begin
  if PlayStatus = plSPause then begin
    PlayStatus:=plSPlay;
    play;
  end
  else begin
    PlayStatus:=plSPause;
    xine_set_param(myXStream,XINE_PARAM_SPEED,XINE_SPEED_PAUSE);
  end;

end; // TPLXine.Pause

procedure TPLXine.Status(var aPos, aTime, aLen: Integer);
var
  zpos, ztime, zlength: Integer;
begin
  xine_get_pos_length(myXStream,@zpos,@ztime,@zlength);
  apos:=zPos; aTime:=ztime; aLen:=zlength;
end;

procedure TPLXine.SetInfo;
begin
  Status(playpos,playtime,PlayLen);
end; // TPLXine.SetInfo

function TPLXine.GetLen(const Stunde:boolean = false): String;
var
  sLen:String;
  aStu, aMin, aSek:Integer;
begin

  aSek:=(PlayLen div 1000) mod 60;
  aMin:=(PlayLen div 60000) mod 60;
  if Stunde then
  begin
    aStu:=(PlayLen div 3600000) mod 60;
    sLen:=Format('%.2D:%.2D:%.2D',[aStu, aMin, aSek])
  end else
    sLen:=Format('%.2D:%.2D',[aMin, aSek]);
  result:=sLen;
end; // TPLXine.GetLen

function TPLXine.GetCurrTime(const aCurr2Time:Boolean = False; Stunde:boolean = false): String;
var
  s:String;
  aStu, aMin, aSek, aT:Integer;
begin
  if not aCurr2Time then
    aT:=PlayTime
  else
    at:=PlayLen-PlayTime;

  aSek:=(aT div 1000) mod 60;
  aMin:=(aT div 60000) mod 60;
  if Stunde then
  begin
    aStu:=(aT div 3600000) mod 60;
    s:=Format('%.2D:%.2D:%.2D',[aStu, aMin, aSek])
  end else
    s:=Format('%.2D:%.2D',[aMin, aSek]);

  result:=s;
end; // TPLXine.GetCurrTime

function TPLXine.GetFileExt: String;
begin
  result:=ExtractFileExt(CurrFileName);
end;

procedure TPLXine.TestEv;
begin

end;

{ TMyThread }

procedure TMyThread.ShowStatus;
var
  s:Integer;
begin
  if t = 1 then begin
    xine.myXine := xine_new();
    xine_config_load(xine.myXine,PChar('/.xine/config'));
    xine_init(xine.myXine);
    xine.ao_driver := xine_open_audio_driver(xine.myXine,'alsa',Nil);
    xine.myXStream := xine_stream_new(xine.myXine,xine.ao_driver,nil);
    xine.queue := xine_event_new_queue (xine.myXStream);
    xine.UserData.OnPlaybackFinished:=xine.OnFINISHED;
    xine_event_create_listener_thread (xine.queue, @XineEventCB, @xine.UserData);
    t:=0;
  end;

  if ( t= 3) and (not xine.NotPlay) and (xine.OpenF) then begin
    writeln('-- Play3 -- ', xine.OpenF);

    if (xine_get_param(xine.myXStream,XINE_PARAM_SPEED) <> XINE_SPEED_PAUSE) then
    begin

       try
         xine_play(xine.myXStream,0,0);
       except
//         xine_open(xine.myXStream,PChar(xine.CurrFileName));
//         xine_play(xine.myXStream,0,0);
       end;
    end;
  ///  xine_set_param(xine.myXStream,XINE_PARAM_SPEED,XINE_SPEED_NORMAL);
    t:=0;
   //Terminate;
  end;
end;

procedure TMyThread.Execute;
begin
  Synchronize(@Showstatus);

{  while not Terminated do begin
    if t > 0 then  begin
      Synchronize(@Showstatus);
    end;
  end;}
end;

constructor TMyThread.Create(CreateSuspended: boolean);
begin
  FreeOnTerminate := False;
  inherited Create(CreateSuspended);
  t:=0;
end;

end.

