Files
go-gst/examples/appsrc/main.go
2020-10-03 21:34:39 +03:00

131 lines
2.8 KiB
Go

package main
import (
"bytes"
"encoding/binary"
"fmt"
"math"
"time"
"github.com/tinyzimmer/go-gst/examples"
"github.com/tinyzimmer/go-gst/gst"
"github.com/tinyzimmer/go-gst/gst/app"
)
func createPipeline() (*gst.Pipeline, error) {
gst.Init(nil)
// Create a pipeline
pipeline, err := gst.NewPipeline("")
if err != nil {
return nil, err
}
// Create the elements
elems, err := gst.NewElementMany("appsrc", "autoaudiosink")
if err != nil {
return nil, err
}
// Add the elements to the pipeline and link them
pipeline.AddMany(elems...)
gst.ElementLinkMany(elems...)
// Get the app sourrce from the first element returned
src := app.SrcFromElement(elems[0])
// We are instructing downstream elements that we are producing raw signed 16-bit integers.
src.SetCaps(gst.NewCapsFromString(
"audio/x-raw, format=S16LE, layout=interleaved, channels=1, rate=44100",
))
// Add a callback for whene the sink requests a sample
i := 1
src.SetCallbacks(&app.SourceCallbacks{
NeedDataFunc: func(src *app.Source, _ uint) {
// Stop after 10 samples
if i == 10 {
src.EndStream()
return
}
fmt.Println("Producing sample", i)
sinWave := newSinWave(44100, 440.0, 1.0, time.Second)
// Allocate a new buffer with the sin wave
buffer := gst.NewBufferFromBytes(sinWave)
// Set the presentation timestamp on thee buffer
pts := time.Second * time.Duration(i)
buffer.SetPresentationTimestamp(pts)
buffer.SetDuration(time.Second)
// Push tehe buffer onto the src
src.PushBuffer(buffer)
i++
},
})
return pipeline, nil
}
func newSinWave(sampleRate int64, freq, vol float64, duration time.Duration) []byte {
numSamples := duration.Milliseconds() * (sampleRate / 1000.0)
buf := new(bytes.Buffer)
for i := int64(0); i < numSamples; i++ {
data := vol * math.Sin(2.0*math.Pi*freq*(1/float64(sampleRate)))
binary.Write(buf, binary.LittleEndian, data)
}
return buf.Bytes()
}
func handleMessage(msg *gst.Message) error {
defer msg.Unref() // Messages are a good candidate for trying out runtime finalizers
switch msg.Type() {
case gst.MessageEOS:
return app.ErrEOS
case gst.MessageError:
return msg.ParseError()
}
return nil
}
func mainLoop(pipeline *gst.Pipeline) error {
defer pipeline.Destroy() // Will stop and unref the pipeline when this function returns
// Start the pipeline
pipeline.SetState(gst.StatePlaying)
// Retrieve the bus from the pipeline
bus := pipeline.GetPipelineBus()
// Loop over messsages from the pipeline
for {
msg := bus.TimedPop(time.Duration(-1))
if msg == nil {
break
}
if err := handleMessage(msg); err != nil {
return err
}
}
return nil
}
func main() {
examples.Run(func() error {
var pipeline *gst.Pipeline
var err error
if pipeline, err = createPipeline(); err != nil {
return err
}
return mainLoop(pipeline)
})
}