Refactoring for HomeKit client

This commit is contained in:
Alexey Khit
2022-11-11 21:56:58 +03:00
parent 7bc3534bcb
commit 77888fe086
22 changed files with 300 additions and 275 deletions

View File

@@ -5,8 +5,8 @@ import (
"fmt"
"github.com/AlexxIT/go2rtc/cmd/app/store"
"github.com/AlexxIT/go2rtc/cmd/streams"
"github.com/AlexxIT/go2rtc/pkg/homekit"
"github.com/AlexxIT/go2rtc/pkg/homekit/mdns"
"github.com/AlexxIT/go2rtc/pkg/hap"
"github.com/AlexxIT/go2rtc/pkg/hap/mdns"
"net/http"
"net/url"
"strings"
@@ -61,42 +61,50 @@ func apiHandler(w http.ResponseWriter, r *http.Request) {
id := r.URL.Query().Get("id")
pin := r.URL.Query().Get("pin")
conn, err := homekit.Pair(id, pin)
if err != nil {
// log error
name := r.URL.Query().Get("name")
if err := hkPair(id, pin, name); err != nil {
log.Error().Err(err).Caller().Send()
// response error
_, err = w.Write([]byte(err.Error()))
return
}
name := r.URL.Query().Get("name")
dict := store.GetDict("streams")
dict[name] = conn.URL()
if err = store.Set("streams", dict); err != nil {
// log error
case "DELETE":
src := r.URL.Query().Get("src")
if err := hkDelete(src); err != nil {
log.Error().Err(err).Caller().Send()
// response error
_, err = w.Write([]byte(err.Error()))
}
}
}
func hkPair(deviceID, pin, name string) (err error) {
var conn *hap.Conn
if conn, err = hap.Pair(deviceID, pin); err != nil {
return
}
streams.New(name, conn.URL())
case "DELETE":
src := r.URL.Query().Get("src")
dict := store.GetDict("streams")
for name, rawURL := range dict {
if name != src {
dict[name] = conn.URL()
return store.Set("streams", dict)
}
func hkDelete(name string) (err error) {
dict := store.GetDict("streams")
for key, rawURL := range dict {
if key != name {
continue
}
conn, err := homekit.Dial(rawURL.(string))
if err != nil {
// log error
log.Error().Err(err).Caller().Send()
// response error
_, err = w.Write([]byte(err.Error()))
var conn *hap.Conn
if conn, err = hap.NewConn(rawURL.(string)); err != nil {
return
}
if err = conn.Dial(); err != nil {
return
}
@@ -107,32 +115,19 @@ func apiHandler(w http.ResponseWriter, r *http.Request) {
}()
if err = conn.ListPairings(); err != nil {
// log error
log.Error().Err(err).Caller().Send()
// response error
_, err = w.Write([]byte(err.Error()))
return
}
if err = conn.DeletePairing(conn.ClientID); err != nil {
// log error
log.Error().Err(err).Caller().Send()
// response error
_, err = w.Write([]byte(err.Error()))
}
delete(dict, name)
if err = store.Set("streams", dict); err != nil {
// log error
log.Error().Err(err).Msg("[api.homekit] store set")
// response error
_, err = w.Write([]byte(err.Error()))
return store.Set("streams", dict)
}
return
}
}
return nil
}
type Device struct {

View File

@@ -3,6 +3,7 @@ package homekit
import (
"github.com/AlexxIT/go2rtc/cmd/api"
"github.com/AlexxIT/go2rtc/cmd/app"
"github.com/AlexxIT/go2rtc/cmd/srtp"
"github.com/AlexxIT/go2rtc/cmd/streams"
"github.com/AlexxIT/go2rtc/pkg/homekit"
"github.com/AlexxIT/go2rtc/pkg/streamer"
@@ -20,14 +21,12 @@ func Init() {
var log zerolog.Logger
func streamHandler(url string) (streamer.Producer, error) {
conn, err := homekit.Dial(url)
conn, err := homekit.NewClient(url, srtp.Server)
if err != nil {
return nil, err
}
exit := make(chan error)
go func() {
//start goroutine for reading responses from camera
exit <- conn.Handle()
}()
return &Client{conn: conn, exit: exit}, nil
if err = conn.Dial();err!=nil{
return nil, err
}
return conn, nil
}

View File

@@ -34,26 +34,15 @@ func Init() {
log.Info().Str("addr", cfg.Mod.Listen).Msg("[srtp] listen")
_, Port, _ = net.SplitHostPort(cfg.Mod.Listen)
// run server
go func() {
server = &srtp.Server{}
if err = server.Serve(conn); err != nil {
Server = &srtp.Server{}
if err = Server.Serve(conn); err != nil {
log.Warn().Err(err).Msg("[srtp] serve")
}
}()
}
var Server *srtp.Server
var log zerolog.Logger
var server *srtp.Server
var Port string
func AddSession(session *srtp.Session) {
server.AddSession(session)
}
func RemoveSession(session *srtp.Session) {
server.RemoveSession(session)
}

4
go.mod
View File

@@ -53,5 +53,7 @@ replace (
// windows support: https://github.com/brutella/dnssd/pull/35
github.com/brutella/dnssd v1.2.2 => github.com/rblenkinsopp/dnssd v1.2.3-0.20220516082132-0923f3c787a1
// RTP tlv8 fix
github.com/brutella/hap v0.0.17 => github.com/AlexxIT/hap v0.0.15-0.20220823033740-ce7d1564e657
github.com/brutella/hap v0.0.17 => github.com/AlexxIT/hap v0.0.15-0.20221108133010-d8a45b7a7045
// fix reading AAC config bytes
github.com/deepch/vdk v0.0.19 => github.com/AlexxIT/vdk v0.0.18-0.20221108193131-6168555b4f92
)

9
go.sum
View File

@@ -1,5 +1,7 @@
github.com/AlexxIT/hap v0.0.15-0.20220823033740-ce7d1564e657 h1:FUzXAJfm6sRLJ8T6vfzvy/Hm3aioX8+fbxgx2VZoI78=
github.com/AlexxIT/hap v0.0.15-0.20220823033740-ce7d1564e657/go.mod h1:c2vEL5pzjRWEx07sa32kTVjzI9bBVlstrwBwKe3DlJ0=
github.com/AlexxIT/hap v0.0.15-0.20221108133010-d8a45b7a7045 h1:xJf3FxQJReJSDyYXJfI1NUWv8tUEAGNV9xigLqNtmrI=
github.com/AlexxIT/hap v0.0.15-0.20221108133010-d8a45b7a7045/go.mod h1:QNA3sm16zE5uUyC8+E/gNkMvQWjqQLuxQKkU5PMi8N4=
github.com/AlexxIT/vdk v0.0.18-0.20221108193131-6168555b4f92 h1:cIeYMGaAirSZnrKRDTb5VgZDDYqPLhYiczElMg4sQW0=
github.com/AlexxIT/vdk v0.0.18-0.20221108193131-6168555b4f92/go.mod h1:7ydHfSkflMZxBXfWR79dMjrT54xzvLxnPaByOa9Jpzg=
github.com/brutella/dnssd v1.2.3 h1:4fBLjZjPH7SbcHhEcIJhZcC9nOhIDZ0m3rn9bjl1/i0=
github.com/brutella/dnssd v1.2.3/go.mod h1:JoW2sJUrmVIef25G6lrLj7HS6Xdwh6q8WUIvMkkBYXs=
github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ=
@@ -7,8 +9,6 @@ github.com/coreos/go-systemd/v22 v22.3.3-0.20220203105225-a9a7ef127534/go.mod h1
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/deepch/vdk v0.0.19 h1:r6xYyBTtXEIEh+csO0XHT00sI7xLF+hQFkJE9/go5II=
github.com/deepch/vdk v0.0.19/go.mod h1:7ydHfSkflMZxBXfWR79dMjrT54xzvLxnPaByOa9Jpzg=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/go-chi/chi v1.5.4 h1:QHdzF2szwjqVV4wmByUnTcsbIg7UGaQ0tPF2t5GcAIs=
@@ -245,6 +245,7 @@ gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWD
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

@@ -1,4 +1,4 @@
# Homekit
# Home Accessory Protocol
> PS. Character = Characteristic

View File

@@ -1,4 +1,4 @@
package homekit
package hap
type Accessory struct {
AID int `json:"aid"`

View File

@@ -2,22 +2,22 @@ package camera
import (
"errors"
"github.com/AlexxIT/go2rtc/pkg/homekit"
"github.com/AlexxIT/go2rtc/pkg/hap"
"github.com/brutella/hap/characteristic"
"github.com/brutella/hap/rtp"
)
type Client struct {
client *homekit.Conn
client *hap.Conn
}
func NewClient(client *homekit.Conn) *Client {
func NewClient(client *hap.Conn) *Client {
return &Client{client: client}
}
func (c *Client) StartStream2(ses *Session) (err error) {
func (c *Client) StartStream(ses *Session) (err error) {
// Step 1. Check if camera ready (free) to stream
var srv *homekit.Service
var srv *hap.Service
if srv, err = c.GetFreeStream(); err != nil {
return err
}
@@ -35,8 +35,8 @@ func (c *Client) StartStream2(ses *Session) (err error) {
// GetFreeStream search free streaming service.
// Usual every HomeKit camera can stream only to two clients simultaniosly.
// So it has two similar services for streaming.
func (c *Client) GetFreeStream() (srv *homekit.Service, err error) {
var accs []*homekit.Accessory
func (c *Client) GetFreeStream() (srv *hap.Service, err error) {
var accs []*hap.Accessory
if accs, err = c.client.GetAccessories(); err != nil {
return
}
@@ -60,7 +60,7 @@ func (c *Client) GetFreeStream() (srv *homekit.Service, err error) {
}
func (c *Client) SetupEndpoins(
srv *homekit.Service, req *rtp.SetupEndpoints,
srv *hap.Service, req *rtp.SetupEndpoints,
) (res *rtp.SetupEndpointsResponse, err error) {
// get setup endpoint character ID
char := srv.GetCharacter(characteristic.TypeSetupEndpoints)
@@ -87,7 +87,7 @@ func (c *Client) SetupEndpoins(
return
}
func (c *Client) SetConfig(srv *homekit.Service, config *rtp.StreamConfiguration) (err error) {
func (c *Client) SetConfig(srv *hap.Service, config *rtp.StreamConfiguration) (err error) {
// get setup endpoint character ID
char := srv.GetCharacter(characteristic.TypeSelectedStreamConfiguration)
char.Event = nil

75
pkg/hap/camera/session.go Normal file
View File

@@ -0,0 +1,75 @@
package camera
import (
cryptorand "crypto/rand"
"encoding/binary"
"github.com/brutella/hap/rtp"
)
type Session struct {
Offer *rtp.SetupEndpoints
Answer *rtp.SetupEndpointsResponse
Config *rtp.StreamConfiguration
}
func NewSession(vp *rtp.VideoParameters, ap *rtp.AudioParameters) *Session {
vp.RTP = rtp.RTPParams{
PayloadType: 99,
Ssrc: RandomUint32(),
Bitrate: 2048,
Interval: 10,
MTU: 1200, // like WebRTC
}
ap.RTP = rtp.RTPParams{
PayloadType: 110,
Ssrc: RandomUint32(),
Bitrate: 32,
Interval: 10,
ComfortNoisePayloadType: 98,
MTU: 0,
}
sessionID := RandomBytes(16)
s := &Session{
Offer: &rtp.SetupEndpoints{
SessionId: sessionID,
Video: rtp.CryptoSuite{
MasterKey: RandomBytes(16),
MasterSalt: RandomBytes(14),
},
Audio: rtp.CryptoSuite{
MasterKey: RandomBytes(16),
MasterSalt: RandomBytes(14),
},
},
Config: &rtp.StreamConfiguration{
Command: rtp.SessionControlCommand{
Identifier: sessionID,
Type: rtp.SessionControlCommandTypeStart,
},
Video: *vp,
Audio: *ap,
},
}
return s
}
func (s *Session) SetLocalEndpoint(host string, port uint16) {
s.Offer.ControllerAddr = rtp.Addr{
IPAddr: host,
VideoRtpPort: port,
AudioRtpPort: port,
}
}
func RandomBytes(size int) []byte {
data := make([]byte, size)
_, _ = cryptorand.Read(data)
return data
}
func RandomUint32() uint32 {
data := make([]byte, 4)
_, _ = cryptorand.Read(data)
return binary.BigEndian.Uint32(data)
}

View File

@@ -1,4 +1,4 @@
package homekit
package hap
import (
"bytes"

View File

@@ -1,4 +1,4 @@
package homekit
package hap
import (
"bufio"
@@ -7,7 +7,7 @@ import (
"encoding/json"
"errors"
"fmt"
"github.com/AlexxIT/go2rtc/pkg/homekit/mdns"
"github.com/AlexxIT/go2rtc/pkg/hap/mdns"
"github.com/AlexxIT/go2rtc/pkg/streamer"
"github.com/brutella/hap"
"github.com/brutella/hap/chacha20poly1305"
@@ -42,7 +42,7 @@ type Conn struct {
httpResponse chan *bufio.Reader
}
func Dial(rawURL string) (*Conn, error) {
func NewConn(rawURL string) (*Conn, error) {
u, err := url.Parse(rawURL)
if err != nil {
return nil, err
@@ -57,31 +57,9 @@ func Dial(rawURL string) (*Conn, error) {
ClientPrivate: DecodeKey(query.Get("client_private")),
}
if err = c.Dial(); err != nil {
return nil, err
}
return c, nil
}
//func NewConn(rawURL string) (*Conn, error) {
// u, err := url.Parse(rawURL)
// if err != nil {
// return nil, err
// }
//
// query := u.Query()
// c := &Conn{
// DeviceAddress: u.Host,
// DeviceID: query.Get("device_id"),
// DevicePublic: DecodeKey(query.Get("device_public")),
// ClientID: query.Get("client_id"),
// ClientPrivate: DecodeKey(query.Get("client_private")),
// }
//
// return c, nil
//}
func Pair(deviceID, pin string) (*Conn, error) {
entry := mdns.GetEntry(deviceID)
if entry == nil {

View File

@@ -1,4 +1,4 @@
package homekit
package hap
import (
"crypto/rand"
@@ -29,13 +29,13 @@ func GenerateUUID() string {
}
type PairVerifyPayload struct {
Method byte `tlv8:"0"`
Identifier string `tlv8:"1"`
PublicKey []byte `tlv8:"3"`
EncryptedData []byte `tlv8:"5"`
State byte `tlv8:"6"`
Status byte `tlv8:"7"`
Signature []byte `tlv8:"10"`
Method byte `tlv8:"0,optional"`
Identifier string `tlv8:"1,optional"`
PublicKey []byte `tlv8:"3,optional"`
EncryptedData []byte `tlv8:"5,optional"`
State byte `tlv8:"6,optional"`
Status byte `tlv8:"7,optional"`
Signature []byte `tlv8:"10,optional"`
}
//func (c *Character) Unmarshal(value interface{}) error {

View File

@@ -1,4 +1,4 @@
package homekit
package hap
import (
"bufio"

View File

@@ -1,4 +1,4 @@
package homekit
package hap
import (
"bufio"

View File

@@ -1,4 +1,4 @@
package homekit
package hap
import (
"encoding/binary"

View File

@@ -1,4 +1,4 @@
package homekit
package hap
import (
"bufio"

View File

@@ -1,103 +0,0 @@
package camera
import (
cryptorand "crypto/rand"
"encoding/binary"
"github.com/brutella/hap/rtp"
)
type Session struct {
Offer *rtp.SetupEndpoints
Answer *rtp.SetupEndpointsResponse
Config *rtp.StreamConfiguration
}
func NewSession() *Session {
sessionID := RandomBytes(16)
s := &Session{
Offer: &rtp.SetupEndpoints{
SessionId: sessionID,
Video: rtp.CryptoSuite{
MasterKey: RandomBytes(16),
MasterSalt: RandomBytes(14),
},
Audio: rtp.CryptoSuite{
MasterKey: RandomBytes(16),
MasterSalt: RandomBytes(14),
},
},
Config: &rtp.StreamConfiguration{
Command: rtp.SessionControlCommand{
Identifier: sessionID,
Type: rtp.SessionControlCommandTypeStart,
},
Video: rtp.VideoParameters{
CodecType: rtp.VideoCodecType_H264,
CodecParams: rtp.VideoCodecParameters{
Profiles: []rtp.VideoCodecProfile{
{Id: rtp.VideoCodecProfileMain},
},
Levels: []rtp.VideoCodecLevel{
{Level: rtp.VideoCodecLevel4},
},
Packetizations: []rtp.VideoCodecPacketization{
{Mode: rtp.VideoCodecPacketizationModeNonInterleaved},
},
},
Attributes: rtp.VideoCodecAttributes{
Width: 1920, Height: 1080, Framerate: 30,
},
RTP: rtp.RTPParams{
PayloadType: 99,
Ssrc: RandomUint32(),
Bitrate: 299,
Interval: 0.5,
ComfortNoisePayloadType: 98,
MTU: 0,
},
},
Audio: rtp.AudioParameters{
CodecType: rtp.AudioCodecType_AAC_ELD,
CodecParams: rtp.AudioCodecParameters{
Channels: 1,
Bitrate: rtp.AudioCodecBitrateVariable,
Samplerate: rtp.AudioCodecSampleRate16Khz,
PacketTime: 30,
},
RTP: rtp.RTPParams{
PayloadType: 110,
Ssrc: RandomUint32(),
Bitrate: 24,
Interval: 5,
MTU: 13,
},
ComfortNoise: false,
},
},
}
return s
}
func (s *Session) SetLocalEndpoint(host string, port uint16) {
s.Offer.ControllerAddr = rtp.Addr{
IPAddr: host,
VideoRtpPort: port,
AudioRtpPort: port,
}
}
func (s *Session) SetVideo() {
}
func RandomBytes(size int) []byte {
data := make([]byte, size)
_, _ = cryptorand.Read(data)
return data
}
func RandomUint32() uint32 {
data := make([]byte, 4)
_, _ = cryptorand.Read(data)
return binary.BigEndian.Uint32(data)
}

View File

@@ -3,26 +3,61 @@ package homekit
import (
"errors"
"fmt"
"github.com/AlexxIT/go2rtc/cmd/srtp"
"github.com/AlexxIT/go2rtc/pkg/homekit"
"github.com/AlexxIT/go2rtc/pkg/homekit/camera"
pkg "github.com/AlexxIT/go2rtc/pkg/srtp"
"github.com/AlexxIT/go2rtc/pkg/hap"
"github.com/AlexxIT/go2rtc/pkg/hap/camera"
"github.com/AlexxIT/go2rtc/pkg/srtp"
"github.com/AlexxIT/go2rtc/pkg/streamer"
"github.com/brutella/hap/characteristic"
"github.com/brutella/hap/rtp"
"net"
"strconv"
"net/url"
)
type Client struct {
streamer.Element
conn *homekit.Conn
conn *hap.Conn
exit chan error
server *srtp.Server
url string
medias []*streamer.Media
tracks []*streamer.Track
sessions []*pkg.Session
sessions []*srtp.Session
}
func NewClient(rawURL string, server *srtp.Server) (*Client, error) {
u, err := url.Parse(rawURL)
if err != nil {
return nil, err
}
query := u.Query()
c := &hap.Conn{
DeviceAddress: u.Host,
DeviceID: query.Get("device_id"),
DevicePublic: hap.DecodeKey(query.Get("device_public")),
ClientID: query.Get("client_id"),
ClientPrivate: hap.DecodeKey(query.Get("client_private")),
}
return &Client{conn: c, server: server}, nil
}
func (c *Client) Dial() error {
if err := c.conn.Dial(); err != nil {
return err
}
c.exit = make(chan error)
go func() {
//start goroutine for reading responses from camera
c.exit <- c.conn.Handle()
}()
return nil
}
func (c *Client) GetMedias() []*streamer.Media {
@@ -56,28 +91,54 @@ func (c *Client) Start() error {
return err
}
// get our server SRTP port
port, err := strconv.Atoi(srtp.Port)
if err != nil {
return err
// TODO: set right config
vp := &rtp.VideoParameters{
CodecType: rtp.VideoCodecType_H264,
CodecParams: rtp.VideoCodecParameters{
Profiles: []rtp.VideoCodecProfile{
{Id: rtp.VideoCodecProfileMain},
},
Levels: []rtp.VideoCodecLevel{
{Level: rtp.VideoCodecLevel4},
},
Packetizations: []rtp.VideoCodecPacketization{
{Mode: rtp.VideoCodecPacketizationModeNonInterleaved},
},
},
Attributes: rtp.VideoCodecAttributes{
Width: 1920, Height: 1080, Framerate: 30,
},
}
ap := &rtp.AudioParameters{
CodecType: rtp.AudioCodecType_AAC_ELD,
CodecParams: rtp.AudioCodecParameters{
Channels: 1,
Bitrate: rtp.AudioCodecBitrateVariable,
Samplerate: rtp.AudioCodecSampleRate16Khz,
// packet time=20 => AAC-ELD packet size=480
// packet time=30 => AAC-ELD packet size=480
// packet time=40 => AAC-ELD packet size=480
// packet time=60 => AAC-LD packet size=960
PacketTime: 40,
},
}
// setup HomeKit stream session
hkSession := camera.NewSession()
hkSession.SetLocalEndpoint(host, uint16(port))
hkSession := camera.NewSession(vp, ap)
hkSession.SetLocalEndpoint(host, c.server.Port())
// create client for processing camera accessory
cam := camera.NewClient(c.conn)
// try to start HomeKit stream
if err = cam.StartStream2(hkSession); err != nil {
panic(err) // TODO: fixme
if err = cam.StartStream(hkSession); err != nil {
return err
}
// SRTP Video Session
vs := &pkg.Session{
vs := &srtp.Session{
LocalSSRC: hkSession.Config.Video.RTP.Ssrc,
RemoteSSRC: hkSession.Answer.SsrcVideo,
Track: c.tracks[0],
}
if err = vs.SetKeys(
hkSession.Offer.Video.MasterKey, hkSession.Offer.Video.MasterSalt,
@@ -87,10 +148,9 @@ func (c *Client) Start() error {
}
// SRTP Audio Session
as := &pkg.Session{
as := &srtp.Session{
LocalSSRC: hkSession.Config.Audio.RTP.Ssrc,
RemoteSSRC: hkSession.Answer.SsrcAudio,
Track: &streamer.Track{},
}
if err = as.SetKeys(
hkSession.Offer.Audio.MasterKey, hkSession.Offer.Audio.MasterSalt,
@@ -99,10 +159,19 @@ func (c *Client) Start() error {
return err
}
srtp.AddSession(vs)
srtp.AddSession(as)
for _, track := range c.tracks {
switch track.Codec.Name {
case streamer.CodecH264:
vs.Track = track
case streamer.CodecAAC:
as.Track = track
}
}
c.sessions = []*pkg.Session{vs, as}
c.server.AddSession(vs)
c.server.AddSession(as)
c.sessions = []*srtp.Session{vs, as}
return <-c.exit
}
@@ -111,7 +180,7 @@ func (c *Client) Stop() error {
err := c.conn.Close()
for _, session := range c.sessions {
srtp.RemoveSession(session)
c.server.RemoveSession(session)
}
return err
@@ -121,16 +190,17 @@ func (c *Client) getMedias() []*streamer.Media {
var medias []*streamer.Media
accs, err := c.conn.GetAccessories()
acc := accs[0]
if err != nil {
panic(err)
return nil
}
acc := accs[0]
// get supported video config (not really necessary)
char := acc.GetCharacter(characteristic.TypeSupportedVideoStreamConfiguration)
v1 := &rtp.VideoStreamConfiguration{}
if err = char.ReadTLV8(v1); err != nil {
panic(err)
return nil
}
for _, hkCodec := range v1.Codecs {
@@ -139,8 +209,10 @@ func (c *Client) getMedias() []*streamer.Media {
switch hkCodec.Type {
case rtp.VideoCodecType_H264:
codec.Name = streamer.CodecH264
codec.FmtpLine = "profile-level-id=420029"
default:
panic(fmt.Sprintf("unknown codec: %d", hkCodec.Type))
fmt.Printf("unknown codec: %d", hkCodec.Type)
continue
}
media := &streamer.Media{
@@ -153,7 +225,7 @@ func (c *Client) getMedias() []*streamer.Media {
char = acc.GetCharacter(characteristic.TypeSupportedAudioStreamConfiguration)
v2 := &rtp.AudioStreamConfiguration{}
if err = char.ReadTLV8(v2); err != nil {
panic(err)
return nil
}
for _, hkCodec := range v2.Codecs {
@@ -165,7 +237,8 @@ func (c *Client) getMedias() []*streamer.Media {
case rtp.AudioCodecType_AAC_ELD:
codec.Name = streamer.CodecAAC
default:
panic(fmt.Sprintf("unknown codec: %d", hkCodec.Type))
fmt.Printf("unknown codec: %d", hkCodec.Type)
continue
}
switch hkCodec.Parameters.Samplerate {

View File

@@ -8,9 +8,19 @@ import (
// Server using same UDP port for SRTP and for SRTCP as the iPhone does
// this is not really necessary but anyway
type Server struct {
conn net.PacketConn
sessions map[uint32]*Session
}
func (s *Server) Port() uint16 {
addr := s.conn.LocalAddr().(*net.UDPAddr)
return uint16(addr.Port)
}
func (s *Server) Close() error {
return s.conn.Close()
}
func (s *Server) AddSession(session *Session) {
if s.sessions == nil {
s.sessions = map[uint32]*Session{}
@@ -23,6 +33,8 @@ func (s *Server) RemoveSession(session *Session) {
}
func (s *Server) Serve(conn net.PacketConn) error {
s.conn = conn
buf := make([]byte, 2048)
for {
n, addr, err := conn.ReadFrom(buf)

View File

@@ -37,6 +37,10 @@ func (s *Session) HandleRTP(data []byte) (err error) {
return
}
if s.Track == nil {
return
}
packet := &rtp.Packet{}
if err = packet.Unmarshal(data); err != nil {
return