meetecho / asterisk-opus

Opus (transcoding) and VP8 (passthrough) support for Asterisk, needed for a better WebRTC integration
GNU General Public License v2.0
77 stars 84 forks source link

Asterisk and Opus not working #10

Closed dki123 closed 10 years ago

dki123 commented 10 years ago

Hello,

We have tried with some custom client and some how asterisk is failed to pass rtp when we have received opus/8000 in original invite and a=fmtp:98 ptime=20; maxplaybackrate=8000; sprop-maxcapturerate=8000 as an FMTP

we have checked asterisk can only pass rtp when we have received opus/48000/2 in rtpmap and this works good even with transcoding.

As OPUS is variable rate codec client can send any sampling rate and playback rate while negotiation.

is there any way and work around on that. we have changed some portion of code to forcefully return opus/8000 but it wont help us and we stuck on this.

Do you guys please provide further information on this.

Below is sample Invite packet: INVITE sip:5678@172.18.100.222 SIP/2.0 Call-ID: 7109a8b9a27b417e69a83cf4f94fe8cd@192.168.1.112 CSeq: 175 INVITE From: "1234" sip:1234@172.18.100.222;tag=745799662 To: sip:5678@172.18.100.222 Via: SIP/2.0/UDP 192.168.1.112:32950;branch=z9hG4bKdd0955fe453d6cd7ae0eeaaa62cf6435353730;rport Max-Forwards: 70 Contact: "1234" sip:1234@192.168.1.112:32950;transport=udp Content-Type: application/sdp Content-Length: 394

v=0 o=- 1401776716457 1401776716462 IN IP4 192.168.1.112 s=- c=IN IP4 192.168.1.112 t=0 0 m=audio 44252 RTP/AVP 98 96 97 3 0 8 127 a=rtpmap:98 opus/8000 a=fmtp:98 ptime=20; maxplaybackrate=8000; sprop-maxcapturerate=8000 a=rtpmap:96 GSM-EFR/8000 a=rtpmap:97 AMR/8000 a=rtpmap:3 GSM/8000 a=rtpmap:0 PCMU/8000 a=rtpmap:8 PCMA/8000 a=rtpmap:127 telephone-event/8000 a=fmtp:127 0-15

Any help appreciated

Thanks In advance

lminiero commented 10 years ago

Hi,

opus/8000 is not a valid rtpmap value for Opus, as http://tools.ietf.org/html/draft-ietf-payload-rtp-opus-01 mandates opus/48000/2. That's why it's not handled in the Asterisk integration.

For what concerns the additional fmtp parameters, the patch in its current state ignores the SDP indications related to Opus. This means that, when creating the codec instance to use, what is used to determine the maximum sampling rate to be used is not what is passed via SDP, but what Asterisk passes to the translator. For instance, if you're going to bridge an Opus call to the PSTN, where the codec is, for instance, a-law, Asterisk will ask for a codec instance that can translate to and from slinear at 8 kHz. At the same time, if you're attaching to a Speex16 call or a wideband ConfBridge room, the Opus codec that will be created will be capped at 16kHz. When I say capped, I mean that the sampling rate is not fixed during the call, but that, as you pointed out, the codec will dynamically change it, without ever going beyond the cap we set though.

If you want it to be always 8 kHz in your case, and are not interested in higher sampling rates, change all the lintoopus_new and opustolin_new constructors so that they always pass 8000 and not the sampling rate they're supposed to adapt to.

dki123 commented 10 years ago

Hello,

Thanks for reply, Actually I have seen Given RFC and as per RFC payload should having value 48000/2 .

Another thing is I would like to do is giving my all client as OPUS but my PSTN provider are providing me G711 codecs only.

so basically I could translate between them . Now when some of client like acrobits in iphone and phonerlite are sending me opus/48000/2 and some fmtp parameter we have negotiate over OPUS to ULAW and this calls work fine without any issue .

But the thing is when I received opus/8000 and given fmtp parameter i would not able to handle call. As per your instructions I have modified code to send same sampling rate as we have received on INVITE at the time of giving 200 OK to client.

