janus模块介绍-SIP Gateway

这篇具有很好参考价值的文章主要介绍了janus模块介绍-SIP Gateway。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

模块启动

默认的SIP GateWay也是https协议,端口为8088或者8089
如果需要在自己搭建的测试服务上测试SIP GateWay模块,则也需要修改为wss
具体改动如下: 找到/opt/janus/share/janus/demos/siptest.js

var server = "wss://" + window.location.hostname + ":8989";

janus unknown request 'subscribe,# janus,linux,服务器,janus,sip
然后重启janus服务,执行

/opt/janus/bin/janus --debug-level=5 --log-file=$HOME/janus-log

打开测试网页,在demos中找到SIP Gateway,点击start开始运行。
janus unknown request 'subscribe,# janus,linux,服务器,janus,sip
janus unknown request 'subscribe,# janus,linux,服务器,janus,sip
点击f12可以看到demo中Using WebSockets to contact Janus: wss://49.232.250.45:8989
janus unknown request 'subscribe,# janus,linux,服务器,janus,sip

模块基本说明

这是Janus的一个简单SIP插件,允许WebRTC对等方在SIP服务器(例如Asterisk)注册,并通过Janus实例调用SIP用户代理。具体地,当连接到插件时,请求对等方提供其SIP服务器证书,即SIP服务器的地址和其用户名/密码。这导致插件在SIP服务器处注册,并代表网络对等方充当SIP客户端。大多数SIP状态和生存期都被插件屏蔽,只有相关事件(例如INVITE和BYE)和功能(呼叫、挂断)可供网络对等方使用:对等方可以在SIP服务器上呼叫扩展或等待传入的INVITE,并且在呼叫期间可以发送DTMF音调。调用可以执行纯RTP或SDES-SRTP。
该插件背后的概念是允许与同一对等方相关联的不同网页,从而允许同一SIP用户同时连接到插件,但只进行一次SIP REGISTER。这同样适用于呼叫:虽然传入的呼叫将被通知给与对等方相关的所有web UI,但只有一个能够接听和接听,这与SIP分叉的工作方式非常相似,但不需要在同一个地方分叉。然而,这一特定功能尚未实现。

SIP Plugin API

我们可以在SIP插件API中发送的所有请求都是异步的,这意味着所有响应(成功和错误)都将作为同一事务的事件传递。
支持的请求包括注册、注销、调用、接受、拒绝、信息、消息、dtmf_info、订阅、取消订阅、传输、录制、保留、取消保留、更新和挂断。顾名思义,register可以用于在SIP注册器处注册用户名以调用和被调用,而unregister则注销该用户名;call用于通过插件向不同的SIP URI发送INVITE,而accept和dence用于在邀请而不是邀请的情况下接受或拒绝呼叫;接送负责有人接送和无人接送(更多详细信息,请参阅有人接送或无人接送);hold和unhold可以分别用于将呼叫挂起和恢复呼叫;info允许您发送一个通用的SIP info请求,而dtmf_info则专注于将info用于dtmf;message是用于向另一个对等方发送SIP消息的方法;subscribe和unsubscribe用于处理SIP事件,即发送subscribe请求,该请求将导致NOTIFY异步事件;相反,录音用于将对话记录到一个或多个.mjr文件中(取决于您想要录制的方向);更新允许您更新现有会话(例如,进行重新协商或强制ICE重新启动);最后,挂断可以用于在任何时候终止通信,或者挂断(BYE)正在进行的呼叫,或者取消/拒绝(cancel/BYE)尚未开始的呼叫。
无论请求如何,错误响应或事件的格式始终如下:

{
        "sip" : "event",
        "error_code" : <numeric ID, check Macros below>,
        "error" : "<error description as a string>"
}

请注意,上面的错误语法指的是插件API消息传递,而不是响应于SIP请求而获得的SIP错误代码,这些错误代码是使用不同的语法通知的:

{
        "sip" : "event",
        "result" : {
                "event" : "<name of the error event>",
                "code" : <SIP error code>,
                "reason" : "<SIP error reason>",
                "reason_header" : "<Reason header text; optional>",
                "reason_header_protocol" : "<Reason header protocol; optional>",
                "reason_header_cause" : "<Reason header cause code; optional>"
        }
}

