Skip to content

Commit

Permalink
[audio] WIP on Gobot audio support using mpg123, based on code from @…
Browse files Browse the repository at this point in the history
…colemanserious

Signed-off-by: deadprogram <[email protected]>
  • Loading branch information
deadprogram committed May 13, 2016
1 parent bf43df5 commit 0ca38b7
Show file tree
Hide file tree
Showing 7 changed files with 221 additions and 0 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
31 changes: 31 additions & 0 deletions examples/audio.go
Original file line number Diff line number Diff line change
@@ -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()
}
Binary file added examples/laser.mp3
Binary file not shown.
60 changes: 60 additions & 0 deletions platforms/audio/audio_adaptor.go
Original file line number Diff line number Diff line change
@@ -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
}
28 changes: 28 additions & 0 deletions platforms/audio/audio_adaptor_test.go
Original file line number Diff line number Diff line change
@@ -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)
}
73 changes: 73 additions & 0 deletions platforms/audio/audio_driver.go
Original file line number Diff line number Diff line change
@@ -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)
}
}
28 changes: 28 additions & 0 deletions platforms/audio/audio_driver_test.go
Original file line number Diff line number Diff line change
@@ -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)
}

0 comments on commit 0ca38b7

Please sign in to comment.