I have also changed sampling rate in codec_opus.c and added following sampling rates there.

static int lintoopus_new(struct ast_trans_pvt *pvt) { return opus_encoder_construct(pvt, 8000); }

static int opustolin_new(struct ast_trans_pvt *pvt) { return opus_decoder_construct(pvt, 8000); }

We have also added extra bandwidth sampling rate there in file you can find in attached file.

Main concern is after giving same sampling rate return in 200 OK to client ,The call is not setup and we could not here each other. So main concern is shall we need to develop any extra functionality to pass voice between client as other clients are working almost fine with OPUS.

as i am not able to attach file here i am attaching here my latest code.

+++++++++++++++===================

/*

/! \file

/*\ MODULEINFO

opus
<support_level>core</support_level>

***/

include "asterisk.h"

ASTERISK_FILE_VERSION(FILE, "$Revision: 328209 $")

include <opus/opus.h>

include "asterisk/translate.h"

include "asterisk/module.h"

include "asterisk/config.h"

include "asterisk/utils.h"

include "asterisk/cli.h"

define BUFFER_SAMPLES 8000

define OPUS_SAMPLES 160

define USE_FEC 0

/* Sample frame data */

include "asterisk/slin.h"

include "ex_opus.h"

/* FIXME: Test */

include "asterisk/file.h"

static int encid = 0; static int decid = 0;

static int opusdebug = 0;

/* Private structures _/ struct opus_coderpvt { void *opus; / May be encoder or decoder */ int sampling_rate; int multiplier; int fec;

int id;

int16_t buf[BUFFER_SAMPLES];    /* FIXME */
int framesize;

FILE *file;

};

/* Helper methods / static int opus_encoder_construct(struct ast_trans_pvt pvt, int sampling_rate) { if(sampling_rate != 8000 && sampling_rate != 12000 && sampling_rate != 16000 && sampling_rate != 24000 && sampling_rate != 48000) return -1; struct opus_coder_pvt *opvt = pvt->pvt; opvt->sampling_rate = sampling_rate; opvt->multiplier = 48000/sampling_rate; opvt->fec = USE_FEC; int error = 0; opvt->opus = opus_encoder_create(sampling_rate, 1, OPUS_APPLICATION_VOIP, &error); if(error != OPUS_OK) { if(opusdebug) ast_verbose("[Opus] Ops! got an error creating the Opus encoder: %d (%s)\n", error, opus_strerror(error)); return -1; } if(sampling_rate == 8000) opus_encoder_ctl(opvt->opus, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_NARROWBAND)); else if(sampling_rate == 12000) opus_encoder_ctl(opvt->opus, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_MEDIUMBAND)); else if(sampling_rate == 16000) opus_encoder_ctl(opvt->opus, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_WIDEBAND)); else if(sampling_rate == 24000) opus_encoder_ctl(opvt->opus, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_SUPERWIDEBAND)); else if(sampling_rate == 48000) opus_encoder_ctl(opvt->opus, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_FULLBAND)); opus_encoder_ctl(opvt->opus, OPUS_SET_INBAND_FEC(opvt->fec)); opvt->framesize = sampling_rate/50; opvt->id = ++encid; if(opusdebug) ast_verbose("[Opus] Created encoder #%d (%d->opus)\n", opvt->id, sampling_rate);

return 0;

}

static int opus_decoder_construct(struct ast_trans_pvt _pvt, int sampling_rate) { if(sampling_rate != 8000 && sampling_rate != 12000 && sampling_rate != 16000 && sampling_rate != 24000 && sampling_rate != 48000) return -1; struct opus_coder_pvt opvt = pvt->pvt; opvt->sampling_rate = sampling_rate; opvt->multiplier = 48000/sampling_rate; opvt->fec = USEFEC; / FIXME: should be triggered by chan_sip / int error = 0; opvt->opus = opus_decoder_create(sampling_rate, 1, &error); if(error != OPUS_OK) { if(opusdebug) ast_verbose("[Opus] Ops! got an error creating the Opus decoder: %d (%s)\n", error, opus_strerror(error)); return -1; } opvt->id = ++decid; if(opusdebug) ast_verbose("[Opus] Created decoder #%d (opus->%d)\n", opvt->id, sampling_rate);

if(opusdebug > 1) {
    char filename[50];
    sprintf(filename, "/home/lminiero/opusdec-%04d-%d.raw", opvt->id, opvt->sampling_rate);
    opvt->file = fopen(filename, "wb");
}

return 0;

}

/* Translator callbacks / static int lintoopus_new(struct ast_trans_pvt pvt) { return opus_encoder_construct(pvt, 8000); }

static int lin12toopus_new(struct ast_trans_pvt *pvt) { return opus_encoder_construct(pvt, 12000); }

static int lin16toopus_new(struct ast_trans_pvt *pvt) { return opus_encoder_construct(pvt, 16000); }

static int lin24toopus_new(struct ast_trans_pvt *pvt) { return opus_encoder_construct(pvt, 24000); }

static int lin48toopus_new(struct ast_trans_pvt *pvt) { return opus_encoder_construct(pvt, 48000); }

static int opustolin_new(struct ast_trans_pvt *pvt) { return opus_decoder_construct(pvt, 8000); }

static int opustolin12_new(struct ast_trans_pvt *pvt) { return opus_decoder_construct(pvt, 12000); }

static int opustolin16_new(struct ast_trans_pvt *pvt) { return opus_decoder_construct(pvt, 16000); }

static int opustolin24_new(struct ast_trans_pvt *pvt) { return opus_decoder_construct(pvt, 24000); }

static int opustolin48_new(struct ast_trans_pvt *pvt) { return opus_decoder_construct(pvt, 48000); }

static int lintoopus_framein(struct ast_trans_pvt pvt, struct ast_frame f) { struct opus_coder_pvt *opvt = pvt->pvt;

/* XXX We should look at how old the rest of our stream is, and if it
   is too old, then we should overwrite it entirely, otherwise we can
   get artifacts of earlier talk that do not belong */