对于可用的请求,您可以使用注册请求发送一个SIP REGISTER。更准确地说,注册请求可能会导致SIP register,因为这种方法实际上提供了无需注册即可开始使用SIP帐户的方法。例如,所谓的访客注册就是这样的情况:如果你注册为访客,这意味着你将使用From标头中提供的SIP URI进行呼叫,但实际上你不会发送SIP register;这对于向不需要注册的服务(例如,IVR系统或会议桥)发出的呼叫特别有用,但也意味着除非对等方知道您的私人SIP地址,否则您将无法接收呼叫。注册为帮助者时也不会发送SIP REGISTER:正如我们稍后将解释的,帮助者会话仅用于方便使用同一帐户设置同时SIP呼叫。
也就是说,注册请求的格式必须如下:

{
        "request" : "register",
        "type" : "<if guest or helper, no SIP REGISTER is actually sent; optional>",
        "send_register" : <true|false; if false, no SIP REGISTER is actually sent; optional>,
        "force_udp" : <true|false; if true, forces UDP for the SIP messaging; optional>,
        "force_tcp" : <true|false; if true, forces TCP for the SIP messaging; optional>,
        "sips" : <true|false; if true, configures a SIPS URI too when registering; optional>,
        "rfc2543_cancel" : <true|false; if true, configures sip client to CANCEL pending INVITEs without having received a provisional response first; optional>,
        "username" : "<SIP URI to register; mandatory>",
        "secret" : "<password to use to register; optional>",
        "ha1_secret" : "<prehashed password to use to register; optional>",
        "authuser" : "<username to use to authenticate (overrides the one in the SIP URI); optional>",
        "display_name" : "<display name to use when sending SIP REGISTER; optional>",
        "user_agent" : "<user agent to use when sending SIP REGISTER; optional>",
        "proxy" : "<server to register at; optional, as won't be needed in case the REGISTER is not goint to be sent (e.g., guests)>",
        "outbound_proxy" : "<outbound proxy to use, if any; optional>",
        "headers" : "<object with key/value mappings (header name/value), to specify custom headers to add to the SIP REGISTER; optional>",
        "contact_params" : "<array of key/value objects, to specify custom Contact URI params to add to the SIP REGISTER; optional>",
        "incoming_header_prefixes" : "<array of strings, to specify custom (non-standard) headers to read on incoming SIP events; optional>",
        "refresh" : "<true|false; if true, only uses the SIP REGISTER as an update and not a new registration; optional>",
        "master_id" : "<ID of an already registered account, if this is an helper for multiple calls (more on that later); optional>",
        "register_ttl" : "<integer; number of seconds after which the registration should expire; optional>"
}

注册事件将被发回,因为这是一个异步请求。
如果需要,此请求将向具有正确凭据的指定服务器发起SIP REGISTER。401和407响应将被自动处理,因此错误将不会被通知回呼叫者,除非它们是决定性的(例如,错误的凭证)。注册失败将返回名称为registration_failed的错误。相反,成功注册会在注册事件中得到通知,格式如下:

{
        "sip" : "event",
        "result" : {
                "event" : "registered",
                "username" : <SIP URI username>,
                "register_sent" : <true|false, depending on whether a REGISTER was sent or not>,
                "master_id" : <unique ID of this registered session in the plugin, if a potential master>
        }
}

要注销,只需发送一个不带其他参数的注销请求:

{
        "request" : "unregister"
}

与以前一样,将发回一个注销事件。和以前一样,这也会发送一个SIP REGISTER,以防它最初被发送。在未注册的事件中通知成功注销:

{
        "sip" : "event",
        "result" : {
                "event" : "unregistered",
                "username" : <SIP URI username>,
                "register_sent" : <true|false, depending on whether a REGISTER was sent or not>
        }
}

注册后,您可以拨打电话或等待来电:请注意,如果您选择从不发送REGISTER,您将无法接听来电。
要发送SIP INVITE,您可以使用呼叫请求,其格式如下:

