/**
 * Creates OPUS packets from PCM data
 */
static void
packetizer ()
{
  char *nbuf;
  size_t new_size;
  int32_t len;
  ogg_packet op;
  ogg_page og;

  while (transmit_buffer_length >= transmit_buffer_index + pcm_length)
  {
    memcpy (pcm_buffer,
	    &transmit_buffer[transmit_buffer_index],
	    pcm_length);
    transmit_buffer_index += pcm_length;
    len =
      opus_encode_float (enc, pcm_buffer, FRAME_SIZE, opus_data,
			 MAX_PAYLOAD_BYTES);

    if (len < 0)
    {
      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                  _("opus_encode_float() failed: %s. Aborting\n"),
                  opus_strerror (len));
      quit (5);
    }
    if (len > UINT16_MAX - sizeof (struct AudioMessage))
    {
      GNUNET_break (0);
      continue;
    }

    /* As per OggOpus spec, granule is calculated as if the audio
       had 48kHz sampling rate. */
    enc_granulepos += FRAME_SIZE * 48000 / SAMPLING_RATE;

    op.packet = (unsigned char *) opus_data;
    op.bytes = len;
    op.b_o_s = 0;
    op.e_o_s = 0;
    op.granulepos = enc_granulepos;
    op.packetno = packet_id++;
    ogg_stream_packetin (&os, &op);

    while (ogg_stream_flush_fill (&os, &og, PAGE_WATERLINE))
    {
      if (og.header_len + og.body_len > UINT16_MAX - sizeof (struct AudioMessage))
      {
        GNUNET_assert (0);
        continue;
      }
      write_page (&og);
    }
  }

  new_size = transmit_buffer_length - transmit_buffer_index;
  if (0 != new_size)
  {
    nbuf = pa_xmalloc (new_size);
    memmove (nbuf,
	     &transmit_buffer[transmit_buffer_index],
	     new_size);
    pa_xfree (transmit_buffer);
    transmit_buffer = nbuf;
  }
  else
  {
    pa_xfree (transmit_buffer);
    transmit_buffer = NULL;
  }
  transmit_buffer_index = 0;
  transmit_buffer_length = new_size;
}
Example #2
0
int writeFrame(uint8_t *framePcmBytes, unsigned int frameByteCount) {
    int cur_frame_size = frame_size;
    _packetId++;

    opus_int32 nb_samples = frameByteCount / 2;
    total_samples += nb_samples;
    if (nb_samples < frame_size) {
        op.e_o_s = 1;
    } else {
        op.e_o_s = 0;
    }

    int nbBytes = 0;

    if (nb_samples != 0) {
        uint8_t *paddedFrameBytes = framePcmBytes;
        int freePaddedFrameBytes = 0;

        if (nb_samples < cur_frame_size) {
            paddedFrameBytes = malloc(cur_frame_size * 2);
            freePaddedFrameBytes = 1;
            memcpy(paddedFrameBytes, framePcmBytes, frameByteCount);
            memset(paddedFrameBytes + nb_samples * 2, 0, cur_frame_size * 2 - nb_samples * 2);
        }

        nbBytes = opus_encode(_encoder, (opus_int16 *)paddedFrameBytes, cur_frame_size, _packet, max_frame_bytes / 10);
        if (freePaddedFrameBytes) {
            free(paddedFrameBytes);
            paddedFrameBytes = NULL;
        }

        if (nbBytes < 0) {
            LOGE("Encoding failed: %s. Aborting.", opus_strerror(nbBytes));
            return 0;
        }

        enc_granulepos += cur_frame_size * 48000 / coding_rate;
        size_segments = (nbBytes + 255) / 255;
        min_bytes = min(nbBytes, min_bytes);
    }

    while ((((size_segments <= 255) && (last_segments + size_segments > 255)) || (enc_granulepos - last_granulepos > max_ogg_delay)) && ogg_stream_flush_fill(&os, &og, 255 * 255)) {
        if (ogg_page_packets(&og) != 0) {
            last_granulepos = ogg_page_granulepos(&og);
        }

        last_segments -= og.header[26];
        int writtenPageBytes = writeOggPage(&og, _fileOs);
        if (writtenPageBytes != og.header_len + og.body_len) {
            LOGE("Error: failed writing data to output stream");
            return 0;
        }
        bytes_written += writtenPageBytes;
        pages_out++;
    }

    op.packet = (unsigned char *)_packet;
    op.bytes = nbBytes;
    op.b_o_s = 0;
    op.granulepos = enc_granulepos;
    if (op.e_o_s) {
        op.granulepos = ((total_samples * 48000 + rate - 1) / rate) + header.preskip;
    }
    op.packetno = 2 + _packetId;
    ogg_stream_packetin(&os, &op);
    last_segments += size_segments;

    while ((op.e_o_s || (enc_granulepos + (frame_size * 48000 / coding_rate) - last_granulepos > max_ogg_delay) || (last_segments >= 255)) ? ogg_stream_flush_fill(&os, &og, 255 * 255) : ogg_stream_pageout_fill(&os, &og, 255 * 255)) {
        if (ogg_page_packets(&og) != 0) {
            last_granulepos = ogg_page_granulepos(&og);
        }
        last_segments -= og.header[26];
        int writtenPageBytes = writeOggPage(&og, _fileOs);
        if (writtenPageBytes != og.header_len + og.body_len) {
            LOGE("Error: failed writing data to output stream");
            return 0;
        }
        bytes_written += writtenPageBytes;
        pages_out++;
    }

    return 1;
}
Example #3
0
void OggOpusFile::EncodeChunks(void* pcmBuf, int numSamples, bool lastChunk)
{
    int numFrames = numSamples/PCM_SAMPLES_IN_FRAME;
    bool flush = false;
    for(int j = 0; j < numFrames; j++)
    {        
        if(j == (numFrames -1) && (lastChunk == true))
        {
            flush =true;
        }
        nb_samples=PCM_SAMPLES_IN_FRAME;//make it 160
        id++;
        int size_segments,cur_frame_size;
        ////frame_size=160 for 8k
        cur_frame_size=frame_size;

        /*Encode current frame*/          
        //Stereo: each pcm samples will have 2 short samples(L/R interlaced) so the num of bytes for each frame will be double to mono
        nbBytes=opus_multistream_encode	(st, (short*)pcmBuf + (j*PCM_SAMPLES_IN_FRAME*chan), cur_frame_size, m_outBuf, max_frame_bytes);
        if(nbBytes<0){
            fprintf(stderr, "Encoding failed: %s. Aborting.\n", opus_strerror(nbBytes));
            return;
        }

        nb_encoded+=cur_frame_size;
        enc_granulepos+=cur_frame_size*48000/coding_rate;
        total_bytes+=nbBytes;
        size_segments=(nbBytes+255)/255;
        peak_bytes=IMAX(nbBytes,peak_bytes);
        min_bytes=IMIN(nbBytes,min_bytes);                      
        //printf("TotalByes:%d\n", total_bytes);

        /*Flush early if adding this packet would make us end up with a
            continued page which we wouldn't have otherwise.*/
        while((((size_segments<=255)&&(last_segments+size_segments>255))|| (enc_granulepos-last_granulepos>max_ogg_delay)) 
                && ogg_stream_flush_fill(&os, &og,255*255)){
            if(ogg_page_packets(&og)!=0)  last_granulepos=ogg_page_granulepos(&og);

            last_segments-=og.header[26];
            ret=oe_write_page(&og);
            if(ret!=og.header_len+og.body_len){
                fprintf(stderr,"Error: failed writing data to output stream\n");
                exit(1);
            }
            bytes_written+=ret;
            pages_out++;
        }

        /*The downside of early reading is if the input is an exact
        multiple of the frame_size you'll get an extra frame that needs
        to get cropped off. The downside of late reading is added delay.
        If your ogg_delay is 120ms or less we'll assume you want the
        low delay behavior.*/
        // if(max_ogg_delay>5760){
        //     nb_samples = inopt.read_samples(inopt.readdata,input,frame_size);
        //     total_samples+=nb_samples;
        //     if(nb_samples==0)op.e_o_s=1;
        // } else nb_samples=-1;

        op.packet=(unsigned char *)m_outBuf;
        op.bytes=nbBytes;
        op.b_o_s=0;
        op.granulepos=enc_granulepos;
        if(flush == true){
            /*We compute the final GP as ceil(len*48k/input_rate)+preskip. When a
            resampling decoder does the matching floor((len-preskip)*input_rate/48k)
            conversion, the resulting output length will exactly equal the original
            input length when 0<input_rate<=48000.*/
            op.granulepos=((original_samples*48000+rate-1)/rate)+header.preskip;
        }
        op.packetno=2+id;
        ogg_stream_packetin(&os, &op);
        last_segments+=size_segments;

        /*If the stream is over or we're sure that the delayed flush will fire,
            go ahead and flush now to avoid adding delay.*/
        while(((flush == true) || (enc_granulepos+(frame_size*48000/coding_rate)-last_granulepos>max_ogg_delay)||
                (last_segments>=255))?
                ogg_stream_flush_fill(&os, &og,255*255):
                ogg_stream_pageout_fill(&os, &og,255*255)){

            if(ogg_page_packets(&og)!=0)last_granulepos=ogg_page_granulepos(&og);
            last_segments-=og.header[26];
            ret=oe_write_page(&og);
            if(ret!=og.header_len+og.body_len){
                fprintf(stderr,"Error: failed writing data to output stream\n");
                exit(1);
            }
            bytes_written+=ret;
            pages_out++;
        }
    }
}