import axios from 'axios'

export function SrsRtcPublisherAsync() {

    const self = {} as any

    self.constraints = {

        audio: true,

        video: { facingMode: 'user', width: 3840, height: 2160, frameRate: { ideal: 60, max: 60 } }

    }

    self.publish = async function (url: any) {

        // console.log(1)

        var conf = self.__internal.prepareUrl(url)

        self.pc.addTransceiver('audio', { direction: 'sendonly' })

        self.pc.addTransceiver('video', { direction: 'sendonly' })

        // console.log(2)

        var stream = await navigator.mediaDevices.getUserMedia(self.constraints)

        stream.getTracks().forEach(function (track) {

            self.pc.addTrack(track)

            self.ontrack && self.ontrack({ track: track })

        })

        // console.log(3)

        var offer = await self.pc.createOffer()

        await self.pc.setLocalDescription(offer)

        // console.log(4)

        var session: any = await new Promise(function (resolve, reject) {

            const params = {

                api: conf.apiUrl,

                tid: conf.tid,

                streamurl: conf.streamUrl,

                clientip: null,

                sdp: offer.sdp

            }

            // console.log(4.1)

            // console.log(conf.apiUrl)

            axios

                .post(conf.apiUrl, params)

                .then(res => {

                    const resData = res.data

                    if (resData.code) {

                        reject(resData)

                        return

                    }

                    // console.log(4.3)

                    // console.log('resData', resData)

                    resolve(resData)

                })

                .catch(err => {

                    reject(err)

                })

            // console.log(4.2)

        })

        // console.log(5)

        await self.pc.setRemoteDescription(new RTCSessionDescription({ type: 'answer', sdp: session.sdp }))

        session.simulator = conf.schema + '//' + conf.urlObject.server + ':' + conf.port + '/rtc/v1/nack/'

        // console.log('推流over', session)

        return session

    }

    // Close the publisher.

    self.close = function () {

        if (self.stream) {

            self.stream.getTracks().map((i: any) => {

                i.stop()

            })

            self.stream = null

        }

        self.pc && self.pc.close()

        self.pc = null

    }

    // The callback when got local stream.

    // @see https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/addStream#Migrating_to_addTrack

    self.ontrack = function (event: any) {

        // Add track to stream of SDK.

        self.stream.addTrack(event.track)

    }

    // Internal APIs.

    self.__internal = {

        defaultPath: '/rtc/v1/publish/',

        prepareUrl: function (webrtcUrl: any) {

            var urlObject = self.__internal.parse(webrtcUrl)

            // If user specifies the schema, use it as API schema.

            var schema = urlObject.user_query.schema

            schema = schema ? schema + ':' : window.location.protocol

            var port = urlObject.port || 1985

            if (schema === 'https:') {

                port = urlObject.port || 443

            }

            // @see https://github.com/rtcdn/rtcdn-draft

            var api = urlObject.user_query.play || self.__internal.defaultPath

            if (api.lastIndexOf('/') !== api.length - 1) {

                api += '/'

            }

            apiUrl = schema + '//' + urlObject.server + ':' + port + api

            for (var key in urlObject.user_query) {

                if (key !== 'api' && key !== 'play') {

                    apiUrl += '&' + key + '=' + urlObject.user_query[key]

                }

            }

            // Replace /rtc/v1/play/&k=v to /rtc/v1/play/?k=v

            var apiUrl: any = apiUrl.replace(api + '&', api + '?')

            var streamUrl = urlObject.url

            return {

                apiUrl: apiUrl,

                streamUrl: streamUrl,

                schema: schema,

                urlObject: urlObject,

                port: port,

                tid: Number(parseInt((new Date().getTime() * Math.random() * 100).toString()))

                    .toString(16)

                    .slice(0, 7)

            }

        },

        parse: function (url: any) {

            // @see: http://stackoverflow.com/questions/10469575/how-to-use-location-object-to-parse-url-without-redirecting-the-page-in-javascri

            var a = document.createElement('a')

            a.href = url.replace('rtmp://', 'http://').replace('webrtc://', 'http://').replace('rtc://', 'http://')

            var vhost = a.hostname

            var app = a.pathname.substring(1, a.pathname.lastIndexOf('/'))

            var stream = a.pathname.slice(a.pathname.lastIndexOf('/') + 1)

            // parse the vhost in the params of app, that srs supports.

            app = app.replace('...vhost...', '?vhost=')

            if (app.indexOf('?') >= 0) {

                var params = app.slice(app.indexOf('?'))

                app = app.slice(0, app.indexOf('?'))

                if (params.indexOf('vhost=') > 0) {

                    vhost = params.slice(params.indexOf('vhost=') + 'vhost='.length)

                    if (vhost.indexOf('&') > 0) {

                        vhost = vhost.slice(0, vhost.indexOf('&'))

                    }

                }

            }

            // when vhost equals to server, and server is ip,

            // the vhost is __defaultVhost__

            if (a.hostname === vhost) {

                var re = /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/

                if (re.test(a.hostname)) {

                    vhost = '__defaultVhost__'

                }

            }

            // parse the schema

            var schema = 'rtmp'

            if (url.indexOf('://') > 0) {

                schema = url.slice(0, url.indexOf('://'))

            }

            var port: any = a.port

            if (!port) {

                if (schema === 'http') {

                    port = 80

                } else if (schema === 'https') {

                    port = 443

                } else if (schema === 'rtmp') {

                    port = 1935

                }

            }

            var ret: any = {

                url: url,

                schema: schema,

                server: a.hostname,

                port: port,

                vhost: vhost,

                app: app,

                stream: stream

            }

            self.__internal.fill_query(a.search, ret)

            // For webrtc API, we use 443 if page is https, or schema specified it.

            if (!ret.port) {

                if (schema === 'webrtc' || schema === 'rtc') {

                    if (ret.user_query.schema === 'https') {

                        ret.port = 443

                    } else if (window.location.href.indexOf('https://') === 0) {

                        ret.port = 443

                    } else {

                        // For WebRTC, SRS use 1985 as default API port.

                        ret.port = 1985

                    }

                }

            }

            return ret

        },

        fill_query: function (query_string: any, obj: any) {

            // pure user query object.

            obj.user_query = {}

            if (query_string.length === 0) {

                return

            }

            // split again for angularjs.

            if (query_string.indexOf('?') >= 0) {

                query_string = query_string.split('?')[1]

            }

            var queries = query_string.split('&')

            for (var i = 0; i < queries.length; i++) {

                var elem = queries[i]

                var query = elem.split('=')

                obj[query[0]] = query[1]

                obj.user_query[query[0]] = query[1]

            }

            // alias domain for vhost.

            if (obj.domain) {

                obj.vhost = obj.domain

            }

        }

    }

    self.pc = new RTCPeerConnection(undefined)

    self.stream = new MediaStream()

    self.adjustSound = function (flag: boolean) {

        self.stream.getAudioTracks()[0].enabled = flag

    }

    self.adjustVideo = function (flag: boolean) {

        self.stream.getVideoTracks()[0].enabled = flag

    }

    return self

}

