コード例 #1
0
ファイル: diag_range.c プロジェクト: 289306290/actor-platform
void save_range(FILE *frange, int frame_size, unsigned char *packet, int nbBytes, opus_uint32 *rngs, int nb_streams){
  int i, parsed_size;
  const unsigned char *subpkt;
  static const char *bw_strings[5]={"NB","MB","WB","SWB","FB"};
  static const char *mode_strings[3]={"LP","HYB","MDCT"};
  fprintf(frange,"%d, %d, ",frame_size,nbBytes);
  subpkt=packet;
  parsed_size=nbBytes;
  for(i=0;i<nb_streams;i++){
    int j,payload_offset,nf;
    const unsigned char *frames[48];
    unsigned char toc;
    short size[48];
    payload_offset=0;
    nf=opus_packet_parse_impl(subpkt,parsed_size,i+1!=nb_streams,
      &toc,frames,size,&payload_offset);
    fprintf(frange,"[[%d",(int)(frames[0]-subpkt));
    for(j=0;j<nf;j++)fprintf(frange,", %d",size[j]);
    fprintf(frange,"], %s, %s, %c, %d",
       mode_strings[((((subpkt[0]>>3)+48)&92)+4)>>5],
       bw_strings[opus_packet_get_bandwidth(subpkt)-OPUS_BANDWIDTH_NARROWBAND],
       subpkt[0]&4?'S':'M',opus_packet_get_samples_per_frame(subpkt,48000));
    fprintf(frange,", %" I64uFORMAT "]%s",(unsigned long long)rngs[i],i+1==nb_streams?"\n":", ");
    parsed_size-=payload_offset;
    subpkt+=payload_offset;
  }
}
コード例 #2
0
JNIEXPORT jbyteArray JNICALL Java_aopus_OpusLibrary_decoderDecode
  (JNIEnv *env, jobject obj, jlong state, jbyteArray encodedData)
{
    Decoder *decoder = (Decoder *)state;
    
    // copy managed to unmanaged
    int encodedLength = (* env)->GetArrayLength(env, encodedData);
    unsigned char *encodedDataBytes = malloc(encodedLength);
    (* env)->GetByteArrayRegion(env, encodedData, 0, encodedLength, encodedDataBytes);

    int numSamplesDecoded;
    int bandwidth = opus_packet_get_bandwidth(encodedDataBytes);
    if (bandwidth == OPUS_INVALID_PACKET)
    {
        numSamplesDecoded = opus_decode(decoder->dec, 0, 0, (opus_int16 *)decoder->buffer, decoder->frameSizePerChannel, 0);
        decoder->previousPacketInvalid = 1;
    }
    else
    {
        numSamplesDecoded = opus_decode(decoder->dec, encodedDataBytes, encodedLength, (opus_int16 *)decoder->buffer, decoder->frameSizePerChannel, decoder->previousPacketInvalid);
        decoder->previousPacketInvalid = 0;
    }
    free(encodedDataBytes);

    if (numSamplesDecoded > 0)
    {
        // copy unmanaged to managed
        int frameLength = numSamplesDecoded * decoder->channels * 2;
        jbyteArray frame = (* env)->NewByteArray(env, frameLength); // 2 bytes per sample
        (* env)->SetByteArrayRegion(env, frame, 0, frameLength, decoder->buffer);
        return frame;
    }

    return NULL;
}
コード例 #3
0
int opus_decode_native(OpusDecoder *st, const unsigned char *data,
      int len, opus_val16 *pcm, int frame_size, int decode_fec,
      int self_delimited, int *packet_offset)
{
   int i, nb_samples;
   int count, offset;
   unsigned char toc;
   int tot_offset;
   /* 48 x 2.5 ms = 120 ms */
   short size[48];
   if (decode_fec<0 || decode_fec>1)
      return OPUS_BAD_ARG;
   if (len==0 || data==NULL)
      return opus_decode_frame(st, NULL, 0, pcm, frame_size, 0);
   else if (len<0)
      return OPUS_BAD_ARG;

   tot_offset = 0;
   st->mode = opus_packet_get_mode(data);
   st->bandwidth = opus_packet_get_bandwidth(data);
   st->frame_size = opus_packet_get_samples_per_frame(data, st->Fs);
   st->stream_channels = opus_packet_get_nb_channels(data);

   count = opus_packet_parse_impl(data, len, self_delimited, &toc, NULL, size, &offset);
   if (count < 0)
      return count;

   data += offset;
   tot_offset += offset;

   if (count*st->frame_size > frame_size)
      return OPUS_BUFFER_TOO_SMALL;
   nb_samples=0;
   for (i=0;i<count;i++)
   {
      int ret;
      ret = opus_decode_frame(st, data, size[i], pcm, frame_size-nb_samples, decode_fec);
      if (ret<0)
         return ret;
      data += size[i];
      tot_offset += size[i];
      pcm += ret*st->channels;
      nb_samples += ret;
   }
   if (packet_offset != NULL)
      *packet_offset = tot_offset;
   return nb_samples;
}
コード例 #4
0
ファイル: opus.c プロジェクト: AntonioLebara/ios-pjsip
static pj_status_t opus_codec_parse(pjmedia_codec *codec, void *pkt,
                                    pj_size_t pkt_size, const pj_timestamp *ts,
                                    unsigned *frame_cnt,
                                    pjmedia_frame frames[]) {
  struct opus_private *opus;
  unsigned char toc;
  const unsigned char *raw_frames[48];
  short size[48];
  int payload_offset, samples_per_frame;
  unsigned i;

  PJ_ASSERT_RETURN(frame_cnt, PJ_EINVAL);

  opus = (struct opus_private *)codec->codec_data;

  *frame_cnt =
      opus_packet_parse(pkt, pkt_size, &toc, raw_frames, size, &payload_offset);

  samples_per_frame = opus_packet_get_samples_per_frame(pkt, opus->externalFs);

#if _TRACE_OPUS
  PJ_LOG(4, (THIS_FILE,
             "Pkt info : bw -> %d , spf -> %d, offset %d, packet_size %d",
             opus_packet_get_bandwidth(pkt), samples_per_frame, payload_offset,
             pkt_size));
#endif

  for (i = 0; i < *frame_cnt; i++) {
    frames[i].type = PJMEDIA_FRAME_TYPE_AUDIO;
    frames[i].bit_info = (((unsigned)ts->u64 & 0xFFFF) << 16) |
                         (((unsigned)pkt & 0xFF) << 8) | i;
    frames[i].buf = pkt;
    frames[i].size = pkt_size;
    frames[i].timestamp.u64 =
        ts->u64 * opus->externalFs / OPUS_CLOCK_RATE + i * samples_per_frame;
#if _TRACE_OPUS
    PJ_LOG(4, (THIS_FILE, "parsed %d of %d", frames[i].size, *frame_cnt));
#endif
  }

  return PJ_SUCCESS;
}
JNIEXPORT jint JNICALL
Java_org_jitsi_impl_neomedia_codec_audio_opus_Opus_packet_1get_1bandwidth
    (JNIEnv *env, jclass clazz, jbyteArray data, jint offset)
{
    int ret;

    if (data)
    {
        jbyte *data_ = (*env)->GetPrimitiveArrayCritical(env, data, NULL);

        if (data_)
        {
            ret = opus_packet_get_bandwidth((unsigned char *) (data_ + offset));
            (*env)->ReleasePrimitiveArrayCritical(env, data, data_, JNI_ABORT);
        }
        else
            ret = OPUS_ALLOC_FAIL;
    }
    else
        ret = OPUS_BAD_ARG;
    return ret;
}
コード例 #6
0
/**
 * Output debug information regarding the state of a single Opus packet
 */
