ref: 142b452d762c751ee0c01c559f2bbfb938934e75
parent: dd10b5ab57391a959da5b8dd586bc372e916b43f
author: Yaroslav Kolomiiets <yarikos@gmail.com>
date: Wed Aug 10 09:12:00 EDT 2016
basic primitives for RPDSND support
--- /dev/null
+++ b/audio.c
@@ -1,0 +1,91 @@
+/* [MS-RDPEA]: Remote Desktop Protocol: Audio Output Virtual Channel Extension */
+#include <u.h>
+#include <libc.h>
+#include "dat.h"
+#include "fns.h"
+
+static char rdpsnd[] = "RDPSND";
+
+enum /* Audiomsg.type */
+{
+ Awav= 2, /* WaveInfo PDU */
+ Awavack= 5, /* Wave Confirm PDU */
+ Aprobe= 6, /* Training PDU or Training Confirm PDU */
+ Afmt= 7, /* Client/Server Audio Formats and Version PDU */
+ /* 2.2.1 RDPSND PDU Header (SNDPROLOG) */
+};
+typedef struct Audiomsg Audiomsg;
+struct Audiomsg
+{
+ uint type;
+ uint nfmt; /* Afmt */
+ uint ack; /* Afmt */
+ uint ver; /* Afmt */
+ uchar *data; /* Afmt */
+ uint ndata; /* Afmt */
+};
+static int getaudiomsg(Audiomsg*,uchar*,int);
+static int putaudiomsg(uchar*,int, Audiomsg*);
+
+enum
+{
+ FmtPCM= 0x01, /* WAVE_FORMAT_PCM */
+ FmtMP3= 0x55, /* WAVE_FORMAT_MPEGLAYER3 */
+ /* RFC2361 Appendix A */
+};
+
+
+void
+audiovcfn(Rdp*, uchar* a, uint nb)
+{
+ Audiomsg r;
+
+fprint(2, " A ");
+ if(getaudiomsg(&r, a, nb) < 0){
+ fprint(2, "audio: %r\n");
+ return;
+ }
+fprint(2, " a%ud ", r.type);
+}
+
+
+/*
+ * 2.2.1 RDPSND PDU Header (SNDPROLOG)
+ * msgtype[1] pad[1] bodysize[2]
+ *
+ * 2.2.2.1 Server Audio Formats and Version PDU
+ * hdr[4] flags[4] vol[4] pitch[4] dgport[2] nfmt[2] ack[1] ver[2] pad[1] nfmt*(afmt[*])
+ *
+ * 2.2.2.1.1 Audio Format (AUDIO_FORMAT)
+ * ftag[2] nchan[2] samphz[4] avgbytehz[4] blocksz[2] sampbitsz[2] ndata[2] data[ndata]
+ */
+
+static int
+getaudiomsg(Audiomsg* m, uchar* a, int nb)
+{
+ ulong len;
+
+ if(nb < 4){
+ werrstr(Eshort);
+ return -1;
+ }
+
+ m->type = *a;
+ len = GSHORT(a+2);
+ switch(m->type){
+ case Afmt:
+ if(len < 20 || nb < len+4){
+ werrstr(Eshort);
+ return -1;
+ }
+ m->nfmt = GSHORT(a+18);
+ m->ack = a[20];
+ m->ver = GSHORT(a+21);
+ m->data = a+24;
+ m->ndata = len-20;
+ return len+4;
+ }
+ werrstr("unrecognized audio msg type");
+ return -1;
+}
+
--- a/dat.h
+++ b/dat.h
@@ -63,6 +63,7 @@
void readnet(Rdp*);
void clipannounce(Rdp*);
void clipvcfn(Rdp*, uchar*,uint);
+void audiovcfn(Rdp*, uchar*,uint);
void pollsnarf(Rdp*);
void initscreen(Rdp*);
--- a/mkfile
+++ b/mkfile
@@ -7,6 +7,7 @@
HFILES=fns.h dat.h
OFILES=\
alloc.$O\
+ audio.$O\
cap.$O\
draw.$O\
eclip.$O\
@@ -30,6 +31,7 @@
THREADOFILES=\
alloc.$O\
+ audio.$O\
cap.$O\
draw.$O\
eclip.$O\
--- a/rpc.c
+++ b/rpc.c
@@ -111,7 +111,7 @@
joinchannel(Rdp* c, int mcsuid, int chanid)
{
Msg t, r;
-
+
t.type = Mjoin;
t.mcsuid = mcsuid;
t.chanid = chanid;
--- a/vchan.c
+++ b/vchan.c
@@ -29,6 +29,12 @@
.fn = clipvcfn,
.flags = Inited,
},
+ {
+ .mcsid = GLOBALCHAN+2,
+ .name = "RDPSND",
+ .fn = audiovcfn,
+ .flags = Inited,
+ },
};
static uint nvc = nelem(vctab);
@@ -68,8 +74,10 @@
int n;
vc = lookupvc(m->chanid);
- if(vc == nil)
+ if(vc == nil){
+ fprint(2, "defragvc: bad chanid\n");
return -1;
+ }
if(m->flags&First)
vc->pos = 0;
@@ -97,8 +105,10 @@
{
Vchan* vc;
vc = lookupvc(m->chanid);
- if(vc == nil)
+ if(vc == nil || vc->fn==nil){
+ fprint(2, "unhandled virtual channel[%d] msg\n", m->chanid);
return;
+ }
vc->fn(c, m->data, m->ndata);
}