Giter VIP home page Giter VIP logo

Comments (69)

ibc avatar ibc commented on September 27, 2024

This is of course a planned featured, but currently WebRTC specs does not easily allow it (or it does not make easy to implement it at SIP level since WebRTC just allows closing the media flow instead).

from jssip.

ibc avatar ibc commented on September 27, 2024

If WebRTC does not provide a emchanism for getting a SDP with "hold" enabled, then that must be done at application level.

from jssip.

AlskiOnTheWeb avatar AlskiOnTheWeb commented on September 27, 2024

OK. One thing I do offer in my other applications that could be added to JsSIP would be a mute/unmute on the Session object. It would simply enable or disable the local streams that are sending media temporarily.

Date: Sun, 10 Feb 2013 04:43:54 -0800
From: [email protected]
To: [email protected]
CC: [email protected]
Subject: Re: [JsSIP] Add SIP hold / retrieve mechanics to the Session (#46)

If WebRTC does not provide a emchanism for getting a SDP with "hold" enabled, then that must be done at application level.

          —

          Reply to this email directly or view it on GitHub..

from jssip.

saghul avatar saghul commented on September 27, 2024

@AlskiOnTheWeb Muting is something that applies to streams, not sessions. Right now JsSIP doesn't expose them with any kind of API. There are plans to do this, but adding them to the sessions feels like a hack.

from jssip.

jfend avatar jfend commented on September 27, 2024

Are there any plans to try and implement some sort of hold/unhold functionality in the near future? I understand the difficulties of it as you have explained... https://www.w3.org/Bugs/Public/show_bug.cgi?id=20816

from jssip.

saghul avatar saghul commented on September 27, 2024

We do have plans, yes, but unfortunately Amazon doesn't sell 24h-extra-per-day ;-)

from jssip.

jfend avatar jfend commented on September 27, 2024

I understand, thanks. :)

from jssip.

ibc avatar ibc commented on September 27, 2024

It is being added into "develop" branch. Let's close this issue as the feature is already being implemented.

from jssip.

ISkomorokh avatar ISkomorokh commented on September 27, 2024

I'm sorry, but there are no code related to hold/unhold in develop branch. Do I miss something?

from jssip.

jmillan avatar jmillan commented on September 27, 2024

Yep,

To be submitted into develop. You can try it using the hold branch.

from jssip.

ISkomorokh avatar ISkomorokh commented on September 27, 2024

Thanks!
Do you have some scheduled time to move it to develop branch?

from jssip.

jmillan avatar jmillan commented on September 27, 2024

It will be done by next week presumably. Feel free to give it a try meanwhile by using the hold branch directly.

from jssip.

ISkomorokh avatar ISkomorokh commented on September 27, 2024

I've tried but I get exceptions when I call hold or unhold. Browser - Chrome 31.0.1650.63 m. Asterisk 11.6.

During build using grunt I have got:
Running "concat:post_dist" (concat) task

Source file "src/SDP/dist/SDP.js" not found.
File "dist/jssip-0.4.0-devel.js" created.

When incoming call:
Thu Jan 09 2014 15:43:04 GMT+0200 (FLE Standard Time) | jssip.rtcsession.rtcmediahandler | unable to set local description jssip.js:142
Thu Jan 09 2014 15:43:04 GMT+0200 (FLE Standard Time) | jssip.rtcsession.rtcmediahandler | SetLocalDescription failed: Failed to push down offer transport description.

When outgoing call:
Uncaught TypeError: Object # has no method 'parseSDP' jssip-devel.js:4903
sendReinvite.mangle jssip-devel.js:4903
(anonymous function) jssip-devel.js:5597
onSetLocalDescriptionSuccess

from jssip.

jmillan avatar jmillan commented on September 27, 2024

Please, update the branch and execute grunt.

The Grunt task generating the SDP parser was not being executed by default.

from jssip.

ibc avatar ibc commented on September 27, 2024

Probably you mean grunt grammar ;)

grunt grammar builds the parser code, you must run it before grunt [ build | devel ].

from jssip.

jmillan avatar jmillan commented on September 27, 2024

Nop. There is a new sdp task for building the SDP parser.

from jssip.

ibc avatar ibc commented on September 27, 2024

Upss, right, in the "hold" branch :)
Remember adding that in the BUILDING.md file ;)

from jssip.

ISkomorokh avatar ISkomorokh commented on September 27, 2024

Sorry but it didn't help. Here what grunt says:

Running "sdp" task
"sdp" task: getting JsSIP parser from "sdp-transform" ...
ERROR: 'browserify' is not recognized as an internal or external command,
operable program or batch file.
OK
Warning: Task "sdp" failed. Use --force to continue.

Aborted due to warnings.

And when I use -force I get:

Running "concat:devel" (concat) task
File "dist/jssip-devel.js" created.

Running "includereplace:devel" (includereplace) task

Processed dist/jssip-devel.js

Running "jshint:devel" (jshint) task

1 file lint free.
Running "concat:post_devel" (concat) task Source file "src/SDP/dist/SDP.js" not found. File "dist/jssip-devel.js" created.
Running "concat:dist" (concat) task
File "dist/jssip-0.4.0-devel.js" created.

Running "includereplace:dist" (includereplace) task

Processed dist/jssip-0.4.0-devel.js

Running "jshint:dist" (jshint) task

1 file lint free.

Running "concat:post_dist" (concat) task

Source file "src/SDP/dist/SDP.js" not found.
File "dist/jssip-0.4.0-devel.js" created.

Running "uglify:dist" (uglify) task
File "dist/jssip-0.4.0-devel.min.js" created.

from jssip.

jmillan avatar jmillan commented on September 27, 2024

Hi,

Did you follow the BUILDING.md and run npm install?

from jssip.

ISkomorokh avatar ISkomorokh commented on September 27, 2024

Hi,

yes, sure.

Master and develop branches work properly. I've even reinstalled npm.

from jssip.

jmillan avatar jmillan commented on September 27, 2024

Master and develop do not make use of browserify. Run npm install over hold branch, it should install browserify

from jssip.

ISkomorokh avatar ISkomorokh commented on September 27, 2024

