Git Product home page Git Product logo

kraken's Introduction

Kraken

๐Ÿ™ High performance WebRTC SFU implemented with pure Go.

Architecture

Kraken SFU only supports simple group audio conferencing, more features may be added easily.

Both Unified Plan and RTCP-MUX supported, so that only one UDP port per participant despite the number of participants in a room.

monitor [WIP]

This is the daemon that load balance all engine instances according to their system load, and it will direct all peers in a room to the same engine instance.

engine

The engine handles rooms, all peers in a room should connect to the same engine instance. No need to create rooms, a room is just an ID to distribute streams.

Access the engine with HTTP JSON-RPC, some pseudocode to demonstrate the full procedure.

var roomId = getUrlQueryParameter('room');
var userId = uuidv4();
var trackId;

var pc = new RTCPeerConnection(configuration);

// send ICE candidate to engine
pc.onicecandidate = ({candidate}) => {
  rpc('trickle', [roomId, userId, trackId, JSON.stringify(candidate)]);
};

// play the audio stream when available
pc.ontrack = (event) => {
  el = document.createElement(event.track.kind)
  el.id = aid;
  el.srcObject = stream;
  el.autoplay = true;
  document.getElementById('peers').appendChild(el)
};

// setup local audio stream from microphone
const stream = await navigator.mediaDevices.getUserMedia(constraints);
stream.getTracks().forEach((track) => {
  pc.addTrack(track, stream);
});
await pc.setLocalDescription(await pc.createOffer());

// RPC publish to roomId, with SDP offer
var res = await rpc('publish', [roomId, userId, JSON.stringify(pc.localDescription)]);
// publish should respond an SDP answer
var jsep = JSON.parse(res.data.jsep);
if (jsep.type == 'answer') {
  await pc.setRemoteDescription(jsep);
  trackId = res.data.track;
  subscribe(pc);
}

// RPC subscribe to roomId periodically
async function subscribe(pc) {
  var res = await rpc('subscribe', [roomId, userId, trackId]);
  var jsep = JSON.parse(res.data.jsep);
  if (jsep.type == 'offer') {
    await pc.setRemoteDescription(jsep);
    var sdp = await pc.createAnswer();
    await pc.setLocalDescription(sdp);
    // RPC anwser the subscribe offer
    await rpc('answer', [roomId, userId, trackId, JSON.stringify(sdp)]);
  }
  setTimeout(function () {
    subscribe(pc);
  }, 3000);
}

