Squawk v2

Free Trial ➡

Squawk is a realtime broadcast which includes important headlines, price movement and rumors as stories develop to give traders and investors news in the fastest and most convenient form.

Connecting to Squawk

There are two ways you can connect to Sqauwk:

Using WebRTC

Squawk is built on top of WebRTC. So one can connect to it through WebRTC supported browser using standard WebRTC API methods. The following are the methods that you will need to implement while writing a client for connecting to squawk.

Create a socket connection

First, create a web socket connection to squawk. The Benzinga Squawk WebRTC service WebSocket address is:

wss://squawk-lb.benzinga.com/squawk

Note: It is advised to add reconnect functionality for WebSocket. It is useful, in case socket connection drops for any reason (maybe the internet is down for a couple of minutes). So add a functionality to try reconnection at some regular interval after WebScoket gets disconnected.

Authenticate

Once the socket connection is created, authenticate with your apikey.

{
    "apikey": "f5kec5x6gplwdv8o5dcn5aydtyx132u8",    
    "role": "viewer",
    "type": "auth",
    "id": "4158f900-d652-483a-8147-866d99ed9f8a"
}

Note: If you do not yet have an API key (apikey), please get in touch with the Benzinga licensing team. This is a one-time process. Save this API key securely.

The ID field (id) is a unique UUID string used to coordinate messages between client and server.

On successful authentication, you should get the following response:

{
    "iceServers": [{
        "urls": "turn:turnserver.benzinga.com:443",
        "username": "1567755301:XQbpzZ0YzltGon1q6paqbfensmE\u003d",
        "credential": "JfJBS295kI/5pjCQgGGJDgHv9ms\u003d"
    }],
    "id": "4158f900-d652-483a-8147-866d99ed9f8a"
}

Use this ice server details to initiate peer connections later with presenters/broadcasters to start listening to them.

Join Room

Once you have received the iceServers details authentication is done. Next, send the join room request/message. The room name for benzinga broadcasts is PRO. Sample join room request format:

{
    "room": "PRO",
    "type": "joinRoom",
    "id": "a5fd1a15-17cf-4f66-83a2-0d77704e1870"
}

In join room response, you should get the list of existing presenters (broadcaster) in the following format:

{
    "existingPresenters": [{
        "userId": "6s7c6:b:53l54g85-bc4d-4pb4-7s3c-e95519546007",
        "username": "Charles Gross"
    }],
    "id": "a5fd1a15-17cf-4f66-83a2-0d77704e1870"
}

Create peer connections

Add the existingPresenters received in joinRoom response as participants and create a peer connection with each of the presenters to start listening to them. Please note that this peer connection type should be receiveOnly, meaning you will be able to only receive the audio stream, and not send anything. The iceServer details received after authentication will be used to create peer connections later. Sample SDP offer for peer connection will look like as below:

{
    "sdpOffer": "v=0\r\no=- 2217917876931547465 2 IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\na=group:BUNDLE 0\r\na=msid-semantic: WMS\r\nm=audio 9 UDP/TLS/RTP/SAVPF 111 103 104 9 0 8 106 105 13 110 112 113 126\r\nc=IN IP4 0.0.0.0\r\na=rtcp:9 IN IP4 0.0.0.0\r\na=ice-ufrag:40GQ\r\na=ice-pwd:6fK0yHKYhailmhIoyClkgcTe\r\na=ice-options:trickle\r\na=fingerprint:sha-256 D2:A1:87:77:B1:42:56:84:6A:C7:74:1D:91:E2:BD:E0:21:10:AF:E3:61:2D:E2:71:B1:5D:D0:09:F3:19:8E:CF\r\na=setup:actpass\r\na=mid:0\r\na=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level\r\na=extmap:2 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01\r\na=extmap:3 urn:ietf:params:rtp-hdrext:sdes:mid\r\na=extmap:4 urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id\r\na=extmap:5 urn:ietf:params:rtp-hdrext:sdes:repaired-rtp-stream-id\r\na=recvonly\r\na=rtcp-mux\r\na=rtpmap:111 opus/48000/2\r\na=rtcp-fb:111 transport-cc\r\na=fmtp:111 minptime=10;useinbandfec=1\r\na=rtpmap:103 ISAC/16000\r\na=rtpmap:104 ISAC/32000\r\na=rtpmap:9 G722/8000\r\na=rtpmap:0 PCMU/8000\r\na=rtpmap:8 PCMA/8000\r\na=rtpmap:106 CN/32000\r\na=rtpmap:105 CN/16000\r\na=rtpmap:13 CN/8000\r\na=rtpmap:110 telephone-event/48000\r\na=rtpmap:112 telephone-event/32000\r\na=rtpmap:113 telephone-event/16000\r\na=rtpmap:126 telephone-event/8000\r\n",
    "userId": "6s7c6:b:53l54g85-bc4d-4pb4-7s3c-e95519546007",
    "type": "receiveMedia",
    "id": "07ad868c-3946-4e8d-a81f-c67ad249f9ef"
}