{
        "request" : "call",
        "call_id" : "<user-defined value of Call-ID SIP header used in all SIP requests throughout the call; optional>",
        "uri" : "<SIP URI to call; mandatory>",
        "refer_id" : <in case this is the result of a REFER, the unique identifier that addresses it; optional>,
        "headers" : "<object with key/value mappings (header name/value), to specify custom headers to add to the SIP INVITE; optional>",
        "srtp" : "<whether to mandate (sdes_mandatory) or offer (sdes_optional) SRTP support; optional>",
        "srtp_profile" : "<SRTP profile to negotiate, in case SRTP is offered; optional>",
        "secret" : "<password to use to call, only needed in case authentication is needed and no REGISTER was sent; optional>",
        "ha1_secret" : "<prehashed password to use to call, only needed in case authentication is needed and no REGISTER was sent; optional>",
        "authuser" : "<username to use to authenticate as to call, only needed in case authentication is needed and no REGISTER was sent; optional>",
        "autoaccept_reinvites" : <true|false, whether we should blindly accept re-INVITEs with a 200 OK instead of relaying the SDP to the application; optional, TRUE by default>
}

调用事件将被发回,因为这是一个异步请求。
请注意,此请求必须与JSEP优惠相关联:无法通过SIP插件发送无优惠INVITE。这将生成一个SIP INVITE,并根据指示进行发送。虽然100秒Trying不会通知回用户,但在振铃事件中,180秒将会响铃:

{
        "sip" : "event",
        "call_id" : "<value of SIP Call-ID header for related call>",
        "result" : {
                "event" : "ringing",
                "headers" : "<object with key/value strings; custom headers extracted from SIP event based on incoming_header_prefix defined in register request; optional>"
        }
}

如果呼叫被拒绝或发生任何其他错误,则会发回挂断错误事件。如果呼叫被接受,则接受的事件将与被叫方发起的JSEP应答一起发送回用户:

{
        "sip" : "event",
        "call_id" : "<value of SIP Call-ID header for related call>",
        "result" : {
                "event" : "accepted",
                "username" : "<SIP URI of the callee>",
                "headers" : "<object with key/value strings; custom headers extracted from SIP event based on incoming_header_prefix defined in register request; optional>"
        }
}

在这一点上,除了PeerConnection相关的考虑因素外,可以认为该调用已建立。SIP插件会自动发送SIP ACK,因此不需要应用程序手动执行任何操作。
请注意,SIP插件通过183个响应响应支持早期媒体。在接收到183响应的情况下,在进度事件中,它将与被叫方发起的JSEP应答一起发送回用户:

{
        "sip" : "event",
        "call_id" : "<value of SIP Call-ID header for related call>",
        "result" : {
                "event" : "progress",
                "username" : "<SIP URI of the callee>",
                "headers" : "<object with key/value strings; custom headers extracted from SIP event based on incoming_header_prefix defined in register request; optional>"
        }
}

如果呼叫者收到进度事件,以下接受的事件将不包含JSEP应答,因为在“会话进度”事件中收到的应答将作为会话的SDP应答。
请注意,您只使用call来开始对话,即第一次INVITE。要通过重新邀请更新会话,例如,重新协商会话以添加/删除流或强制ICE重新启动,您不使用调用,而是使用另一个名为update的请求。这个请求不需要任何参数,因为整个上下文都是从会话的当前状态派生的。不过,作为重新谈判的一部分,它确实需要新的JSEP报价。

{
        "request" : "update"
}

更新事件将被发回,因为这是一个异步请求。
虽然呼叫请求允许您发送SIP INVITE(更新请求允许您更新现有会话),但也有一种方法可以对SIP INVITEs做出反应,即处理传入呼叫。传入呼叫通过传入呼叫事件通知应用程序:

{
        "sip" : "event",
        "call_id" : "<value of SIP Call-ID header for related call>",
        "result" : {
                "event" : "incomingcall",
                "username" : "<SIP URI of the caller>",
                "displayname" : "<display name of the caller, if available; optional>",
                "callee" : "<SIP URI that was called (in case the user is associated with multiple public URIs)>",
                "referred_by" : "<SIP URI header conveying the identity of the transferor, if this is a transfer; optional>",
                "replaces" : "<call-ID of the call that this is supposed to replace, if this is an attended transfer; optional>",
                "srtp" : "<whether the caller mandates (sdes_mandatory) or offers (sdes_optional) SRTP support; optional>",
                "headers" : "<object with key/value strings; custom headers extracted from SIP event based on incoming_header_prefix defined in register request; optional>"
        }
}

来电可能会也可能不会附带JSEP报价,这取决于来电者发送的是无报价邀请还是常规邀请。无论哪种方式,您都可以通过接受请求来接受来电:

