Ejemplo n.º 1
0
static void mad_decode_data (audio_decoder_t *this_gen, buf_element_t *buf) {

  mad_decoder_t *this = (mad_decoder_t *) this_gen;
  int bytes_in_buffer_at_pts;

  lprintf ("decode data, size: %d, decoder_flags: %d\n", buf->size, buf->decoder_flags);

  if (buf->size>(INPUT_BUF_SIZE-this->bytes_in_buffer)) {
    xprintf (this->xstream->xine, XINE_VERBOSITY_DEBUG,
	     "libmad: ALERT input buffer too small (%d bytes, %d avail)!\n",
	     buf->size, INPUT_BUF_SIZE-this->bytes_in_buffer);
    buf->size = INPUT_BUF_SIZE-this->bytes_in_buffer;
  }

  if ((buf->decoder_flags & BUF_FLAG_HEADER) == 0) {

    /* reset decoder on leaving preview mode */
    if ((buf->decoder_flags & BUF_FLAG_PREVIEW) == 0) {
      if (this->preview_mode) {
	mad_reset (this_gen);
      }
    } else {
      this->preview_mode = 1;
    }

    bytes_in_buffer_at_pts = this->bytes_in_buffer;

    xine_fast_memcpy (&this->buffer[this->bytes_in_buffer],
                        buf->content, buf->size);
    this->bytes_in_buffer += buf->size;

    /*
    printf ("libmad: decode data - doing it\n");
    */

    mad_stream_buffer (&this->stream, this->buffer,
		       this->bytes_in_buffer);

    if (this->bytes_in_buffer < MAD_MIN_SIZE && buf->pts == 0)
      return;

    if (!this->needs_more_data) {
      this->pts = buf->pts;
      if (buf->decoder_flags & BUF_FLAG_AUDIO_PADDING) {
        this->start_padding = buf->decoder_info[1];
        this->end_padding = buf->decoder_info[2];
      } else {
        this->start_padding = 0;
        this->end_padding = 0;
      }
    }

    while (1) {

      if (mad_frame_decode (&this->frame, &this->stream) != 0) {

	if (this->stream.next_frame) {
	  int num_bytes =
	    this->buffer + this->bytes_in_buffer - this->stream.next_frame;

	  /* printf("libmad: MAD_ERROR_BUFLEN\n"); */

	  memmove(this->buffer, this->stream.next_frame, num_bytes);
	  this->bytes_in_buffer = num_bytes;
	}

	switch (this->stream.error) {

	case MAD_ERROR_BUFLEN:
	  /* libmad wants more data */
	  this->needs_more_data = 1;
	  return;

	default:
	  lprintf ("error 0x%04X, mad_stream_buffer %d bytes\n", this->stream.error, this->bytes_in_buffer);
	  mad_stream_buffer (&this->stream, this->buffer,
			     this->bytes_in_buffer);
	}

      } else {
	int mode = (this->frame.header.mode == MAD_MODE_SINGLE_CHANNEL) ? AO_CAP_MODE_MONO : AO_CAP_MODE_STEREO;

	if (!this->output_open
	    || (this->output_sampling_rate != this->frame.header.samplerate)
	    || (this->output_mode != mode)) {

	  lprintf ("audio sample rate %d mode %08x\n", this->frame.header.samplerate, mode);

          /* the mpeg audio demuxer can set audio bitrate */
          if (! _x_stream_info_get(this->xstream, XINE_STREAM_INFO_AUDIO_BITRATE)) {
            _x_stream_info_set(this->xstream, XINE_STREAM_INFO_AUDIO_BITRATE,
                               this->frame.header.bitrate);
          }

          /* the mpeg audio demuxer can set this meta info */
          if (! _x_meta_info_get(this->xstream, XINE_META_INFO_AUDIOCODEC)) {
            switch (this->frame.header.layer) {
            case MAD_LAYER_I:
              _x_meta_info_set_utf8(this->xstream, XINE_META_INFO_AUDIOCODEC,
                "MPEG audio layer 1 (lib: MAD)");
              break;
            case MAD_LAYER_II:
              _x_meta_info_set_utf8(this->xstream, XINE_META_INFO_AUDIOCODEC,
                "MPEG audio layer 2 (lib: MAD)");
              break;
            case MAD_LAYER_III:
              _x_meta_info_set_utf8(this->xstream, XINE_META_INFO_AUDIOCODEC,
                "MPEG audio layer 3 (lib: MAD)");
              break;
            default:
              _x_meta_info_set_utf8(this->xstream, XINE_META_INFO_AUDIOCODEC,
                "MPEG audio (lib: MAD)");
            }
          }

	  if (this->output_open) {
	    this->xstream->audio_out->close (this->xstream->audio_out, this->xstream);
	    this->output_open = 0;
          }
          if (!this->output_open) {
	    this->output_open = (this->xstream->audio_out->open) (this->xstream->audio_out,
				   this->xstream, 16,
				   this->frame.header.samplerate,
			           mode) ;
          }
          if (!this->output_open) {
            return;
          }
	  this->output_sampling_rate = this->frame.header.samplerate;
	  this->output_mode = mode;
	}

	mad_synth_frame (&this->synth, &this->frame);

	if ( (buf->decoder_flags & BUF_FLAG_PREVIEW) == 0 ) {

	  unsigned int         nchannels, nsamples;
	  mad_fixed_t const   *left_ch, *right_ch;
	  struct mad_pcm      *pcm = &this->synth.pcm;
	  audio_buffer_t      *audio_buffer;
	  uint16_t            *output;
          int                  bitrate;
          int                  pts_offset;

	  audio_buffer = this->xstream->audio_out->get_buffer (this->xstream->audio_out);
	  output = audio_buffer->mem;

	  nchannels = pcm->channels;
	  nsamples  = pcm->length;
	  left_ch   = pcm->samples[0];
	  right_ch  = pcm->samples[1];

	  /* padding */
	  if (this->start_padding || this->end_padding) {
	    /* check padding validity */
	    if (nsamples < (this->start_padding + this->end_padding)) {
	      lprintf("invalid padding data");
	      this->start_padding = 0;
	      this->end_padding = 0;
	    }
	    lprintf("nsamples=%d, start_padding=%d, end_padding=%d\n",
	            nsamples, this->start_padding, this->end_padding);
	    nsamples -= this->start_padding + this->end_padding;
	    left_ch  += this->start_padding;
	    right_ch += this->start_padding;
	  }
	  audio_buffer->num_frames = nsamples;
	  audio_buffer->vpts       = this->pts;

	  while (nsamples--) {
	    /* output sample(s) in 16-bit signed little-endian PCM */

	    *output++ = scale(*left_ch++);

	    if (nchannels == 2)
	      *output++ = scale(*right_ch++);

	  }

	  audio_buffer->num_frames = pcm->length;

          /* pts computing */
          if (this->frame.header.bitrate > 0) {
            bitrate = this->frame.header.bitrate;
          } else {
            bitrate = _x_stream_info_get(this->xstream, XINE_STREAM_INFO_AUDIO_BITRATE);
            lprintf("offset %d bps\n", bitrate);
          }
          audio_buffer->vpts = buf->pts;
          if (audio_buffer->vpts && (bitrate > 0)) {
            pts_offset = (bytes_in_buffer_at_pts * 8 * 90) / (bitrate / 1000);
            lprintf("pts: %"PRId64", offset: %d pts, %d bytes\n", buf->pts, pts_offset, bytes_in_buffer_at_pts);
            if (audio_buffer->vpts < pts_offset)
              pts_offset = audio_buffer->vpts;
            audio_buffer->vpts -= pts_offset;
          }

	  this->xstream->audio_out->put_buffer (this->xstream->audio_out, audio_buffer, this->xstream);

	  this->pts = buf->pts;
	  buf->pts = 0;
	  if (buf->decoder_flags & BUF_FLAG_AUDIO_PADDING) {
	    this->start_padding = buf->decoder_info[1];
	    this->end_padding = buf->decoder_info[2];
	    buf->decoder_info[1] = 0;
	    buf->decoder_info[2] = 0;
	  } else {
	    this->start_padding = 0;
	    this->end_padding = 0;
	  }
	}
	lprintf ("decode worked\n");
      }
    }
  }
}
Ejemplo n.º 2
0
/*  Try to compute the length of the fifo in 1/1000 s
 *  2 methods :
 *    if the bitrate is known
 *      use the size of the fifo
 *    else
 *      use the the first and the last pts of the fifo
 */