memcpy(opvt->buf + pvt->samples, f->data.ptr, f->datalen);
pvt->samples += f->samples;

return 0;

}

static struct ast_frame lintoopus_frameout(struct ast_trans_pvt pvt) { struct opus_coder_pvt *opvt = pvt->pvt;

/* We can't work on anything less than a frame in size */
if (pvt->samples < opvt->framesize)
    return NULL;

int datalen = 0;    /* output bytes */
int samples = 0;    /* output samples */

/* Encode 160 samples (or more if it's not narrowband) */
if(opusdebug > 1)
    ast_verbose("[Opus] [Encoder #%d (%d)] %d samples, %d bytes\n", opvt->id, opvt->sampling_rate, opvt->framesize, opvt->framesize*2);
datalen = opus_encode(opvt->opus, opvt->buf, opvt->framesize, pvt->outbuf.uc, BUFFER_SAMPLES);
if(datalen < 0) {
    if(opusdebug)
        ast_verbose("[Opus] Ops! got an error encoding the Opus frame: %d (%s)\n", datalen, opus_strerror(datalen));
    return NULL;
}
samples += opvt->framesize;
pvt->samples -= opvt->framesize;
/* Move the data at the end of the buffer to the front */
if (pvt->samples)
    memmove(opvt->buf, opvt->buf + samples, pvt->samples * 2);

if(opusdebug > 1)
    ast_verbose("[Opus] [Encoder #%d (%d)]   >> Got %d samples, %d bytes\n", opvt->id, opvt->sampling_rate, opvt->multiplier*samples, datalen);

if(opvt->file)
    fwrite(opvt->buf, sizeof(int16_t), opvt->multiplier*samples, opvt->file);

return ast_trans_frameout(pvt, datalen, opvt->multiplier*samples);

}