{
        "request" : "accept",
        "srtp" : "<whether to mandate (sdes_mandatory) or offer (sdes_optional) SRTP support; optional>",
        "headers" : "<object with key/value mappings (header name/value), to specify custom headers to add to the SIP OK; optional>"
        "autoaccept_reinvites" : <true|false, whether we should blindly accept re-INVITEs with a 200 OK instead of relaying the SDP to the browser; optional, TRUE by default>
}

由于这是一个异步请求,将发回一个接受事件。
这将导致200 OK被发送回呼叫者。接受请求必须始终附有JSEP回复(如果incomingcall事件包含要约)或要约(如果是无要约邀请)。在前一种情况下,接受的事件将被发回,只是为了确认呼叫可以被视为已建立;相反,在后一种情况下,接受事件将被发送回,而接受的事件只会在稍后,只要在呼叫者发送回的SIP ACK中有JSEP应答可用,就紧随其后。
请注意,如果您在另一个呼叫中接到来电,您将不会收到incomingcall事件,而是收到missed_call事件,这只是一个通知,因为在SIP插件中,无法在同一句柄上同时进行两个呼叫:

{
        "sip" : "event",
        "call_id" : "<value of SIP Call-ID header for related call>",
        "result" : {
                "event" : "missed_call",
                "caller" : "<SIP URI of the caller>",
                "displayname" : "<display name of the caller, if available; optional>",
                "callee" : "<SIP URI that was called (in case the user is associated with multiple public URIs)>"
        }
}

此外,您只能使用accept来回答第一个INVITE。要接受重新邀请(将通过updatingcall事件通知),您不使用accept,而是使用之前引入的更新。这个请求不需要任何参数,因为整个上下文都是从会话的当前状态派生的。不过,作为重新谈判的一部分,它确实需要新的JSEP答案来提供。和以前一样,由于这是一个异步请求,因此会发回一个更新的事件。
关闭会话取决于调用状态。如果您有不想接听的来电,请使用拒绝请求;在所有其他情况下,请改用挂断请求。这两个请求都不需要额外的参数,因为整个上下文可以从插件中会话的当前状态中提取:

{
        "request" : "decline",
        "code" : <SIP code to be sent, if not set, 486 is used; optional>",
        "headers" : "<object with key/value mappings (header name/value), to specify custom headers to add to the SIP request; optional>"
}
{
        "request" : "hangup",
        "headers" : "<object with key/value mappings (header name/value), to specify custom headers to add to the SIP BYE; optional>"
}

由于这些都是异步请求,您将得到一个响应事件:如果使用了谢绝,则拒绝;如果使用了挂起,则挂起。
如前所述,当呼叫被拒绝或挂断时,会发送一个挂断事件,这基本上是一个SIP错误事件通知,因为它包括代码和原因。例如,常规BYE将被通知200和SIP BYE,尽管也可以提供更详细的描述。
建立会话后,可以使用不同的请求与会话进行交互。
首先,您可以使用挂起请求将呼叫挂起。默认情况下,此请求将向对等方发送一个新的INVITE,其中包含媒体的sendonly方向,但如果您想设置不同的方向(recvonly或inactive),也可以通过传递direction属性来实现:

{
        "request" : "hold",
        "direction" : "<sendonly, recvonly or inactive>"
}

持有者方不涉及WebRTC重新协商,因为这只会触发SIP方的重新INVITE。要从挂起状态移除调用,只需向插件发送一个取消挂起的请求,该请求不需要其他属性:

{
        "request" : "unhold"
}

并且将恢复在保持呼叫之前在SDP中设置的媒体方向。
消息请求允许您向对等方发送SIP message。默认情况下,在活动呼叫期间,它在对话框中发送。但是,如果用户已经注册,它也可能被发送到对话框之外。在这种情况下,uri参数是必需的。

{
        "request" : "message",
        "call_id" : "<user-defined value of Call-ID SIP header used to send the message; optional>",
        "content_type" : "<content type; optional>"
        "content" : "<text to send>",
        "uri" : "<SIP URI of the peer; optional; if set, the message will be sent out of dialog>",
        "headers" : "<object with key/value mappings (header name/value), to specify custom headers to add to the SIP MESSAGE; optional>"
}

messagesend事件将被发回。相反,传入的SIP消息会在消息事件中得到通知:

