$ git clone http://tcclient.ion.nu/tc_client.git
commit a9d34968c2e44d23ba0527737966f1e191392da2
Author: Alicia <...>
Date:   Sun Sep 11 21:05:23 2016 +0200

    Implemented RTMP acknowledgement on outgoing data, with dropping video packets if necessary.

diff --git a/ChangeLog b/ChangeLog
index 72a4106..8da0425 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,6 +1,7 @@
 0.39:
 Added a /closecam command to stop receiving a cam stream.
 Use uintX_t for endianness functions instead of unsigned long*x int.
+Implemented RTMP acknowledgement on outgoing data, with dropping video packets if necessary.
 bugfix: brought back announcing when a cam stream ends.
 modbot: only use youtube-dl's 'ytsearch:' for --get-id, and only if it doesn't appear to be an ID already.
 tc_client-gtk: handle only one sendmessage event at a time, and don't send empty lines.
diff --git a/rtmp.c b/rtmp.c
index 8a145c0..be0cecd 100644
--- a/rtmp.c
+++ b/rtmp.c
@@ -1,6 +1,6 @@
 /*
     tc_client, a simple non-flash client for tinychat(.com)
-    Copyright (C) 2015  alicia@ion.nu
+    Copyright (C) 2015-2016  alicia@ion.nu
 
     This program is free software: you can redistribute it and/or modify
     it under the terms of the GNU Affero General Public License as published by
@@ -38,6 +38,10 @@ unsigned int chunksize_in=128;
 int rtmplog=-1;
 #endif
 
+#define ackwindow 0x20200
+uint32_t rtmpsent=0;
+uint32_t rtmpack=ackwindow;
+
 size_t fullread(int fd, void* buf, size_t len)
 {
   size_t remaining=len;
@@ -84,13 +88,13 @@ char rtmp_get(int sock, struct rtmp* rtmp)
   x=le32(x);
   unsigned int chunkid=x&0x3f;
   unsigned int fmt=(x&0xc0)>>6;
-  struct chunk* chunk=chunk_get(chunkid);
   // Handle extended stream IDs
   if(chunkid<2) // (0=1 extra byte, 1=2 extra bytes)
   {
     fullread(sock, &x, chunkid+1);
     chunkid=64+x;
   }
+  struct chunk* chunk=chunk_get(chunkid);
   if(fmt<3)
   {
     // Timestamp
@@ -139,6 +143,12 @@ char rtmp_get(int sock, struct rtmp* rtmp)
       chunksize_in=be32(chunksize_in);
 //      printf("Server set chunk size to %u (packet size: %u)\n", chunksize_in, chunk->length);
     }
+    else if(chunk->type==RTMP_ACKNOWLEDGEMENT && chunk->length==4)
+    {
+      uint32_t bytes=*(unsigned int*)chunk->buf;
+      rtmpack=be32(bytes)+ackwindow;
+      return 2;
+    }
 // printf("Got chunk: chunkid=%u, type=%u, length=%u, streamid=%u\n", chunk->id, chunk->type, chunk->length, chunk->streamid);
     rtmp->type=chunk->type;
     rtmp->chunkid=chunk->id;
@@ -156,33 +166,35 @@ char rtmp_get(int sock, struct rtmp* rtmp)
 char firstpacket=1;
 void rtmp_send(int sock, struct rtmp* rtmp)
 {
+  #define rwrite(x,y,z) write(x,y,z); rtmpsent+=z // Add to the data sent counter
+  if(rtmpsent>rtmpack && rtmp->type==RTMP_VIDEO){return;}
   // Header format and stream ID
   unsigned int fmt=(rtmp->msgid?0:1);
   if(firstpacket){firstpacket=fmt=0;}
   unsigned char basicheader=(rtmp->chunkid<64?rtmp->chunkid:(rtmp->chunkid<256?0:1)) | (fmt<<6);
-  write(sock, &basicheader, sizeof(basicheader));
+  rwrite(sock, &basicheader, sizeof(basicheader));
   if(rtmp->chunkid>=64) // Handle large stream IDs
   {
     if(rtmp->chunkid<256)
     {
       unsigned char chunkid=rtmp->chunkid-64;
-      write(sock, &chunkid, sizeof(chunkid));
+      rwrite(sock, &chunkid, sizeof(chunkid));
     }else{
       unsigned short chunkid=le16(rtmp->chunkid-64);
-      write(sock, &chunkid, sizeof(chunkid));
+      rwrite(sock, &chunkid, sizeof(chunkid));
     }
   }
   unsigned int x=0;
   // Timestamp
-  write(sock, &x, 3); // Time is irrelevant
+  rwrite(sock, &x, 3); // Time is irrelevant
   // Length
   x=be32(rtmp->length);
-  write(sock, ((void*)&x)+1, 3);
+  rwrite(sock, ((void*)&x)+1, 3);
   // Type
-  write(sock, &rtmp->type, sizeof(rtmp->type));
+  rwrite(sock, &rtmp->type, sizeof(rtmp->type));
   if(fmt<1) // Send message ID if there is one (that isn't 0)
   {
-    write(sock, &rtmp->msgid, sizeof(rtmp->msgid));
+    rwrite(sock, &rtmp->msgid, sizeof(rtmp->msgid));
   }
   // Send 128 bytes at a time separated by a "continuation header", the 0xc3 byte for chunk 3
   void* pos=rtmp->buf;
@@ -203,4 +215,5 @@ void rtmp_send(int sock, struct rtmp* rtmp)
 // printf("Wrote %i bytes\n", w);
     pos+=128;
   }
+  rtmpsent+=rtmp->length;
 }