static void nbc_compute_fifo_length(nbc_t *this,
                                    fifo_buffer_t *fifo,
                                    buf_element_t *buf,
                                    int action) {
  int fifo_free, fifo_fill, fifo_div;
  int64_t video_br, audio_br, diff;
  int has_video, has_audio;

  has_video = _x_stream_info_get(this->stream, XINE_STREAM_INFO_HAS_VIDEO);
  has_audio = _x_stream_info_get(this->stream, XINE_STREAM_INFO_HAS_AUDIO);
  video_br  = _x_stream_info_get(this->stream, XINE_STREAM_INFO_VIDEO_BITRATE);
  audio_br  = _x_stream_info_get(this->stream, XINE_STREAM_INFO_AUDIO_BITRATE);

  fifo_free = fifo->buffer_pool_num_free;
  fifo_fill = fifo->fifo_size;
  fifo_div = fifo_fill + fifo_free - 1;
  if (fifo_div == 0)
    fifo_div = 1; /* avoid a possible divide-by-zero */

  if (fifo == this->video_fifo) {
    this->video_fifo_free = fifo_free;
    this->video_fifo_fill = (100 * fifo_fill) / fifo_div;
    this->video_fifo_size = fifo->fifo_data_size;
    
Ejemplo n.º 3
0
/* Put callback the fifo mutex is locked */
static void enigma_nbc_put_cb (fifo_buffer_t *fifo, buf_element_t *buf, void *this_gen) {
  nbc_t *this = (nbc_t*)this_gen;
  int64_t progress = 0;
  int64_t video_p = 0;
  int64_t audio_p = 0;
  int has_video, has_audio;

  lprintf("enter enigma_nbc_put_cb\n");
  pthread_mutex_lock(&this->mutex);

  if ((buf->type & BUF_MAJOR_MASK) != BUF_CONTROL_BASE) {

    if (this->enabled) {
      if (this->dvbspeed)
        dvbspeed_put (this, fifo, buf);
      else {
      nbc_compute_fifo_length(this, fifo, buf, FIFO_PUT);

      if (this->buffering) {

        has_video = _x_stream_info_get(this->stream, XINE_STREAM_INFO_HAS_VIDEO);
        has_audio = _x_stream_info_get(this->stream, XINE_STREAM_INFO_HAS_AUDIO);
        /* restart playing if high_water_mark is reached by all fifos
         * do not restart if has_video and has_audio are false to avoid
         * a yoyo effect at the beginning of the stream when these values
         * are not yet known.
         *
         * be sure that the next buffer_pool_alloc() call will not deadlock,
         * we need at least 2 buffers (see buffer.c)
         */
//printf("this->video_last_pts %lld   this->audio_last_pts %lld\n", this->video_last_pts, this->audio_last_pts);
        int64_t first_pts = this->video_first_pts>this->audio_first_pts?this->video_first_pts:this->audio_first_pts;
        int64_t last_pts = this->video_last_pts<this->audio_last_pts?this->video_last_pts:this->audio_last_pts;
//printf("AAA first_pts %lld  last_pts %lld\n", first_pts, last_pts);
        if ( has_video && has_audio && (last_pts-first_pts)>DEFAULT_PTS_START ) {
          this->progress = 100;
          //report_progress (this->stream, 100);
          this->buffering = 0;
          nbc_set_speed_normal(this);
        }
        else if ((((!has_video) || (this->video_fifo_length > this->high_water_mark)) &&
             ((!has_audio) || (this->audio_fifo_length > this->high_water_mark)) &&
             (has_video || has_audio))) {

          this->progress = 100;
          //report_progress (this->stream, 100);
          this->buffering = 0;

          xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, "\nnet_buf_ctrl: enigma_nbc_put_cb: stops buffering\n");

          nbc_set_speed_normal(this);

          this->high_water_mark += this->high_water_mark / 2;

        } else {
          /*  compute the buffering progress
           *    50%: video
           *    50%: audio */
          video_p = ((this->video_fifo_length * 50) / this->high_water_mark);
          if (video_p > 50) video_p = 50;
          audio_p = ((this->audio_fifo_length * 50) / this->high_water_mark);
          if (audio_p > 50) audio_p = 50;

          if ((has_video) && (has_audio)) {
            progress = video_p + audio_p;
          } else if (has_video) {
            progress = 2 * video_p;
          } else {
            progress = 2 * audio_p;
          }

          /* if the progress can't be computed using the fifo length,
             use the number of buffers */
          if (!progress) {
            video_p = this->video_fifo_fill;
            audio_p = this->audio_fifo_fill;
            progress = (video_p > audio_p) ? video_p : audio_p;
          }

          if (progress > this->progress) {
            //report_progress (this->stream, progress);
            this->progress = progress;
          }
        }
      }
      //if(this->stream->xine->verbosity >= XINE_VERBOSITY_DEBUG)
      //  display_stats(this);

      //report_stats(this, 0);
      }
  	}
  } else {

    switch (buf->type) {
      case BUF_CONTROL_START:
        lprintf("BUF_CONTROL_START\n");
        if (!this->enabled) {
          /* a new stream starts */
          xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, "\nnet_buf_ctrl: enigma_nbc_put_cb: starts buffering\n");
          this->enabled           = 1;
          this->buffering         = 1;
          this->video_first_pts   = 0;
          this->video_last_pts    = 0;
          this->audio_first_pts   = 0;
          this->audio_last_pts    = 0;
          this->video_fifo_length = 0;
          this->audio_fifo_length = 0;
          dvbspeed_init (this, 1);
          if (!this->dvbspeed) nbc_set_speed_pause(this);
/*          this->progress = 0;
          report_progress (this->stream, progress);*/
        }
        break;
      case BUF_CONTROL_NOP:
        if (!(buf->decoder_flags & BUF_FLAG_END_USER) &&
            !(buf->decoder_flags & BUF_FLAG_END_STREAM)) {
          break;
        }
        /* fall through */
      case BUF_CONTROL_END:
      case BUF_CONTROL_QUIT:
        lprintf("BUF_CONTROL_END\n");
        dvbspeed_close (this);
        if (this->enabled) {
          /* end of stream :
           *   - disable the nbc
           *   - unpause the engine if buffering
           */
          this->enabled = 0;

          lprintf("DISABLE netbuf\n");

          if (this->buffering) {
            this->buffering = 0;
            this->progress = 100;
            //report_progress (this->stream, this->progress);

            xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, "\nnet_buf_ctrl: enigma_nbc_put_cb: stops buffering\n");

            nbc_set_speed_normal(this);
          }
        }
        break;

      case BUF_CONTROL_NEWPTS:
        /* discontinuity management */
        if (fifo == this->video_fifo) {
          this->video_in_disc++;
          xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG,
		  "\nnet_buf_ctrl: enigma_nbc_put_cb video disc %d\n", this->video_in_disc);
        } else {
          this->audio_in_disc++;
          xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG,
		  "\nnet_buf_ctrl: enigma_nbc_put_cb audio disc %d\n", this->audio_in_disc);
        }
        break;
    }

    if (fifo == this->video_fifo) {
      this->video_fifo_free = fifo->buffer_pool_num_free;
      this->video_fifo_size = fifo->fifo_data_size;
    } else {
      this->audio_fifo_free = fifo->buffer_pool_num_free;
      this->audio_fifo_size = fifo->fifo_data_size;
    }
  }
  pthread_mutex_unlock(&this->mutex);
  lprintf("exit enigma_nbc_put_cb\n");
}
Ejemplo n.º 4
0
static void *audio_decoder_loop (void *stream_gen) {

  buf_element_t   *buf = NULL;
  buf_element_t   *first_header = NULL;
  buf_element_t   *last_header = NULL;
  int              replaying_headers = 0;
  xine_stream_t   *stream = (xine_stream_t *) stream_gen;
  xine_ticket_t   *running_ticket = stream->xine->port_ticket;
  int              running = 1;
  int              prof_audio_decode = -1;
  uint32_t         buftype_unknown = 0;
  int              audio_channel_user = stream->audio_channel_user;

  if (prof_audio_decode == -1)
    prof_audio_decode = xine_profiler_allocate_slot ("audio decoder/output");

  while (running) {

    lprintf ("audio_loop: waiting for package...\n");

    if( !replaying_headers )
      buf = stream->audio_fifo->get (stream->audio_fifo);

    lprintf ("audio_loop: got package pts = %"PRId64", type = %08x\n", buf->pts, buf->type);

    _x_extra_info_merge( stream->audio_decoder_extra_info, buf->extra_info );
    stream->audio_decoder_extra_info->seek_count = stream->video_seek_count;

    switch (buf->type) {

    case BUF_CONTROL_HEADERS_DONE:
      pthread_mutex_lock (&stream->counter_lock);
      stream->header_count_audio++;
      pthread_cond_broadcast (&stream->counter_changed);
      pthread_mutex_unlock (&stream->counter_lock);
      break;

    case BUF_CONTROL_START:

      lprintf ("start\n");

      /* decoder dispose might call port functions */
      running_ticket->acquire(running_ticket, 0);

      if (stream->audio_decoder_plugin) {

	lprintf ("close old decoder\n");

	stream->keep_ao_driver_open = !!(buf->decoder_flags & BUF_FLAG_GAPLESS_SW);
	_x_free_audio_decoder (stream, stream->audio_decoder_plugin);
	stream->audio_decoder_plugin = NULL;
	stream->audio_track_map_entries = 0;
	stream->audio_type = 0;
	stream->keep_ao_driver_open = 0;
      }

      running_ticket->release(running_ticket, 0);

      if( !(buf->decoder_flags & BUF_FLAG_GAPLESS_SW) )
        stream->metronom->handle_audio_discontinuity (stream->metronom, DISC_STREAMSTART, 0);

      buftype_unknown = 0;
      break;

    case BUF_CONTROL_END:

      /* free all held header buffers, see comments below */
      if( first_header ) {
        buf_element_t  *cur, *next;

        cur = first_header;
        while( cur ) {
          next = cur->next;
          cur->free_buffer (cur);
          cur = next;
        }
        first_header = last_header = NULL;
      }

      /*
       * wait the output fifos to run dry before sending the notification event
       * to the frontend. this test is only valid if there is only a single
       * stream attached to the current output port.
       */
      while(1) {
        int num_bufs, num_streams;

        running_ticket->acquire(running_ticket, 0);
        num_bufs = stream->audio_out->get_property(stream->audio_out, AO_PROP_BUFS_IN_FIFO);
        num_streams = stream->audio_out->get_property(stream->audio_out, AO_PROP_NUM_STREAMS);
        running_ticket->release(running_ticket, 0);

        if( num_bufs > 0 && num_streams == 1 && !stream->early_finish_event)
          xine_usec_sleep (10000);
        else
          break;
      }

      /* wait for video to reach this marker, if necessary */
      pthread_mutex_lock (&stream->counter_lock);

      stream->finished_count_audio++;

      lprintf ("reached end marker # %d\n", stream->finished_count_audio);

      pthread_cond_broadcast (&stream->counter_changed);

      if (stream->video_thread_created) {
        while (stream->finished_count_video < stream->finished_count_audio) {
          struct timeval tv;
          struct timespec ts;
          gettimeofday(&tv, NULL);
          ts.tv_sec  = tv.tv_sec + 1;
          ts.tv_nsec = tv.tv_usec * 1000;
          /* use timedwait to workaround buggy pthread broadcast implementations */
          pthread_cond_timedwait (&stream->counter_changed, &stream->counter_lock, &ts);
        }
      }
      pthread_mutex_unlock (&stream->counter_lock);
      stream->audio_channel_auto = -1;

      break;

    case BUF_CONTROL_QUIT:
      /* decoder dispose might call port functions */
      running_ticket->acquire(running_ticket, 0);

      if (stream->audio_decoder_plugin) {
	_x_free_audio_decoder (stream, stream->audio_decoder_plugin);
	stream->audio_decoder_plugin = NULL;
	stream->audio_track_map_entries = 0;
	stream->audio_type = 0;
      }

      running_ticket->release(running_ticket, 0);
      running = 0;
      break;

    case BUF_CONTROL_NOP:
      break;

    case BUF_CONTROL_RESET_DECODER:
      lprintf ("reset\n");

      _x_extra_info_reset( stream->audio_decoder_extra_info );
      if (stream->audio_decoder_plugin) {
	running_ticket->acquire(running_ticket, 0);
	stream->audio_decoder_plugin->reset (stream->audio_decoder_plugin);
	running_ticket->release(running_ticket, 0);
      }
      break;

    case BUF_CONTROL_DISCONTINUITY:
      if (stream->audio_decoder_plugin) {
	running_ticket->acquire(running_ticket, 0);
	stream->audio_decoder_plugin->discontinuity (stream->audio_decoder_plugin);
	running_ticket->release(running_ticket, 0);
      }

      stream->metronom->handle_audio_discontinuity (stream->metronom, DISC_RELATIVE, buf->disc_off);
      break;

    case BUF_CONTROL_NEWPTS:
      if (stream->audio_decoder_plugin) {
	running_ticket->acquire(running_ticket, 0);
	stream->audio_decoder_plugin->discontinuity (stream->audio_decoder_plugin);
	running_ticket->release(running_ticket, 0);
      }

      if (buf->decoder_flags & BUF_FLAG_SEEK) {
        stream->metronom->handle_audio_discontinuity (stream->metronom, DISC_STREAMSEEK, buf->disc_off);
      } else {
        stream->metronom->handle_audio_discontinuity (stream->metronom, DISC_ABSOLUTE, buf->disc_off);
      }
      break;

    case BUF_CONTROL_AUDIO_CHANNEL:
      {
	xprintf(stream->xine, XINE_VERBOSITY_DEBUG,
		"audio_decoder: suggested switching to stream_id %02x\n", buf->decoder_info[0]);
	stream->audio_channel_auto = buf->decoder_info[0] & 0xff;
      }
      break;

    case BUF_CONTROL_RESET_TRACK_MAP:
      if (stream->audio_track_map_entries)
      {
        xine_event_t ui_event;

        stream->audio_track_map_entries = 0;

        ui_event.type        = XINE_EVENT_UI_CHANNELS_CHANGED;
        ui_event.data_length = 0;
        xine_event_send(stream, &ui_event);
      }
      break;


    default:

      if (_x_stream_info_get(stream, XINE_STREAM_INFO_IGNORE_AUDIO))
        break;

      xine_profiler_start_count (prof_audio_decode);

      running_ticket->acquire(running_ticket, 0);

      if ( (buf->type & 0xFF000000) == BUF_AUDIO_BASE ) {

	uint32_t audio_type = 0;
	int      i,j;
	uint32_t chan=buf->type&0x0000FFFF;

	/*
        printf("audio_decoder: buf_type=%08x auto=%08x user=%08x\n",
	       buf->type,
	       stream->audio_channel_auto,
	       audio_channel_user);
	       */

        /* update track map */

        i = 0;
        while ( (i<stream->audio_track_map_entries) && ((stream->audio_track_map[i]&0x0000FFFF)<chan) )
          i++;

        if ( (i==stream->audio_track_map_entries)
	     || ((stream->audio_track_map[i]&0x0000FFFF)!=chan) ) {
          xine_event_t  ui_event;

          j = stream->audio_track_map_entries;

          if (j >= 50)
            break;

          while (j>i) {
            stream->audio_track_map[j] = stream->audio_track_map[j-1];
            j--;
          }
          stream->audio_track_map[i] = buf->type;
          stream->audio_track_map_entries++;
          /* implicit channel change - reopen decoder below */
          if ((i == 0) && (audio_channel_user == -1) && (stream->audio_channel_auto < 0))
            stream->audio_decoder_streamtype = -1;

	  ui_event.type        = XINE_EVENT_UI_CHANNELS_CHANGED;
	  ui_event.data_length = 0;
	  xine_event_send (stream, &ui_event);
        }

	/* find out which audio type to decode */

	lprintf ("audio_channel_user = %d, map[0]=%08x\n",
		 audio_channel_user,
		 stream->audio_track_map[0]);

	if (audio_channel_user > -2) {

	  if (audio_channel_user == -1) {

	    /* auto */

	    lprintf ("audio_channel_auto = %d\n", stream->audio_channel_auto);

	    if (stream->audio_channel_auto>=0) {

	      if ((buf->type & 0xFF) == stream->audio_channel_auto) {
		audio_type = buf->type;
	      } else
		audio_type = -1;

	    } else
	      audio_type = stream->audio_track_map[0];

	  } else {
	    if (audio_channel_user <= stream->audio_track_map_entries)
	      audio_type = stream->audio_track_map[audio_channel_user];
	    else
	      audio_type = -1;
	  }

	  /* now, decode stream buffer if it's the right audio type */

	  if (buf->type == audio_type) {

	    int streamtype = (buf->type>>16) & 0xFF;

	    /* close old decoder of audio type has changed */

            if( buf->type != buftype_unknown &&
                (stream->audio_decoder_streamtype != streamtype ||
                !stream->audio_decoder_plugin) ) {

              if (stream->audio_decoder_plugin) {
                _x_free_audio_decoder (stream, stream->audio_decoder_plugin);
              }

              stream->audio_decoder_streamtype = streamtype;
              stream->audio_decoder_plugin = _x_get_audio_decoder (stream, streamtype);

              _x_stream_info_set(stream, XINE_STREAM_INFO_AUDIO_HANDLED,
				 (stream->audio_decoder_plugin != NULL));
            }

	    if (audio_type != stream->audio_type) {

	      if (stream->audio_decoder_plugin) {
		xine_event_t event;

		stream->audio_type = audio_type;

		event.type         = XINE_EVENT_UI_CHANNELS_CHANGED;
		event.data_length  = 0;
		xine_event_send(stream, &event);
	      }
	    }

	    /* finally - decode data */

	    if (stream->audio_decoder_plugin)
	      stream->audio_decoder_plugin->decode_data (stream->audio_decoder_plugin, buf);

	    if (buf->type != buftype_unknown &&
	        !_x_stream_info_get(stream, XINE_STREAM_INFO_AUDIO_HANDLED)) {
	      xine_log (stream->xine, XINE_LOG_MSG,
			_("audio_decoder: no plugin available to handle '%s'\n"), _x_buf_audio_name( buf->type ) );

              if( !_x_meta_info_get(stream, XINE_META_INFO_AUDIOCODEC) )
                _x_meta_info_set_utf8(stream, XINE_META_INFO_AUDIOCODEC, _x_buf_audio_name( buf->type ));

	      buftype_unknown = buf->type;

	      /* fatal error - dispose plugin */
	      if (stream->audio_decoder_plugin) {
	        _x_free_audio_decoder (stream, stream->audio_decoder_plugin);
	        stream->audio_decoder_plugin = NULL;
	      }
	    }
	  }
	}
      } else if( buf->type != buftype_unknown ) {