ace/servers/qemuserver/server.go

214 lines
4.4 KiB
Go
Raw Normal View History

2022-09-26 03:04:07 +00:00
package qemuserver
import (
"fmt"
2022-09-30 04:24:32 +00:00
"io"
2022-09-26 03:04:07 +00:00
"net/url"
2022-09-27 02:21:06 +00:00
"os"
"time"
2022-09-26 03:04:07 +00:00
2022-09-30 04:24:32 +00:00
"git.sense-t.eu.org/ACE/ace/drivers/audio"
"git.sense-t.eu.org/ACE/ace/drivers/video"
2022-09-26 03:04:07 +00:00
"git.sense-t.eu.org/ACE/ace/lib/qemuconnection"
"github.com/digitalocean/go-qemu/qemu"
"github.com/digitalocean/go-qemu/qmp"
"github.com/pion/mediadevices/pkg/driver"
"github.com/sirupsen/logrus"
)
2022-09-30 04:24:32 +00:00
const waveHeaderSize = audio.FmtHeaderSizeDefault
2022-09-30 04:24:32 +00:00
var waveHeader *audio.WavHeader
func init() {
2022-09-30 04:24:32 +00:00
waveHeader = audio.DefaultHeader()
}
2022-09-26 03:04:07 +00:00
type Server struct {
options *Options
2022-09-27 02:21:06 +00:00
qemu *qemu.Domain
2022-09-30 04:24:32 +00:00
audioHeader chan *audio.WavHeader
pcm chan []byte
ppm chan io.ReadCloser
2022-09-26 03:04:07 +00:00
}
var DefaultServer *Server
2022-09-26 08:07:25 +00:00
func NewServer(o *Options) (*Server, error) {
2022-09-26 03:04:07 +00:00
server := &Server{
2022-09-27 02:21:06 +00:00
options: o,
2022-09-30 04:24:32 +00:00
audioHeader: make(chan *audio.WavHeader, 1),
pcm: make(chan []byte),
2022-10-10 23:47:04 +00:00
ppm: make(chan io.ReadCloser), // to be configured
2022-09-26 03:04:07 +00:00
}
2022-09-26 08:07:25 +00:00
u, err := url.Parse(o.QmpAddress)
2022-09-26 03:04:07 +00:00
if err != nil {
2022-09-26 08:07:25 +00:00
return nil, err
2022-09-26 03:04:07 +00:00
}
var address string
if u.Scheme == "unix" {
address = u.Path
} else {
address = u.Host
}
logrus.Debugf("trying to connect qmp with %s://%s", u.Scheme, address)
2022-09-26 08:07:25 +00:00
qmpConnection, err := qmp.NewSocketMonitor(u.Scheme, address, o.Timeout)
2022-09-26 03:04:07 +00:00
if err != nil {
2022-09-26 08:07:25 +00:00
return nil, err
2022-09-26 03:04:07 +00:00
}
if err := qmpConnection.Connect(); err != nil {
2022-09-26 08:07:25 +00:00
return nil, err
2022-09-26 03:04:07 +00:00
}
logrus.Debug("qmp connected")
2022-09-26 08:07:25 +00:00
qemu, err := qemu.NewDomain(qmpConnection, o.Name)
2022-09-26 03:04:07 +00:00
if err != nil {
2022-09-26 08:07:25 +00:00
return nil, err
2022-09-26 03:04:07 +00:00
}
2022-09-26 08:07:25 +00:00
server.qemu = qemu
2022-09-30 04:24:32 +00:00
audio := &audio.PCMStreamDriver{
PCM: server.pcm,
WaveHeader: waveHeader,
2022-10-02 11:29:57 +00:00
BufferSizeByBytes: o.Audio.BufferSize, // to be configured
2022-09-30 04:24:32 +00:00
}
2022-09-26 08:07:25 +00:00
if err := driver.GetManager().Register(
2022-09-27 02:21:06 +00:00
audio,
2022-09-26 08:07:25 +00:00
driver.Info{
Label: "audioFifo",
DeviceType: driver.Microphone,
Priority: driver.PriorityNormal,
},
); err != nil {
return nil, err
}
2022-09-27 02:21:06 +00:00
2022-09-30 04:24:32 +00:00
video := &video.PPMStreamDriver{
2022-10-02 11:29:57 +00:00
Height: o.Video.Height,
Width: o.Video.Width,
FPS: o.Video.FPS,
2022-09-30 04:24:32 +00:00
PPMImage: server.ppm,
}
2022-09-26 08:07:25 +00:00
if err := driver.GetManager().Register(
2022-09-30 04:24:32 +00:00
video,
2022-09-26 08:07:25 +00:00
driver.Info{
Label: "vnc",
DeviceType: driver.Camera,
Priority: driver.PriorityNormal,
},
); err != nil {
return nil, err
}
return server, nil
}
2022-09-26 03:04:07 +00:00
2022-09-26 08:07:25 +00:00
func (s *Server) Run() error {
logrus.Debug("qemu server running")
2022-10-02 11:29:57 +00:00
path, err := s.options.MakeFIFO()
if err != nil {
return err
}
go func() {
logrus.Debug("screen capture start")
defer close(s.ppm)
2022-10-10 11:12:26 +00:00
ticker := time.NewTicker(time.Second / time.Duration(s.options.Video.FPS))
defer ticker.Stop()
for { // to be configured
2022-10-02 11:29:57 +00:00
ppm, err := s.qemu.ScreenDump()
if err != nil {
logrus.Error(err)
continue
}
2022-10-10 11:12:26 +00:00
select {
case s.ppm <- ppm:
case <-ticker.C:
continue
}
2022-10-10 23:47:04 +00:00
<-ticker.C
2022-10-02 11:29:57 +00:00
}
}()
2022-09-26 03:04:07 +00:00
2022-09-30 04:24:32 +00:00
go func() {
2022-10-02 11:29:57 +00:00
f, err := os.Open(path)
2022-09-30 04:24:32 +00:00
if err != nil {
logrus.Fatal(err)
}
defer f.Close()
logrus.Debug("start reading fifo")
logrus.Debug("skip wave headers, to the PCM!")
// skip to pcm data, for 44 bytes.
2022-10-02 11:29:57 +00:00
var _dataChunkHeader [audio.FmtHeaderOffset +
audio.FmtHeaderIDSize + audio.FmtHeaderChunkSizeSize + waveHeaderSize +
audio.DataChunkIDSize + audio.DataChunkSizeSize]byte
2022-09-30 04:24:32 +00:00
if _, err := f.Read(_dataChunkHeader[:]); err != nil {
logrus.Fatal(err)
}
2022-09-30 05:46:58 +00:00
logrus.Debug("start reading PCM")
2022-09-30 04:24:32 +00:00
defer close(s.pcm)
2022-10-10 11:12:26 +00:00
ticker := time.NewTicker(waveHeader.GetLatnecy(s.options.Audio.BufferSize))
defer ticker.Stop()
2022-09-30 04:24:32 +00:00
for {
2022-10-03 00:15:43 +00:00
b := make([]byte, s.options.Audio.BufferSize) // to be configured
2022-09-30 04:24:32 +00:00
if _, err := f.Read(b[:]); err != nil {
logrus.Error(err)
}
select {
case s.pcm <- b:
2022-10-10 11:12:26 +00:00
case <-ticker.C:
2022-09-30 04:24:32 +00:00
}
}
}()
2022-09-27 04:32:23 +00:00
2022-09-27 02:21:06 +00:00
go func() {
logrus.Debug("setting audio capture")
2022-09-27 02:21:06 +00:00
if _, err := s.qemu.Run(qmp.Command{
Execute: "human-monitor-command",
Args: map[string]string{
"command-line": fmt.Sprintf(
"wavcapture %s %s %d %d %d",
2022-10-02 11:29:57 +00:00
path,
s.options.Audio.Device,
waveHeader.SampleRate,
waveHeader.BitsPerSample,
waveHeader.NumChannels,
2022-09-27 02:21:06 +00:00
),
},
}); err != nil {
logrus.Fatal("run audio command failed: ", err)
2022-09-26 03:04:07 +00:00
}
2022-09-27 02:21:06 +00:00
logrus.Debug("audio capture set")
2022-09-26 03:04:07 +00:00
}()
2022-09-30 04:24:32 +00:00
select {}
2022-09-26 03:04:07 +00:00
}
2022-09-27 02:21:06 +00:00
func (s *Server) SendEvent(b []byte) error {
2022-09-26 03:04:07 +00:00
ev, err := qemuconnection.ParseEvent(b)
if err != nil {
return err
}
for _, cmd := range ev.ToQemuCommand() {
_, err := s.qemu.Run(cmd)
if err != nil {
return err
}
}
2022-09-26 03:04:07 +00:00
return nil
}
2022-09-27 02:21:06 +00:00
func (s *Server) GetStatus() qemu.Status {
status, err := s.qemu.Status()
if err != nil {
return qemu.StatusIOError
2022-09-26 03:04:07 +00:00
}
return status
2022-09-26 03:04:07 +00:00
}