{
        "sip" : "event",
        "result" : {
                "event" : "message",
                "sender" : "<SIP URI of the message sender>",
                "displayname" : "<display name of the sender, if available; optional>",
                "content_type" : "<content type of the message>",
                "content" : "<content of the message>",
                "headers" : "<object with key/value strings; custom headers extracted from SIP event based on incoming_header_prefix defined in register request; optional>"
        }
}

传递后,消息传递事件将与SIP服务器响应一起发送回。用于跟踪邮件的传递状态。

{
        "sip" : "event",
        "call_id" : "<value of SIP Call-ID header for related message>",
        "result" : {
                "event" : "messagedelivery",
                "code" : "<SIP error code>",
                "reason" : "<SIP error reason>",
        }
}

SIP INFO的工作方式几乎相同,只是您使用一个对一个对等体的信息请求:

{
        "request" : "info",
        "type" : "<content type>"
        "content" : "<message to send>",
        "headers" : "<object with key/value mappings (header name/value), to specify custom headers to add to the SIP INFO; optional>"
}

将发回一个infosend事件。相反,传入的SIP info会在信息事件中得到通知:

{
        "sip" : "event",
        "result" : {
                "event" : "info",
                "sender" : "<SIP URI of the message sender>",
                "displayname" : "<display name of the sender, if available; optional>",
                "type" : "<content type of the message>",
                "content" : "<content of the message>",
                "headers" : "<object with key/value strings; custom headers extracted from SIP event based on incoming_header_prefix defined in register request; optional>"
        }
}

正如预期的那样,使用SUBSCRIBE和NOTIFY机制也支持SIP事件。要做到这一点,您需要使用订阅请求,该请求的格式如下:

{
        "request" : "subscribe",
        "call_id" : "<user-defined value of Call-ID SIP header used in all SIP requests throughout the subscription; optional>",
        "event" : "<the event to subscribe to, e.g., 'message-summary'; mandatory>",
        "accept" : "<what should be put in the Accept header; optional>",
        "to" : "<who should be the SUBSCRIBE addressed to; optional, will use the user's identity if missing>",
        "subscribe_ttl" : "<integer; number of seconds after which the subscription should expire; optional>",
        "headers" : "<array of key/value objects, to specify custom headers to add to the SIP SUBSCRIBE; optional>"
}

如果subscribe请求被接受,则会发回订阅事件,然后是subscribe_succeed,如果事务失败,则会返回subscribe_failed。相反,传入的SIP NOTIFY事件在通知事件中得到通知:

{
        "sip" : "event",
        "call_id" : "<value of SIP Call-ID header for related subscription>",
        "result" : {
                "event" : "notify",
                "notify" : "<name of the event that the user is subscribed to, e.g., 'message-summary'>",
                "substate" : "<substate of the subscription, e.g., 'active'>",
                "content-type" : "<content-type of the message>"
                "content" : "<content of the message>",
                "headers" : "<object with key/value strings; custom headers extracted from SIP event based on incoming_header_prefix defined in register request; optional>"
        }
}

您还可以录制SIP调用,它的工作原理与VideoCall插件的工作原理几乎相同。具体来说,您可以使用录制请求来启动或停止录制,使用以下语法:

{
        "request" : "recording",
        "action" : "<start|stop, depending on whether you want to start or stop recording something>"
        "audio" : <true|false; whether or not our audio should be recorded>,
        "video" : <true|false; whether or not our video should be recorded>,
        "peer_audio" : <true|false; whether or not our peer's audio should be recorded>,
        "peer_video" : <true|false; whether or not our peer's video should be recorded>,
        "send_peer_pli" : <true|false; whether or not send PLI to request keyframe from peer>,
        "filename" : "<base path/filename to use for all the recordings>"
}

正如您所看到的,这意味着对话的双方是分开录制的,音频和视频流也是如此(如果可用)。您可以选择要记录的内容,以防您只对子集感兴趣。文件名部分只是一个前缀,指示将用于最多四个可能需要启用的录制的实际文件名。
如果请求成功,则会发回已记录的更新事件。

Simultaneous SIP calls using the same account