static int opustolin_framein(struct ast_trans_pvt _pvt, struct ast_frame f) { struct opus_coder_pvt opvt = pvt->pvt; / Decode / if(opusdebug > 1) ast_verbose("[Opus] [Decoder #%d (%d)] %d samples, %d bytes\n", opvt->id, opvt->sampling_rate, f->samples, f->datalen); int error = opus_decode(opvt->opus, f->data.ptr, f->datalen, pvt->outbuf.i16, BUFFER_SAMPLES, opvt->fec); if(error < 0) { if(opusdebug) ast_verbose("[Opus] Ops! got an error decoding the Opus frame: %d (%s)\n", error, opus_strerror(error)); return -1; } pvt->samples += error; pvt->datalen += error_2;

if(opusdebug > 1)
    ast_verbose("[Opus] [Decoder #%d (%d)]   >> Got %d samples, %d bytes\n", opvt->id, opvt->sampling_rate, pvt->samples, pvt->datalen);

if(opvt->file)
    fwrite(pvt->outbuf.i16, sizeof(int16_t), pvt->samples, opvt->file);

return 0;

}

static void lintoopus_destroy(struct ast_trans_pvt arg) { struct opus_coder_pvt opvt = arg->pvt; if(opvt == NULL || opvt->opus == NULL) return; opus_encoder_destroy(opvt->opus); if(opusdebug) ast_verbose("[Opus] Destroyed encoder #%d (%d->opus)\n", opvt->id, opvt->sampling_rate); opvt->opus = NULL;

if(opvt->file)
    fclose(opvt->file);
opvt->file = NULL;

}

static void opustolin_destroy(struct ast_trans_pvt arg) { struct opus_coder_pvt opvt = arg->pvt; if(opvt == NULL || opvt->opus == NULL) return; opus_decoder_destroy(opvt->opus); if(opusdebug) ast_verbose("[Opus] Destroyed decoder #%d (opus->%d)\n", opvt->id, opvt->sampling_rate); opvt->opus = NULL;

if(opvt->file)
    fclose(opvt->file);
opvt->file = NULL;

}

/* Translators / static struct ast_translator lintoopus = { .name = "lintoopus", .newpvt = lintoopus_new, .framein = lintoopus_framein, .frameout = lintoopus_frameout, .destroy = lintoopus_destroy, .sample = slin8_sample, .desc_size = sizeof(struct opus_coder_pvt), .buffer_samples = BUFFER_SAMPLES, .buf_size = BUFFER_SAMPLES \ 2, };

static struct ast_translator lin12toopus = { .name = "lin12toopus", .newpvt = lin12toopus_new, .framein = lintoopus_framein, .frameout = lintoopus_frameout, .destroy = lintoopus_destroy, .desc_size = sizeof(struct opus_coder_pvt), .buffer_samples = BUFFER_SAMPLES, .buf_size = BUFFER_SAMPLES * 2, };

static struct ast_translator lin16toopus = { .name = "lin16toopus", .newpvt = lin16toopus_new, .framein = lintoopus_framein, .frameout = lintoopus_frameout, .destroy = lintoopus_destroy, .sample = slin16_sample, .desc_size = sizeof(struct opus_coder_pvt), .buffer_samples = BUFFER_SAMPLES, .buf_size = BUFFER_SAMPLES * 2, };

static struct ast_translator lin24toopus = { .name = "lin24toopus", .newpvt = lin24toopus_new, .framein = lintoopus_framein, .frameout = lintoopus_frameout, .destroy = lintoopus_destroy, .desc_size = sizeof(struct opus_coder_pvt), .buffer_samples = BUFFER_SAMPLES, .buf_size = BUFFER_SAMPLES * 2, };

static struct ast_translator lin48toopus = { .name = "lin48toopus", .newpvt = lin48toopus_new, .framein = lintoopus_framein, .frameout = lintoopus_frameout, .destroy = lintoopus_destroy, .desc_size = sizeof(struct opus_coder_pvt), .buffer_samples = BUFFER_SAMPLES, .buf_size = BUFFER_SAMPLES * 2, };

static struct ast_translator opustolin = { .name = "opustolin", .newpvt = opustolin_new, .framein = opustolin_framein, .destroy = opustolin_destroy, .sample = opus_sample, .desc_size = sizeof(struct opus_coder_pvt), .buffer_samples = BUFFER_SAMPLES, .buf_size = BUFFER_SAMPLES * 2, .native_plc = 1, /* FIXME: needed? */ };

