diff --git a/cmd/server/server.go b/cmd/server/server.go index 483ce4a..a81b702 100644 --- a/cmd/server/server.go +++ b/cmd/server/server.go @@ -54,6 +54,7 @@ func (s *Server) Run() error { logrus.Fatal("cannot run qemuserver with error: ", err) } }() + logrus.Debug("qemu server running") return webServer.Run() } diff --git a/lib/audiodriver/wavfifo.go b/lib/audiodriver/wavfifo.go index 85adb76..0d16517 100644 --- a/lib/audiodriver/wavfifo.go +++ b/lib/audiodriver/wavfifo.go @@ -23,7 +23,7 @@ const BitsPerByte = 8 type WavFIFODriver struct { PCM <-chan [BufferSize]byte - WaveHeader <-chan *WavHeader + WaveHeader *WavHeader closed <-chan struct{} cancel func() } @@ -42,19 +42,19 @@ func (w *WavFIFODriver) Open() error { } func (w *WavFIFODriver) Close() error { - defer w.cancel() + w.cancel() return nil } func (w *WavFIFODriver) Properties() []prop.Media { - waveHeader := <-w.WaveHeader - logrus.Debugf("wave header: %v", waveHeader) + logrus.Debugf("wave header: %v", w.WaveHeader) return []prop.Media{ { Audio: prop.Audio{ - SampleRate: int(waveHeader.SampleRate), - ChannelCount: int(waveHeader.NumChannels), - Latency: waveHeader.GetLatnecy(), + SampleRate: int(w.WaveHeader.SampleRate), + ChannelCount: int(w.WaveHeader.NumChannels), + SampleSize: int(w.WaveHeader.BitsPerSample), + Latency: w.WaveHeader.GetLatnecy(), IsFloat: false, // just 8bit or 16bit with qemu IsBigEndian: false, // qemu should be little endian IsInterleaved: true, @@ -64,13 +64,14 @@ func (w *WavFIFODriver) Properties() []prop.Media { } func (w *WavFIFODriver) AudioRecord(p prop.Media) (audio.Reader, error) { - a := wave.NewInt16Interleaved(wave.ChunkInfo{ - Len: BufferSize / int(p.SampleSize/BitsPerByte), - Channels: p.ChannelCount, - SamplingRate: p.SampleRate, - }) + logrus.Debug(p) reader := func() (wave.Audio, func(), error) { + a := wave.NewInt16Interleaved(wave.ChunkInfo{ + Len: BufferSize / int(p.SampleSize/BitsPerByte), + Channels: p.ChannelCount, + SamplingRate: p.SampleRate, + }) select { case <-w.closed: return nil, func() {}, io.EOF diff --git a/lib/qemuconnection/events.go b/lib/qemuconnection/events.go index 3ece627..e03cbd7 100644 --- a/lib/qemuconnection/events.go +++ b/lib/qemuconnection/events.go @@ -29,7 +29,7 @@ type CommandLine struct { } func ParseEvent(b []byte) (*Event, error) { - var event *Event + event := &Event{} if err := json.Unmarshal(b, event); err != nil { return nil, err } diff --git a/lib/webrtcconnection/connection.go b/lib/webrtcconnection/connection.go index 19a3adb..d827d8c 100644 --- a/lib/webrtcconnection/connection.go +++ b/lib/webrtcconnection/connection.go @@ -6,6 +6,7 @@ import ( "github.com/pion/mediadevices/pkg/codec/opus" "github.com/pion/mediadevices/pkg/codec/x264" "github.com/pion/mediadevices/pkg/driver" + "github.com/pion/mediadevices/pkg/prop" "github.com/pion/webrtc/v3" "github.com/sirupsen/logrus" ) @@ -45,7 +46,10 @@ func New(o *Options) (*Connection, error) { } s, err := mediadevices.GetUserMedia(mediadevices.MediaStreamConstraints{ - Video: func(mtc *mediadevices.MediaTrackConstraints) {}, + Video: func(mtc *mediadevices.MediaTrackConstraints) { + mtc.Height = prop.Int(o.Video.Height) + mtc.Width = prop.Int(o.Video.Width) + }, Audio: func(mtc *mediadevices.MediaTrackConstraints) {}, Codec: codecSelector, }) @@ -84,7 +88,7 @@ func (c *Connection) Regist(offer *webrtc.SessionDescription) (*webrtc.SessionDe for _, track := range c.stream.GetTracks() { track.OnEnded(func(err error) { - logrus.Errorf("Track (ID: %s) ended with error: %v", track.ID(), err) + logrus.Errorf("Track (ID: %s, kind: %s) ended with error: %v", track.ID(), track.Kind().String(), err) }) _, err := rtc.AddTransceiverFromTrack(track, webrtc.RTPTransceiverInit{ Direction: webrtc.RTPTransceiverDirectionSendonly, diff --git a/servers/qemuserver/server.go b/servers/qemuserver/server.go index f5f0bf8..a4ae5f3 100644 --- a/servers/qemuserver/server.go +++ b/servers/qemuserver/server.go @@ -15,12 +15,19 @@ import ( "github.com/sirupsen/logrus" ) +const waveHeaderSize = 16 + +var waveHeader = &audiodriver.WavHeader{ + Size: waveHeaderSize, + AudioFormat: 1, + NumChannels: 2, + SampleRate: 44100, + BlockAlign: 4, + BitsPerSample: 16, +} + type Server struct { - options *Options - QmpConnector struct { - RX chan *qemuconnection.Event - TX chan qemu.Status - } + options *Options qemu *qemu.Domain audioHeader chan *audiodriver.WavHeader pcm chan [audiodriver.BufferSize]byte @@ -38,8 +45,6 @@ func NewServer(o *Options) (*Server, error) { audioHeader: make(chan *audiodriver.WavHeader, 1), pcm: make(chan [audiodriver.BufferSize]byte), } - server.QmpConnector.RX = make(chan *qemuconnection.Event) - server.QmpConnector.TX = make(chan qemu.Status) u, err := url.Parse(o.QmpAddress) if err != nil { @@ -80,7 +85,7 @@ func NewServer(o *Options) (*Server, error) { return nil, err } audio.PCM = server.pcm - audio.WaveHeader = server.audioHeader + audio.WaveHeader = waveHeader if err := driver.GetManager().Register( vncdriver.NewVnc(o.VNCAddress), @@ -98,84 +103,26 @@ func NewServer(o *Options) (*Server, error) { func (s *Server) Run() error { logrus.Debug("qemu server running") - defer logrus.Debug("qemu server exit") - defer s.qemu.Close() - s.startCapture() - logrus.Debug("qemu capture start") - - for ev := range s.QmpConnector.RX { - if ev.Type == qemuconnection.QueryStatusEvent { - status, err := s.qemu.Status() - if err != nil { - logrus.Error("get qemu status error: ", err) - continue - } - s.QmpConnector.TX <- status - continue - } - for _, cmd := range ev.ToQemuCommand() { - _, err := s.qemu.Run(cmd) - if err != nil { - logrus.Error("run command error: ", err) - } - } - } - return nil -} - -func (s *Server) startCapture() { - const waveHeaderSize = 16 - waveHeader := &audiodriver.WavHeader{ - Size: waveHeaderSize, - AudioFormat: 1, - NumChannels: 2, - SampleRate: 44100, - BlockAlign: 4, - BitsPerSample: 16, + f, err := os.Open(s.options.AudioPipe) + if err != nil { + logrus.Fatal(err) } + defer f.Close() + logrus.Debug("start reading fifo") go func() { - f, err := os.Open(s.options.AudioPipe) - if err != nil { - logrus.Fatal(err) - } - defer f.Close() - - logrus.Debug("start reading from fifo") - - s.audioHeader <- waveHeader - close(s.audioHeader) // only once - - // skip to pcm data, for 44 bytes. - var _dataChunkHeader [audiodriver.FmtHeaderOffset + - audiodriver.FmtHeaderIDSize + audiodriver.FmtHeaderChunkSizeSize + waveHeaderSize + - audiodriver.DataChunkIDSize + audiodriver.DataChunkSizeSize]byte - if _, err := f.Read(_dataChunkHeader[:]); err != nil { - logrus.Fatal(err) - } - - defer close(s.pcm) - for { - var b [audiodriver.BufferSize]byte - if _, err := f.Read(b[:]); err != nil { - logrus.Error(err) - } - select { - case s.pcm <- b: - case <-time.After(waveHeader.GetLatnecy()): - } - } - }() - - go func() { + logrus.Debug("setting audio capture") if _, err := s.qemu.Run(qmp.Command{ Execute: "human-monitor-command", Args: map[string]string{ "command-line": fmt.Sprintf( - "wavcapture %s %s", + "wavcapture %s %s %d %d %d", s.options.AudioPipe, s.options.AudioDevice, + waveHeader.SampleRate, + waveHeader.BitsPerSample, + waveHeader.NumChannels, ), }, }); err != nil { @@ -183,6 +130,27 @@ func (s *Server) startCapture() { } logrus.Debug("audio capture set") }() + + logrus.Debug("skip wave headers, to the PCM!") + // skip to pcm data, for 44 bytes. + var _dataChunkHeader [audiodriver.FmtHeaderOffset + + audiodriver.FmtHeaderIDSize + audiodriver.FmtHeaderChunkSizeSize + waveHeaderSize + + audiodriver.DataChunkIDSize + audiodriver.DataChunkSizeSize]byte + if _, err := f.Read(_dataChunkHeader[:]); err != nil { + logrus.Fatal(err) + } + + defer close(s.pcm) + for { + var b [audiodriver.BufferSize]byte + if _, err := f.Read(b[:]); err != nil { + logrus.Error(err) + } + select { + case s.pcm <- b: + case <-time.After(waveHeader.GetLatnecy()): + } + } } func (s *Server) SendEvent(b []byte) error { @@ -190,13 +158,19 @@ func (s *Server) SendEvent(b []byte) error { if err != nil { return err } - s.QmpConnector.RX <- ev + for _, cmd := range ev.ToQemuCommand() { + _, err := s.qemu.Run(cmd) + if err != nil { + return err + } + } return nil } func (s *Server) GetStatus() qemu.Status { - s.QmpConnector.RX <- &qemuconnection.Event{ - Type: qemuconnection.QueryStatusEvent, + status, err := s.qemu.Status() + if err != nil { + return qemu.StatusIOError } - return <-s.QmpConnector.TX + return status } diff --git a/web/src/components/AceScreen.vue b/web/src/components/AceScreen.vue index 201a3e2..4645b60 100644 --- a/web/src/components/AceScreen.vue +++ b/web/src/components/AceScreen.vue @@ -1,5 +1,8 @@