如前几节所述,使用Janus句柄附加到SIP插件意味着代表用户或应用程序创建SIP堆栈:这通常意味着注册帐户,并能够启动或接收调用、处理订阅等。这也意味着,由于在Janus中,每个核心句柄只能与单个PeerConnection相关联,因此每个SIP帐户每次仅限于一个调用:如果用户已经在SIP会话中,并且另一个调用传入,则会自动拒绝,并显示486 Busy。
虽然通常不是什么大问题,但在某些用例中,支持多个并发调用是有意义的,并且可以从一个无缝地切换到另一个。这在使用所谓的助手会话的SIP插件中是可能的。具体来说,助手会话在假设存在正常注册的主会话(即“常规”SIP插件句柄)的情况下工作,并且这些助手会话可以简单地与之关联:任何时候需要另一个并发调用,如果主会话繁忙,则可以使用其中一个助手;可用的助手会话越多,可以建立的同时调用就越多。
其工作方式很简单:
您以通常的方式创建SIP会话,并在那里发送常规注册表;这将是主会话,并在成功注册时返回master_id;
对于要添加的每个助手,您将新的Janus句柄附加到SIP插件,并发送一个类型为“helper”的寄存器,并提供与主会话相同的用户名,以及引用主会话的master_id属性;
此时,新的助手与主机相关联,这意味着它可以用于启动新的调用或接收与主会话完全相同的调用,并使用相同的帐户信息、凭据等。
请注意,一旦主服务器注销,或者它所在的Janus句柄被分离,与它相关的所有助手会话也会自动删除。具体来说,插件将强制分离相关句柄。如果您需要再次注册,并希望在那里也有一些助手,您将不得不再次添加他们。
如果您想在实践中看到这一点,SIP插件演示有一个“隐藏”函数,您可以从JavaScript控制台调用该函数来玩助手:调用addHelper()函数将添加一个新的助手,并显示其他控件。您可以根据需要添加任意数量的辅助对象。

Attended and blind transfers

Janus SIP插件支持有人参与和盲传输,并且这样做主要依赖于多个调用功能:因此,请确保您已经阅读并熟悉关于使用相同帐户进行同步SIP调用的部分。
大多数与传输相关的功能都基于上一节中已经记录的现有消息和事件,但有几个方面需要注意。首先,如果您是传输者,则需要使用名为transfer的新请求,该请求允许您向受让者发送SIPREFER,以便到达不同的目标。传输请求的格式必须如下所示:

{
        "request" : "transfer",
        "uri" : "<SIP URI to send the transferee too>",
        "replace" : "<call-ID of the call this attended transfer is supposed to replace; default is none, which means blind/unattended transfer>"
}

无论是盲传输(无替换调用)还是有人参与传输,都将发回传输事件,因为这是一个异步请求。进一步的更新将以NOTIFY相关事件的形式出现,因为REFER隐式创建订阅。
相反,REFER的接收者将接收一个名为transfer的异步事件,其中包含它需要知道的信息。事实上,SIP插件不会自动执行任何操作:传入的REFER被通知给应用程序,以便它可以决定是否跟踪传输。事件的语法如下:

{
        "sip" : "event",
        "result" : {
                "event" : "transfer",
                "refer_id" : <unique ID, internal to Janus, of this referral>,
                "refer_to" : "<SIP URI to call>",
                "referred_by" : "<SIP URI SIP URI header conveying the identity of the transferor; optional>",
                "replaces" : "<call-ID of the call this transfer is supposed to replace; optional, and only present for attended transfers>",
                "headers" : "<object with key/value strings; custom headers extracted from SIP event based on incoming_header_prefix defined in register request; optional>"
        }
}

该列表中最重要的属性是refer_id,因为如果传输被接受,则该值必须包含在调用请求中以调用目标:事实上,这是SIP插件必须将新的传出调用与前一个传输请求相关联的唯一方法,从而能够通过notify事件通知传输者调用的进展情况。请注意,如果受让人决定跟踪转移请求,并且他们已经在通话中(例如,与转发器),则他们必须为此目的使用不同的句柄,例如,通过使用相同帐户部分的同步SIP呼叫中描述的助手。
传输目标将完全像前面讨论的那样接收调用,不同的是,出于信息目的,它可能包含或不包含referred_by属性。就像受让人一样,如果他们已经在调用中,则应由应用程序创建一个助手来设置一个新的Janus句柄以接受传输。
请注意,插件不会将涉及的调用置于等待状态,或自动关闭打算由传输替换的调用。所有这些都是应用程序的责任,因此开发人员应该相应地对事件做出反应。文章来源地址https://www.toymoban.com/news/detail-861779.html

