[audio] WIP on Gobot audio support using mpg123, based on code from @colemanserious

Signed-off-by: deadprogram <ron@hybridgroup.com>
This commit is contained in:
deadprogram 2016-05-13 16:09:36 -07:00
parent bf43df59b5
commit 0ca38b77e5
7 changed files with 221 additions and 0 deletions

View File

@ -98,6 +98,7 @@ Gobot has a extensible system for connecting to hardware devices. The following
- [Ardrone](http://ardrone2.parrot.com/) <=> [Package](https://github.com/hybridgroup/gobot/tree/master/platforms/ardrone)
- [Arduino](http://www.arduino.cc/) <=> [Package](https://github.com/hybridgroup/gobot/tree/master/platforms/firmata)
- Audio <=> [Package](https://github.com/hybridgroup/gobot/tree/master/platforms/audio)
- [Beaglebone Black](http://beagleboard.org/Products/BeagleBone+Black/) <=> [Package](https://github.com/hybridgroup/gobot/tree/master/platforms/beaglebone)
- [Bebop](http://www.parrot.com/usa/products/bebop-drone/) <=> [Package](https://github.com/hybridgroup/gobot/tree/master/platforms/bebop)
- [C.H.I.P](http://www.nextthing.co/pages/chip) <=> [Package](https://github.com/hybridgroup/gobot/tree/master/platforms/chip)

31
examples/audio.go Normal file
View File

@ -0,0 +1,31 @@
package main
import (
"time"
"github.com/hybridgroup/gobot"
"github.com/hybridgroup/gobot/platforms/audio"
)
func main() {
gbot := gobot.NewGobot()
e := audio.NewAudioAdaptor("sound")
laser := audio.NewAudioDriver(e, "laser", nil)
work := func() {
gobot.Every(1*time.Second, func() {
laser.Sound("./examples/laser.mp3")
})
}
robot := gobot.NewRobot("soundBot",
[]gobot.Connection{e},
[]gobot.Device{laser},
work,
)
gbot.AddRobot(robot)
gbot.Start()
}

BIN
examples/laser.mp3 Normal file

Binary file not shown.

View File

@ -0,0 +1,60 @@
// Based on aplay audio adaptor written by @colemanserious (https://github.com/colemanserious)
package audio
import (
"errors"
"github.com/hybridgroup/gobot"
"log"
"os"
"os/exec"
)
var _ gobot.Adaptor = (*AudioAdaptor)(nil)
type AudioAdaptor struct {
name string
}
func NewAudioAdaptor(name string) *AudioAdaptor {
return &AudioAdaptor{
name: name,
}
}
func (a *AudioAdaptor) Name() string { return a.name }
func (a *AudioAdaptor) Connect() []error { return nil }
func (a *AudioAdaptor) Finalize() []error { return nil }
func (a *AudioAdaptor) Sound(fileName string) []error {
var errorsList []error
var err error
if fileName == "" {
log.Println("Require filename for MP3 file.")
errorsList = append(errorsList, errors.New("Requires filename for MP3 file."))
return errorsList
}
_, err = os.Open(fileName)
if err != nil {
log.Println(err)
errorsList = append(errorsList, err)
return errorsList
}
// command to play a MP3 file
cmd := exec.Command("mpg123", fileName)
err = cmd.Run()
if err != nil {
log.Println(err)
errorsList = append(errorsList, err)
return errorsList
}
// Need to return to fulfill function sig, even though returning an empty
return nil
}

View File

@ -0,0 +1,28 @@
// Based on aplay audio adaptor written by @colemanserious (https://github.com/colemanserious)
package audio
import (
"os/exec"
"testing"
"github.com/hybridgroup/gobot/gobottest"
)
func TestAudioAdaptor(t *testing.T) {
a := NewAudioAdaptor("tester")
gobottest.Assert(t, a.Name(), "tester")
gobottest.Assert(t, len(a.Connect()), 0)
_, err := exec.LookPath("mpg123")
numErrsForTest := 0
if err != nil {
numErrsForTest = 1
}
gobottest.Assert(t, len(a.Sound("../resources/foo.wav")), numErrsForTest)
gobottest.Assert(t, len(a.Connect()), 0)
gobottest.Assert(t, len(a.Finalize()), 0)
}

View File

@ -0,0 +1,73 @@
// Based on aplay audio adaptor written by @colemanserious (https://github.com/colemanserious)
package audio
import (
"fmt"
"github.com/hybridgroup/gobot"
"time"
)
var _ gobot.Driver = (*AudioDriver)(nil)
type AudioDriver struct {
name string
connection gobot.Connection
interval time.Duration
halt chan bool
gobot.Eventer
gobot.Commander
queue chan string
}
func NewAudioDriver(a *AudioAdaptor, name string, queue chan string) *AudioDriver {
d := &AudioDriver{
name: name,
connection: a,
interval: 500 * time.Millisecond,
queue: queue,
halt: make(chan bool, 0),
Eventer: gobot.NewEventer(),
Commander: gobot.NewCommander(),
}
return d
}
func (d *AudioDriver) Name() string { return d.name }
func (d *AudioDriver) Connection() gobot.Connection {
return d.connection
}
func (d *AudioDriver) Sound(fileName string) []error {
return d.Connection().(*AudioAdaptor).Sound(fileName)
}
func (d *AudioDriver) adaptor() *AudioAdaptor {
return d.Connection().(*AudioAdaptor)
}
func (d *AudioDriver) Start() (err []error) {
go d.serve(d.queue)
return
}
func (d *AudioDriver) Halt() (err []error) {
return
}
// Use semaphore to control how many sounds might be playing at a time
var sem = make(chan int, 1)
// See example at https://golang.org/doc/effective_go.html#concurrency
// Purpose: receive messages on channel, but throttle execution of playing
func (d *AudioDriver) serve(queue chan string) {
for req := range queue {
sem <- 1
go func(req string) {
fmt.Printf("Playing sound %v\n", req)
d.Sound(req)
<-sem
}(req)
}
}

View File

@ -0,0 +1,28 @@
// Based on aplay audio adaptor written by @colemanserious (https://github.com/colemanserious)
package audio
import (
"os/exec"
"testing"
"github.com/hybridgroup/gobot/gobottest"
)
func TestAudioDriver(t *testing.T) {
d := NewAudioDriver(NewAudioAdaptor("conn"), "dev", nil)
gobottest.Assert(t, d.Name(), "dev")
gobottest.Assert(t, d.Connection().Name(), "conn")
gobottest.Assert(t, len(d.Start()), 0)
gobottest.Assert(t, len(d.Halt()), 0)
_, err := exec.LookPath("mpg123")
numErrsForTest := 0
if err != nil {
numErrsForTest = 1
}
gobottest.Assert(t, len(d.Sound("../resources/foo.mp3")), numErrsForTest)
}