| @@ -37,6 +37,9 @@ struct Packet { · 36 unmodified lines |
| 37 | 37 | u32int ts; |
| 38 | 38 | u8int *data; |
| 39 | 39 | int sz; |
| 40 | + int left; |
| 41 | + Packet *prev; |
| 42 | + Packet *next; |
| 40 | 43 | }; |
| 41 | 44 | |
| 42 | 45 | struct RTMP { |
| @@ -45,6 +48,7 @@ struct RTMP { · 2 unmodified lines |
| 45 | 48 | char *path; |
| 46 | 49 | char *tcurl; |
| 47 | 50 | Packet pk; |
| 51 | + Packet *ch; |
| 48 | 52 | u8int *b, *p, *e; |
| 49 | 53 | int mode; |
| 50 | 54 | int bsz; |
| @@ -66,6 +70,39 @@ struct RTMP { · 15 unmodified lines |
| 66 | 70 | #define putkvbool(name, s) do{ r->p = amfkvbool(r->p, r->e, name, s); }while(0) |
| 67 | 71 | |
| 68 | 72 | int rtmpdump = 0; |
| 73 | +extern int debug; |
| 74 | + |
| 75 | +static Packet * |
| 76 | +pk4chan(RTMP *r, int chan) |
| 77 | +{ |
| 78 | + Packet *p; |
| 79 | + |
| 80 | + for(p = r->ch; p != nil && p->chan != chan; p = p->next); |
| 81 | + |
| 82 | + if(p == nil){ |
| 83 | + if((p = calloc(1, sizeof(*p))) == nil) |
| 84 | + sysfatal("memory"); |
| 85 | + p->type = -1; |
| 86 | + p->chan = chan; |
| 87 | + if((p->next = r->ch) != nil) |
| 88 | + r->ch->prev = p; |
| 89 | + } |
| 90 | + |
| 91 | + return p; |
| 92 | +} |
| 93 | + |
| 94 | +static void |
| 95 | +pkfree(RTMP *r, Packet *p) |
| 96 | +{ |
| 97 | + if(p->prev != nil) |
| 98 | + p->prev->next = p->next; |
| 99 | + if(p->next != nil) |
| 100 | + p->next->prev = p->prev; |
| 101 | + if(r->ch == p) |
| 102 | + r->ch = p->next; |
| 103 | + |
| 104 | + free(p->data); |
| 105 | +} |
| 69 | 106 | |
| 70 | 107 | static void |
| 71 | 108 | newpacket(RTMP *r, int type, int hsz, int chan) |
| @@ -85,6 +122,22 @@ newpacket(RTMP *r, int type, int hsz, int chan) · 13 unmodified lines |
| 85 | 122 | } |
| 86 | 123 | } |
| 87 | 124 | |
| 125 | +static void |
| 126 | +bextend(RTMP *r, int bsz) |
| 127 | +{ |
| 128 | + u8int *ob; |
| 129 | + |
| 130 | + if(r->bsz >= bsz) |
| 131 | + return; |
| 132 | + ob = r->b; |
| 133 | + if((r->b = realloc(r->b, bsz*2)) == nil) |
| 134 | + sysfatal("memory"); |
| 135 | + if(ob != nil) |
| 136 | + r->p = r->b + (intptr)(ob - r->p); |
| 137 | + r->bsz *= 2; |
| 138 | + r->e = r->b + r->bsz; |
| 139 | +} |
| 140 | + |
| 88 | 141 | static int |
| 89 | 142 | handshake(int f) |
| 90 | 143 | { |
| @@ -117,6 +170,60 @@ err: · 26 unmodified lines |
| 117 | 170 | return -1; |
| 118 | 171 | } |
| 119 | 172 | |
| 173 | +static int |
| 174 | +rtmprecv(RTMP *r) |
| 175 | +{ |
| 176 | + u8int *h, *e, type; |
| 177 | + int hsz, chan, bodysz, dummy; |
| 178 | + u32int ts; |
| 179 | + |
| 180 | + r->p = r->b; |
| 181 | + if(readn(r->i, r->p, 1) != 1) |
| 182 | + goto err; |
| 183 | + hsz = (r->p[0] & 0xc0)>>6; |
| 184 | + chan = r->p[0] & 0x3f; |
| 185 | + if(debug) |
| 186 | + fprint(2, "hsz=%d chan=%d\n", hsz, chan); |
| 187 | + if(readn(r->i, r->p+1, hsz-1) != hsz-1) |
| 188 | + goto err; |
| 189 | + |
| 190 | + memset(&r->pk, 0, sizeof(r->pk)); |
| 191 | + r->pk.hsz = hsz; |
| 192 | + r->pk.chan = chan; |
| 193 | + |
| 194 | + h = r->p + 1; |
| 195 | + e = r->p + hsz; |
| 196 | + r->pk.type = -1; |
| 197 | + bodysz = 0; |
| 198 | + if(hsz >= SzSmall){ |
| 199 | + h = amfi24get(h, e, (s32int*)&ts); /* FIXME proper timestamps? */ |
| 200 | + if(hsz >= SzMedium){ |
| 201 | + h = amfi24get(h, e, &bodysz); |
| 202 | + h = amfbyteget(h, e, &type); |
| 203 | + r->pk.type = type; |
| 204 | + if(hsz >= SzLarge) |
| 205 | + h = amfi32get(h, e, &dummy); /* FIXME seems to be always 0? */ |
| 206 | + } |
| 207 | + } |
| 208 | + |
| 209 | + if(ts == 0xffffff){ /* exntended timestamp */ |
| 210 | + if(readn(r->i, h, 4) != 4) |
| 211 | + goto err; |
| 212 | + h = amfi32get(h, h+4, (s32int*)&ts); |
| 213 | + } |
| 214 | + |
| 215 | + bextend(r, bodysz); |
| 216 | + if(readn(r->i, h, bodysz) != bodysz) |
| 217 | + goto err; |
| 218 | + h += bodysz; |
| 219 | + |
| 220 | + return 0; |
| 221 | + |
| 222 | +err: |
| 223 | + werrstr("rtmprecv: %r"); |
| 224 | + return -1; |
| 225 | +} |
| 226 | + |
| 120 | 227 | static int |
| 121 | 228 | rtmpsend(RTMP *r) |
| 122 | 229 | { |
| @@ -147,7 +254,6 @@ rtmpsend(RTMP *r) · 24 unmodified lines |
| 147 | 254 | hsz = e - r->b; |
| 148 | 255 | for(; hsz+bodysz > 0;){ |
| 149 | 256 | n = min(bodysz, Chunk); |
| 150 | | − fprint(2, "header is %d bytes, writing %d+%d=%d\n", hsz, hsz, n, hsz+n); |
| 151 | 257 | if(Bwrite(r, p, hsz+n) < 0) |
| 152 | 258 | goto err; |
| 153 | 259 | if(rtmpdump) |
| @@ -162,6 +268,7 @@ rtmpsend(RTMP *r) · 8 unmodified lines |
| 162 | 268 | } |
| 163 | 269 | |
| 164 | 270 | r->p = nil; |
| 271 | + Bflush(r); |
| 165 | 272 | |
| 166 | 273 | return 0; |
| 167 | 274 | err: |
| @@ -247,16 +354,15 @@ rtmpdial(char *url, int w, int h, int withaudio) · 79 unmodified lines |
| 247 | 354 | |
| 248 | 355 | if(handshake(f) != 0) |
| 249 | 356 | goto err; |
| 250 | | − if((r = calloc(1, sizeof(*r))) == nil || (r->b = malloc(Bufsz)) == nil) |
| 357 | + if((r = calloc(1, sizeof(*r))) == nil) |
| 251 | 358 | sysfatal("memory"); |
| 252 | 359 | if((r->app = strdup(app)) == nil || (path != nil && (r->path = strdup(path)) == nil)) |
| 253 | 360 | sysfatal("memory"); |
| 361 | + bextend(r, Bufsz); |
| 254 | 362 | r->tcurl = url; |
| 255 | | − r->bsz = Bufsz; |
| 256 | | − r->e = r->b + r->bsz; |
| 257 | 363 | Binits(r, f, OWRITE, r->biobuf, sizeof(r->biobuf)); |
| 258 | 364 | r->i = f; |
| 259 | | − if(connect(r) != 0) |
| 365 | + if(connect(r) != 0 || rtmprecv(r) != 0) |
| 260 | 366 | goto err; |
| 261 | 367 | |
| 262 | 368 | return r; |