到了这里,关于janus模块介绍-SIP Gateway的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • GB28181协议--SIP协议介绍

      SIP(Session Initiation Protocol,会话初始协议)是一个用于建立、更改和终止多媒体会话的应用层控制协议,其中的会话可以是IP电话、多媒体会话或多媒体会议(GB28181安防使用的是SIP协议)。SIP是IETF多媒体数据和控制体系结构的核心协议。其主要目的是为了解决IP网中的信

    2023年04月23日
    浏览(37)
  • 煤矿调度IP语音对讲广播模块一键求助对讲矿用调度通信系统SIP语音对讲求助终端

     SV-2101VP /  SV-2103VP 系列网络音频模块,所有外部连接采用端子,电源采用2.0mm的端子,网络采用标准RJ45连接器,其他都是1.25mm的连接器。 端口类型定义 P ———— 电源 AI ———— 模拟输入(在这里是音频输入) AO ———— 模拟输出(在这里是音频输出) I ———— 数

    2024年02月12日
    浏览(30)
  • wget数据下载失败:HTTP request sent, awaiting response... 401 Unauthorized Unknown authentication

    去掉–auth-no-challenge=on,改为 这个只是一种解决方案,wget在Windows上是有些问题的,有的可以解决,但是在有的电脑上不行,大家请多做尝试吧

    2024年02月13日
    浏览(30)
  • Linux 编译内核模块出现--Unknown symbol mcount

    Linux suse: 在编译SUSE Linux Enterprise Server 12 SP时,使用低版本的docker镜像编译内核模块时,加载内核模块时出现: 加载内核模块时: (1) 指示系统可能受到 Spectre V2 漏洞的影响,并且正在加载的模块没有使用 retpoline 编译器进行编译。 Spectre V2(CVE-2017-5715)是 Spectre 漏洞家族

    2024年02月11日
    浏览(42)
  • janus-Gateway的服务端部署

    需求是前后端的 webRTC 推拉流,但是后端用的是c++,于是使用了这个库做视频流的推送和拉取,记录踩坑过程。 如果你也需要自己部署janus的服务端并在前端拉流测试,希望对你有所帮助。 由于janus的服务器搭建需要linux环境,源码并不支持windows,因此需要准备局域网下的另

    2024年02月15日
    浏览(14)
  • python—requests模块详解

    1、requests简介 requests是一个很实用的Python HTTP客户端库,爬虫和测试服务器响应数据时经常会用到,它是python语言的第三方的库,专门用于发送HTTP请求,使用起来比urllib更简洁也更强大。 2、requests库的安装 方法1:命令行安装 windows操作系统:pip install requests Mac操作系统:p

    2024年02月07日
    浏览(34)
  • python requests模块

    目录 一:介绍 二:发送get请求 三:发送post请求 四:发送put请求 五:发送delele请求 六:响应信息 一:介绍 requests 是 Python 中的一个非常流行的 HTTP 客户端库,用于发送 HTTP 请求。它使得发送 GET、POST、PUT、DELETE 等请求变得非常简单。 二:发送get请求 import requests      #

    2024年01月20日
    浏览(29)
  • Android单编模块报FAILED: ninja: unknown target ‘MODULES-IN-vendor错误解决

    有时我们需要单编Android AOSP一个APK或库文件或二进制,用来调试。 但可能这个模块本身是不参与系统整编编译的。我们在使用mmm或mm单独编译时就会报这个错误。 在检查Android.mk或Android.bp无误后,就要怀疑是不是这个目录的上级目录是不是没有包含这个目录的Android.mk,导致编

    2024年02月04日
    浏览(31)
  • 自学爬虫—作业1—requests模块

    视频: 肯德基地址查询,爬某个,获取下面的所有page的信息,存到一个json或者txt。 关键点 ,(1)每一个ajax的请求第一个键值对就是所有获得的地址的总数,然后充分利用这个信息。(2)对于json对于[]  部分可以看成数组,对于{}部分可以看成字典,用key取值。

    2024年02月07日
    浏览(29)
  • Python爬虫之requests模块

    requests文档http://docs.python-requests.org/zh_CN/latest/index.html 1、requests模块的作用: 发送http请求,获取响应数据 2、requests模块是一个第三方模块,需要在你的python(虚拟)环境中额外安装 pip/pip3 install requests 3、requests模块发送get请求 需求:通过requests向百度首页发送请求,获取该页面

    2024年02月09日
    浏览(33)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包