:) I have mentioned that I reinstall npm and I can see browserify in node_modules folder in hold branch. But when I run grunt I get :(

Running "sdp" task
"sdp" task: getting JsSIP parser from "sdp-transform" ...
ERROR: 'browserify' is not recognized as an internal or external command,
operable program or batch file.
OK
Warning: Task "sdp" failed. Use --force to continue.

Aborted due to warnings.

What version should it be?
"name": "browserify",
"version": "2.36.1",

from jssip.

ibc avatar ibc commented on September 27, 2024

Yep, this is not ok. Let we fix the Gruntfile.

from jssip.

ibc avatar ibc commented on September 27, 2024

We know the reason of the error. Working on it right now.

from jssip.

jmillan avatar jmillan commented on September 27, 2024

Change commited. Please, give it a try, and thank you for reporting!

from jssip.

ISkomorokh avatar ISkomorokh commented on September 27, 2024

Hi guys! Thank you for your work. Now it is building properly. But... :( I have tried to use hold and the try was unsuccessful. I'll try to explain what I do. Sorry for my English :)

I am using jssip and trying to call between two browsers. Server Asterisk 11.6 + WebRTC. Calls work fine. I can call, terminate, answer.
Now I'm trying to hold an active call and here what I get:

sometimes I get no exceptions and silence on the line but as far as I can see, this is not because of hold but because of an exception on Asterisk which says:
WARNING[791][C-0000001d]: chan_sip.c:10454 process_sdp: Rejecting secure audio stream without encryption details: audio 54102 RTP/SAVPF 111 103 104 0 8 106 105 13 126

After this I call unhold, but nothing get changed. Except an exception in console:
unhold() Sat Jan 11 2014 16:49:30 GMT+0200 (FLE Standard Time) | jssip.rtcsession.rtcmediahandler | unable to set local description jssip-devel.js:142 Sat Jan 11 2014 16:49:30 GMT+0200 (FLE Standard Time) | jssip.rtcsession.rtcmediahandler | SetLocalDescription failed: Failed to push down offer transport description. jssip-devel.js:142

And here is some part of Asterisk log. May be this can help.
[Jan 11 16:49:05] DEBUG[791][C-0000001d]: sip/sdp_crypto.c:285 sdp_crypto_process: Accepting crypto tag 0 [Jan 11 16:49:05] DEBUG[791][C-0000001d]: sip/sdp_crypto.c:310 sdp_crypto_offer: Crypto line: a=crypto:0 AES_CM_128_HMAC_SHA1_32 inline:6eplV2+Nz/OAzI+80fH6BoxJgmzgNd/CDiXttli1 -- Executing [11@cw:1] Wait("SIP/2-0000003a", "1") in new stack -- Executing [11@cw:2] Dial("SIP/2-0000003a", "SIP/1,60,r") in new stack == Using SIP RTP CoS mark 5 [Jan 11 16:49:06] DEBUG[793][C-0000001d]: sip/sdp_crypto.c:310 sdp_crypto_offer: Crypto line: a=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:YAPrcoiCii9avNHCcyTUhmnrahOy5qtaAQmi7cnF -- Called SIP/1 -- SIP/1-0000003b is ringing [Jan 11 16:49:08] DEBUG[792][C-0000001d]: sip/sdp_crypto.c:285 sdp_crypto_process: Accepting crypto tag 1 [Jan 11 16:49:08] DEBUG[792][C-0000001d]: sip/sdp_crypto.c:310 sdp_crypto_offer: Crypto line: a=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:YAPrcoiCii9avNHCcyTUhmnrahOy5qtaAQmi7cnF -- SIP/1-0000003b answered SIP/2-0000003a [Jan 11 16:49:08] DEBUG[793][C-0000001d]: sip/sdp_crypto.c:310 sdp_crypto_offer: Crypto line: a=crypto:0 AES_CM_128_HMAC_SHA1_32 inline:6eplV2+Nz/OAzI+80fH6BoxJgmzgNd/CDiXttli1 > 0x7f08c8032da0 -- Probation passed - setting RTP source address to 192.168.34.73:57868 > 0x7f08c0043780 -- Probation passed - setting RTP source address to 192.168.34.75:54102 [Jan 11 16:49:13] WARNING[791][C-0000001d]: chan_sip.c:10454 process_sdp: Rejecting secure audio stream without encryption details: audio 54102 RTP/SAVPF 111 103 104 0 8 106 105 13 126 == Spawn extension (cw, 11, 2) exited non-zero on 'SIP/2-0000003a'

from jssip.

ibc avatar ibc commented on September 27, 2024

Asterisk does not support hold/unhold in WebRTC calls. Please try calls
through a proxy with direct RTP between browsers.

Iñaki Baz Castillo
[email protected]
On Jan 11, 2014 4:15 PM, "Igor Skomorokh" [email protected] wrote:

Hi guys! Thank you for your work. Now it is building properly. But... :( I
have tried to use hold and the try was unsuccessful. I'll try to explain
what I do. Sorry for my English :)

I am using jssip and trying to call between two browsers. Server Asterisk
11.6 + WebRTC. Calls work fine. I can call, terminate, answer.
Now I'm trying to hold an active call and here what I get:

sometimes I get no exceptions and silence on the line but as far as I can
see, this is not because of hold but because of an exception on Asterisk
which says:

WARNING[791][C-0000001d]: chan_sip.c:10454 process_sdp: Rejecting secure
audio stream without encryption details: audio 54102 RTP/SAVPF 111 103 104
0 8 106 105 13 126

After this I call unhold, but nothing get changed. Except an exception in
console:

unhold()
Sat Jan 11 2014 16:49:30 GMT+0200 (FLE Standard Time) |
jssip.rtcsession.rtcmediahandler | unable to set local description
jssip-devel.js:142
Sat Jan 11 2014 16:49:30 GMT+0200 (FLE Standard Time) |
jssip.rtcsession.rtcmediahandler | SetLocalDescription failed: Failed to
push down offer transport description. jssip-devel.js:142

And here is some part of Asterisk log. May be this can help.

[Jan 11 16:49:05] DEBUG[791][C-0000001d]: sip/sdp_crypto.c:285
sdp_crypto_process: Accepting crypto tag 0
[Jan 11 16:49:05] DEBUG[791][C-0000001d]: sip/sdp_crypto.c:310
sdp_crypto_offer: Crypto line: a=crypto:0 AES_CM_128_HMAC_SHA1_32
inline:6eplV2+Nz/OAzI+80fH6BoxJgmzgNd/CDiXttli1
-- Executing [11@cw:1] Wait("SIP/2-0000003a", "1") in new stack
-- Executing [11@cw:2] Dial("SIP/2-0000003a", "SIP/1,60,r") in new stack
== Using SIP RTP CoS mark 5
[Jan 11 16:49:06] DEBUG[793][C-0000001d]: sip/sdp_crypto.c:310
sdp_crypto_offer: Crypto line: a=crypto:1 AES_CM_128_HMAC_SHA1_80
inline:YAPrcoiCii9avNHCcyTUhmnrahOy5qtaAQmi7cnF
-- Called SIP/1
-- SIP/1-0000003b is ringing
[Jan 11 16:49:08] DEBUG[792][C-0000001d]: sip/sdp_crypto.c:285
sdp_crypto_process: Accepting crypto tag 1
[Jan 11 16:49:08] DEBUG[792][C-0000001d]: sip/sdp_crypto.c:310
sdp_crypto_offer: Crypto line: a=crypto:1 AES_CM_128_HMAC_SHA1_80
inline:YAPrcoiCii9avNHCcyTUhmnrahOy5qtaAQmi7cnF
-- SIP/1-0000003b answered SIP/2-0000003a
[Jan 11 16:49:08] DEBUG[793][C-0000001d]: sip/sdp_crypto.c:310
sdp_crypto_offer: Crypto line: a=crypto:0 AES_CM_128_HMAC_SHA1_32
inline:6eplV2+Nz/OAzI+80fH6BoxJgmzgNd/CDiXttli1

0x7f08c8032da0 -- Probation passed - setting RTP source address to
192.168.34.73:57868
0x7f08c0043780 -- Probation passed - setting RTP source address to
192.168.34.75:54102
[Jan 11 16:49:13] WARNING[791][C-0000001d]: chan_sip.c:10454 process_sdp:
Rejecting secure audio stream without encryption details: audio 54102
RTP/SAVPF 111 103 104 0 8 106 105 13 126
== Spawn extension (cw, 11, 2) exited non-zero on 'SIP/2-0000003a'


Reply to this email directly or view it on GitHubhttps://github.com//issues/46#issuecomment-32098479
.

from jssip.

ISkomorokh avatar ISkomorokh commented on September 27, 2024

Well ... that's bad :( Thanks anyway. I'll try to first understand your proposition and later to try it.
BTW, why http://sipml5.org/ can hold and unhold with all the same setting and servers?

Please try calls through a proxy with direct RTP between browsers.
Well, I'm not sure, but isn't WebRTC?

from jssip.

jmillan avatar jmillan commented on September 27, 2024

@ISkomorokh, calling through a proxy with a direct RTP means not using a Media Server (like Asterisk) between both browsers but just use a signaling server (a SIP proxy) and let the RTP go directly between browsers.

You are not guaranteed to make hold feature work with Asterisk if they don't fully support it for WebRTC. Perhaps they support holding when using only audio, but those errors in the Asterisk server should be addressed in the Asterisk-dev mailing list. There is little to do in the client side until the server side can correctly handle it.

That's why @ibc told you to avoid using any intermediate node dealing with the media, and suggested you to try the hold feature using solely a SIP proxy and letting the RTP go directly browser to browser.

from jssip.

ISkomorokh avatar ISkomorokh commented on September 27, 2024

@jmillan Thank you for your reply. Now it's clear for me. Unfortunately this approach is not sufficient for us because we need to record calls and many other features which depends on Asterisk.
So, as I understand I have two hopes for now:

  1. Asterisk team to support hold/unhold in WebRTC module (btw, I have created related topic on the forum);
  2. Try to use sipml5 :( (I am not happy with this, cause I really like JsSip more, but we really need hold/unhold and transfer and all this suppose to work through Asterisk)

from jssip.

jmillan avatar jmillan commented on September 27, 2024

Good @ISkomorokh,

Well done opening the topic in Asterisk. As soon as they support WebRTC hold, you'll be able to use it.

Regards.

from jssip.

ISkomorokh avatar ISkomorokh commented on September 27, 2024

I have just checked sipml5 and hold is working fine with the same configuration and users. Could you please check their solution?

from jssip.

ibc avatar ibc commented on September 27, 2024

@ISkomorokh could you please paste the hold re-INVITE from SIPml5 and the 200 OK from Asterisk?

from jssip.

ISkomorokh avatar ISkomorokh commented on September 27, 2024

I hope this is it. I took it from the browser console.
`
__on_add_stream SIPml-api.js?svn=179:1
onSetRemoteDescriptionSuccess SIPml-api.js?svn=179:1
State machine: x0100_Connected_2_Holding_X_oHold SIPml-api.js?svn=179:1
SEND: INVITE sip:[email protected]:5060;transport=WS SIP/2.0
Via: SIP/2.0/WS df7jal23ls0d.invalid;branch=z9hG4bKf8CZJxn741MT42TdaRVsAKJylV40xsI7;rport
From: sip:[email protected];tag=8Q3QgOtQgceSbC9ycsBa
To: sip:[email protected];tag=as3c728f6e
Contact: "undefined"sip:[email protected];rtcweb-breaker=no;click2call=no;transport=ws
Call-ID: 437aa396-01dc-053f-a6b1-fe8c28e52977
CSeq: 52846 INVITE
Content-Type: application/sdp
Content-Length: 1852
Max-Forwards: 70
Authorization: Digest username="2",realm="asterisk",nonce="7d56fc58",uri="sip:[email protected]:5060;transport=WS",response="270ab5d8dc5b448537cfef6e1ffe4f08",algorithm=MD5

v=0
o=- 9197917715861079000 3 IN IP4 127.0.0.1
s=Doubango Telecom - chrome
t=0 0
a=group:BUNDLE audio
a=msid-semantic: WMS IdSOBnmwBI8hIM3jagOVXVwTM2SFUCXOxKBf
m=audio 57226 RTP/SAVPF 111 103 104 0 8 106 105 13 126
c=IN IP4 193.84.77.194
a=rtcp:57226 IN IP4 193.84.77.194
a=candidate:1162875081 1 udp 2113937151 192.168.34.75 57226 typ host generation 0
a=candidate:1162875081 2 udp 2113937151 192.168.34.75 57226 typ host generation 0
a=candidate:3289912957 1 udp 1845501695 193.84.77.194 57226 typ srflx raddr 192.168.34.75 rport 57226 generation 0
a=candidate:3289912957 2 udp 1845501695 193.84.77.194 57226 typ srflx raddr 192.168.34.75 rport 57226 generation 0
a=candidate:198437945 1 tcp 1509957375 192.168.34.75 0 typ host generation 0
a=candidate:198437945 2 tcp 1509957375 192.168.34.75 0 typ host generation 0
a=ice-ufrag:htjHp1CtZKnYFmHJ
a=ice-pwd:5nTgi8MxbgCQPRLEwicEzA8s
a=ice-options:google-ice
a=fingerprint:sha-256 45:54:CB:F2:33:71:85:A7:C9:C1:70:AC:32:EE:1E:04:88:34:BF:D5:D2:3A:CC:22:5C:D7:BF:F9:E0:B5:5F:39
a=setup:actpass
a=mid:audio
a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level
a=sendonly
a=rtcp-mux
a=crypto:0 AES_CM_128_HMAC_SHA1_32 inline:v1rwq7ko1xY1ogY8d6UULNK6Fe1VvNf/WvyBWg7b
a=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:SybtBrmM9ja6WaMiRwpL8Ch9B0IsfV4QgvY5wSzL
a=rtpmap:111 opus/48000/2
a=fmtp:111 minptime=10
a=rtpmap:103 ISAC/16000
a=rtpmap:104 ISAC/32000
a=rtpmap:0 PCMU/8000
a=rtpmap:8 PCMA/8000
a=rtpmap:106 CN/32000
a=rtpmap:105 CN/16000
a=rtpmap:13 CN/8000
a=rtpmap:126 telephone-event/8000
a=maxptime:60
a=ssrc:294502122 cname:KK120ZwZ0xHgEhCj
a=ssrc:294502122 msid:IdSOBnmwBI8hIM3jagOVXVwTM2SFUCXOxKBf IdSOBnmwBI8hIM3jagOVXVwTM2SFUCXOxKBfa0
a=ssrc:294502122 mslabel:IdSOBnmwBI8hIM3jagOVXVwTM2SFUCXOxKBf
a=ssrc:294502122 label:IdSOBnmwBI8hIM3jagOVXVwTM2SFUCXOxKBfa0
SIPml-api.js?svn=179:1
__tsip_transport_ws_onmessage SIPml-api.js?svn=179:1
recv=SIP/2.0 100 Trying
Via: SIP/2.0/WS df7jal23ls0d.invalid;rport=33247;received=192.168.34.75;branch=z9hG4bKf8CZJxn741MT42TdaRVsAKJylV40xsI7
From: sip:[email protected];tag=8Q3QgOtQgceSbC9ycsBa
To: sip:[email protected];tag=as3c728f6e
Contact: sip:[email protected]:5060;transport=WS
Call-ID: 437aa396-01dc-053f-a6b1-fe8c28e52977
CSeq: 52846 INVITE
Content-Length: 0
Server: Asterisk PBX 11.6.0
Allow: INVITE,ACK,CANCEL,OPTIONS,BYE,REFER,SUBSCRIBE,NOTIFY,INFO,PUBLISH
Supported: replaces,timer

SIPml-api.js?svn=179:1
State machine: x0000_Any_2_Any_X_i1xx SIPml-api.js?svn=179:1
__tsip_transport_ws_onmessage SIPml-api.js?svn=179:1
recv=SIP/2.0 200 OK
Via: SIP/2.0/WS df7jal23ls0d.invalid;rport=33247;received=192.168.34.75;branch=z9hG4bKf8CZJxn741MT42TdaRVsAKJylV40xsI7
From: sip:[email protected];tag=8Q3QgOtQgceSbC9ycsBa
To: sip:[email protected];tag=as3c728f6e
Contact: sip:[email protected]:5060;transport=WS
Call-ID: 437aa396-01dc-053f-a6b1-fe8c28e52977
CSeq: 52846 INVITE
Content-Type: application/sdp
Content-Length: 592
Server: Asterisk PBX 11.6.0
Allow: INVITE,ACK,CANCEL,OPTIONS,BYE,REFER,SUBSCRIBE,NOTIFY,INFO,PUBLISH
Supported: replaces,timer

v=0
o=root 359669290 359669291 IN IP4 172.19.2.10
s=Asterisk PBX 11.6.0
c=IN IP4 172.19.2.10
t=0 0
m=audio 16168 RTP/SAVPF 0 8 101
a=rtpmap:0 PCMU/8000
a=rtpmap:8 PCMA/8000
a=rtpmap:101 telephone-event/8000
a=fmtp:101 0-16
a=silenceSupp:off - - - -
a=ptime:20
a=ice-ufrag:6a4962137df4e5dc748e6ebc4bfeaec3
a=ice-pwd:74d62ea078ccca977330dae92b90d581
a=candidate:Hac13020a 1 UDP 2130706431 172.19.2.10 16168 typ host
a=candidate:Hac13020a 2 UDP 2130706430 172.19.2.10 16169 typ host
a=recvonly
a=crypto:0 AES_CM_128_HMAC_SHA1_32 inline:7GK358Fmv5hryeMOZMxZDJAoTEp4Nqd6D2grJTi+
SIPml-api.js?svn=179:1
State machine: x0101_Holding_2_Connected_X_ixxx SIPml-api.js?svn=179:1
SEND: ACK sip:[email protected]:5060;transport=WS SIP/2.0
Via: SIP/2.0/WS df7jal23ls0d.invalid;branch=z9hG4bK1N8O2CrSeVPXSn0oh2OM;rport
From: sip:[email protected];tag=8Q3QgOtQgceSbC9ycsBa
To: sip:[email protected];tag=as3c728f6e
Contact: "undefined"sip:[email protected];rtcweb-breaker=no;click2call=no;transport=ws
Call-ID: 437aa396-01dc-053f-a6b1-fe8c28e52977
CSeq: 52846 ACK
Content-Length: 0
Max-Forwards: 70
Authorization: Digest username="2",realm="asterisk",nonce="7d56fc58",uri="sip:[email protected]:5060;transport=WS",response="aba12e9c9ba602b253884fba9fbe62e9",algorithm=MD5
`

from jssip.

ISkomorokh avatar ISkomorokh commented on September 27, 2024

And here is Asterisk console output for a call -> hold -> terminate. Sorry for verbosity and thank you for patience.

http://tinyurl.com/ma8quc8

from jssip.

ibc avatar ibc commented on September 27, 2024

Thanks @ISkomorokh. Please could you also paste the JsSIP's hold re-INVITE and Asterisk's SIP error response? I would appreciate it.

from jssip.

ISkomorokh avatar ISkomorokh commented on September 27, 2024

Yes, sure.
call -> hold -> terminate
JsSip console log - http://tinyurl.com/nwytfoo
Asterisk log - http://tinyurl.com/p749q58

BTW I make call between browser and desktop application. Call goes from browser, hold called in browser, but terminate called in desktop application.

from jssip.

ibc avatar ibc commented on September 27, 2024

In the JsSIP log you show an empty line in the SDP of the re-INVITE:

[...]
a=rtpmap:13 CN/8000
a=fmtp:111 minptime=10
a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level

a=setup:actpass
a=mid:audio
a=maxptime:60
[...]

Is that line real? or a bug when copy&pasting?

from jssip.

ibc avatar ibc commented on September 27, 2024

I've also realized of a bug in the SDP library that JsSIP uses: #185

from jssip.

ISkomorokh avatar ISkomorokh commented on September 27, 2024

I've checked once again. It is real line. It is not copy & paste bug.
Created log once again http://tinyurl.com/p7pbxuz

from jssip.

ibc avatar ibc commented on September 27, 2024

Thanks @ISkomorokh, that's for sure the error. Let's take a look to it.

from jssip.

ibc avatar ibc commented on September 27, 2024

Let's handle this issue in #186.

from jssip.

ibc avatar ibc commented on September 27, 2024

Fixed in sdp-transform master branch. Still not present in a node package due to NPM issues. Let's wait until we can include it into JsSIP. The author of sdp-transform is on it.

from jssip.

ibc avatar ibc commented on September 27, 2024

Fixed in 501ff59 (currently in "hold" branch). Run npm install && grunt to update.

from jssip.

ISkomorokh avatar ISkomorokh commented on September 27, 2024

Hi guys. Sorry but the problem didn't gone :(
Here is new logs:
Asterisk - http://tinyurl.com/o48taej
JsSip - http://tinyurl.com/oqe3lvl

from jssip.

jmillan avatar jmillan commented on September 27, 2024

Sorry @ISkomorokh, there are some missing lines in the reINVITE's SDP.

The corresponding issue has been opened in sdp-transform. 16

Thanks

from jssip.

ibc avatar ibc commented on September 27, 2024

sdp-transform 0.5.1 fixes the missing lines issue.

@ISkomorokh may you please update your "hold" branch and try again? Remember running "npm install" before "grunt".

from jssip.

ISkomorokh avatar ISkomorokh commented on September 27, 2024

Updated. The situation didn't change.
Here are new log files:
Asterisk - http://tinyurl.com/lfmmtfg
JsSip - http://tinyurl.com/krbt27c

BTW, if it simplify the process, I could provide you an access to the Asterisk.

from jssip.

jmillan avatar jmillan commented on September 27, 2024

Thanks @ISkomorokh, we already have an Asterisk. It's just a matter of time.

from jssip.

ibc avatar ibc commented on September 27, 2024

Confirmed that something happens. I will paste here basically the same as before (and note that a=crypto lines are missing):

JsSIP "hold" branch wiht sdp-transform 0.5.2 (JsSIP to JsSIP call through an OverSIP):

Initial INVITE's SDP from JsSIP-A

v=0
o=- 1225311702902347071 2 IN IP4 127.0.0.1
s=-
t=0 0
a=group:BUNDLE audio
a=msid-semantic: WMS ISrWnIiG8ktJRkhq8Ljt6uQVSr6y0R1zQ008
m=audio 52930 RTP/SAVPF 111 103 104 0 8 106 105 13 126
c=IN IP4 88.84.249.26
a=rtcp:52930 IN IP4 88.84.249.26
a=candidate:239783647 1 udp 2113937151 88.84.249.26 52930 typ host generation 0
a=candidate:239783647 2 udp 2113937151 88.84.249.26 52930 typ host generation 0
a=candidate:1086927407 1 tcp 1509957375 88.84.249.26 0 typ host generation 0
a=candidate:1086927407 2 tcp 1509957375 88.84.249.26 0 typ host generation 0
a=ice-ufrag:NrkTrrZQ843ld8HB
a=ice-pwd:H0s71NVCILUSwSFcKNpmcpJE
a=ice-options:google-ice
a=fingerprint:sha-256 04:53:09:3F:18:9A:1E:C8:13:55:CC:24:6A:30:82:23:30:80:61:9F:6F:E1:E6:01:D3:8A:5D:F3:3F:8C:E7:EA
a=setup:actpass
a=mid:audio
a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level
a=sendrecv
a=rtcp-mux
a=crypto:0 AES_CM_128_HMAC_SHA1_32 inline:FjsegEPpHgCS3WYD7+YOV25PNWMYwqJwC5pr+uV8
a=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:HH/7hS8W08dPwGSryLS1WtDP9726fOEAeNisVLdh
a=rtpmap:111 opus/48000/2
a=fmtp:111 minptime=10
a=rtpmap:103 ISAC/16000
a=rtpmap:104 ISAC/32000
a=rtpmap:0 PCMU/8000
a=rtpmap:8 PCMA/8000
a=rtpmap:106 CN/32000
a=rtpmap:105 CN/16000
a=rtpmap:13 CN/8000
a=rtpmap:126 telephone-event/8000
a=maxptime:60
a=ssrc:708928107 cname:XNFSq/4r8p6p3ryH
a=ssrc:708928107 msid:ISrWnIiG8ktJRkhq8Ljt6uQVSr6y0R1zQ008 a502039a-7866-4233-b76a-0bb8eba5b960
a=ssrc:708928107 mslabel:ISrWnIiG8ktJRkhq8Ljt6uQVSr6y0R1zQ008
a=ssrc:708928107 label:a502039a-7866-4233-b76a-0bb8eba5b960

200's SDP frlom JsSIP-B

v=0
o=- 845600329057459683 2 IN IP4 127.0.0.1
s=-
t=0 0
a=group:BUNDLE audio
a=msid-semantic: WMS vTgcYdhKbXYqhJMrRKzXGeOANFd0AjTneCue
m=audio 60007 RTP/SAVPF 111 103 104 0 8 106 105 13 126
c=IN IP4 88.84.249.26
a=rtcp:1 IN IP4 0.0.0.0
a=candidate:239783647 1 udp 2113937151 88.84.249.26 60007 typ host generation 0
a=candidate:1086927407 1 tcp 1509957375 88.84.249.26 0 typ host generation 0
a=ice-ufrag:n0ZUUzBxL9HIsqNo
a=ice-pwd:fx4ZZEjd2wRU/KiceKvhP7ni
a=fingerprint:sha-256 04:53:09:3F:18:9A:1E:C8:13:55:CC:24:6A:30:82:23:30:80:61:9F:6F:E1:E6:01:D3:8A:5D:F3:3F:8C:E7:EA
a=setup:active
a=mid:audio
a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level
a=sendrecv
a=rtcp-mux
a=rtpmap:111 opus/48000/2
a=fmtp:111 minptime=10
a=rtpmap:103 ISAC/16000
a=rtpmap:104 ISAC/32000
a=rtpmap:0 PCMU/8000
a=rtpmap:8 PCMA/8000
a=rtpmap:106 CN/32000
a=rtpmap:105 CN/16000
a=rtpmap:13 CN/8000
a=rtpmap:126 telephone-event/8000
a=maxptime:60
a=ssrc:2277168312 cname:cKHvHWSq15TmS2Y3
a=ssrc:2277168312 msid:vTgcYdhKbXYqhJMrRKzXGeOANFd0AjTneCue ea117b4f-8f84-4300-9e8b-44993ffb02d8
a=ssrc:2277168312 mslabel:vTgcYdhKbXYqhJMrRKzXGeOANFd0AjTneCue
a=ssrc:2277168312 label:ea117b4f-8f84-4300-9e8b-44993ffb02d8

Hold re-INVITE's SDP from JsSIP-A

v=0
o=- 1225311702902347071 3 IN IP4 127.0.0.1
s=-
t=0 0
a=msid-semantic: WMS ISrWnIiG8ktJRkhq8Ljt6uQVSr6y0R1zQ008
a=group:BUNDLE audio
m=audio 52930 RTP/SAVPF 111 103 104 0 8 106 105 13 126
c=IN IP4 88.84.249.26
a=rtpmap:111 opus/48000/2
a=rtpmap:103 ISAC/16000
a=rtpmap:104 ISAC/32000
a=rtpmap:0 PCMU/8000
a=rtpmap:8 PCMA/8000
a=rtpmap:106 CN/32000
a=rtpmap:105 CN/16000
a=rtpmap:13 CN/8000
a=rtpmap:126 telephone-event/8000
a=fmtp:111 minptime=10
a=rtcp:52930 IN IP4 88.84.249.26
a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level
a=setup:actpass
a=mid:audio
a=maxptime:60
a=sendonly
a=ice-ufrag:NrkTrrZQ843ld8HB
a=ice-pwd:H0s71NVCILUSwSFcKNpmcpJE
a=fingerprint:sha-256 04:53:09:3F:18:9A:1E:C8:13:55:CC:24:6A:30:82:23:30:80:61:9F:6F:E1:E6:01:D3:8A:5D:F3:3F:8C:E7:EA
a=candidate:239783647 1 udp 2113937151 88.84.249.26 52930 typ host
a=candidate:239783647 2 udp 2113937151 88.84.249.26 52930 typ host
a=candidate:1086927407 1 tcp 1509957375 88.84.249.26 0 typ host
a=candidate:1086927407 2 tcp 1509957375 88.84.249.26 0 typ host
a=ice-options:google-ice
a=ssrc:708928107 cname:XNFSq/4r8p6p3ryH
a=ssrc:708928107 msid:ISrWnIiG8ktJRkhq8Ljt6uQVSr6y0R1zQ008 a502039a-7866-4233-b76a-0bb8eba5b960
a=ssrc:708928107 mslabel:ISrWnIiG8ktJRkhq8Ljt6uQVSr6y0R1zQ008
a=ssrc:708928107 label:a502039a-7866-4233-b76a-0bb8eba5b960
a=rtcp-mux

The exact differences between INVITE and re-INVITE (after sorting lines alphabetically) are those:

diff -Nu invite.sort reinvite.sort
--- invite.sort 2014-01-17 16:21:52.000000000 +0100
+++ reinvite.sort   2014-01-17 16:22:02.000000000 +0100
@@ -1,10 +1,8 @@

-a=candidate:1086927407 1 tcp 1509957375 88.84.249.26 0 typ host generation 0
-a=candidate:1086927407 2 tcp 1509957375 88.84.249.26 0 typ host generation 0
-a=candidate:239783647 1 udp 2113937151 88.84.249.26 52930 typ host generation 0
-a=candidate:239783647 2 udp 2113937151 88.84.249.26 52930 typ host generation 0
-a=crypto:0 AES_CM_128_HMAC_SHA1_32 inline:FjsegEPpHgCS3WYD7+YOV25PNWMYwqJwC5pr+uV8
-a=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:HH/7hS8W08dPwGSryLS1WtDP9726fOEAeNisVLdh
+a=candidate:1086927407 1 tcp 1509957375 88.84.249.26 0 typ host
+a=candidate:1086927407 2 tcp 1509957375 88.84.249.26 0 typ host
+a=candidate:239783647 1 udp 2113937151 88.84.249.26 52930 typ host
+a=candidate:239783647 2 udp 2113937151 88.84.249.26 52930 typ host
 a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level
 a=fingerprint:sha-256 04:53:09:3F:18:9A:1E:C8:13:55:CC:24:6A:30:82:23:30:80:61:9F:6F:E1:E6:01:D3:8A:5D:F3:3F:8C:E7:EA
 a=fmtp:111 minptime=10
@@ -26,7 +24,7 @@
 a=rtpmap:126 telephone-event/8000
 a=rtpmap:13 CN/8000
 a=rtpmap:8 PCMA/8000
-a=sendrecv
+a=sendonly
 a=setup:actpass
 a=ssrc:708928107 cname:XNFSq/4r8p6p3ryH
 a=ssrc:708928107 label:a502039a-7866-4233-b76a-0bb8eba5b960
@@ -34,7 +32,7 @@
 a=ssrc:708928107 mslabel:ISrWnIiG8ktJRkhq8Ljt6uQVSr6y0R1zQ008
 c=IN IP4 88.84.249.26
 m=audio 52930 RTP/SAVPF 111 103 104 0 8 106 105 13 126
-o=- 1225311702902347071 2 IN IP4 127.0.0.1
+o=- 1225311702902347071 3 IN IP4 127.0.0.1
 s=-
 t=0 0
 v=0

Note that a=crypto is just used in SDES-SRTP (and not in DTLS-SRTP). Anyhow, I don't understand why those lines are missing in the re-INVITE if they did exist in the initial INVITE.

from jssip.

ibc avatar ibc commented on September 27, 2024

@ISkomorokh please test with Firefox (hopefully Firefox Nightly):

  • Call from Firefox to your Asterisk. Note that Firefox does not implement SDES but just DTLS (the official crypto mechanism for WebRTC) so this will test whether your Asterisk has DTLS support or not (IMHO it is using SDES right now due the presence of a a=crypto line in the 200 OK).
  • Let's us know if the call is established or not (or rejected with 488 as I expect).
  • Paste please JsSIP and Asterisk logs.

Note that, even if the call is established, "hold()" will not work in Firefox due to a known issue of Firefox.

from jssip.

ibc avatar ibc commented on September 27, 2024

@ISkomorokh from your Asterisk logs (in the SIPml5 test) I get this:

[Jan 13 14:35:00] DEBUG[1572][C-00000028]: chan_sip.c:10449 process_sdp: Processing media-level (audio) SDP a=fingerprint:sha-256 45:54:CB:F2:33:71:85:A7:C9:C1:70:AC:32:EE:1E:04:88:34:BF:D5:D2:3A:CC:22:5C:D7:BF:F9:E0:B5:5F:39... UNSUPPORTED OR FAILED.

If Asterisk does not understand the "a=fingerprint" line it means that it DOES NOT support DTLS. So, the problem is the following:

  • JsSIP generates a SDP offer with both DTLS (a=fingerprint) and SDES (a=crypto) support.
  • Asterisk chooses SDES (the SDP answer has a a=crypto line).
  • When calling hold() JsSIP call to RTCPeerConnection.createOffer() to get a SessionDescription (SDP) representing the current media properties of the RTC session.
  • In that moment there is a bug in Chrome since the retrieved SessionDescription does NO LONGER contain "a=crypto" lines and hence Asterisk cannot establish a SDES session (so 488 response).

Why does it work with SIPml5? Because "probably" SIPml5 does not call again to RTCPeerConnection.createOffer() when it generates a reINVITE (a SDP re-offer) but instead uses the first SDP generated for the previous initial INVITE (which DOES contain the "a=crypto" lines). We, in JsSIP, strongly prefer to call to createOffer() in order to get an updated and proper SessionDescription.

So yes, there is a bug in Chrome, but given that SDES is DECRECATED in WebRTC (Firefox does not even support it) we cannot open an issue for that in Chromium tracker.

from jssip.

ibc avatar ibc commented on September 27, 2024

From the asterisk-devel mailing list:

Asterisk only enforces DTLS-SRTP when it receives UDP/TLS/RTP/SAVP as the protocol to be used in the SDP, but both Chrome and Firefox negotiate RTP/SAVPF.

This is, if you have compiled DTLS support in Asterisk (for what you need libdtls), and Asterisk receives an INVITE with an SDP offer containing:

m=audio 52930 UDP/TLS/RTP/SAVP 111 103 104 0 8 106 105 13 126

then Asterisk will choose DTLS. But Chrome and Firefox use:

m=audio 52930 RTP/SAVPF 111 103 104 0 8 106 105 13 126

and hence Asterisk does not use DTLS at all and instead relies on SDES (if the SDP offer contains "a=crypto" lines) which is not the case in the re-INVITE of JsSIP due the bug in Chrome explained in my previous comment.

from jssip.

ISkomorokh avatar ISkomorokh commented on September 27, 2024

@ibc you are absolutely right! Firefox rejected to call with 488. Here are Firefox and Asterisk logs (sdp-transform 5.0.3):
JsSip - http://tinyurl.com/p4o74eu
Asterisk - http://tinyurl.com/pc48a89

And here are Chrome and Asterisk logs:
Asterisk - http://tinyurl.com/ptb9f9a
JsSip - http://tinyurl.com/pwlycgy

So, as far as I understand I need to rebuild my Asterisk with necessary libs?
Also, in the same topic which says about browsers bugs is mentioned that this could be overcome next way:
I did it in the signalling gateway, others may do this somewhere else (e.g., directly in JavaScript after producing an offer and before passing an answer)

Is it possible?

from jssip.

ibc avatar ibc commented on September 27, 2024

You may try to do a text replacement of the "request.body" field within the on("newRTCSession") event (when direction is "outgoing"), by replacing "RTP/SAVPF" with "UDP/TLS/RTP/SAVPF". Note however that there is currently no way of doing that for incoming calls (there is no way to mangle the body of the generated 200 OK).

from jssip.

ISkomorokh avatar ISkomorokh commented on September 27, 2024

Well, adding libdtls made everything worse :( Now I can't even call (no mater what browser is).

PS: no blaming - just providing info

from jssip.

ISkomorokh avatar ISkomorokh commented on September 27, 2024

I think I found the reason, why (re)invite was missing. Probably it is because all the peers I use for testing has canreinvite=NO, because they are used sometimes with legacy devices.

I'll try to check it tomorrow if administrators recover virtual machine with Asterisk with no dtls lib installed.

from jssip.

ISkomorokh avatar ISkomorokh commented on September 27, 2024

Ok. We installed Asterisk 11.7 today. Now calls are working again. But hold and Firefox - not working :(
I have set canreinvite=yes to all the peers but nothing has changed. Should I upload new log files?

Could you please give an example how to install that libdtls (Centos, Asterisk). May be this will fix calls in Firefox.

from jssip.

jmillan avatar jmillan commented on September 27, 2024

Hi @ISkomorokh, I'm affraid you'd better ask the Asterisk DTLS support questions in the Asterisk mailing list. At least I can't be of much help here.

from jssip.

ibc avatar ibc commented on September 27, 2024

AFAIR (@jmillan knows more about it) there is a bug in Firefox that prevents the JsSIP "hold" feature, but I'm not sure of that in this case since JsSIP just gets the current local SDP and mangles it (a=sendonly and so on). Please, paste the logs.

from jssip.

jmillan avatar jmillan commented on September 27, 2024

The reason Firefox doesn't support hold is because its RTCPeerConnection does not support re-Offer.

from jssip.

ibc avatar ibc commented on September 27, 2024

Right, but when JsSIP calls "hold" the only it does is calling RTCPeerConnection.createOffer() again. So do you mean that the issue is in that?

from jssip.

ISkomorokh avatar ISkomorokh commented on September 27, 2024

Thanks for trying to help!

Ok, now I'll send some logs for different cases.
First case:
Asterisk 11.7, Chrome
Call from JsSip to some desktop client -> hold on jssip side -> terminate on desktop side:
Asterisk -http://tinyurl.com/khtewl7
JsSip - http://tinyurl.com/lp4gjvo

Case 2. Latest Firefox. BUT - I got an error while calling from jssip so I cant even try hold.
Asterisk - http://tinyurl.com/ksakjzp
JsSip - http://tinyurl.com/knlpjgg

Later I have found next section in Asterisk sip.conf:
;------------------------------------------------------------------------------ ; DTLS-SRTP CONFIGURATION ; ; DTLS-SRTP support is available if the underlying RTP engine in use supports it. ; ; dtlsenable = yes ; Enable or disable DTLS-SRTP support ; dtlsverify = no;yes ; Verify that the provided peer certificate is valid ; dtlsrekey = 60 ; Interval at which to renegotiate the TLS session and rekey the SRTP session ; ; If this is not set or the value provided is 0 rekeying will be disabled ; dtlscertfile = file ; Path to certificate file to present ; dtlsprivatekey = file ; Path to private key for certificate file ; dtlscipher = <SSL cipher string> ; Cipher to use for TLS negotiation ; ; A list of valid SSL cipher strings can be found at: ; ; http://www.openssl.org/docs/apps/ciphers.html#CIPHER_STRINGS ; dtlscafile = file ; Path to certificate authority certificate ; dtlscapath = path ; Path to a directory containing certificate authority certificates ; dtlssetup = actpass ; Whether we are willing to accept connections, connect to the other party, or both. ; ; Valid options are active (we want to connect to the other party), passive (we want to ; ; accept connections only), and actpass (we will do both). This value will be used in ; ; the outgoing SDP when offering and for incoming SDP offers when the remote party sends ; ; actpass

So I believe this is the way I can turn dtls on. For now I set and gathered logs:
dtlsenable = yes
dtlsverify = no

Chrome:
Asterisk - http://tinyurl.com/ltyuzfq
JsSip - http://tinyurl.com/mhegofw

Firefox:
Asterisk - http://tinyurl.com/kfg9kry
JsSip - http://tinyurl.com/lc5wyhk

And logs when I initiate call from desktop:
to Firefox
JsSip - http://tinyurl.com/kf44e7c
Asterisk - http://tinyurl.com/mzbsrcm

to Chrome (In this case call reached jssip, I answered and invoked call and later terminate)
JsSip - http://tinyurl.com/kczmu6w
Asterisk -http://tinyurl.com/knjwalf

from jssip.

ISkomorokh avatar ISkomorokh commented on September 27, 2024

When I enable dtlssetup = actpass in sip config, while trying to call from FF I see this in Asterisk:
[Jan 21 13:20:18] WARNING[17986][C-00000001]: chan_sip.c:10487 process_sdp: Rejecting secure audio stream without encryption details: audio 65216 RTP/SAVPF 109 0 8 101

from jssip.

ibc avatar ibc commented on September 27, 2024

When I enable dtlssetup = actpass in sip config, while trying to call from FF I see this in Asterisk:

[Jan 21 13:20:18] WARNING[17986][C-00000001]: chan_sip.c:10487 process_sdp: Rejecting secure audio stream without encryption details: audio 65216 RTP/SAVPF 109 0 8 101

That is due the error explained above: Asterisk does NOT apply DTLS unless the SDP has "UDP/TLS/RTP/SAVPF" in the m line, but both Chrome and Firefox set "RTP/SAVPF".

Honestly, this is becoming more and more an Asterisk issue, and we cannot do lot here.

from jssip.

dpocock avatar dpocock commented on September 27, 2024

there seem to be many things mixed up in this issue. I'm opening a separate issue for the protocol sub-field of the media descriptor

from jssip.

jmillan avatar jmillan commented on September 27, 2024

Already merged in develop branch

from jssip.

jayesh1017 avatar jayesh1017 commented on September 27, 2024

We're using the develop branch with freeswitch and jssip and still seem to get the same problem. When we initiate a Re-Invite from freeswitch towards JSSIP for Hold, it responds back with 500 Server Internal Error with the following console log:

Wed Jul 02 2014 10:20:57 GMT+0530 (IST) | jssip.rtcsession | re-INVITE received jssip-0.4.0-devel.min.js:9
Wed Jul 02 2014 10:20:57 GMT+0530 (IST) | jssip.rtcsession.rtcmediahandler | unable to set local description jssip-0.4.0-devel.min.js:9
Wed Jul 02 2014 10:20:57 GMT+0530 (IST) | jssip.rtcsession.rtcmediahandler | Failed to set local answer sdp: Failed to push down transport description: Failed to apply remote fingerprint.

from jssip.

ibc avatar ibc commented on September 27, 2024

Please, try it first with two instances of JsSIP and a transparent SIP proxy in the middles (so no Asterisk, FreeSwitch or anything that speaks RTP).

Really, we have no time to investigate other WebRTC implementations.

from jssip.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.