// Depends on adapter-7.4.0.min.js from https://github.com/webrtc/adapter

// Async-await-promise based SRS RTC Player.

export function SrsRtcPlayerAsync() {

    var self = {} as any

    self.play = async function (url: any) {

        var conf = self.__internal.prepareUrl(url)

        self.pc.addTransceiver('audio', { direction: 'recvonly' })

        self.pc.addTransceiver('video', { direction: 'recvonly' })

        var offer = await self.pc.createOffer()

        await self.pc.setLocalDescription(offer)

        var session: any = await new Promise(function (resolve, reject) {

            var params = {

                api: conf.apiUrl,

                tid: conf.tid,

                streamurl: conf.streamUrl,

                clientip: null,

                sdp: offer.sdp

            }

            // console.log('Generated offer: ', params)

            axios

                .post(conf.apiUrl, params)

                .then(res => {

                    const resData = res.data

                    // console.log('Got answer: ', resData)

                    if (resData.code) {

                        reject(resData)

                        return

                    }

                    resolve(resData)

                })

                .catch(err => {

                    reject(err)

                })

        })

        await self.pc.setRemoteDescription(new RTCSessionDescription({ type: 'answer', sdp: session.sdp }))

        session.simulator = conf.schema + '//' + conf.urlObject.server + ':' + conf.port + '/rtc/v1/nack/'

        // console.log('拉流', session)

        return session

    }

    // Close the player.

    self.close = function () {

        self.pc && self.pc.close()

        self.pc = null

    }

    // The callback when got remote track.

    // Note that the onaddstream is deprecated, @see https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/onaddstream

    self.ontrack = function (event: any) {

        // https://webrtc.org/getting-started/remote-streams

        self.stream.addTrack(event.track)

    }

    // Internal APIs.

    self.__internal = {

        defaultPath: '/rtc/v1/play/',

        prepareUrl: function (webrtcUrl: any) {

            var urlObject = self.__internal.parse(webrtcUrl)

            // If user specifies the schema, use it as API schema.

            var schema = urlObject.user_query.schema

            schema = schema ? schema + ':' : window.location.protocol

            var port = urlObject.port || 1985

            if (schema === 'https:') {

                port = urlObject.port || 443

            }

            // @see https://github.com/rtcdn/rtcdn-draft

            var api = urlObject.user_query.play || self.__internal.defaultPath

            if (api.lastIndexOf('/') !== api.length - 1) {

                api += '/'

            }

            apiUrl = schema + '//' + urlObject.server + ':' + port + api

            for (var key in urlObject.user_query) {

                if (key !== 'api' && key !== 'play') {

                    apiUrl += '&' + key + '=' + urlObject.user_query[key]

                }

            }

            // Replace /rtc/v1/play/&k=v to /rtc/v1/play/?k=v

            var apiUrl: any = apiUrl.replace(api + '&', api + '?')

            var streamUrl = urlObject.url

            return {

                apiUrl: apiUrl,

                streamUrl: streamUrl,

                schema: schema,

                urlObject: urlObject,

                port: port,

                tid: Number(parseInt((new Date().getTime() * Math.random() * 100).toString()))

                    .toString(16)

                    .slice(0, 7)

            }

        },

        parse: function (url: any) {

            // @see: http://stackoverflow.com/questions/10469575/how-to-use-location-object-to-parse-url-without-redirecting-the-page-in-javascri

            var a = document.createElement('a')

            a.href = url.replace('rtmp://', 'http://').replace('webrtc://', 'http://').replace('rtc://', 'http://')

            var vhost = a.hostname

            var app = a.pathname.substring(1, a.pathname.lastIndexOf('/'))

            var stream = a.pathname.slice(a.pathname.lastIndexOf('/') + 1)

            // parse the vhost in the params of app, that srs supports.

            app = app.replace('...vhost...', '?vhost=')

            if (app.indexOf('?') >= 0) {

                var params = app.slice(app.indexOf('?'))

                app = app.slice(0, app.indexOf('?'))

                if (params.indexOf('vhost=') > 0) {

                    vhost = params.slice(params.indexOf('vhost=') + 'vhost='.length)

                    if (vhost.indexOf('&') > 0) {

                        vhost = vhost.slice(0, vhost.indexOf('&'))

                    }

                }

            }

            // when vhost equals to server, and server is ip,

            // the vhost is __defaultVhost__

            if (a.hostname === vhost) {

                var re = /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/

                if (re.test(a.hostname)) {

                    vhost = '__defaultVhost__'

                }

            }

            // parse the schema

            var schema = 'rtmp'

            if (url.indexOf('://') > 0) {

                schema = url.slice(0, url.indexOf('://'))

            }

            var port: any = a.port

            if (!port) {

                if (schema === 'http') {

                    port = 80

                } else if (schema === 'https') {

                    port = 443

                } else if (schema === 'rtmp') {

                    port = 1935

                }

            }

            var ret: any = {

                url: url,

                schema: schema,

                server: a.hostname,

                port: port,

                vhost: vhost,

                app: app,

                stream: stream

            }

            self.__internal.fill_query(a.search, ret)

            // For webrtc API, we use 443 if page is https, or schema specified it.

            if (!ret.port) {

                if (schema === 'webrtc' || schema === 'rtc') {

                    if (ret.user_query.schema === 'https') {

                        ret.port = 443

                    } else if (window.location.href.indexOf('https://') === 0) {

                        ret.port = 443

                    } else {

                        // For WebRTC, SRS use 1985 as default API port.

                        ret.port = 1985

                    }

                }

            }

            return ret

        },

        fill_query: function (query_string: any, obj: any) {

            // pure user query object.

            obj.user_query = {}

            if (query_string.length === 0) {

                return

            }

            // split again for angularjs.

            if (query_string.indexOf('?') >= 0) {

                query_string = query_string.split('?')[1]

            }

            var queries = query_string.split('&')

            for (var i = 0; i < queries.length; i++) {

                var elem = queries[i]

                var query = elem.split('=')

                obj[query[0]] = query[1]

                obj.user_query[query[0]] = query[1]

            }

            // alias domain for vhost.

            if (obj.domain) {

                obj.vhost = obj.domain

            }

        }

    }

    self.pc = new RTCPeerConnection(undefined)

    // Create a stream to add track to the stream, @see https://webrtc.org/getting-started/remote-streams

    self.stream = new MediaStream()

    // https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/ontrack

    self.pc.ontrack = function (event: any) {

        if (self.ontrack) {

            self.ontrack(event)

        }

    }

    return self

}

// Format the codec of RTCRtpSender, kind(audio/video) is optional filter.

// https://developer.mozilla.org/en-US/docs/Web/Media/Formats/WebRTC_codecs#getting_the_supported_codecs

export function SrsRtcFormatSenders(senders: any, kind: any) {

    var codecs = [] as any

    senders.forEach(function (sender: any) {

        var params = sender.getParameters()

        params &&

            params.codecs &&

            params.codecs.forEach(function (c: any) {

                if (kind && sender.track.kind !== kind) {

                    return

                }

                if (

                    c.mimeType.indexOf('/red') > 0 ||

                    c.mimeType.indexOf('/rtx') > 0 ||

                    c.mimeType.indexOf('/fec') > 0

                ) {

                    return

                }

                var s = ''

                s += c.mimeType.replace('audio/', '').replace('video/', '')

                s += ', ' + c.clockRate + 'HZ'

                if (sender.track.kind === 'audio') {

                    s += ', channels: ' + c.channels

                }

                s += ', pt: ' + c.payloadType

                codecs.push(s)

            })

    })

    return codecs.join(', ')

}

Logo

邀请您加入社区

更多推荐