/* MuSE - Multiple Streaming Engine
 * Copyright (C) 2000-2003 Denis Rojo aka jaromil <jaromil@dyne.org>
 *
 * This source code is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Public License as published 
 * by the Free Software Foundation; either version 2 of the License,
 * or (at your option) any later version.
 *
 * This source code is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * Please refer to the GNU Public License for more details.
 *
 * You should have received a copy of the GNU Public License along with
 * this source code; if not, write to:
 * Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 * "$Id: shouter.cpp,v 1.5 2004/12/15 18:18:06 jaromil Exp $"
 *
 */

#include <shouter.h>
#include <jutils.h>
#include <generic.h>
#include <config.h>

extern bool got_sigpipe;

Shouter::Shouter()
  : Entry() {

  /*
  int vermaj,vermin,verpat;
  shout_version(&vermaj,&vermin,&verpat);
  func("Shouter::Shouter() using libshout version %i.%i.%i",vermaj,vermin,verpat);
  */

  ice = shout_new();
  
  //  to do this, more of the code must be changed
  //  shout_set_nonblocking(ice,1);

  running = false;
  retry = 0;
  errors = 0;

  /* setup defaults */
  host("localhost");
  ip("127.0.0.1");
  port(8000);
  pass("hackme");
  mount("live");
  login(SHOUT_PROTOCOL_HTTP); // defaults to icecast 2 login now
  name("Streaming with MuSE");
  url("http://muse.dyne.org");
  desc("Free Software Multiple Streaming Engine");
  bps("24000");
  freq("22050");
  channels("1");

  profile_changed = true;
}

Shouter::~Shouter() {
  func("Shouter::~Shouter");
  stop();
  shout_free(ice);
}

bool Shouter::start() {
  int res;
  char srv[64];
  switch(login()) {
  case SHOUT_PROTOCOL_HTTP: sprintf(srv,"icecast2"); break;
  case SHOUT_PROTOCOL_ICY: sprintf(srv,"shoutcast"); break;
  default: sprintf(srv,"icecast 1"); break;
  }

  if(shout_get_connected(ice)) {
    // if allready connected, reconnect
    func("icecast still connected: disconnecting");
    shout_sync(ice);
    shout_close(ice);
  }
  
  notice("Contacting %s server %s on port %u",srv,host(),port());
  
  shout_sync(ice);
  res = shout_open(ice);
  func("Shouter::start() shout_open returns %i",res);
  
  if(res==SHOUTERR_SUCCESS) {
    notice("started streaming on %s",streamurl);
    running = true;
  } else {
    error("shout_open: %s",shout_get_error(ice));
    shout_sync(ice);
    shout_close(ice);
    running = false;
  }
  
  return(running);
}

bool Shouter::stop() {
  if(running) {
    notice("closed stream to %s",streamurl);
    shout_close(ice);
    running = false;
  }
  return true;
}

bool Shouter::apply_profile() {
  char temp[256];
  func("Shouter::apply_profile() on shouter id %i",id);

  bool was_running = running, res = true;
  if(was_running) stop();

  if(shout_set_host(ice,host()))
    error("shout_set_host: %s",shout_get_error(ice));
  
  if( shout_set_port(ice,port()) )
    error("shout_set_port: %s",shout_get_error(ice));
  
  if( shout_set_password(ice,pass()) )
    error("shout_set_password: %s",shout_get_error(ice));

  // === fixes the format of the mountpoint
  if((mount())[0]!='/') {
    char tmp[MAX_VALUE_SIZE];
    sprintf(tmp,"/%s",mount());
    mount(tmp);
  }

  // use a .ogg termination on ogg streams
  // this fixes stream codec recognization in xmms et al.
  if(format == SHOUT_FORMAT_VORBIS)
    if(!strstr(mount(),".ogg")) {
      char tmp[MAX_VALUE_SIZE];
      sprintf(tmp,"%s.ogg",mount());
      mount(tmp);
    }
  

  if( shout_set_mount(ice,mount()) )
    error("shout_set_mount: %s",shout_get_error(ice));

  if( shout_set_name(ice,name()) )
    error("shout_set_name: %s",shout_get_error(ice));

  if( shout_set_url(ice,url()) )
    error("shout_set_url: %s",shout_get_error(ice));

  if( shout_set_description(ice,desc()) )
    error("shout_set_description: %s",shout_get_error(ice));

  
  //if( shout_set_bitrate(ice,_bps) )
  //  error("shout_set_bitrate: %s",shout_get_error(ice));
  
  if( shout_set_audio_info(ice, SHOUT_AI_BITRATE, bps()) )
    error("shout_set_audio_info %s: %s",SHOUT_AI_BITRATE, bps());

  if( shout_set_audio_info(ice, SHOUT_AI_SAMPLERATE, freq()) )
    error("shout_set_audio_info %s: %s",SHOUT_AI_SAMPLERATE, freq());
  
  if( shout_set_audio_info(ice, SHOUT_AI_CHANNELS, channels()) )
    error("shout_set_audio_info %s: %s",SHOUT_AI_CHANNELS, channels());

  func("Shouter audio info: %sKbp/s %sHz %s channels",
       shout_get_audio_info(ice, SHOUT_AI_BITRATE),
       shout_get_audio_info(ice, SHOUT_AI_SAMPLERATE),
       shout_get_audio_info(ice, SHOUT_AI_CHANNELS));

  if( shout_set_protocol(ice,login()) )
    error("shout_set_protocol %i: %s",login(),shout_get_error(ice));

  if( shout_set_format(ice,format) )
    error("shout_set_format: %s",shout_get_error(ice));

  if( shout_set_user(ice,"source") )
    error("shout_set_user: %s",shout_get_error(ice));

  snprintf(temp,256,"%s ver. %s",PACKAGE,VERSION);
  if( shout_set_agent(ice,temp) )
    error("shout_set_agent: %s",shout_get_error(ice));
  
  snprintf(streamurl,MAX_VALUE_SIZE,
	   "http://%s:%i%s",host(),port(),mount());
  
  if(was_running) { res = start(); }
  profile_changed = false;
  return res; 
}

int Shouter::send(short int *buf, unsigned int enc) {
  int res = 0;
  if(!running) return(0);
  if(enc<1) return res;

  shout_sync(ice);

  res = shout_send(ice,(unsigned char*) buf, enc);
  if(res) {
    error("shout_send: %s",shout_get_error(ice));
    if (got_sigpipe && (res==SHOUTERR_SOCKET)) {
      errors++;
      got_sigpipe = false;
      if(errors>10) {
	res = -2;
	errors = 0;
      }
    } else res = -1;
  } else errors = 0;

  return(res);
}
