Ejemplo n.º 1
0
int handle_seek_opt(ogg123_options_t *options, decoder_t *decoder, format_t *format) {

  float pos=decoder->format->statistics(decoder)->current_time;

  /* this functions handles a seek request. It prevents seeking out
     of band, i.e. before the beginning or after the end. Instead,
	 it seeks to the start or near-end resp. */

  if (options->seekmode != DECODER_SEEK_NONE) {

    if (options->seekmode == DECODER_SEEK_START) {
      pos = options->seekoff;
    } else {
      pos += options->seekoff;
    }

    if (pos < 0) {
      pos = 0;
    }

    if (pos > decoder->format->statistics(decoder)->total_time) {
      /* seek to almost the end of the stream */
      pos = decoder->format->statistics(decoder)->total_time - 0.01;
    }

    if (!format->seek(decoder, pos, DECODER_SEEK_START)) {
      status_error(_("Could not skip to %f in audio stream."), options->seekoff);
#if 0
      /* Handle this fatally -- kill the audio thread */
      if (audio_buffer != NULL)
	buffer_thread_kill(audio_buffer);
#endif
    }
  }

  options->seekmode = DECODER_SEEK_NONE;

  return 1;
}
Ejemplo n.º 2
0
void play (char *source_string)
{
  transport_t *transport;
  format_t *format;
  data_source_t *source;
  decoder_t *decoder;

  decoder_callbacks_t decoder_callbacks;
  void *decoder_callbacks_arg;

  /* Preserve between calls so we only open the audio device when we 
     have to */
  static audio_format_t old_audio_fmt = { 0, 0, 0, 0, 0 };
  audio_format_t new_audio_fmt;
  audio_reopen_arg_t *reopen_arg;

  /* Flags and counters galore */
  int eof = 0, eos = 0, ret;
  int nthc = 0, ntimesc = 0;
  int next_status = 0;
  static int status_interval = 0;

  /* Reset all of the signal flags */
  sig_request.cancel   = 0;
  sig_request.skipfile = 0;
  sig_request.exit     = 0;
  sig_request.pause    = 0;

  /* Set preferred audio format (used by decoder) */
  new_audio_fmt.big_endian = ao_is_big_endian();
  new_audio_fmt.signed_sample = 1;
  new_audio_fmt.word_size = 2;

  /* Select appropriate callbacks */
  if (audio_buffer != NULL) {
    decoder_callbacks.printf_error = &decoder_buffered_error_callback;
    decoder_callbacks.printf_metadata = &decoder_buffered_metadata_callback;
    decoder_callbacks_arg = audio_buffer;
  } else {
    decoder_callbacks.printf_error = &decoder_error_callback;
    decoder_callbacks.printf_metadata = &decoder_metadata_callback;
    decoder_callbacks_arg = NULL;
  }

  /* Locate and use transport for this data source */  
  if ( (transport = select_transport(source_string)) == NULL ) {
    status_error(_("No module could be found to read from %s.\n"), source_string);
    return;
  }
  
  if ( (source = transport->open(source_string, &options)) == NULL ) {
    status_error(_("Cannot open %s.\n"), source_string);
    return;
  }

  /* Detect the file format and initialize a decoder */
  if ( (format = select_format(source)) == NULL ) {
    status_error(_("The file format of %s is not supported.\n"), source_string);
    return;
  }
  
  if ( (decoder = format->init(source, &options, &new_audio_fmt, 
			       &decoder_callbacks,
			       decoder_callbacks_arg)) == NULL ) {

    /* We may have failed because of user command */
    if (!sig_request.cancel)
      status_error(_("Error opening %s using the %s module."
		     "  The file may be corrupted.\n"), source_string,
		   format->name);
    return;
  }

  /* Decide which statistics are valid */
  select_stats(stat_format, &options, source, decoder, audio_buffer);

  /* Start the audio playback thread before we begin sending data */    
  if (audio_buffer != NULL) {
    
    /* First reset mutexes and other synchronization variables */
    buffer_reset (audio_buffer);
    buffer_thread_start (audio_buffer);
  }

  /* Show which file we are playing */
  decoder_callbacks.printf_metadata(decoder_callbacks_arg, 1,
				    _("Playing: %s"), source_string);

  /* Skip over audio */
  if (options.seekpos > 0.0) {
    if (!format->seek(decoder, options.seekpos, DECODER_SEEK_START)) {
      status_error(_("Could not skip %f seconds of audio."), options.seekpos);
      if (audio_buffer != NULL)
	buffer_thread_kill(audio_buffer);
      return;
    }
  }

  /* Main loop:  Iterates over all of the logical bitstreams in the file */
  while (!eof && !sig_request.exit) {
    
    /* Loop through data within a logical bitstream */
    eos = 0;    
    while (!eos && !sig_request.exit) {
      
      /* Check signals */
      if (sig_request.skipfile) {
	eof = eos = 1;
	break;
      }

      if (sig_request.pause) {
	if (audio_buffer)
	  buffer_thread_pause (audio_buffer);

	kill (getpid(), SIGSTOP); /* We block here until we unpause */
	
	/* Done pausing */
	if (audio_buffer)
	  buffer_thread_unpause (audio_buffer);

	sig_request.pause = 0;
      }


      /* Read another block of audio data */
      ret = format->read(decoder, convbuffer, convsize, &eos, &new_audio_fmt);

      /* Bail if we need to */
      if (ret == 0) {
	eof = eos = 1;
	break;
      } else if (ret < 0) {
	status_error(_("Error: Decoding failure.\n"));
	break;
      }

      
      /* Check to see if the audio format has changed */
      if (!audio_format_equal(&new_audio_fmt, &old_audio_fmt)) {
	old_audio_fmt = new_audio_fmt;
	
	/* Update our status printing interval */
	status_interval = new_audio_fmt.word_size * new_audio_fmt.channels * 
	  new_audio_fmt.rate / options.status_freq;
	next_status = 0;

	reopen_arg = new_audio_reopen_arg(options.devices, &new_audio_fmt);

	if (audio_buffer)	  
	  buffer_insert_action_at_end(audio_buffer, &audio_reopen_action,
				      reopen_arg);
	else
	  audio_reopen_action(NULL, reopen_arg);
      }
      

      /* Update statistics display if needed */
      if (next_status <= 0) {
	display_statistics(stat_format, audio_buffer, source, decoder); 
	next_status = status_interval;
      } else
	next_status -= ret;

      if (options.endpos > 0.0 && options.endpos <= current_time(decoder)) {
	eof = eos = 1;
	break;
      }


      /* Write audio data block to output, skipping or repeating chunks
	 as needed */
      do {
	
	if (nthc-- == 0) {
	  if (audio_buffer)
	    buffer_submit_data(audio_buffer, convbuffer, ret);
	  else
	    audio_play_callback(convbuffer, ret, eos, &audio_play_arg);
	  
	  nthc = options.nth - 1;
	}
	
      } while (!sig_request.exit && !sig_request.skipfile &&
	       ++ntimesc < options.ntimes);

      ntimesc = 0;
            
    } /* End of data loop */
    
  } /* End of logical bitstream loop */
  
  /* Done playing this logical bitstream.  Clean up house. */

  if (audio_buffer) {
    
    if (!sig_request.exit && !sig_request.skipfile) {
      buffer_mark_eos(audio_buffer);
      buffer_wait_for_empty(audio_buffer);
    }

    buffer_thread_kill(audio_buffer);
  }

  /* Print final stats */
  display_statistics_quick(stat_format, audio_buffer, source, decoder); 
   
  
  format->cleanup(decoder);
  transport->close(source);
  status_reset_output_lock();  /* In case we were killed mid-output */

  status_message(1, _("Done."));
  
  if (sig_request.exit)
    exit (0);
}