Skip to content

Commit

Permalink
add client->server audio support
Browse files Browse the repository at this point in the history
  • Loading branch information
Tim Cooper committed Nov 3, 2014
1 parent 32f880a commit 9ad87e5
Show file tree
Hide file tree
Showing 4 changed files with 188 additions and 0 deletions.
33 changes: 33 additions & 0 deletions audio.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package gumble

type AudioFlag int

const (
AudioSource AudioFlag = 1 << iota // An audio stream that outputs audio
)

type AudioStream interface {
OnAttach() error
OnAttachSource(chan<- []int16) error
OnDetach()
}

type Audio interface {
Detachable
}

type audioImpl struct {
client *Client
stream AudioStream
flags AudioFlag
outgoing chan []int16
}

func (a *audioImpl) Detach() {
if a.client.audio != a {
return
}
a.client.audio = nil
a.stream.OnDetach()
close(a.outgoing)
}
27 changes: 27 additions & 0 deletions audio_outgoing.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package gumble

import (
"github.com/bontibon/gumble/gopus"
)

func audioOutgoing(audio *audioImpl) {
outgoing := audio.outgoing
message := audioMessage{
Format: audioOpus,
Target: audioNormal,
}
encoder, _ := opus.NewEncoder(48000, 1, opus.Voip)
encoder.SetVbr(false)
encoder.SetBitrate(40000)
for {
if buf, ok := <-outgoing; !ok {
return
} else {
if opusBuf, err := encoder.Encode(buf, 480, 1024); err == nil {
audio.client.outgoing <- &message
message.sequence = (message.sequence + 1) % 10000
message.opus = opusBuf
}
}
}
}
31 changes: 31 additions & 0 deletions client.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ type Client struct {
users Users
channels Channels

audio *audioImpl

end chan bool
closeMutex sync.Mutex
outgoing chan Message
Expand Down Expand Up @@ -152,6 +154,35 @@ func (c *Client) Attach(listener EventListener) Detachable {
return c.listeners.Attach(listener)
}

// AttachAudio will attach an AudioStream to the client.
//
// Only one AudioStream can be attached at a time. If one is already attached,
// it will be detached before the new stream is attached.
func (c *Client) AttachAudio(stream AudioStream, flags AudioFlag) (Audio, error) {
if c.audio != nil {
c.audio.Detach()
}

audio := &audioImpl{
client: c,
stream: stream,
flags: flags,
}
if err := stream.OnAttach(); err != nil {
return nil, err
}
if (flags & AudioSource) != 0 {
audio.outgoing = make(chan []int16)
go audioOutgoing(audio)
if err := stream.OnAttachSource(audio.outgoing); err != nil {
close(audio.outgoing)
return nil, err
}
}
c.audio = audio
return audio, nil
}

// State returns the current state of the client.
func (c *Client) State() State {
return c.state
Expand Down
97 changes: 97 additions & 0 deletions message_audio.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
package gumble

import (
"bytes"
"encoding/binary"
"errors"
"io"
)

type audioFormat byte

const (
audioOpus audioFormat = 4
)

type audioTarget byte

const (
audioNormal audioTarget = 0
)

type audioMessage struct {
Format audioFormat
Target audioTarget
opus []byte
sequence int
}

func (am *audioMessage) WriteTo(w io.Writer) (int64, error) {
var written int64 = 0
// Create audio header
var header bytes.Buffer
formatTarget := byte(am.Format)<<5 | byte(am.Target)
if err := header.WriteByte(formatTarget); err != nil {
return 0, err
}
if _, err := writeVarint(int64(am.sequence), &header); err != nil {
return 0, err
}
if _, err := writeVarint(int64(len(am.opus)), &header); err != nil {
return 0, err
}

// Write packet header
wireType := uint16(1)
wireLength := uint32(header.Len() + len(am.opus))
if err := binary.Write(w, binary.BigEndian, wireType); err != nil {
return written, err
} else {
written += 2
}
if err := binary.Write(w, binary.BigEndian, wireLength); err != nil {
return written, err
} else {
written += 4
}

// Write audio header
if n, err := header.WriteTo(w); err != nil {
return (written + n), err
} else {
written += n
}

// Write audio data
if n, err := w.Write(am.opus); err != nil {
return (written + int64(n)), err
} else {
written += int64(n)
}
return written, nil
}

func writeVarint(value int64, w io.Writer) (int64, error) {
var buff []byte
if value <= 0x7F {
buff = []byte{
byte(value),
}
} else if value <= 0x3FFF {
buff = []byte{
byte(((value >> 8) & 0x3F) | 0x80),
byte(value & 0xFF),
}
}
if buff != nil {
if n, err := w.Write(buff); err != nil {
return int64(n), err
} else {
return int64(n), nil
}
}
return 0, errors.New("out of range")
}

func (am *audioMessage) gumbleMessage() {
}

0 comments on commit 9ad87e5

Please sign in to comment.