async function rpc(method, params = []) {
  const response = await fetch('http://localhost:7000', {
    method: 'POST',
    mode: 'cors',
    headers: {
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({id: uuidv4(), method: method, params: params})
  });
  return response.json();
}

Quick Start

Setup Golang development environment at first.

git clone https://github.com/MixinNetwork/kraken
cd kraken && go build

cp config/engine.example.toml config/engine.toml
ip address # get your network interface name, edit config/engine.toml

./kraken -c config/engine.toml -s engine

Get the source code of either kraken.fm or Mornin, follow their guides to use your local kraken API.

Community

Kraken is built with Pion, we have discussions over their Slack.

kraken's People

Contributors

cedricfung avatar crossle avatar josharian avatar sean-der avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

kraken's Issues

Obscure API and very slow dev

https://vec.io/posts/kraken-high-performance-webrtc-sfu

This is a very disrespectful post. It's ok that you discard SFUs just because they are not written in Go (the only language valid for you) but at least do not write shit about them.

A "SFU just for audio" can be done in 15 minutes, so you have done nothing special.

And BTW:

  • Unified-Plan is not a "super recent and cool WebRTC feature". It's been there for long years.
  • Adding video is not "an easy extension". Well, you'll see when you try to implement it.

In short: you should not write shit about others just because you want to promote your own solution on Go.

A problem about deploying the project

I just wanted to deploy the project to the server, but now I have this problem.Don't know how to solve it.
Looking at the log, I think it's a connection error.But I don't know what's wrong?

`
image
image
image

`

documentation questions

I have some questions that are not covered by the documentation:

Is port 9000 used for anything? (it shows up in netstat)

Do I need coturn or does kraken also work without a turnserver?
https://github.com/MixinNetwork/kraken#quick-start doesn't mention a turnserver,
but https://vec.io/posts/deploy-a-group-audio-conferencing-service does.

I'm running kraken inside a container with a local IP and and a reverse proxy on the public IP. Do I have to configure any additional port forwards? (UDP ports?)

go build: cannot find package

Following setup instructions, I get the following:

$ go build
main.go:11:2: cannot find package "github.com/MixinNetwork/kraken/engine" in any of:
        /usr/lib/go-1.6/src/github.com/MixinNetwork/kraken/engine (from $GOROOT)
        ($GOPATH not set)
main.go:12:2: cannot find package "github.com/MixinNetwork/kraken/monitor" in any of:
        /usr/lib/go-1.6/src/github.com/MixinNetwork/kraken/monitor (from $GOROOT)
        ($GOPATH not set)
main.go:13:2: cannot find package "github.com/MixinNetwork/mixin/logger" in any of:
        /usr/lib/go-1.6/src/github.com/MixinNetwork/mixin/logger (from $GOROOT)
        ($GOPATH not set)

Use server-sent events to push remote SDP instead of polling with subscribe request

It might be more efficent to use server-sent events to push the SDP of remote peer connections to a participant instead of polling for them with subscribe requests using JavasScript setTimeout.

I am a Java developer and not a Go developer otherwise, I would have sent you a PR using one of the available Go implementations eventsource or go-sse

BTW, I am a fan of your work and I love your blogs. I appreciate your contributions to real-time communications even though WebRTC is not your main focus and English is probably not your only language of communication.

Possibility of memory leak?

When someone get connected and disconnected to the kraken server, the occupied memory usage seems still consuming the resources.

Is it due to nginx' cache problem or just time-consuming work to flush allocated memory?

Creating a listen only method

I am using Kraken to build an application which requires some room participants to be listeners only (i.e. do not publish their audio to the room). I am trying to figure out the best way to go about this.

  1. Can the current subscribe method already handle this? Do I just need to reconfigure the client side javascript to handle this?
  2. Regardless of the first question, there is a security design question this brings up. If a user is in listen-only mode and joins via the same room ID as those using who are publishing their audio, a user could theoretically inject a publish method themselves via client side code. One clever workaround here could be to create two room ID's for each room - one that allows a user to subscribe and publish, and one that only allows the user to subscribe.

Happy to help on building this out and submitting a PR but quite frankly don't know where to start.

SSL Certificates

How to use ssl certificates for the server?, we all knew that WEBRTC needs an HTPS protocol to work

Question: video only

I am trying to reuse this awesome audio only SFU to make it video only.
I replaced the registered codec to accept VP8 and accept 96 as PayloadType in peer.go

However, it seems that for video I have to send a PLI every 3 seconds inside the same peer.pc.OnTrack method.

Question: why don't we need to send these PLI for audio only?

Here's the code I've added:

peer.pc.OnTrack(func(rt *webrtc.TrackRemote, receiver *webrtc.RTPReceiver) {
		logger.Printf("HandlePeer(%s) OnTrack(%d, %d)\n", peer.id(), rt.PayloadType(), rt.SSRC())
		if peer.track != nil || (111 != rt.PayloadType() && 109 != rt.PayloadType() && 96 != rt.PayloadType()) {
			return
		}
		peer.connected <- true

		peer.Lock()
		lt, err := webrtc.NewTrackLocalStaticRTP(rt.Codec().RTPCodecCapability, peer.cid, peer.uid)
		if err != nil {
			panic(err)
		}
		peer.track = lt
		peer.Unlock()

                 // NEW FUNCTION HERE TO REQUEST A PLI FROM THE REMOTE VIDEO TRACK
		go func() {
			ticker := time.NewTicker(rtcpPLIInterval)
			for range ticker.C {
				if rtcpSendErr := peer.pc.WriteRTCP([]rtcp.Packet{&rtcp.PictureLossIndication{MediaSSRC: uint32(rt.SSRC())}}); rtcpSendErr != nil {
					fmt.Println(rtcpSendErr)
				}
			}
		}()

The issue is how do I stop this function when the remote track ends or the connection closes?

Currently, my code displays the rtcpSendErr but I'd like to stop this go func.

Coturn to Kraken communication

Hi, Cedric. Thanks for your work on this! I've been troubleshooting my current setup pretty extensively. I was trying to mock up a production configuration for kraken while using the kraken.fm source code to test it out. I'm using the latest code from both projects, btw. And I'm using the "relay" option in the kraken.fm code. Could you embellish on a proper setup for coturn to get this working? Thanks!

Current status:

  • kraken.fm is able to connect to the api (I'm running the coturn server and the kraken service on the same ec2 instance, btw)
  • the coturn server is handling packets and mapping ports
  • after about 10 seconds I get these errors:
2020/09/21 14:18:16 HandlePeer(testing:ca5a8823-64e2-4b0f-9851-8fc9cd9cfb75%3ASGV5dGhlcmU%3D:aa8888df-fc40-4c6f-8df1-7b34d2e593b8) OnSignalingStateChange(have-remote-offer)
2020/09/21 14:18:16 HandlePeer(testing:ca5a8823-64e2-4b0f-9851-8fc9cd9cfb75%3ASGV5dGhlcmU%3D:aa8888df-fc40-4c6f-8df1-7b34d2e593b8) OnICEConnectionStateChange(checking)
2020/09/21 14:18:16 HandlePeer(testing:ca5a8823-64e2-4b0f-9851-8fc9cd9cfb75%3ASGV5dGhlcmU%3D:aa8888df-fc40-4c6f-8df1-7b34d2e593b8) OnSignalingStateChange(stable)
2020/09/21 14:18:16 RPC.handle(id: 4d007d8a-76ee-4d0a-aa63-14f535455aa6, time: 0.026520s) OK
2020/09/21 14:18:16 RPC.handle(id: 6b2ecad7-4984-4c19-afcd-4b1fa2a38db6, method: subscribe, params: [testing ca5a8823-64e2-4b0f-9851-8fc9cd9cfb75%3ASGV5dGhlcmU%3D aa8888df-fc40-4c6f-8df1-7b34d2e593b8])
2020/09/21 14:18:16 RPC.handle(id: 6b2ecad7-4984-4c19-afcd-4b1fa2a38db6, time: 0.000125s) OK
2020/09/21 14:18:20 RPC.handle(id: a2b36796-57b2-4c80-89d7-70057c4535ff, method: subscribe, params: [testing ca5a8823-64e2-4b0f-9851-8fc9cd9cfb75%3ASGV5dGhlcmU%3D aa8888df-fc40-4c6f-8df1-7b34d2e593b8])
2020/09/21 14:18:20 RPC.handle(id: a2b36796-57b2-4c80-89d7-70057c4535ff, time: 0.000121s) OK
2020/09/21 14:18:23 RPC.handle(id: defe36ab-20ae-4cd5-ad70-7a2cecd0be9c, method: subscribe, params: [testing ca5a8823-64e2-4b0f-9851-8fc9cd9cfb75%3ASGV5dGhlcmU%3D aa8888df-fc40-4c6f-8df1-7b34d2e593b8])
2020/09/21 14:18:23 RPC.handle(id: defe36ab-20ae-4cd5-ad70-7a2cecd0be9c, time: 0.000090s) OK
2020/09/21 14:18:26 RPC.handle(id: fda56f2d-7f59-43bf-b77a-bdf86c8c9c2d, method: subscribe, params: [testing ca5a8823-64e2-4b0f-9851-8fc9cd9cfb75%3ASGV5dGhlcmU%3D aa8888df-fc40-4c6f-8df1-7b34d2e593b8])
2020/09/21 14:18:26 RPC.handle(id: fda56f2d-7f59-43bf-b77a-bdf86c8c9c2d, time: 0.000139s) OK
2020/09/21 14:18:26 HandlePeer(testing:ca5a8823-64e2-4b0f-9851-8fc9cd9cfb75%3ASGV5dGhlcmU%3D:aa8888df-fc40-4c6f-8df1-7b34d2e593b8) OnTrackTimeout()
2020/09/21 14:18:26 PeerClose(testing:ca5a8823-64e2-4b0f-9851-8fc9cd9cfb75%3ASGV5dGhlcmU%3D:aa8888df-fc40-4c6f-8df1-7b34d2e593b8) now
2020/09/21 14:18:26 PeerClose(testing:ca5a8823-64e2-4b0f-9851-8fc9cd9cfb75%3ASGV5dGhlcmU%3D:CLOSED) with <nil>
2020/09/21 14:18:26 HandlePeer(testing:ca5a8823-64e2-4b0f-9851-8fc9cd9cfb75%3ASGV5dGhlcmU%3D:CLOSED) OnConnectionStateChange(closed)
2020/09/21 14:18:26 HandlePeer(testing:ca5a8823-64e2-4b0f-9851-8fc9cd9cfb75%3ASGV5dGhlcmU%3D:CLOSED) OnICEConnectionStateChange(closed)
2020/09/21 14:18:29 RPC.handle(id: 72e68ef2-b410-4a91-9d30-92130868cd01, method: subscribe, params: [testing ca5a8823-64e2-4b0f-9851-8fc9cd9cfb75%3ASGV5dGhlcmU%3D aa8888df-fc40-4c6f-8df1-7b34d2e593b8])
2020/09/21 14:18:29 RPC.handle(id: 72e68ef2-b410-4a91-9d30-92130868cd01, time: 0.000090s) ERROR {"status":202,"code":5002002,"description":"peer ca5a8823-64e2-4b0f-9851-8fc9cd9cfb75%3ASGV5dGhlcmU%3D closed in testing"}
2020/09/21 14:18:32 RPC.handle(id: cde4f29a-df09-4606-87b4-229bf817e67b, method: subscribe, params: [testing ca5a8823-64e2-4b0f-9851-8fc9cd9cfb75%3ASGV5dGhlcmU%3D aa8888df-fc40-4c6f-8df1-7b34d2e593b8])
2020/09/21 14:18:32 RPC.handle(id: cde4f29a-df09-4606-87b4-229bf817e67b, time: 0.000089s) ERROR {"status":202,"code":5002002,"description":"peer ca5a8823-64e2-4b0f-9851-8fc9cd9cfb75%3ASGV5dGhlcmU%3D closed in testing"}```


Get the list of rooms?

Is it possible to get the list of rooms with the REST API?
It would be great to have a JSON with the list of rooms + participants in each room

Something like this:

{"rooms": [
    {"name": "room1", users: 17},
    {"name": "room2", users: 5},
    {"name": "room3", users: 8},
    ...
]}

Also I noticed there is a quite long delay before a disconnected user is removed from the room, is this configurable?

Last point, the method "info" seems to be computed only once every 30 sec, is that also something that can be configured? if not could you give me a pointer about what part of the source code is responsible for this? :)

Thanks a lot for this great piece of OSS :)

Why not delete room or peer if they are useless

type pmap struct {
	sync.RWMutex
	id string
	m  map[string]*Peer
}
type rmap struct {
	sync.RWMutex
	m map[string]*pmap
}

I found the peer and room data in these 2 struct will never be deleted. I think this memory leak is a problem if the service running for a long time. What do you think?

Is it possible to change opus bandwidth a little lower than 48000?

Hi, Cedric.

After I checked the kraken system perfectly working on ec2 env, I found kraken using the opus codec and the setting has 48000 bandwidth.

But, that means to me, even if I send just a bit of data stream, there is sort of waste of data on time, I think.

Is it possible to change opus bandwidth a little lower than 48000?

Thank you again, Cedric.

Scalability with limited amount of UDP port for kraken

I saw your blog post, it stated each participants will consume 1 udp port on kraken, which means i could only have maximum of 48127 participants online simultaneously (common available udp port range 1024 to 49151), How to scale it up to allow more than that amount of users?

Here's the idea i got, make a daemon that actively monitor the usage of the kraken UDP port availability, and magically use a Load Balancing to distribute the traffic to others instance

Kraken service will be stuck after running 1 week

I deployed a kraken service recently, only deployed in one machine. I found the rpc http api will always timeout with no response after running about 1 week. If I restart the service, the http api will work again.

Do you have similar issue in your cluster? Is there any diagnostic data I can collect when the service stuck?

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.