WebRTC audio/video call and conferencing server.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

210 lines
6.9 KiB

/*
* Spreed WebRTC.
* Copyright (C) 2013-2015 struktur AG
*
* This file is part of Spreed WebRTC.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package api
import (
"log"
"github.com/strukturag/spreed-webrtc/go/channelling"
)
const (
maxConferenceSize = 100
apiVersion = 1.4 // Keep this in sync with CHANNELING-API docs.Hand
)
type channellingAPI struct {
RoomStatusManager channelling.RoomStatusManager
SessionEncoder channelling.SessionEncoder
SessionManager channelling.SessionManager
StatsCounter channelling.StatsCounter
ContactManager channelling.ContactManager
TurnDataCreator channelling.TurnDataCreator
Unicaster channelling.Unicaster
BusManager channelling.BusManager
PipelineManager channelling.PipelineManager
config *channelling.Config
}
// New creates and initializes a new ChannellingAPI using
// various other services for initialization. It is intended to handle
// incoming and outgoing channeling API events from clients.
func New(config *channelling.Config,
roomStatus channelling.RoomStatusManager,
sessionEncoder channelling.SessionEncoder,
sessionManager channelling.SessionManager,
statsCounter channelling.StatsCounter,
contactManager channelling.ContactManager,
turnDataCreator channelling.TurnDataCreator,
unicaster channelling.Unicaster,
busManager channelling.BusManager,
pipelineManager channelling.PipelineManager) channelling.ChannellingAPI {
return &channellingAPI{
roomStatus,
sessionEncoder,
sessionManager,
statsCounter,
contactManager,
turnDataCreator,
unicaster,
busManager,
pipelineManager,
config,
}
}
func (api *channellingAPI) OnConnect(client *channelling.Client, session *channelling.Session) (interface{}, error) {
api.Unicaster.OnConnect(client, session)
self, err := api.HandleSelf(session)
if err == nil {
api.BusManager.Trigger(channelling.BusManagerConnect, session.Id, "", nil, nil)
}
return self, err
}
func (api *channellingAPI) OnDisconnect(client *channelling.Client, session *channelling.Session) {
api.Unicaster.OnDisconnect(client, session)
api.BusManager.Trigger(channelling.BusManagerDisconnect, session.Id, "", nil, nil)
}
func (api *channellingAPI) OnIncoming(sender channelling.Sender, session *channelling.Session, msg *channelling.DataIncoming) (interface{}, error) {
var pipeline *channelling.Pipeline
switch msg.Type {
case "Self":
return api.HandleSelf(session)
case "Hello":
if msg.Hello == nil {
return nil, channelling.NewDataError("bad_request", "message did not contain Hello")
}
return api.HandleHello(session, msg.Hello, sender)
case "Offer":
if msg.Offer == nil || msg.Offer.Offer == nil {
log.Println("Received invalid offer message.", msg)
break
}
if _, ok := msg.Offer.Offer["_token"]; !ok {
pipeline = api.PipelineManager.GetPipeline(channelling.PipelineNamespaceCall, sender, session, msg.Offer.To)
// Trigger offer event when offer has no token, so this is
// not triggered for peerxfer and peerscreenshare offers.
api.BusManager.Trigger(channelling.BusManagerOffer, session.Id, msg.Offer.To, nil, pipeline)
}
session.Unicast(msg.Offer.To, msg.Offer, pipeline)
case "Candidate":
if msg.Candidate == nil || msg.Candidate.Candidate == nil {
log.Println("Received invalid candidate message.", msg)
break
}
pipeline = api.PipelineManager.GetPipeline(channelling.PipelineNamespaceCall, sender, session, msg.Candidate.To)
session.Unicast(msg.Candidate.To, msg.Candidate, pipeline)
case "Answer":
if msg.Answer == nil || msg.Answer.Answer == nil {
log.Println("Received invalid answer message.", msg)
break
}
if _, ok := msg.Answer.Answer["_token"]; !ok {
pipeline = api.PipelineManager.GetPipeline(channelling.PipelineNamespaceCall, sender, session, msg.Answer.To)
// Trigger answer event when answer has no token. so this is
// not triggered for peerxfer and peerscreenshare answers.
api.BusManager.Trigger(channelling.BusManagerAnswer, session.Id, msg.Answer.To, nil, pipeline)
}
session.Unicast(msg.Answer.To, msg.Answer, pipeline)
case "Users":
return api.HandleUsers(session)
case "Authentication":
if msg.Authentication == nil || msg.Authentication.Authentication == nil {
return nil, channelling.NewDataError("bad_request", "message did not contain Authentication")
}
return api.HandleAuthentication(session, msg.Authentication.Authentication)
case "Bye":
if msg.Bye == nil {
log.Println("Received invalid bye message.", msg)
break
}
pipeline = api.PipelineManager.GetPipeline(channelling.PipelineNamespaceCall, sender, session, msg.Bye.To)
api.BusManager.Trigger(channelling.BusManagerBye, session.Id, msg.Bye.To, nil, pipeline)
session.Unicast(msg.Bye.To, msg.Bye, pipeline)
if pipeline != nil {
pipeline.Close()
}
case "Status":
if msg.Status == nil {
log.Println("Received invalid status message.", msg)
break
}
//log.Println("Status", msg.Status)
session.Update(&channelling.SessionUpdate{Types: []string{"Status"}, Status: msg.Status.Status})
session.BroadcastStatus()
case "Chat":
if msg.Chat == nil || msg.Chat.Chat == nil {
log.Println("Received invalid chat message.", msg)
break
}
api.HandleChat(session, msg.Chat)
case "Conference":
if msg.Conference == nil {
log.Println("Received invalid conference message.", msg)
break
}
api.HandleConference(session, msg.Conference)
case "Alive":
return msg.Alive, nil
case "Sessions":
if msg.Sessions == nil || msg.Sessions.Sessions == nil {
return nil, channelling.NewDataError("bad_request", "message did not contain Sessions")
}
return api.HandleSessions(session, msg.Sessions.Sessions)
case "Room":
if msg.Room == nil {
return nil, channelling.NewDataError("bad_request", "message did not contain Room")
}
return api.HandleRoom(session, msg.Room)
case "Leave":
if err := api.HandleLeave(session); err != nil {
return nil, err
}
return nil, nil
default:
log.Println("OnText unhandled message type", msg.Type)
}
return nil, nil
}
func (api *channellingAPI) OnIncomingProcessed(sender channelling.Sender, session *channelling.Session, msg *channelling.DataIncoming, reply interface{}, err error) {
switch msg.Type {
case "Hello":
api.HelloProcessed(sender, session, msg, reply, err)
case "Room":
api.RoomProcessed(sender, session, msg, reply, err)
}
}