Notice that the userId is the same as you receive in presenters list after joining the room. And in response you should get following SDP Answer with the same id:

{
    "sdpAnswer": "v\u003d0\r\no\u003d- 3776677610 3776677610 IN IP4 0.0.0.0\r\ns\u003dKurento Media Server\r\nc\u003dIN IP4 0.0.0.0\r\nt\u003d0 0\r\na\u003dmsid-semantic: WMS\r\na\u003dgroup:BUNDLE 0\r\nm\u003daudio 1 UDP/TLS/RTP/SAVPF 111 0\r\na\u003dsendonly\r\na\u003dmid:0\r\na\u003drtcp:9 IN IP4 0.0.0.0\r\na\u003drtpmap:111 opus/48000/2\r\na\u003drtpmap:0 PCMU/8000\r\na\u003dsetup:active\r\na\u003drtcp-mux\r\na\u003dfmtp:111 minptime\u003d10;useinbandfec\u003d1\r\na\u003dssrc:3259874899 cname:user3003646761@host-f035f63\r\na\u003dice-ufrag:ZEqH\r\na\u003dice-pwd:c9hVTWeSptMEFmUB8BTUnY\r\na\u003dfingerprint:sha-256 BF:AE:4D:4B:72:78:40:0F:72:E7:B3:41:31:DB:1D:D6:A6:F6:45:DB:31:36:03:49:30:0C:70:7A:7D:85:86:6A\r\n",
    "id": "07ad868c-3946-4e8d-a81f-c67ad249f9ef"
}

If you receive any error then, reject the connection.

Send ICE Candidate to peers

Typical request/message format to send iceCandidate:

{
    "candidate": {
        "candidate": "candidate:2315357691 1 udp 2113937151 192.168.2.5 49040 typ host generation 0 ufrag IRp1 network-cost 999",
        "sdpMid": "0",
        "sdpMLineIndex": 0
    },
    "userId": "5e098:b:53d53f95-ad4d-4eb4-9b4c-c84519546030",
    "type": "iceCandidate",
    "id": "50438f33-f2b5-47aa-a0b2-0cb2a082af96"
}

Message Types

You should add a handler for the following message types

  • newPresenterArrived Indicating the new presenter/broadcaster has joined. Add new presenter creating a new peer connection. typical newPresenterArrived message will be as follow:
{
    "user": {
        "userId": "6s7c6:b:53l54g85-bc4d-4pb4-7s3c-e95519546007",
        "username": "Charles Gross"
    },
    "type": "newPresenterArrived"
}
  • iceCandidate Add the iceCandidate to the participant. A typical iceCandidate message/request will be in the following format:
{
    "userId": "6s7c6:b:53l54g85-bc4d-4pb4-7s3c-e95519546007",
    "candidate": {
        "candidate": "candidate:5 2 TCP 1015022078 10.0.2.227 9 typ host tcptype active",
        "sdpMid": "0",
        "sdpMLineIndex": 0
    },
    "type": "iceCandidate"
}

From userId, you can map the iceCandidate to the existing presenter/participant.

  • presenterLeft Close the peer connection and remove the presenter using received userId in the message. Typical presenterLeft message will be received in below format:
{
    "userId": "6s7c6:b:53l54g85-bc4d-4pb4-7s3c-e95519546007",
    "type": "presenterLeft"
}
  • mediaOverride Meaning this user has started playing from another session (could be logged in from another browser/client). So discard all peer connections and disconnect from this session. The mediaOverride message will be in the following format:
{
    "type": "mediaOverride"
}

Ping/Pong mechanism to keep alive the Web Socket

Implement the regular interval ping messages to keep the Web Socket connection alive. Every 25-30 seconds should be good enough. Ping request format:

{
    "type": "ping",
    "id": "e4809b6b-319a-4fa9-94e0-94ae86a33f13"
}

In response, you should just get the same id:

{
    "id": "e4809b6b-319a-4fa9-94e0-94ae86a33f13"
}

Logout

Send the logout message when you want to stop listening or your container application's session ends. The logout request/message should be:

{
    "type": "logout",
    "id": "9461455c-6f4b-438d-b182-72cc2304521d"
}

Note that the value of id (here UUID) is unique with each message chain.

Using RTP

