
/*
 * --- GSMP-COPYRIGHT-NOTE-BEGIN ---
 * 
 * This copyright note is auto-generated by ./scripts/Create-CopyPatch.
 * Please add additional copyright information _after_ the line containing
 * the GSMP-COPYRIGHT-NOTE-END tag. Otherwise it might get removed by
 * the ./scripts/Create-CopyPatch script. Do not edit this copyright text!
 * 
 * GSMP: pcm/tests/ALSAHelper.cc
 * General Sound Manipulation Program is Copyright (C) 2000 - 2004
 *   Valentin Ziegler and René Rebe
 * 
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; version 2. A copy of the GNU General
 * Public License can be found in the file LICENSE.
 * 
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANT-
 * ABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
 * Public License for more details.
 * 
 * --- GSMP-COPYRIGHT-NOTE-END ---
 */

#include <iostream>

#include "OggVorbisStream.hh"
#include "MP3Stream.hh"

#include "ALSAHelper.hh"

#include <sys/time.h>

using namespace std;
using namespace GSMP;

int main()
{
  const int period_size = 1024;
  BasicStream stream (2, period_size);
  int16_t raw_stream [period_size * 2];
  
  std::string cname = "hw:0";
  
  ALSAControl alsa_control;
  ALSAPCM alsa_pcm;
  
  if (alsa_pcm.Open (cname, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK) )
    {    
      if (!alsa_pcm.SetAccess (SND_PCM_ACCESS_RW_INTERLEAVED) )
	std::cout << "Setting RW_INTERLEAVED failed!" << std::endl;
  
      // try the formats we support ...
      if (alsa_pcm.SetFormat (SND_PCM_FORMAT_S16) ) {
	std::cout << "Format 16 bit" << std::endl;
      }
      else if (alsa_pcm.SetFormat (SND_PCM_FORMAT_S32) ) {
	std::cout << "Format 32 bit" << std::endl;
      }
      
      if (!alsa_pcm.SetChannels (2) )
	std::cout << "Setting the channels failed!" << std::endl;
      
      std::cout << "Rate min: " << alsa_pcm.GetRateMin () << std::endl;
      std::cout << "Rate max: " << alsa_pcm.GetRateMax () << std::endl;
      alsa_pcm.SetRateNear (44100);
      
      std::cout << "Periods min: " << alsa_pcm.GetPeriodsMin () << std::endl;
      std::cout << "Periods max: " << alsa_pcm.GetPeriodsMax () << std::endl;
      
      if (!alsa_pcm.SetPeriodsNear (4) )
    	std::cout << "Setting periods near failed!" << std::endl;
      
      if (!alsa_pcm.SetPeriodTimeNear (400000 / 4) )
	std::cout << "Setting period time near failed!" << std::endl;
      
      if (!alsa_pcm.InstallParams () )
	std::cout << "Setting params failed!" << std::endl;
      
      if (!alsa_pcm.InstallSwParams () )
	std::cout << "Setting software params failed!" << std::endl;
      
      std::cout << "Period Size: " << alsa_pcm.GetPeriodSize() << std::endl;
      std::cout << "Get periods: " << alsa_pcm.GetPeriods() << std::endl;
      
      OggVorbisFileStream ogg_stream;
      ogg_stream.Open ("test.ogg");
      
      MP3FileStream mp3_stream;
      mp3_stream.Open ("test.mp3");
      
      BasicFileStream& used_stream = ogg_stream;
      
      while (true)
      {
	int written = 0;
	used_stream.Read (period_size, &stream);
	
	for (int ch = 0; ch < 2; ++ch) {
	  for (int i = 0; i < period_size; ++i)
	    raw_stream [i*2 + ch] =
	      PcmConvert<int32_t,int16_t>::Convert ((*stream[ch])[i]);
	}
	
	while (written < period_size) {
	  int t_written = alsa_pcm.WriteI (raw_stream, period_size - written);
	  if (t_written < 0)
	    {
	      if (t_written == -EAGAIN) {
		//std::cout << "try again ..." << std::endl;
		usleep (200);
	      }
	      else if (t_written == -EPIPE) { // xrun
		std::cout << "xrun" << std::endl;
		
		struct timeval now, diff, tstamp;
		gettimeofday(&now, 0);
		
		alsa_pcm.GetTriggerTStamp (&tstamp);
		timersub(&now, &tstamp, &diff);
		std::cout << "  !!!-->> XRUNx !!! (at least "
			  << diff.tv_sec * 1000 + diff.tv_usec / 1000.0
			  << " ms long)" << std::endl;
      
		if (!alsa_pcm.Prepare () )
		  std::cout << "  BUR: can't reprepare during XRun!! "
			    << std::endl;
	      }
	      else
		std::cout << "error: " << snd_strerror (t_written)
			  << std::endl;
	    }
	  else {
	    written += t_written;
	  }
	}
      }
      mp3_stream.Close ();
      ogg_stream.Close ();
      
      alsa_pcm.Close ();
    }
  
  return 0;
}
