-- (c) Warren W. Gay VE3WWG ve3wwg@home.com, ve3wwg@yahoo.com
--
-- Protected under the GNU GPL License
-- Modified by K Burtch

with Ada.Text_IO,
Ada.Command_Line,
GNAT.Command_Line;
-- with Ada.IO_Exceptions;
-- with Gnat.Command_Line;

-- use Ada.Text_IO;

--with BC.Containers;
--with BC.Containers.Lists;
--with BC.Containers.Lists.Single;

--with WC.Host, WC.Host.Glue;
--with WC.Global_Heap;
--with WC.Pathname;
--with WC.Streams.Audio;
--with WC.Streams.DSP;
--with WC.Streams.AU;
--with WC.Streams.Wave;
--with WC.Streams.Codec;

--use Ada.Characters.Handling, Ada.Characters.Latin_1;
--use WC.Streams.Audio;
--use WC.Streams.DSP;
--use WC.Streams.AU;
--use WC.Streams.Wave;
--use WC.Streams.Codec;

with world, scanner.communications;
use  world, scanner, scanner.communications;

package body spar_os.sound is

   Default_CDROM_Path : constant string := "/dev/cdrom";

   cdrom_fd     : aFileDescriptor := -1;

   --Default_DSP_Path : constant String := "/dev/dsp";

   -- Release : constant String := "ADAVOX Release 0.51, Warren W. Gay VE3WWG";

   -- GSTREAMER PLAY FILE
   --
   -- Play the given sound file through the gstreamer library.
   -- Sound path must be an absolute path (there are ways to fix this
   -- but they involve more elaborate gstreamer programming).
   -- TODO: should be moved to parser where more utility functions are
   -- available.
   --------------------------------------------------------------------------

   --type String_Ptr is access all String;
   --type Source_Type is (
   --   No_Source,                    -- No source has been specified
   --   AU_File,                      -- *.au file
   --   Wave_File                     -- *.wav file
   --);

   --type Target_Type is (
   --   Device_DSP                    -- /dev/dsp
   --);

   --type Source_Request is
   --   record
   --      Format :       Source_Type;   -- The type of the sound file
   --      Pathname :     String_Ptr;    -- The pathname of the sound file
   --   end record;

   --package Containers is new BC.Containers(Item => Source_Request);
   --package Lists is new Containers.Lists;
   --package SL is new Lists.Single(Storage_Manager => WC.Global_Heap.Pool,Storage => WC.Global_Heap.Storage);
   --use Containers, Lists, SL;

   --RC :        Ada.Command_Line.Exit_Status := 0;
   --Opt_D :     String_Ptr;          -- (-d /dev/dsp) DSP device
   --Opt_R :     Integer := Integer'First; -- (-R priority) Default: use low priority

   --Play_List : List;

   --------------------------------------------------
   -- REALTIME SCHEDULING (IF ANY)
   --------------------------------------------------
   --procedure Real_Time_Scheduling(Priority : Integer) is
   --   use WC.Host, WC.Host.Glue, Ada.Text_IO;
   --   Z : Errno_Type := ENOERR;
   --begin