static struct ast_translator opustolin12 = { .name = "opustolin12", .newpvt = opustolin12_new, .framein = opustolin_framein, .destroy = opustolin_destroy, .sample = opus_sample, .desc_size = sizeof(struct opus_coder_pvt), .buffer_samples = BUFFER_SAMPLES, .buf_size = BUFFER_SAMPLES * 2, .native_plc = 1, /* FIXME: needed? */ };

static struct ast_translator opustolin16 = { .name = "opustolin16", .newpvt = opustolin16_new, .framein = opustolin_framein, .destroy = opustolin_destroy, .sample = opus_sample, .desc_size = sizeof(struct opus_coder_pvt), .buffer_samples = BUFFER_SAMPLES, .buf_size = BUFFER_SAMPLES * 2, .native_plc = 1, /* FIXME: needed? */ };

static struct ast_translator opustolin24 = { .name = "opustolin24", .newpvt = opustolin24_new, .framein = opustolin_framein, .destroy = opustolin_destroy, .sample = opus_sample, .desc_size = sizeof(struct opus_coder_pvt), .buffer_samples = BUFFER_SAMPLES, .buf_size = BUFFER_SAMPLES * 2, .native_plc = 1, /* FIXME: needed? */ };

static struct ast_translator opustolin48 = { .name = "opustolin48", .newpvt = opustolin48_new, .framein = opustolin_framein, .destroy = opustolin_destroy, .sample = opus_sample, .desc_size = sizeof(struct opus_coder_pvt), .buffer_samples = BUFFER_SAMPLES, .buf_size = BUFFER_SAMPLES * 2, .native_plc = 1, /* FIXME: needed? */ };

/* Simple CLI interface to enable/disable debugging / static char handle_cli_opus_set_debug(struct ast_cli_entry e, int cmd, struct ast_cli_args a) { switch (cmd) { case CLI_INIT: e->command = "opus set debug"; e->usage = "Usage: opus set debug {status|none|normal|huge}\n" " Enable/Disable Opus debugging: normal only debugs setup and errors, huge debugs every single packet\n"; return NULL; case CLI_GENERATE: return NULL; }

if (a->argc != 4)
    return CLI_SHOWUSAGE;

if (!strncasecmp(a->argv[a->argc-1], "status", 6)) {
    ast_cli(a->fd, "Opus debugging %s\n", opusdebug > 1 ? "huge" : opusdebug > 0 ? "normal" : "none");
    return CLI_SUCCESS;
}
if (!strncasecmp(a->argv[a->argc-1], "huge", 4))
    opusdebug = 2;
else if (!strncasecmp(a->argv[a->argc-1], "normal", 6))
    opusdebug = 1;
else if (!strncasecmp(a->argv[a->argc-1], "none", 4))
    opusdebug = 0;
else
    return CLI_SHOWUSAGE;

ast_cli(a->fd, "Opus debugging %s\n", opusdebug > 1 ? "huge" : opusdebug > 0 ? "normal" : "none");
return CLI_SUCCESS;

}

static struct ast_cli_entry cli_opus[] = { AST_CLI_DEFINE(handle_cli_opus_set_debug, "Enable/Disable Opus debugging"), };

/* Configuration and module setup _/ static int parseconfig(int reload) { / TODO: place stuff to negotiate/enforce here */ return 0; }

static int reload(void) { if(parse_config(1)) return AST_MODULE_LOAD_DECLINE; return AST_MODULE_LOAD_SUCCESS; }