void DebugFrameInfoInternal(const uint8* PacketData, uint32 PacketLength, uint32 SampleRate, bool bEncode)
{
	int32 NumFrames = opus_packet_get_nb_frames(PacketData, PacketLength);
	if (NumFrames == OPUS_BAD_ARG || NumFrames == OPUS_INVALID_PACKET)
	{
		UE_LOG(LogVoice, Warning, TEXT("opus_packet_get_nb_frames: Invalid voice packet data!"));
	}

	int32 NumSamples = opus_packet_get_nb_samples(PacketData, PacketLength, SampleRate);
	if (NumSamples == OPUS_BAD_ARG || NumSamples == OPUS_INVALID_PACKET)
	{
		UE_LOG(LogVoice, Warning, TEXT("opus_packet_get_nb_samples: Invalid voice packet data!"));
	}

	int32 NumSamplesPerFrame = opus_packet_get_samples_per_frame(PacketData, SampleRate);
	int32 Bandwidth = opus_packet_get_bandwidth(PacketData);

	const TCHAR* BandwidthStr = NULL;
	switch (Bandwidth)
	{
	case OPUS_BANDWIDTH_NARROWBAND: // Narrowband (4kHz bandpass)
		BandwidthStr = TEXT("NB");
		break;
	case OPUS_BANDWIDTH_MEDIUMBAND: // Mediumband (6kHz bandpass)
		BandwidthStr = TEXT("MB");
		break;
	case OPUS_BANDWIDTH_WIDEBAND: // Wideband (8kHz bandpass)
		BandwidthStr = TEXT("WB");
		break;
	case OPUS_BANDWIDTH_SUPERWIDEBAND: // Superwideband (12kHz bandpass)
		BandwidthStr = TEXT("SWB");
		break;
	case OPUS_BANDWIDTH_FULLBAND: // Fullband (20kHz bandpass)
		BandwidthStr = TEXT("FB");
		break;
	case OPUS_INVALID_PACKET: 
	default:
		BandwidthStr = TEXT("Invalid");
		break;
	}

	/*
	 *	0
	 *	0 1 2 3 4 5 6 7
	 *	+-+-+-+-+-+-+-+-+
	 *	| config  |s| c |
	 *	+-+-+-+-+-+-+-+-+
	 */
	uint8 TOC;
	// (max 48 x 2.5ms frames in a packet = 120ms)
	const uint8* frames[48];
	int16 size[48];
	int32 payload_offset = 0;
	int32 NumFramesParsed = opus_packet_parse(PacketData, PacketLength, &TOC, frames, size, &payload_offset);

	// Frame Encoding see http://tools.ietf.org/html/rfc6716#section-3.1
	int32 TOCEncoding = (TOC & 0xf8) >> 3;

	// Number of channels
	bool TOCStereo = (TOC & 0x4) != 0 ? true : false;

	// Number of frames and their configuration
	// 0: 1 frame in the packet
	// 1: 2 frames in the packet, each with equal compressed size
    // 2: 2 frames in the packet, with different compressed sizes
	// 3: an arbitrary number of frames in the packet
	int32 TOCMode = TOC & 0x3;

	if (bEncode)
	{
		UE_LOG(LogVoiceEncode, Verbose, TEXT("PacketLength: %d NumFrames: %d NumSamples: %d Bandwidth: %s Encoding: %d Stereo: %d FrameDesc: %d"),
			PacketLength, NumFrames, NumSamples, BandwidthStr, TOCEncoding, TOCStereo, TOCMode);
	}
	else
	{
		UE_LOG(LogVoiceDecode, Verbose, TEXT("PacketLength: %d NumFrames: %d NumSamples: %d Bandwidth: %s Encoding: %d Stereo: %d FrameDesc: %d"),
			PacketLength, NumFrames, NumSamples, BandwidthStr, TOCEncoding, TOCStereo, TOCMode);
	}
}
コード例 #7
0
ファイル: audio.c プロジェクト: GrayHatter/toxcore
void ac_iterate(ACSession *ac)
{
    if (!ac) {
        return;
    }

    /* TODO(mannol): fix this and jitter buffering */

    /* Enough space for the maximum frame size (120 ms 48 KHz stereo audio) */
    int16_t tmp[5760 * 2];

    struct RTPMessage *msg;
    int rc = 0;

    pthread_mutex_lock(ac->queue_mutex);

    while ((msg = jbuf_read((struct JitterBuffer *)ac->j_buf, &rc)) || rc == 2) {
        pthread_mutex_unlock(ac->queue_mutex);

        if (rc == 2) {
            LOGGER_DEBUG(ac->log, "OPUS correction");
            int fs = (ac->lp_sampling_rate * ac->lp_frame_duration) / 1000;
            rc = opus_decode(ac->decoder, NULL, 0, tmp, fs, 1);
        } else {
            /* Get values from packet and decode. */
            /* NOTE: This didn't work very well */
#if 0
            rc = convert_bw_to_sampling_rate(opus_packet_get_bandwidth(msg->data));

            if (rc != -1) {
                cs->last_packet_sampling_rate = rc;
            } else {
                LOGGER_WARNING(ac->log, "Failed to load packet values!");
                rtp_free_msg(msg);
                continue;
            }

#endif


            /* Pick up sampling rate from packet */
            memcpy(&ac->lp_sampling_rate, msg->data, 4);
            ac->lp_sampling_rate = net_ntohl(ac->lp_sampling_rate);

            ac->lp_channel_count = opus_packet_get_nb_channels(msg->data + 4);

            /** NOTE: even though OPUS supports decoding mono frames with stereo decoder and vice versa,
              * it didn't work quite well.
              */
            if (!reconfigure_audio_decoder(ac, ac->lp_sampling_rate, ac->lp_channel_count)) {
                LOGGER_WARNING(ac->log, "Failed to reconfigure decoder!");
                free(msg);
                continue;
            }

            rc = opus_decode(ac->decoder, msg->data + 4, msg->len - 4, tmp, 5760, 0);
            free(msg);
        }

        if (rc < 0) {
            LOGGER_WARNING(ac->log, "Decoding error: %s", opus_strerror(rc));
        } else if (ac->acb.first) {
            ac->lp_frame_duration = (rc * 1000) / ac->lp_sampling_rate;

            ac->acb.first(ac->av, ac->friend_number, tmp, rc, ac->lp_channel_count,
                          ac->lp_sampling_rate, ac->acb.second);
        }

        return;
    }

    pthread_mutex_unlock(ac->queue_mutex);
}
コード例 #8
0
ファイル: opus_decoder.c プロジェクト: biddyweb/azfone-ios
int opus_decode_native(OpusDecoder *st, const unsigned char *data,
                       opus_int32 len, opus_val16 *pcm, int frame_size, int decode_fec,
                       int self_delimited, opus_int32 *packet_offset, int soft_clip)
{
    int i, nb_samples;
    int count, offset;
    unsigned char toc;
    int packet_frame_size, packet_bandwidth, packet_mode, packet_stream_channels;
    /* 48 x 2.5 ms = 120 ms */
    opus_int16 size[48];
    if (decode_fec<0 || decode_fec>1)
        return OPUS_BAD_ARG;
    /* For FEC/PLC, frame_size has to be to have a multiple of 2.5 ms */
    if ((decode_fec || len==0 || data==NULL) && frame_size%(st->Fs/400)!=0)
        return OPUS_BAD_ARG;
    if (len==0 || data==NULL)
    {
        int pcm_count=0;
        do {
            int ret;
            ret = opus_decode_frame(st, NULL, 0, pcm+pcm_count*st->channels, frame_size-pcm_count, 0);
            if (ret<0)
                return ret;
            pcm_count += ret;
        } while (pcm_count < frame_size);
        celt_assert(pcm_count == frame_size);
        if (OPUS_CHECK_ARRAY(pcm, pcm_count*st->channels))
            OPUS_PRINT_INT(pcm_count);
        st->last_packet_duration = pcm_count;
        return pcm_count;
    } else if (len<0)
        return OPUS_BAD_ARG;

    packet_mode = opus_packet_get_mode(data);
    packet_bandwidth = opus_packet_get_bandwidth(data);
    packet_frame_size = opus_packet_get_samples_per_frame(data, st->Fs);
    packet_stream_channels = opus_packet_get_nb_channels(data);

    count = opus_packet_parse_impl(data, len, self_delimited, &toc, NULL,
                                   size, &offset, packet_offset);
    if (count<0)
        return count;

    data += offset;

    if (decode_fec)
    {
        int duration_copy;
        int ret;
        /* If no FEC can be present, run the PLC (recursive call) */
        if (frame_size < packet_frame_size || packet_mode == MODE_CELT_ONLY || st->mode == MODE_CELT_ONLY)
            return opus_decode_native(st, NULL, 0, pcm, frame_size, 0, 0, NULL, soft_clip);
        /* Otherwise, run the PLC on everything except the size for which we might have FEC */
        duration_copy = st->last_packet_duration;
        if (frame_size-packet_frame_size!=0)
        {
            ret = opus_decode_native(st, NULL, 0, pcm, frame_size-packet_frame_size, 0, 0, NULL, soft_clip);
            if (ret<0)
            {
                st->last_packet_duration = duration_copy;
                return ret;
            }
            celt_assert(ret==frame_size-packet_frame_size);
        }
        /* Complete with FEC */
        st->mode = packet_mode;
        st->bandwidth = packet_bandwidth;
        st->frame_size = packet_frame_size;
        st->stream_channels = packet_stream_channels;
        ret = opus_decode_frame(st, data, size[0], pcm+st->channels*(frame_size-packet_frame_size),
                                packet_frame_size, 1);
        if (ret<0)
            return ret;
        else {
            if (OPUS_CHECK_ARRAY(pcm, frame_size*st->channels))
                OPUS_PRINT_INT(frame_size);
            st->last_packet_duration = frame_size;
            return frame_size;
        }
    }

    if (count*packet_frame_size > frame_size)
        return OPUS_BUFFER_TOO_SMALL;

    /* Update the state as the last step to avoid updating it on an invalid packet */
    st->mode = packet_mode;
    st->bandwidth = packet_bandwidth;
    st->frame_size = packet_frame_size;
    st->stream_channels = packet_stream_channels;

    nb_samples=0;
    for (i=0; i<count; i++)
    {
        int ret;
        ret = opus_decode_frame(st, data, size[i], pcm+nb_samples*st->channels, frame_size-nb_samples, 0);
        if (ret<0)
            return ret;
        celt_assert(ret==packet_frame_size);
        data += size[i];
        nb_samples += ret;
    }
    st->last_packet_duration = nb_samples;
    if (OPUS_CHECK_ARRAY(pcm, nb_samples*st->channels))
        OPUS_PRINT_INT(nb_samples);
#ifndef FIXED_POINT
    if (soft_clip)
        opus_pcm_soft_clip(pcm, nb_samples, st->channels, st->softclip_mem);
    else
        st->softclip_mem[0]=st->softclip_mem[1]=0;
#endif
    return nb_samples;
}
コード例 #9
0
ファイル: gstopusdec.c プロジェクト: LCW523/gst-plugins-bad
static GstFlowReturn
opus_dec_chain_parse_data (GstOpusDec * dec, GstBuffer * buf,
    GstClockTime timestamp, GstClockTime duration)
{
  GstFlowReturn res = GST_FLOW_OK;
  gint size;
  guint8 *data;
  GstBuffer *outbuf;
  gint16 *out_data;
  int n;

  if (timestamp != -1) {
    dec->segment.last_stop = timestamp;
    dec->granulepos = -1;
  }

  if (dec->state == NULL) {
    GstCaps *caps;

    dec->state = opus_decoder_create (dec->sample_rate, dec->n_channels);

    /* set caps */
    caps = gst_caps_new_simple ("audio/x-raw-int",
        "rate", G_TYPE_INT, dec->sample_rate,
        "channels", G_TYPE_INT, dec->n_channels,
        "signed", G_TYPE_BOOLEAN, TRUE,
        "endianness", G_TYPE_INT, G_BYTE_ORDER,
        "width", G_TYPE_INT, 16, "depth", G_TYPE_INT, 16, NULL);

    GST_DEBUG_OBJECT (dec, "rate=%d channels=%d frame-size=%d",
        dec->sample_rate, dec->n_channels, dec->frame_size);

    if (!gst_pad_set_caps (dec->srcpad, caps))
      GST_ERROR ("nego failure");

    gst_caps_unref (caps);
  }

  if (buf) {
    data = GST_BUFFER_DATA (buf);
    size = GST_BUFFER_SIZE (buf);

    GST_DEBUG_OBJECT (dec, "received buffer of size %u", size);

    /* copy timestamp */
  } else {
    /* concealment data, pass NULL as the bits parameters */
    GST_DEBUG_OBJECT (dec, "creating concealment data");
    data = NULL;
    size = 0;
  }

  GST_DEBUG ("bandwidth %d", opus_packet_get_bandwidth (data));
  GST_DEBUG ("samples_per_frame %d", opus_packet_get_samples_per_frame (data,
          48000));
  GST_DEBUG ("channels %d", opus_packet_get_nb_channels (data));

  res = gst_pad_alloc_buffer_and_set_caps (dec->srcpad,
      GST_BUFFER_OFFSET_NONE, dec->frame_samples * dec->n_channels * 2,
      GST_PAD_CAPS (dec->srcpad), &outbuf);

  if (res != GST_FLOW_OK) {
    GST_DEBUG_OBJECT (dec, "buf alloc flow: %s", gst_flow_get_name (res));
    return res;
  }

  out_data = (gint16 *) GST_BUFFER_DATA (outbuf);

  GST_LOG_OBJECT (dec, "decoding frame");

  n = opus_decode (dec->state, data, size, out_data, dec->frame_samples, TRUE);
  if (n < 0) {
    GST_ELEMENT_ERROR (dec, STREAM, DECODE, ("Decoding error: %d", n), (NULL));
    return GST_FLOW_ERROR;
  }

  if (!GST_CLOCK_TIME_IS_VALID (timestamp)) {
    timestamp = gst_util_uint64_scale_int (dec->granulepos - dec->frame_size,
        GST_SECOND, dec->sample_rate);
  }

  GST_DEBUG_OBJECT (dec, "timestamp=%" GST_TIME_FORMAT,
      GST_TIME_ARGS (timestamp));

  GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (buf);
  GST_BUFFER_DURATION (outbuf) = GST_BUFFER_DURATION (buf);
  if (dec->discont) {
    GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
    dec->discont = 0;
  }

  dec->segment.last_stop += dec->frame_duration;

  GST_LOG_OBJECT (dec, "pushing buffer with ts=%" GST_TIME_FORMAT ", dur=%"
      GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
      GST_TIME_ARGS (dec->frame_duration));

  res = gst_pad_push (dec->srcpad, outbuf);

  if (res != GST_FLOW_OK)
    GST_DEBUG_OBJECT (dec, "flow: %s", gst_flow_get_name (res));

  return res;
}
コード例 #10
0
ファイル: opus_decoder.c プロジェクト: Daninet/jamulus
int opus_decode_native(OpusDecoder *st, const unsigned char *data,
      opus_int32 len, opus_val16 *pcm, int frame_size, int decode_fec,
      int self_delimited, int *packet_offset)
{
   int i, nb_samples;
   int count, offset;
   unsigned char toc;
   int tot_offset;
   int packet_frame_size, packet_bandwidth, packet_mode, packet_stream_channels;
   /* 48 x 2.5 ms = 120 ms */
   short size[48];
   if (decode_fec<0 || decode_fec>1)
      return OPUS_BAD_ARG;
   /* For FEC/PLC, frame_size has to be to have a multiple of 2.5 ms */
   if ((decode_fec || len==0 || data==NULL) && frame_size%(st->Fs/400)!=0)
      return OPUS_BAD_ARG;
   if (len==0 || data==NULL)
   {
      int pcm_count=0;
      do {
         int ret;
         ret = opus_decode_frame(st, NULL, 0, pcm, frame_size-pcm_count, 0);
         if (ret<0)
            return ret;
         pcm += st->channels*ret;
         pcm_count += ret;
      } while (pcm_count < frame_size);
      st->last_packet_duration = pcm_count;
      return pcm_count;
   } else if (len<0)
      return OPUS_BAD_ARG;

   packet_mode = opus_packet_get_mode(data);
   packet_bandwidth = opus_packet_get_bandwidth(data);
   packet_frame_size = opus_packet_get_samples_per_frame(data, st->Fs);
   packet_stream_channels = opus_packet_get_nb_channels(data);

   count = opus_packet_parse_impl(data, len, self_delimited, &toc, NULL, size, &offset);

   data += offset;

   if (decode_fec)
   {
      int duration_copy;
      int ret;
      /* If no FEC can be present, run the PLC (recursive call) */
      if (frame_size <= packet_frame_size || packet_mode == MODE_CELT_ONLY || st->mode == MODE_CELT_ONLY)
         return opus_decode_native(st, NULL, 0, pcm, frame_size, 0, 0, NULL);
      /* Otherwise, run the PLC on everything except the size for which we might have FEC */
      duration_copy = st->last_packet_duration;
      ret = opus_decode_native(st, NULL, 0, pcm, frame_size-packet_frame_size, 0, 0, NULL);
      if (ret<0)
      {
         st->last_packet_duration = duration_copy;
         return ret;
      }
      /* Complete with FEC */
      st->mode = packet_mode;
      st->bandwidth = packet_bandwidth;
      st->frame_size = packet_frame_size;
      st->stream_channels = packet_stream_channels;
      ret = opus_decode_frame(st, data, size[0], pcm+st->channels*(frame_size-packet_frame_size),
            packet_frame_size, 1);
      if (ret<0)
         return ret;
      st->last_packet_duration = frame_size;
      return frame_size;
   }
   tot_offset = 0;
   if (count < 0)
      return count;

   tot_offset += offset;

   if (count*packet_frame_size > frame_size)
      return OPUS_BUFFER_TOO_SMALL;

   /* Update the state as the last step to avoid updating it on an invalid packet */
   st->mode = packet_mode;
   st->bandwidth = packet_bandwidth;
   st->frame_size = packet_frame_size;
   st->stream_channels = packet_stream_channels;

   nb_samples=0;
   for (i=0;i<count;i++)
   {
      int ret;
      ret = opus_decode_frame(st, data, size[i], pcm, frame_size-nb_samples, decode_fec);
      if (ret<0)
         return ret;
      data += size[i];
      tot_offset += size[i];
      pcm += ret*st->channels;
      nb_samples += ret;
   }
   if (packet_offset != NULL)
      *packet_offset = tot_offset;
   st->last_packet_duration = nb_samples;
   return nb_samples;
}