--
   --   if Have_Real_Time then
   --      declare
   --         Hi, Lo : Integer;
   --         P :      Integer := Priority;
   --      begin
   --         Hi := Get_Scheduler_Priority(Sched_FIFO,True);
   --         Lo := Get_Scheduler_Priority(Sched_FIFO,False);

   --         if P < Lo then
   --            P := Lo + 1;
   --         end if;

   --         if P > Hi then
   --            P := Hi;
   --         end if;

   --         Z := Set_Scheduler_Policy(Sched_FIFO,P);

            -- Report the error if not WC.host.EPERM
   --         if Z /= ENOERR and Z /= WC.host.EPERM then
   --            Put(Standard_Error,"WARNING: ");
   --            Put(Strerror(Z));
   --            Put(": sched_setscheduler(0,FIFO,");
   --            Put(Integer'Image(P));
   --            Put_Line(")");
   --         end if;
   --      end;
--
   --   end if;

   --end Real_Time_Scheduling;

   -- PLAY
   --
   -- Play a sound.  Priority is deprecated.
   --------------------------------------------------

   procedure Play( soundFile : unbounded_string; priority : integer := 0) is
      use Ada.Text_IO;
      use Ada.Command_Line;
      use GNAT.Command_Line;

      --Optch :  Character;
      --Req :    Source_Request;

   begin
      null;
      --if priority > 0 then
      --   Opt_R := priority;
      --end if;
      --if trace then
      --   put_trace( "Sound priority " & Opt_R'img );
      --end if;

      --gstreamer_play_file( soundFile );

      ------------------------------
      -- Set default DSP path, if necessary
      ------------------------------
      --if Opt_D = null then
      --   Opt_D := new String(1..Default_DSP_Path'Length);
      --   Opt_D.all := Default_DSP_Path;
      --end if;

      --if trace and boolean(verboseOpt) then
      --   Put_Trace(Release);
      --end if;

-- this was a loop but now only one song at a time.
-- put the loop back in to queue songs

      --declare
      --   use WC.Pathname;
      --   Arg :    String := to_string( soundFile );
      --   Suf :    String := To_Lower(Suffix(Arg,No_Exceptions));
      --begin
      --
      --   --exit when Arg = "";

      --   if Suf = "au" then
      --      Req.Format := AU_File;
      --      Req.Pathname := new String(1..Arg'Length);
      --      Req.Pathname.all := Arg;
      --      Append(Play_List,Req);
      --   elsif Suf = "wav" then
      --      Req.Format := Wave_File;
      --      Req.Pathname := new String(1..Arg'Length);
      --      Req.Pathname.all := Arg;
      --      Append(Play_List,Req);
      --   else
      --      err( "wavplay: Unknown sound file type: " & Arg);
      --      RC := 2;
      --   end if;
      --end;

      --if RC /= 0 then
      --   return;
      --end if;

      ------------------------------
      -- Set realtime priority
      ------------------------------
      --Real_Time_Scheduling(Opt_R);  -- Set realtime priority if scheduling enabled
      --WC.Host.Squash_Root;          -- Eliminate root if we are running setuid

      ------------------------------
      -- Now iterate through the requests
      ------------------------------
      --declare
      --   Iter :      Iterator'Class := New_Iterator(Play_List);

      --   DSP :       DSP_Stream_Type;
      --   Au :        Au_Stream_Type;
      --   Wav :       Wave_Stream_Type;

      --   In_Strm :   Audio_Stream;
      --   Out_Strm :  Audio_Stream;

      --   Request :   Source_Request;
      --begin

      --   Reset(Iter);
      --   loop
      --      exit when Is_Done(Iter);

            ------------------------------
            -- Open output stream
            ------------------------------
      --      begin
      --         Open(DSP,Out_Mode,Opt_D.all);
      --         Out_Strm := Stream(DSP);
      --      exception
      --         when WC.Streams.DSP.IO_ERROR =>
      --            err( "wavplay: Unable to open sound device: " & Opt_D.all);
      --            RC := 4;
      --            exit;
      --      end;

            ------------------------------
            -- Determine Request
            ------------------------------
      --      Request := Current_Item(Iter);

            ------------------------------
            -- Open Input Stream
            ------------------------------
      --      begin
      --         case Request.Format is
      --            when AU_File =>
      --               Open(Au,In_Mode,Request.Pathname.all);
      --               In_Strm := Stream(Au);
      --            when Wave_File =>
      --               Open(Wav,In_Mode,Request.Pathname.all);
      --               In_Strm := Stream(Wav);
      --            when others =>
      --               err( "wavplay: internal error: unable to handle sound format" );
      --               raise Program_Error;
      --         end case;
      --      exception
      --         when ADA.IO_Exceptions.Name_Error =>
      --            err( "wavplay: Unable to open sound file: " & Request.Pathname.all);
      --            Close(DSP);
      --            RC := 8;
      --            exit;
      --         when WC.Streams.Wave.Unsupported_Format | WC.Streams.AU.Unsupported_Format =>
      --            err( "wavplay: Unsupported compression scheme: " & Request.Pathname.all);
      --            Close(DSP);
      --            RC := 8;
      --            exit;
      --         when WC.Streams.Wave.Not_Riff_Format =>
      --            err( "wavplay: This is not a RIFF file: " & Request.Pathname.all);
      --            Close(DSP);
      --            RC := 8;
      --            exit;
      --         when WC.Streams.Wave.Not_Riff_Wave =>
      --            err( "wavplay: This is not a RIFF(WAVE) file: " & Request.Pathname.all);
      --            Close(DSP);
      --            RC := 8;
      --            exit;
      --         when WC.Streams.Wave.Bad_Wave_File | WC.Streams.Wave.End_File =>
      --            err( "wavplay: File is corrupt or incomplete: " & Request.Pathname.all);
      --            Close(DSP);
      --            RC := 8;
      --            exit;
      --         when WC.Streams.Wave.Seek_Error =>
      --            err( "wavplay: Seek Error: " & Request.Pathname.all);
      --            Close(DSP);
      --            RC := 8;
      --            exit;
      --         when WC.Streams.AU.Not_AU_Format =>
      --            err( "wavplay: Not a *.au format file: " & Request.Pathname.all);
      --            Close(DSP);
      --            RC := 8;
      --            exit;
      --         when WC.Streams.AU.Bad_AU_Format | WC.Streams.AU.Bad_Data_Loc =>
      --            err( "wavplay: Corrupt *.au format file: " & Request.Pathname.all);
      --            Close(DSP);
      --            RC := 8;
      --            exit;
      --         when others =>
      --            err( "wavplay: *** THE BUDGIE DIED ***");
      --            raise;            -- This category of exceptions represents possible bugs
      --      end;

            ------------------------------
            -- Play Request
            ------------------------------
      --      if trace then
      --         Put_Trace("File        : " & Request.Pathname.all);
      --      end if;

            ------------------------------
            -- Report Parameters if verbose
            ------------------------------
      --      if trace then
      --         declare
      --            Chans :        Audio_Channels;      -- # of audio channels
      --            Samp_Rate :    Audio_Sample_Rate;   -- Sample rate in samples / second
      --            Samp_Size :    Audio_Sample_Size;   -- Sample size in bits
      --            Samp_Type :    Audio_Sample_Type;   -- Sample Data Format

      --         begin

      --            Samp_Type := Sample_Type(In_Strm.all);
      --            Chans     := Channels(In_Strm.all);
      --            Samp_Rate := Sample_Rate(In_Strm.all);
      --            Samp_Size := Sample_Size(In_Strm.all);

      --            Put_Trace("Info: " & Audio_Sample_Type'image(Samp_Type) &
      --              ", " & Audio_Channels'image(Chans) & " channels, " &
      --              Audio_Sample_Rate'image(Samp_Rate) & " Hz, " &
      --              Audio_Sample_Size'image(Samp_Size) & " bits");
      --         end;
      --      end if; -- trace

      --      Pump(In_Strm,Out_Strm);

            ------------------------------
            -- Close input stream
            ------------------------------
      --      case Request.Format is
      --         when AU_File =>      Close(Au);
      --         when Wave_File =>    Close(Wav);
      --         when others =>       raise Program_Error;
      --      end case;

       --     Close(DSP);

      --      Next(Iter);
      --   end loop;

      --end;

      --if RC /= 0 then
      --   err( "wavplay: Error #" & RC'img );
      --end if;

      -- Clear( Play_List );



   end Play;

procedure PlayCD( altCdPath : unbounded_string ) is
   CDPath       : unbounded_string;
   playinfo     : cdrom_ti;
   ioctl_result : integer;
   dummy        : aDummyParam := 0;
begin
   if cdrom_fd > 0 then
      stopCD;
      return;
   end if;
   if length( altCdPath ) > 0 then
      CDPath := altCdPath;
   else
      CDPath := to_unbounded_string( Default_CDROM_Path );
   end if;
   cdrom_fd := open( to_string( CDPath ) & ASCII.NUL, O_RDONLY+O_NONBLOCK, 0 );
   if cdrom_fd < 0 then
      err( contextNotes => +"using the optical drive",
           subjectNotes => +"the drive",
           reason => +"could not be opened because syscall open() returned",
           obstructorNotes => getEmOSError
      );
      StopCD;
   end if;
   ioctl_cdromstart( ioctl_result, cdrom_fd, CDROMSTART, dummy );
   if ioctl_result < 0 then
      err( contextNotes => +"using the optical drive",
           subjectNotes => +"the disk",
           reason => +"could not be started because syscall ioctl() returned",
           obstructorNotes => getEmOSError
      );
      StopCD;
   end if;
   playinfo.start_track := 1; -- first track
   playinfo.start_index := 0; -- no effect
   playinfo.end_track := 99;   -- final track (inclusive)
   playinfo.end_index := 0;   -- no effect
   ioctl_playtrkind( ioctl_result, cdrom_fd, CDROMPLAYTRKIND, playinfo );
   if ioctl_result < 0 then
      if C_errno = EINVAL then
         err( contextNotes => +"using the optical drive",
              subjectNotes => +"a disk track",
              reason => +"could not be started because syscall ioctl() returned",
              obstructorNotes => em( "CD is not an audio CD" )
         );
      else
         err( contextNotes => +"using the optical drive",
              subjectNotes => +"a disk track",
              reason => +"could not be started because syscall ioctl() returned",
              obstructorNotes => getEmOSError
         );
      end if;
      StopCD;
   end if;
end PlayCD;

procedure StopCD is
   dummy        : aDummyParam := 0;
   ioctl_result : integer;
   res          : int;
begin
   if cdrom_fd <= 0 then
      err( pl("CD-ROM drive is not in use" ) );
      return;
   end if;
   ioctl_cdromstop( ioctl_result, cdrom_fd, CDROMSTOP, dummy );
   if ioctl_result < 0 then
      err( contextNotes => +"using the optical drive",
           subjectNotes => +"a disk track",
           reason => +"could not be stopped because syscall ioctl() returned",
           obstructorNotes => getEmOSError
      );
   end if;
<<retry>>
   res := close( cdrom_fd );
   if res < 0 then
      if C_errno = EINTR then
         goto retry;
      end if;
   end if;
   cdrom_fd := -1;
end StopCD;

end spar_os.sound;

