static switch_status_t switch_amrwb_encode(switch_codec_t *codec, switch_codec_t *other_codec, void *decoded_data, uint32_t decoded_data_len, uint32_t decoded_rate, void *encoded_data, uint32_t *encoded_data_len, uint32_t *encoded_rate, unsigned int *flag) { #ifdef AMRWB_PASSTHROUGH switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "This codec is only usable in passthrough mode!\n"); return SWITCH_STATUS_FALSE; #else struct amrwb_context *context = codec->private_info; if (!context) { return SWITCH_STATUS_FALSE; } *encoded_data_len = E_IF_encode(context->encoder_state, context->enc_mode, (int16_t *) decoded_data, (switch_byte_t *) encoded_data, 0); return SWITCH_STATUS_SUCCESS; #endif }
/* * Encode frame. */ static pj_status_t amr_codec_encode( pjmedia_codec *codec, const struct pjmedia_frame *input, unsigned output_buf_len, struct pjmedia_frame *output) { struct amr_data *amr_data = (struct amr_data*) codec->codec_data; unsigned char *bitstream; pj_int16_t *speech; unsigned nsamples, samples_per_frame; enum {MAX_FRAMES_PER_PACKET = 16}; pjmedia_frame frames[MAX_FRAMES_PER_PACKET]; pj_uint8_t *p; unsigned i, out_size = 0, nframes = 0; pj_size_t payload_len; unsigned dtx_cnt, sid_cnt; pj_status_t status; pj_assert(amr_data != NULL); PJ_ASSERT_RETURN(input && output, PJ_EINVAL); nsamples = input->size >> 1; samples_per_frame = amr_data->clock_rate * FRAME_LENGTH_MS / 1000; PJ_ASSERT_RETURN(nsamples % samples_per_frame == 0, PJMEDIA_CODEC_EPCMFRMINLEN); nframes = nsamples / samples_per_frame; PJ_ASSERT_RETURN(nframes <= MAX_FRAMES_PER_PACKET, PJMEDIA_CODEC_EFRMTOOSHORT); /* Encode the frames */ speech = (pj_int16_t*)input->buf; bitstream = (unsigned char*)output->buf; while (nsamples >= samples_per_frame) { int size; if (amr_data->enc_setting.amr_nb) { #ifdef USE_AMRNB size = Encoder_Interface_Encode (amr_data->encoder, amr_data->enc_mode, speech, bitstream, 0); #else size = 0; #endif } else { #ifdef USE_AMRWB size = E_IF_encode (amr_data->encoder, amr_data->enc_mode, speech, bitstream, 0); #else size = 0; #endif } if (size == 0) { output->size = 0; output->buf = NULL; output->type = PJMEDIA_FRAME_TYPE_NONE; TRACE_((THIS_FILE, "AMR encode() failed")); return PJMEDIA_CODEC_EFAILED; } nsamples -= samples_per_frame; speech += samples_per_frame; bitstream += size; out_size += size; TRACE_((THIS_FILE, "AMR encode(): mode=%d, size=%d", amr_data->enc_mode, out_size)); } /* Pack payload */ p = (pj_uint8_t*)output->buf + output_buf_len - out_size; pj_memmove(p, output->buf, out_size); dtx_cnt = sid_cnt = 0; for (i = 0; i < nframes; ++i) { pjmedia_codec_amr_bit_info *info = (pjmedia_codec_amr_bit_info*) &frames[i].bit_info; info->frame_type = (pj_uint8_t)((*p >> 3) & 0x0F); info->good_quality = (pj_uint8_t)((*p >> 2) & 0x01); info->mode = (pj_int8_t)amr_data->enc_mode; info->start_bit = 0; frames[i].buf = p + 1; if (amr_data->enc_setting.amr_nb) { frames[i].size = (info->frame_type <= 8)? pjmedia_codec_amrnb_framelen[info->frame_type] : 0; } else { frames[i].size = (info->frame_type <= 9)? pjmedia_codec_amrwb_framelen[info->frame_type] : 0; } p += frames[i].size + 1; /* Count the number of SID and DTX frames */ if (info->frame_type == 15) /* DTX*/ ++dtx_cnt; else if (info->frame_type == 8) /* SID */ ++sid_cnt; } /* VA generates DTX frames as DTX+SID frames switching quickly and it * seems that the SID frames occur too often (assuming the purpose is * only for keeping NAT alive?). So let's modify the behavior a bit. * Only an SID frame will be sent every PJMEDIA_CODEC_MAX_SILENCE_PERIOD * milliseconds. */ if (sid_cnt + dtx_cnt == nframes) { pj_int32_t dtx_duration; dtx_duration = pj_timestamp_diff32(&amr_data->last_tx, &input->timestamp); if (PJMEDIA_CODEC_MAX_SILENCE_PERIOD == -1 || dtx_duration < PJMEDIA_CODEC_MAX_SILENCE_PERIOD* amr_data->clock_rate/1000) { output->size = 0; output->type = PJMEDIA_FRAME_TYPE_NONE; output->timestamp = input->timestamp; return PJ_SUCCESS; } } payload_len = output_buf_len; status = pjmedia_codec_amr_pack(frames, nframes, &amr_data->enc_setting, output->buf, &payload_len); if (status != PJ_SUCCESS) { output->size = 0; output->buf = NULL; output->type = PJMEDIA_FRAME_TYPE_NONE; TRACE_((THIS_FILE, "Failed to pack AMR payload, status=%d", status)); return status; } output->size = payload_len; output->type = PJMEDIA_FRAME_TYPE_AUDIO; output->timestamp = input->timestamp; amr_data->last_tx = input->timestamp; return PJ_SUCCESS; }
int main(int argc, char *argv[]) { FILE *f_speech = NULL; /* File of speech data */ FILE *f_serial = NULL; /* File of serial bits for transmission */ FILE *f_mode = NULL; /* File of modes for each frame */ Word32 serial_size, frame; Word16 signal[L_FRAME16k]; /* Buffer for speech @ 16kHz */ Word16 coding_mode = 0, allow_dtx, mode_file, mode = 0; UWord8 serial[NB_SERIAL_MAX]; void *st; fprintf(stderr, "\n"); fprintf(stderr, "===================================================================\n"); fprintf(stderr, " 3GPP AMR-WB Floating-point Speech Coder, v6.0.0, Dec 14, 2004\n"); fprintf(stderr, "===================================================================\n"); fprintf(stderr, "\n"); /* * Open speech file and result file (output serial bit stream) */ if ((argc < 4) || (argc > 6)) { fprintf(stderr, "Usage : encoder (-dtx) mode speech_file bitstream_file\n"); fprintf(stderr, "\n"); fprintf(stderr, "Format for speech_file:\n"); fprintf(stderr, " Speech is read form a binary file of 16 bits data.\n"); fprintf(stderr, "\n"); fprintf(stderr, "Format for bitstream_file:\n"); #ifdef IF2 fprintf(stderr, " Described in TS26.201.\n"); #else fprintf(stderr, " Described in RFC 3267 (Sections 5.1 and 5.3).\n"); #endif fprintf(stderr, "\n"); fprintf(stderr, "mode: 0 to 8 (9 bits rates) or\n"); fprintf(stderr, " -modefile filename\n"); fprintf(stderr, " ===================================================================\n"); fprintf(stderr, " mode : (0) (1) (2) (3) (4) (5) (6) (7) (8) \n"); fprintf(stderr, " bitrate: 6.60 8.85 12.65 14.25 15.85 18.25 19.85 23.05 23.85 kbit/s\n"); fprintf(stderr, " ===================================================================\n"); fprintf(stderr, "\n"); fprintf(stderr, "-dtx if DTX is ON, default is OFF\n"); fprintf(stderr, "\n"); exit(0); } allow_dtx = 0; if (strcmp(argv[1], "-dtx") == 0) { allow_dtx = 1; argv++; } mode_file = 0; if (strcmp(argv[1], "-modefile") == 0) { mode_file = 1; argv++; if ((f_mode = fopen(argv[1], "r")) == NULL) { fprintf(stderr, "Error opening input file %s !!\n", argv[1]); exit(0); } fprintf(stderr, "Mode file: %s\n", argv[1]); } else { mode = (Word16) atoi(argv[1]); if ((mode < 0) || (mode > 8)) { fprintf(stderr, " error in bit rate mode %d: use 0 to 8\n", mode); exit(0); } } if ((f_speech = fopen(argv[2], "rb")) == NULL) { fprintf(stderr, "Error opening input file %s !!\n", argv[2]); exit(0); } fprintf(stderr, "Input speech file: %s\n", argv[2]); if ((f_serial = fopen(argv[3], "wb")) == NULL) { fprintf(stderr, "Error opening output bitstream file %s !!\n", argv[3]); exit(0); } fprintf(stderr, "Output bitstream file: %s\n", argv[3]); /* * Initialisation */ st = E_IF_init(); #ifndef IF2 /* If MMS output is selected, write the magic number at the beginning of the * bitstream file */ fwrite(AMRWB_MAGIC_NUMBER, sizeof(char), strlen(AMRWB_MAGIC_NUMBER), f_serial); #endif /* * Loop for every analysis/transmission frame. * -New L_FRAME data are read. (L_FRAME = number of speech data per frame) * -Conversion of the speech data from 16 bit integer to real * -Call coder to encode the speech. * -The compressed serial output stream is written to a file. */ fprintf(stderr, "\n --- Running ---\n"); frame = 0; while (fread(signal, sizeof(Word16), L_FRAME16k, f_speech) == L_FRAME16k) { if (mode_file) { if (fscanf(f_mode, "%hd", &mode) == EOF) { mode = coding_mode; fprintf(stderr, "\n end of mode control file reached\n"); fprintf(stderr, " From now on using mode: %hd.\n", mode); mode_file = 0; } if ((mode < 0) || (mode > 8)) { fprintf(stderr, " error in bit rate mode %hd: use 0 to 8\n", mode); E_IF_exit(st); fclose(f_speech); fclose(f_serial); fclose(f_mode); exit(0); } } coding_mode = mode; frame++; fprintf(stderr, " Frames processed: %ld\r", frame); serial_size = E_IF_encode(st, coding_mode, signal, serial, allow_dtx); fwrite(serial, 1, serial_size, f_serial); } E_IF_exit(st); fclose(f_speech); fclose(f_serial); if (f_mode != NULL) { fclose(f_mode); } return 0; }
static GstFlowReturn gst_voamrwbenc_chain (GstPad * pad, GstBuffer * buffer) { GstVoAmrWbEnc *amrwbenc; GstFlowReturn ret = GST_FLOW_OK; const int buffer_size = sizeof (short) * L_FRAME16k; amrwbenc = GST_VOAMRWBENC (gst_pad_get_parent (pad)); g_return_val_if_fail (amrwbenc->handle, GST_FLOW_WRONG_STATE); if (amrwbenc->rate == 0 || amrwbenc->channels == 0) { ret = GST_FLOW_NOT_NEGOTIATED; goto done; } /* discontinuity clears adapter, FIXME, maybe we can set some * encoder flag to mask the discont. */ if (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DISCONT)) { gst_adapter_clear (amrwbenc->adapter); amrwbenc->ts = 0; amrwbenc->discont = TRUE; } if (GST_BUFFER_TIMESTAMP_IS_VALID (buffer)) amrwbenc->ts = GST_BUFFER_TIMESTAMP (buffer); ret = GST_FLOW_OK; gst_adapter_push (amrwbenc->adapter, buffer); /* Collect samples until we have enough for an output frame */ while (gst_adapter_available (amrwbenc->adapter) >= buffer_size) { GstBuffer *out; guint8 *data; gint outsize; out = gst_buffer_new_and_alloc (buffer_size); GST_BUFFER_DURATION (out) = GST_SECOND * L_FRAME16k / (amrwbenc->rate * amrwbenc->channels); GST_BUFFER_TIMESTAMP (out) = amrwbenc->ts; if (amrwbenc->ts != -1) { amrwbenc->ts += GST_BUFFER_DURATION (out); } if (amrwbenc->discont) { GST_BUFFER_FLAG_SET (out, GST_BUFFER_FLAG_DISCONT); amrwbenc->discont = FALSE; } gst_buffer_set_caps (out, gst_pad_get_caps (amrwbenc->srcpad)); data = (guint8 *) gst_adapter_peek (amrwbenc->adapter, buffer_size); /* encode */ outsize = E_IF_encode (amrwbenc->handle, amrwbenc->bandmode, (const short *) data, (unsigned char *) GST_BUFFER_DATA (out), 0); gst_adapter_flush (amrwbenc->adapter, buffer_size); GST_BUFFER_SIZE (out) = outsize; /* play */ if ((ret = gst_pad_push (amrwbenc->srcpad, out)) != GST_FLOW_OK) break; } done: gst_object_unref (amrwbenc); return ret; }