static int unload_module(void) { int res = 0;

res |= ast_unregister_translator(&opustolin);
res |= ast_unregister_translator(&lintoopus);
res |= ast_unregister_translator(&opustolin12);
res |= ast_unregister_translator(&lin12toopus);
res |= ast_unregister_translator(&opustolin16);
res |= ast_unregister_translator(&lin16toopus);
res |= ast_unregister_translator(&opustolin24);
res |= ast_unregister_translator(&lin24toopus);
res |= ast_unregister_translator(&opustolin48);
res |= ast_unregister_translator(&lin48toopus);

ast_cli_unregister_multiple(cli_opus, ARRAY_LEN(cli_opus));

return res;

}

static int load_module(void) { int res = 0;

if(parse_config(0))
    return AST_MODULE_LOAD_DECLINE;

/* 8khz (nb) */
ast_format_set(&opustolin.src_format, AST_FORMAT_OPUS, 0);
ast_format_set(&opustolin.dst_format, AST_FORMAT_SLINEAR, 0);
ast_format_set(&lintoopus.src_format, AST_FORMAT_SLINEAR, 0);
ast_format_set(&lintoopus.dst_format, AST_FORMAT_OPUS, 0);
/* 12khz (mb) */
ast_format_set(&opustolin12.src_format, AST_FORMAT_OPUS, 0);
ast_format_set(&opustolin12.dst_format, AST_FORMAT_SLINEAR12, 0);
ast_format_set(&lin12toopus.src_format, AST_FORMAT_SLINEAR12, 0);
ast_format_set(&lin12toopus.dst_format, AST_FORMAT_OPUS, 0);
/* 16khz (wb) */
ast_format_set(&opustolin16.src_format, AST_FORMAT_OPUS, 0);
ast_format_set(&opustolin16.dst_format, AST_FORMAT_SLINEAR16, 0);
ast_format_set(&lin16toopus.src_format, AST_FORMAT_SLINEAR16, 0);
ast_format_set(&lin16toopus.dst_format, AST_FORMAT_OPUS, 0);
/* 24khz (swb) */
ast_format_set(&opustolin24.src_format, AST_FORMAT_OPUS, 0);
ast_format_set(&opustolin24.dst_format, AST_FORMAT_SLINEAR24, 0);
ast_format_set(&lin24toopus.src_format, AST_FORMAT_SLINEAR24, 0);
ast_format_set(&lin24toopus.dst_format, AST_FORMAT_OPUS, 0);
/* 48khz (fb) */
ast_format_set(&opustolin48.src_format, AST_FORMAT_OPUS, 0);
ast_format_set(&opustolin48.dst_format, AST_FORMAT_SLINEAR48, 0);
ast_format_set(&lin48toopus.src_format, AST_FORMAT_SLINEAR48, 0);
ast_format_set(&lin48toopus.dst_format, AST_FORMAT_OPUS, 0);

res |= ast_register_translator(&opustolin);
res |= ast_register_translator(&lintoopus);
res |= ast_register_translator(&opustolin12);
res |= ast_register_translator(&lin12toopus);
res |= ast_register_translator(&opustolin16);
res |= ast_register_translator(&lin16toopus);
res |= ast_register_translator(&opustolin24);
res |= ast_register_translator(&lin24toopus);
res |= ast_register_translator(&opustolin48);
res |= ast_register_translator(&lin48toopus);

ast_cli_register_multiple(cli_opus, sizeof(cli_opus) / sizeof(struct ast_cli_entry));

return res;

}

AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Opus Coder/Decoder", .load = load_module, .unload = unload_module, .reload = reload, );

lminiero commented 10 years ago

Ah ok, so your issue is only with respect to the rtpmap being negotiated. Ok, so please disregard my suggestion.

My first comment would be: tell the developers of the clients using opus/8000 to update them and use opus/48000/2 instead (which as you said works fine with those who do), because they're not following the standard and cannot complain if it doesn't work... ;-)

