Skip to content

Commit 8df117a

Browse files
authored
Merge pull request #89 from millicast/develop
Release v0.1.9
2 parents d0575ee + 0f89817 commit 8df117a

13 files changed

+236
-24
lines changed

packages/millicast-sdk/package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/millicast-sdk/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@millicast/sdk",
3-
"version": "0.1.8",
3+
"version": "0.1.9",
44
"description": "SDK for building a realtime broadcaster using the Millicast platform.",
55
"keywords": [
66
"sdk",

packages/millicast-sdk/src/Director.js

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ const streamTypes = {
77
RTMP: 'Rtmp'
88
}
99

10+
let liveWebsocketDomain = ''
1011
export const defaultApiEndpoint = 'https://director.millicast.com'
1112
let apiEndpoint = defaultApiEndpoint
1213

@@ -59,6 +60,26 @@ export default class Director {
5960
return apiEndpoint
6061
}
6162

63+
/**
64+
* Set Websocket Live domain from Director API response.
65+
* If it is set to empty, it will not parse the response.
66+
*
67+
* @param {String} domain - New Websocket Live domain
68+
*/
69+
static setLiveDomain (domain) {
70+
liveWebsocketDomain = domain.replace(/\/$/, '')
71+
}
72+
73+
/**
74+
* Get current Websocket Live domain.
75+
*
76+
* By default is empty which corresponds to not parse the Director response.
77+
* @returns {String} Websocket Live domain
78+
*/
79+
static getLiveDomain () {
80+
return liveWebsocketDomain
81+
}
82+
6283
/**
6384
* Get publisher connection data.
6485
* @param {DirectorPublisherOptions | String} options - Millicast options or *Deprecated Millicast Publishing Token.*
@@ -96,7 +117,8 @@ export default class Director {
96117
const headers = { Authorization: `Bearer ${optionsParsed.token}` }
97118
const url = `${this.getEndpoint()}/api/director/publish`
98119
try {
99-
const { data } = await axios.post(url, payload, { headers })
120+
let { data } = await axios.post(url, payload, { headers })
121+
data = parseIncomingDirectorResponse(data)
100122
logger.debug('Getting publisher response: ', data)
101123
return data.data
102124
} catch (e) {
@@ -149,7 +171,8 @@ export default class Director {
149171
}
150172
const url = `${this.getEndpoint()}/api/director/subscribe`
151173
try {
152-
const { data } = await axios.post(url, payload, { headers })
174+
let { data } = await axios.post(url, payload, { headers })
175+
data = parseIncomingDirectorResponse(data)
153176
logger.debug('Getting subscriber response: ', data)
154177
return data.data
155178
} catch (e) {
@@ -182,3 +205,12 @@ const getSubscriberOptions = (options, legacyStreamAccountId, legacySubscriberTo
182205
}
183206
return parsedOptions
184207
}
208+
209+
const parseIncomingDirectorResponse = (directorResponse) => {
210+
if (Director.getLiveDomain()) {
211+
const domainRegex = /(?<=\/\/)(.*?)(?=\/)/
212+
const urlsParsed = directorResponse.data.urls.map(url => url.replace(domainRegex, Director.getLiveDomain()))
213+
directorResponse.data.urls = urlsParsed
214+
}
215+
return directorResponse
216+
}

packages/millicast-sdk/src/PeerConnection.js

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ export const webRTCEvents = {
1515
connectionStateChange: 'connectionStateChange'
1616
}
1717

18+
export const defaultTurnServerLocation = 'https://turn.millicast.com/webrtc/_turn'
19+
let turnServerLocation = defaultTurnServerLocation
20+
1821
const localSDPOptions = {
1922
stereo: false,
2023
mediaStream: null,
@@ -40,6 +43,25 @@ export default class PeerConnection extends EventEmitter {
4043
this.peerConnectionStats = null
4144
}
4245

46+
/**
47+
* Set TURN server location.
48+
*
49+
* @param {String} url - New TURN location
50+
*/
51+
static setTurnServerLocation (url) {
52+
turnServerLocation = url
53+
}
54+
55+
/**
56+
* Get current TURN location.
57+
*
58+
* By default, https://turn.millicast.com/webrtc/_turn is the current TURN location.
59+
* @returns {String} TURN url
60+
*/
61+
static getTurnServerLocation () {
62+
return turnServerLocation
63+
}
64+
4365
/**
4466
* Instance new RTCPeerConnection.
4567
* @param {RTCConfiguration} config - Peer configuration.
@@ -91,10 +113,11 @@ export default class PeerConnection extends EventEmitter {
91113

92114
/**
93115
* Get Ice servers from a Millicast signaling server.
94-
* @param {String} location - URL of signaling server where Ice servers will be obtained.
116+
* @param {String} location - *Deprecated, use .setTurnServerLocation() method instead* URL of signaling server where Ice servers will be obtained.
95117
* @returns {Promise<Array<RTCIceServer>>} Promise object which represents a list of Ice servers.
96118
*/
97-
async getRTCIceServers (location = 'https://turn.millicast.com/webrtc/_turn') {
119+
async getRTCIceServers (location) {
120+
location = location ?? turnServerLocation
98121
logger.info('Getting RTC ICE servers')
99122
logger.debug('RTC ICE servers request location: ', location)
100123

packages/millicast-sdk/src/StreamEvents.js

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ const logger = Logger.get('StreamEvents')
88
const messageType = { REQUEST: 1, RESPONSE: 3 }
99
let invocationId = 0
1010

11+
export const defaultEventsLocation = 'wss://streamevents.millicast.com/ws'
12+
let eventsLocation = defaultEventsLocation
13+
1114
const errorMsg = 'You need to initialize stream event with StreamEvents.init()'
1215

1316
/**
@@ -40,12 +43,31 @@ export default class StreamEvents {
4043
*/
4144
static async init () {
4245
const instance = new StreamEvents()
43-
instance.eventSubscriber = new EventSubscriber()
46+
instance.eventSubscriber = new EventSubscriber(this.getEventsLocation())
4447
await instance.eventSubscriber.initializeHandshake()
4548

4649
return instance
4750
}
4851

52+
/**
53+
* Set Websocket Stream Events location.
54+
*
55+
* @param {String} url - New Stream Events location
56+
*/
57+
static setEventsLocation (url) {
58+
eventsLocation = url
59+
}
60+
61+
/**
62+
* Get current Websocket Stream Events location.
63+
*
64+
* By default, wss://streamevents.millicast.com/ws is the location.
65+
* @returns {String} Stream Events location
66+
*/
67+
static getEventsLocation () {
68+
return eventsLocation
69+
}
70+
4971
/**
5072
* Subscribes to User Count event and invokes the callback once a new message is available.
5173
* @param {String} accountId - Millicast Account Id.

packages/millicast-sdk/src/utils/EventSubscriber.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,13 @@ import Logger from '../Logger'
22
import EventEmitter from 'events'
33

44
const logger = Logger.get('EventSubscriber')
5-
export const eventsLocation = 'wss://streamevents.millicast.com/ws'
65
export const recordSeparator = '\x1E'
76

87
export default class EventSubscriber extends EventEmitter {
9-
constructor () {
8+
constructor (eventsLocation) {
109
super()
1110
this.webSocket = null
11+
this.eventsLocation = eventsLocation
1212
}
1313

1414
/**
@@ -41,7 +41,7 @@ export default class EventSubscriber extends EventEmitter {
4141
if (this.webSocket?.readyState !== WebSocket.CONNECTING && this.webSocket?.readyState !== WebSocket.OPEN) {
4242
return new Promise((resolve, reject) => {
4343
logger.info('Starting events WebSocket handshake.')
44-
this.webSocket = new WebSocket(eventsLocation)
44+
this.webSocket = new WebSocket(this.eventsLocation)
4545
this.webSocket.onopen = () => {
4646
logger.info('Connection established with events WebSocket.')
4747
const handshakeRequest = {

packages/millicast-sdk/tests/features/GetIceServer.feature

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,8 @@ Feature: As a user I want to get ICE server so I can configure a peer connection
2424
Given I do not have an ICE server location
2525
When I want to get the RTC Ice Servers and server responds with 500 error
2626
Then returns empty ICE Servers
27+
28+
Scenario: Get RTC Ice servers with custom location set in static method
29+
Given I have an ICE server location
30+
When I set the TURN server location and I want to get the RTC Ice Servers
31+
Then returns the ICE Servers

packages/millicast-sdk/tests/features/GetPublisherConnectionPath.feature

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,9 @@ Feature: As a user I want to publish to a Millicast Stream so I can get a connec
2323
Scenario: Publish with an existing stream name, valid token and options as object
2424
Given I have a valid token and an existing stream name
2525
When I request a connection path to Director API using options object
26+
Then I get the publish connection path
27+
28+
Scenario: Publish to an existing stream name, valid token and custom live websocket domain
29+
Given I have a valid token and an existing stream name
30+
When I set a custom live websocket domain and I request a connection path to Director API
2631
Then I get the publish connection path

packages/millicast-sdk/tests/features/GetSubscriberConnectionPath.feature

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,9 @@ Feature: As a user I want to subscribe to a Millicast Stream so I can get a conn
2323
Scenario: Subscribe to an existing unrestricted stream, valid accountId, no token and options as object
2424
Given I have an existing stream name, accountId and no token
2525
When I request a connection path to Director API using options object
26+
Then I get the subscriber connection path
27+
28+
Scenario: Subscribe to an existing stream, valid accountId, no token and custom live websocket domain
29+
Given I have an existing stream name, accountId and no token
30+
When I set a custom live websocket domain and I request a connection path to Director API
2631
Then I get the subscriber connection path

packages/millicast-sdk/tests/features/step-definitions/GetIceServer.steps.js

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
import { loadFeature, defineFeature } from 'jest-cucumber'
22
import axios from 'axios'
3-
import PeerConnection from '../../../src/PeerConnection'
3+
import PeerConnection, { defaultTurnServerLocation } from '../../../src/PeerConnection'
44
import './__mocks__/MockMediaStream'
55
const feature = loadFeature('../GetIceServer.feature', { loadRelativePath: true, errors: true })
66

77
jest.mock('axios')
88

99
defineFeature(feature, test => {
1010
afterEach(async () => {
11+
PeerConnection.setTurnServerLocation(defaultTurnServerLocation)
1112
jest.restoreAllMocks()
1213
})
1314

@@ -167,4 +168,46 @@ defineFeature(feature, test => {
167168
expect(iceServers).toEqual([])
168169
})
169170
})
171+
172+
test('Get RTC Ice servers with custom location set in static method', ({ given, when, then }) => {
173+
const peerConnection = new PeerConnection()
174+
const axiosResponse = {
175+
data: {
176+
v: {
177+
iceServers: [
178+
{
179+
url: 'stun:us-turn4.xirsys.com'
180+
},
181+
{
182+
username: 'gXvMYEfTmYMN0kBpnL0jJ947Fadjts8n4CFUTS4j_eqZ0De7Lx4lHzlI40gLyhI8AAAAAGCC7OptaWxsaWNhc3Q=',
183+
url: 'turn:us-turn4.xirsys.com:80?transport=udp',
184+
credential: 'b74d7ac6-a44b-11eb-a304-0242ac140004'
185+
}
186+
]
187+
},
188+
s: 'ok'
189+
}
190+
}
191+
let location
192+
let iceServers
193+
194+
given('I have an ICE server location', async () => {
195+
location = 'https://myIceServersLocation.com/webrtc'
196+
})
197+
198+
when('I set the TURN server location and I want to get the RTC Ice Servers', async () => {
199+
axios.put.mockResolvedValue(axiosResponse)
200+
PeerConnection.setTurnServerLocation(location)
201+
iceServers = await peerConnection.getRTCIceServers()
202+
})
203+
204+
then('returns the ICE Servers', async () => {
205+
expect(PeerConnection.getTurnServerLocation()).toBe(location)
206+
for (const iceServer of iceServers) {
207+
expect(iceServer.url).toBeUndefined()
208+
expect(iceServer.urls).not.toBeUndefined()
209+
expect(axiosResponse.data.v.iceServers.filter(x => x.url === iceServer.urls)).toBeDefined()
210+
}
211+
})
212+
})
170213
})

0 commit comments

Comments
 (0)