Squawk also supports RTP streaming, which can be useful if you are looking to re-broadcast from your media server or for any other RTP specific purpose. One can connect to squawk RTP by implementing the following mechanism.

For RTP receiver sample implementation, you can refer https://github.com/Benzinga/benzinga-squawk-client

Create a socket connection

Similar to WebRTC, for RTP also, the authentication, SDP negotiation, and other message exchange happens over WebSocket. So first connect to WebSocket. The Benzinga Squawk RTP service WebSocket address is:

wss://squawk-lb.benzinga.com/squawk/rtp

Note: Similar to WebRTC, RTP is also using WebSocket to exchange messages (auth,SDP, etc). So it is advised to add reconnect functionality in case socket connection drops. On socket connection close, the client should try for reconnecting at some interval. This will make it resilient.

Authenticate

Once the socket connection is created, authenticate with your apikey.

{
    "id": "2712dda2-fbde-11e9-92fe-39dd75a3017f",
    "role": "rtpreceiver",
    "type": "auth",
    "apikey": "f5kec5x6gplwdv8o5dcn5aydtyx132u8",
    "room": "PRO"
}

Note: Please get in touch with the Benzinga licensing team for acquiring apiKey. This is a one-time process. Save this API key securely.

Also, similar to WebRTC, the ID field (id) is a unique UUID string used to coordinate messages between client and server.

On successful authentication, you should get the following response:

{
    "status": "success",
    "type": "auth",
    "id": "2712dda2-fbde-11e9-92fe-39dd75a3017f"
}

Please take a note that, in response to each message you send, the id and type will be same. This makes it convinient to handle the incoming messages in the Squawk client library.

SDP negotiation

On successful authentication send the SDP offer message. Sample format as shown below:

{
    "id": "5599bc87-fbe2-11e9-8d09-51fadd4884apins9",
    "type": "sdp-offer",
    "sdpOffer": "v=0\nt=0 0\nm=audio 8449 RTP/AVP 98\nc=IN IP4 127.0.0.1\na=recvonly\na=rtpmap:98 opus/48000/2\na=fmtp:98 stereo=0; sprop-stereo=0; useinbandfec=1"
}

Quick overview of SDP fields

Sample SDP offer:

v=0
t=0 0
m=audio 8449 RTP/AVP 98
c=IN IP4 127.0.0.1
a=recvonly
a=rtpmap:98 opus/48000/2
a=fmtp:98 stereo=0; sprop-stereo=0; useinbandfec=1

Please note that to receive RTP stream on your end you must have a publicly accessible IP:Port. This IP and Port should be used in the SDP offer. For e.g. in the above SDP offer you should replace 127.0.0.1 in c=IN IP4 127.0.0.1 with your IP and replace 8449 in m=audio 8449 RTP/AVP 98 with your open port.

On successful negotiation you should get below response:

{
    "sdpAnswer": "v=0\r\no=- 3781517337 3781517337 IN IP4 172.19.0.1\r\ns=Kurento Media Server\r\nc=IN IP4 172.19.0.1\r\nt=0 0\r\nm=audio 64264 RTP/AVP 98\r\na=sendonly\r\na=rtpmap:98 opus/48000/2\r\na=fmtp:98 stereo=0; sprop-stereo=0; useinbandfec=1\r\na=ssrc:3730683656 cname:user554953802@host-4470434b\r\n",
    "type": "sdp-offer",
    "id": "5599bc87-fbe2-11e9-8d09-51fadd4884a9"
}

sdpAnswer can be useful if you are aiming to re-broadcast the stream via WebRTC through any media server on your end. If not then simply ignore that. At this point, after successful SDP negotiation, you should start receiving RTP audio stream from Squawk.

Logout

Send the logout message when you want to stop receiving RTP stream

{
    "type": "logout",
    "id": "9461455c-6f4b-438d-b182-72cc2304521d"
}

Ideally, you should send a logout message to Squawk before closing/shutting down your application.

Media Override Notification

This is the notification that will be sent from Squawk to WebSocket client in a case where you logged in from another session (somewhere else) using the same API key.

So you should add a handler for this message in your client. The media override message will be in the below format:

{
    "type": "media-override"
}

Probably, you should close the socket connection in the current session on receiving the media override notification.

Ping/Pong mechanism

Similar to WebRTC socket, implement the regular interval ping messages to keep the Web Socket connection alive. Every 25-30 seconds should be good enough. Ping request format:

{
    "type": "ping",
    "id": "e4809b6b-319a-4fa9-94e0-94ae86a33f13"
}

In case if you are using a WebSocket library, it may already have this mechanism and in such a case, you don't need to add the ping message sending functionality.