Anyway, if you want it to work with those clients as well, you'll have to modify a bit chan_sip.c and not codec_opus.c. I don't think the patch validates the opus/48000/2 when receiving calls: if I remember correctly, it just checks if opus is there, and if it is, it replies with opus/48000/2 as it should. Since you want thus behaviour to be dynamic (reply opus/48000/2 when receiving opus/48000/2, and reply opus/8000 when opus/8000 is received) you'll have to modify the chan_sip structures to remember what was negotiated. So, when it's time to reply, where the "Opus mandates 2 channels in rtpmap" line is you have to also check the value you stored before, and only use the correct standard procedure if the caller did as well, and use the normal one otherwise.

dki123 commented 10 years ago

Hey Man,

we did what you suggested and still having an issue with voice only . Let me describe the concerned and call flow.

There are 2 SIP client in my sip.conf

1) 1234 - OPUS 2) 5678 - ULAW

Now when My partner client send me call for 5678 with following INVITE

INVITE sip:5678@172.18.100.222 SIP/2.0 Call-ID: b21f9f982d0972d00dcdb848aeaf9d3e@192.168.1.112 CSeq: 1910 INVITE From: "1234" sip:1234@172.18.100.222;tag=4032765025 To: sip:5678@172.18.100.222 Via: SIP/2.0/UDP 192.168.1.112:32950;branch=z9hG4bK0a1f581c9f0104e3b1b5cfb0f896c210353730;rport Max-Forwards: 70 Contact: "1234" sip:1234@192.168.1.112:32950;transport=udp Content-Type: application/sdp Content-Length: 394

v=0 o=- 1401776970908 1401776970910 IN IP4 192.168.1.112 s=- c=IN IP4 192.168.1.112 t=0 0 m=audio 38024 RTP/AVP 98 96 97 3 0 8 127 a=rtpmap:98 opus/8000 a=fmtp:98 ptime=20; maxplaybackrate=8000; sprop-maxcapturerate=8000 a=rtpmap:96 GSM-EFR/8000 a=rtpmap:97 AMR/8000 a=rtpmap:3 GSM/8000 a=rtpmap:0 PCMU/8000 a=rtpmap:8 PCMA/8000 a=rtpmap:127 telephone-event/8000 a=fmtp:127 0-15 <------------->

Asterisk Reply with following 200 OK <-------------> SIP/2.0 200 OK Via: SIP/2.0/UDP 192.168.1.112:32950;branch=z9hG4bK0a1f581c9f0104e3b1b5cfb0f896c210353730;received=67.160.248.223;rport=32950 From: "1234" sip:1234@172.18.100.222;tag=4032765025 To: sip:5678@172.18.100.222;tag=as062baa6d Call-ID: b21f9f982d0972d00dcdb848aeaf9d3e@192.168.1.112 CSeq: 1910 INVITE Server: Asterisk-11.9.0 Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, SUBSCRIBE, NOTIFY, INFO, PUBLISH, MESSAGE Supported: replaces, timer Contact: sip:5678@172.18.100.222:5060 Content-Type: application/sdp Content-Length: 345

v=0 o=root 1385027278 1385027278 IN IP4 172.18.100.222 s=root c=IN IP4 172.18.100.222 t=0 0 m=audio 23436 RTP/AVP 98 127 a=rtpmap:98 opus/8000 a=maxptime:60 a=fmtp:98 maxplaybackrate=8000; stereo=0; sprop-stereo=0; useinbandfec=0 a=rtpmap:127 telephone-event/8000 a=fmtp:127 0-16 a=silenceSupp:off - - - - a=ptime:20 a=sendrecv

Once giving this. client not understand this and would not send any media . Hope you understand I think we need to send same fmtp too????

lminiero commented 10 years ago

Hi,

from the dumps I can see that's what you wanted: the non-standard client sending a opus/8000 rtpmap, and Asterisk doing the same instead of replying with opus48000/2. Why would the client not understand this, if that's exactly what it's doing in the first place? I'm afraid you'll have to ask the developers of that client what they're expecting, or tell them to align to the standard.

lminiero commented 10 years ago

Closing as that's not an issue with the patch.