(*
  this file is a part of audio components suite v 2.3.
  copyright (c) 2002-2005 andrei borovsky. all rights reserved.
  see the license file for more details.
  you can contact me at mail@z0m3ie.de
*)

{$Log: acs_aolive.pas,v $
{Revision 1.2  2006/01/01 18:46:40  z0m3ie
{*** empty log message ***
{
{Revision 1.1  2005/12/19 18:36:05  z0m3ie
{*** empty log message ***
{
{Revision 1.2  2005/09/14 21:19:37  z0m3ie
{*** empty log message ***
{
{Revision 1.1  2005/09/13 21:53:45  z0m3ie
{maked seperat driver (not complete jet)
{}

unit acs_aolive;

interface

uses
  Classes,ACS_Classes,ACS_Audio,libao,SysUtils,ACS_Strings,ACS_Types;

const
  LATENCY = 45;//how to measure ?

type

  { TAOLiveAudioOut }

  TAOLiveAudioOut = class(TACSBaseAudioOut)
  private
    _device : PAODevice;
    FVolume : Byte;
    FDrivers : TStringList;
    FCurrentDriver,
    FDefaultDriver : String;
    function IsDevicePlayable(const Dev : String) : Boolean;
  protected
    procedure Done; override;
    function DoOutput(Abort : Boolean):Boolean; override;
    procedure Prepare; override;
    procedure SetDevice(Ch : Integer);override;
    function GetDeviceInfo : TACSDeviceInfo;override;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  end;

implementation

  constructor TAOLiveAudioOut.Create;
  var
    DrList : PPAOInfo;
    DrCount, i : Integer;
    Info : PAOInfo;
  begin
    if not LibaoLoaded then
    raise EACSException.Create(Format(strCoudntloadlib,[LibaoPath]));
    inherited Create(AOwner);
    if AOInitialized = 0 then
    ao_initialize;
    Inc(AOInitialized);
    FDrivers := TStringList.Create;
    DrList := ao_driver_info_list(DrCount);
    for i := 0 to DrCount-1 do
    begin
      if DrList^._type = AO_TYPE_LIVE then
      begin
        FDrivers.Add(String(DrList^.short_name));
      end;
      Inc(DrList);
    end;
    Info := ao_driver_info(ao_default_driver_id);
    FDefaultDriver := Info.short_name;
    FVolume := 255;
  end;

  destructor TAOLiveAudioOut.Destroy;
  begin
    FDrivers.Free;
    if AOInitialized = 1 then
    ao_shutdown;
    Dec(AOInitialized);
    inherited Destroy;
  end;

  procedure TAOLiveAudioOut.Prepare;
  var
    did : Integer;
    sf : ao_sample_format;
    opt : PAOOption;
    Info : PAOInfo;
  begin
    FInput.Init;
    if FCurrentDriver = '' then
    begin
      did := ao_default_driver_id;
      Info := ao_driver_info(did);
      FCurrentDriver := Info.short_name;
    end
    else did := ao_driver_id(@FCurrentDriver[1]);
    opt := nil;
    sf.bits := Finput.BitsPerSample;
    sf.rate := Finput.SampleRate;
    sf.channels := Finput.Channels;
    sf.byte_format := AO_FMT_NATIVE;
    _device := ao_open_live(did, @sf, opt);
    FreeOptionsList(Opt);
    if _device = nil then
    raise EACSException.Create(Format(strDevnotplayable,['+FCurrentDriver+']));
  end;

procedure TAOLiveAudioOut.SetDevice(Ch: Integer);
begin
  if ch < FDrivers.Count-1 then
    if IsDevicePlayable(FDrivers[ch]) then
      FCurrentDriver := FDrivers[ch];
end;

function TAOLiveAudioOut.GetDeviceInfo: TACSDeviceInfo;
begin
end;

  procedure TAOLiveAudioOut.Done;
  begin
    Finput.Flush;
    if _device <> nil then
    ao_close(_device);
  end;

function TAOLiveAudioOut.DoOutput(Abort : Boolean):Boolean;
var
  Len, i : Integer;
  P : Pointer;
  P1 : PACSBuffer8;
  P2 : PACSBuffer16;
begin
  // No exceptions Here
  Result := True;
  if not CanOutput then Exit;
  Len := 0;
  if Abort then
  begin
    ao_close(_device);
    _device := nil;
    Result := False;
    Exit;
  end;
  try
    P := @FBuffer[0];
    while InputLock do;
    InputLock := True;
    Len := Finput.GetData(P, FBufferSize);
    InputLock := False;
    if FVolume < 255 then
    begin
      if FInput.BitsPerSample = 16 then
      begin
        P2 := @FBuffer[0];
        for i := 0 to (Len shr 1) -1 do
        P2[i] := Round(P2[i]*(FVolume/255));
      end else
      begin
        P1 := @FBuffer[0];
        for i := 0 to Len - 1 do
        P1[i] := Round(P1[i]*(FVolume/255));
      end;
    end;
    ao_play(_device, P, Len);
  except
  end;
  if Len > 0 then Result := True
  else Result := False;
end;

  function TAOLiveAudioOut.IsDevicePlayable(const Dev : String) : Boolean;
  var
    i, did : Integer;
    sf : ao_sample_format;
    opt : PAOOption;
  begin
    Result := True;
    if Dev = '' then Exit;
    if Busy then
    raise EACSException.Create(strBusy);
    for i := 0 to FDrivers.Count-1 do
    if FDrivers.Strings[i] = Dev then
    begin
      did := ao_driver_id(@Dev[1]);
      sf.bits := 16;
      sf.rate := 22050;
      sf.channels := 2;
      sf.byte_format := AO_FMT_NATIVE;
      opt := nil;
      _device := ao_open_live(did, @sf, opt);
      if _device <> nil then
      begin
        ao_close(_device);
        FreeOptionsList(Opt);
        Exit;
      end else Break;
    end;
    Result := False;
  end;

initialization
  RegisterAudioOut('AOlive',TAOLiveAudioOut,LATENCY);

end.

