├── .gitignore ├── .vscode └── c_cpp_properties.json ├── Makefile ├── README.md ├── examples └── voip.ino ├── library.properties └── src ├── Debug.h ├── MD5.cpp ├── MD5.h ├── RTP.cpp ├── RTP.h ├── SdpHeader.cpp ├── SdpHeader.h ├── SipHeader.cpp ├── SipHeader.h ├── SipMachine.cpp ├── SipMachine.h ├── SipStreamIn.cpp └── SipStreamIn.h /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | 34 | #password 35 | secret.* -------------------------------------------------------------------------------- /.vscode/c_cpp_properties.json: -------------------------------------------------------------------------------- 1 | { 2 | "configurations": [ 3 | { 4 | "name": "Linux", 5 | "includePath": [ 6 | "/home/retep/projects/Arduino/src" 7 | ], 8 | "forcedInclude": [], 9 | "defines": [ 10 | "USBCON" 11 | ], 12 | "intelliSenseMode": "gcc-x64", 13 | "compilerPath": "/usr/bin/gcc", 14 | "cStandard": "gnu17", 15 | "cppStandard": "gnu++14" 16 | } 17 | ], 18 | "version": 4 19 | } -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | TARGET_EXEC := 2 | PATHS := /home/retep/projects/Arduino 3 | BUILD_DIR ?= build 4 | SRC_DIRS ?= src 5 | include /home/retep/projects/Makefile/makefile 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SipMachine 2 | Voip for Arduino 3 | -------------------------------------------------------------------------------- /examples/voip.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include "WiFi.h" 3 | #include "SipMachine.h" 4 | #include "Debug.h" 5 | 6 | #include "SD.h" 7 | 8 | const char *ssid = "XXXX"; // your network SSID (name) 9 | const char *password = "XX"; // your network password (use for WPA, or use as key for WEP) 10 | 11 | 12 | 13 | String telNr="225"; 14 | #endif 15 | SipMachine sipMachine = SipMachine("relleum", "XXXXXXX", telNr, "b2b.domain", "192.168.1.1"); //esp 16 | 17 | 18 | String translateEncryptionType(wifi_auth_mode_t encryptionType) 19 | { 20 | switch (encryptionType) 21 | { 22 | case (WIFI_AUTH_OPEN): 23 | return "Open"; 24 | case (WIFI_AUTH_WEP): 25 | return "WEP"; 26 | case (WIFI_AUTH_WPA_PSK): 27 | return "WPA_PSK"; 28 | case (WIFI_AUTH_WPA2_PSK): 29 | return "WPA2_PSK"; 30 | case (WIFI_AUTH_WPA_WPA2_PSK): 31 | return "WPA_WPA2_PSK"; 32 | case (WIFI_AUTH_WPA2_ENTERPRISE): 33 | return "WPA2_ENTERPRISE"; 34 | default: 35 | return ""; 36 | } 37 | } 38 | fs::File f; 39 | fs::File fo; 40 | void scanNetworks() 41 | { 42 | 43 | int numberOfNetworks = WiFi.scanNetworks(); 44 | debug_println(String(" Number of networks found: ") + String(numberOfNetworks)); 45 | 46 | for (int i = 0; i < numberOfNetworks; i++) 47 | { 48 | debug_println(String(" Network name: ") + String(WiFi.SSID(i).c_str())); 49 | debug_println(String(" Signal strength: ") + String(WiFi.RSSI(i))); 50 | debug_println(String(" MAC address: ") + WiFi.BSSIDstr(i)); 51 | debug_println(String(" Encryption type: ") + translateEncryptionType((wifi_auth_mode_t)WiFi.encryptionType(i))); 52 | debug_println(String(" -----------------------")); 53 | } 54 | } 55 | 56 | void connectToNetwork() 57 | { 58 | WiFi.begin(ssid, password); 59 | while (WiFi.status() != WL_CONNECTED) 60 | { 61 | delay(1000); 62 | debug_println(String(" Establishing connection to WiFi...")); 63 | } 64 | debug_println(String(" Connected to network")); 65 | } 66 | 67 | void setup() 68 | { 69 | Serial.begin(115200); 70 | scanNetworks(); 71 | connectToNetwork(); 72 | debug_println(String(" Mac Address ") + WiFi.macAddress()); 73 | debug_println(String(" IP Address ") + WiFi.localIP().toString()); 74 | debug_println(String(" Gateway IP ") + WiFi.gatewayIP().toString()); 75 | sipMachine.setup(WiFi.localIP().toString(), WiFi.gatewayIP().toString()); 76 | 77 | if (!SD.begin(4)) 78 | { 79 | Serial.println("Card Mount Failed"); 80 | return; 81 | } 82 | else {} 83 | } 84 | 85 | bool b = true; 86 | unsigned long t = millis(); 87 | unsigned long t2 = millis(); 88 | unsigned long x = 0; 89 | unsigned long t3 = millis(); 90 | unsigned long t4 = micros(); 91 | unsigned long t5 = millis(); 92 | 93 | SipMachine::Status status; 94 | int16_t pcmOut=0; 95 | int16_t pcmIn; 96 | 97 | 98 | int16_t minP=0; 99 | int16_t maxP=0; 100 | 101 | void loop() 102 | { 103 | 104 | pcmIn = sipMachine.loop(pcmOut); 105 | pcmOut=0; 106 | status=sipMachine.getStatus(); 107 | 108 | switch (status) 109 | { 110 | case SipMachine::ringIn: 111 | // debug_println(String("Ringing Call Nr. ") + sipMachine.getTelNr()); 112 | if (sipMachine.getTelNrIncomingCall().toInt() < 300) 113 | { 114 | debug_println(String("Accept incoming Call ") + sipMachine.getTelNrIncomingCall()); 115 | sipMachine.acceptIncomingCall(); 116 | } 117 | break; 118 | case SipMachine::idle: 119 | if ((t2 + 5000 < millis()) & (t2 + 6000 > millis())) 120 | if (!telNr.equals("222")) 121 | { 122 | sipMachine.makeCall("222"); 123 | } 124 | if (f) 125 | { 126 | f.close(); 127 | } 128 | if (fo) 129 | { 130 | fo.close(); 131 | } 132 | break; 133 | case SipMachine::call: 134 | if ((t5+20000)maxP) 158 | { 159 | maxP=pcmIn; 160 | } 161 | if (pcmIn1) 169 | { 170 | fo.read((uint8_t*)&pcmOut,2); 171 | } 172 | else 173 | { 174 | fo.close(); 175 | } 176 | } 177 | break; 178 | default: 179 | break; 180 | } 181 | x++; 182 | 183 | if (millis() % 10000 == 0 && t != millis()) 184 | { 185 | t = millis(); 186 | 187 | debugL1_print(x); 188 | x = 0; 189 | debugL1_print(" min "); 190 | debugL1_print(String(minP)); 191 | debugL1_print(" max "); 192 | debugL1_print(String(maxP)); 193 | debugL1_print(" "); 194 | debugL1_print(millis()); 195 | debugL1_print(" dtmf: "); 196 | debugL1_println(sipMachine.getKeyPressedLast20()); 197 | } 198 | } 199 | 200 | //#ifdef __ESP_ARDU 201 | 202 | int main() 203 | { 204 | setup(); 205 | while (true==true) 206 | { 207 | loop(); 208 | } 209 | } 210 | 211 | //#endif 212 | -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=sipMachine 2 | version=1.1.1 3 | author=Peter Müller 4 | maintainer=Arduino 5 | sentence=Voip for Arduino. 6 | paragraph=Voip for Arduino. 7 | category=telefonie 8 | url=http:// 9 | architectures=avr,megaavr,sam,samd,nrf52,stm32f4,mbed,esp32 10 | -------------------------------------------------------------------------------- /src/Debug.h: -------------------------------------------------------------------------------- 1 | #ifndef DEBUG_H_INCLUDED 2 | #define DEBUG_H_INCLUDED 3 | #include 4 | 5 | 6 | #define DEBUG 1 7 | #define debug_print(str) do { if (DEBUG) Serial.print(str); } while (0) 8 | #define debug_println( str) do { if (DEBUG) Serial.println(str); } while (0) 9 | 10 | 11 | #define DEBUG1 1 12 | #define debugL1_print(str) do { if (DEBUG1) Serial.print(str); } while (0) 13 | #define debugL1_println( str) do { if (DEBUG1) Serial.println(str); } while (0) 14 | 15 | #define DEBUG2 0 16 | #define debugL2_print(str) do { if (DEBUG2) Serial.print(str); } while (0) 17 | #define debugL2_println( str) do { if (DEBUG2) Serial.println(str); } while (0) 18 | 19 | 20 | #define DEBUG3 0 21 | #define debugL3_print(str) do { if (DEBUG3) Serial.print(str); } while (0) 22 | #define debugL3_println( str) do { if (DEBUG3) Serial.println(str); } while (0) 23 | 24 | #endif // DEBUG_H_INCLUDED 25 | -------------------------------------------------------------------------------- /src/MD5.cpp: -------------------------------------------------------------------------------- 1 | #include "MD5.h" 2 | #include "Debug.h" 3 | MD5::MD5() 4 | { 5 | //nothing 6 | return; 7 | } 8 | 9 | char* MD5::make_digest(const unsigned char *digest, int len) /* {{{ */ 10 | { 11 | char * md5str = (char*) malloc(sizeof(char)*(len*2+1)); 12 | static const char hexits[17] = "0123456789abcdef"; 13 | int i; 14 | 15 | for (i = 0; i < len; i++) { 16 | md5str[i * 2] = hexits[digest[i] >> 4]; 17 | md5str[(i * 2) + 1] = hexits[digest[i] & 0x0F]; 18 | } 19 | md5str[len * 2] = '\0'; 20 | return md5str; 21 | } 22 | 23 | /* 24 | * The basic MD5 functions. 25 | * 26 | * E and G are optimized compared to their RFC 1321 definitions for 27 | * architectures that lack an AND-NOT instruction, just like in Colin Plumb's 28 | * implementation. 29 | * E() has been used instead of F() because F() is already defined in the Arduino core 30 | */ 31 | #define E(x, y, z) ((z) ^ ((x) & ((y) ^ (z)))) 32 | #define G(x, y, z) ((y) ^ ((z) & ((x) ^ (y)))) 33 | #define H(x, y, z) ((x) ^ (y) ^ (z)) 34 | #define I(x, y, z) ((y) ^ ((x) | ~(z))) 35 | 36 | /* 37 | * The MD5 transformation for all four rounds. 38 | */ 39 | #define STEP(f, a, b, c, d, x, t, s) \ 40 | (a) += f((b), (c), (d)) + (x) + (t); \ 41 | (a) = (((a) << (s)) | (((a) & 0xffffffff) >> (32 - (s)))); \ 42 | (a) += (b); 43 | 44 | /* 45 | * SET reads 4 input bytes in little-endian byte order and stores them 46 | * in a properly aligned word in host byte order. 47 | * 48 | * The check for little-endian architectures that tolerate unaligned 49 | * memory accesses is just an optimization. Nothing will break if it 50 | * doesn't work. 51 | */ 52 | #if defined(__i386__) || defined(__x86_64__) || defined(__vax__) 53 | # define SET(n) \ 54 | (*(MD5_u32plus *)&ptr[(n) * 4]) 55 | # define GET(n) \ 56 | SET(n) 57 | #else 58 | # define SET(n) \ 59 | (ctx->block[(n)] = \ 60 | (MD5_u32plus)ptr[(n) * 4] | \ 61 | ((MD5_u32plus)ptr[(n) * 4 + 1] << 8) | \ 62 | ((MD5_u32plus)ptr[(n) * 4 + 2] << 16) | \ 63 | ((MD5_u32plus)ptr[(n) * 4 + 3] << 24)) 64 | # define GET(n) \ 65 | (ctx->block[(n)]) 66 | #endif 67 | 68 | /* 69 | * This processes one or more 64-byte data blocks, but does NOT update 70 | * the bit counters. There are no alignment requirements. 71 | */ 72 | const void *MD5::body(void *ctxBuf, const void *data, size_t size) 73 | { 74 | MD5_CTX *ctx = (MD5_CTX*)ctxBuf; 75 | const unsigned char *ptr; 76 | MD5_u32plus a, b, c, d; 77 | MD5_u32plus saved_a, saved_b, saved_c, saved_d; 78 | 79 | ptr = (unsigned char*)data; 80 | 81 | a = ctx->a; 82 | b = ctx->b; 83 | c = ctx->c; 84 | d = ctx->d; 85 | 86 | do { 87 | saved_a = a; 88 | saved_b = b; 89 | saved_c = c; 90 | saved_d = d; 91 | 92 | /* Round 1 93 | * E() has been used instead of F() because F() is already defined in the Arduino core 94 | */ 95 | STEP(E, a, b, c, d, SET(0), 0xd76aa478, 7) 96 | STEP(E, d, a, b, c, SET(1), 0xe8c7b756, 12) 97 | STEP(E, c, d, a, b, SET(2), 0x242070db, 17) 98 | STEP(E, b, c, d, a, SET(3), 0xc1bdceee, 22) 99 | STEP(E, a, b, c, d, SET(4), 0xf57c0faf, 7) 100 | STEP(E, d, a, b, c, SET(5), 0x4787c62a, 12) 101 | STEP(E, c, d, a, b, SET(6), 0xa8304613, 17) 102 | STEP(E, b, c, d, a, SET(7), 0xfd469501, 22) 103 | STEP(E, a, b, c, d, SET(8), 0x698098d8, 7) 104 | STEP(E, d, a, b, c, SET(9), 0x8b44f7af, 12) 105 | STEP(E, c, d, a, b, SET(10), 0xffff5bb1, 17) 106 | STEP(E, b, c, d, a, SET(11), 0x895cd7be, 22) 107 | STEP(E, a, b, c, d, SET(12), 0x6b901122, 7) 108 | STEP(E, d, a, b, c, SET(13), 0xfd987193, 12) 109 | STEP(E, c, d, a, b, SET(14), 0xa679438e, 17) 110 | STEP(E, b, c, d, a, SET(15), 0x49b40821, 22) 111 | 112 | /* Round 2 */ 113 | STEP(G, a, b, c, d, GET(1), 0xf61e2562, 5) 114 | STEP(G, d, a, b, c, GET(6), 0xc040b340, 9) 115 | STEP(G, c, d, a, b, GET(11), 0x265e5a51, 14) 116 | STEP(G, b, c, d, a, GET(0), 0xe9b6c7aa, 20) 117 | STEP(G, a, b, c, d, GET(5), 0xd62f105d, 5) 118 | STEP(G, d, a, b, c, GET(10), 0x02441453, 9) 119 | STEP(G, c, d, a, b, GET(15), 0xd8a1e681, 14) 120 | STEP(G, b, c, d, a, GET(4), 0xe7d3fbc8, 20) 121 | STEP(G, a, b, c, d, GET(9), 0x21e1cde6, 5) 122 | STEP(G, d, a, b, c, GET(14), 0xc33707d6, 9) 123 | STEP(G, c, d, a, b, GET(3), 0xf4d50d87, 14) 124 | STEP(G, b, c, d, a, GET(8), 0x455a14ed, 20) 125 | STEP(G, a, b, c, d, GET(13), 0xa9e3e905, 5) 126 | STEP(G, d, a, b, c, GET(2), 0xfcefa3f8, 9) 127 | STEP(G, c, d, a, b, GET(7), 0x676f02d9, 14) 128 | STEP(G, b, c, d, a, GET(12), 0x8d2a4c8a, 20) 129 | 130 | /* Round 3 */ 131 | STEP(H, a, b, c, d, GET(5), 0xfffa3942, 4) 132 | STEP(H, d, a, b, c, GET(8), 0x8771f681, 11) 133 | STEP(H, c, d, a, b, GET(11), 0x6d9d6122, 16) 134 | STEP(H, b, c, d, a, GET(14), 0xfde5380c, 23) 135 | STEP(H, a, b, c, d, GET(1), 0xa4beea44, 4) 136 | STEP(H, d, a, b, c, GET(4), 0x4bdecfa9, 11) 137 | STEP(H, c, d, a, b, GET(7), 0xf6bb4b60, 16) 138 | STEP(H, b, c, d, a, GET(10), 0xbebfbc70, 23) 139 | STEP(H, a, b, c, d, GET(13), 0x289b7ec6, 4) 140 | STEP(H, d, a, b, c, GET(0), 0xeaa127fa, 11) 141 | STEP(H, c, d, a, b, GET(3), 0xd4ef3085, 16) 142 | STEP(H, b, c, d, a, GET(6), 0x04881d05, 23) 143 | STEP(H, a, b, c, d, GET(9), 0xd9d4d039, 4) 144 | STEP(H, d, a, b, c, GET(12), 0xe6db99e5, 11) 145 | STEP(H, c, d, a, b, GET(15), 0x1fa27cf8, 16) 146 | STEP(H, b, c, d, a, GET(2), 0xc4ac5665, 23) 147 | 148 | /* Round 4 */ 149 | STEP(I, a, b, c, d, GET(0), 0xf4292244, 6) 150 | STEP(I, d, a, b, c, GET(7), 0x432aff97, 10) 151 | STEP(I, c, d, a, b, GET(14), 0xab9423a7, 15) 152 | STEP(I, b, c, d, a, GET(5), 0xfc93a039, 21) 153 | STEP(I, a, b, c, d, GET(12), 0x655b59c3, 6) 154 | STEP(I, d, a, b, c, GET(3), 0x8f0ccc92, 10) 155 | STEP(I, c, d, a, b, GET(10), 0xffeff47d, 15) 156 | STEP(I, b, c, d, a, GET(1), 0x85845dd1, 21) 157 | STEP(I, a, b, c, d, GET(8), 0x6fa87e4f, 6) 158 | STEP(I, d, a, b, c, GET(15), 0xfe2ce6e0, 10) 159 | STEP(I, c, d, a, b, GET(6), 0xa3014314, 15) 160 | STEP(I, b, c, d, a, GET(13), 0x4e0811a1, 21) 161 | STEP(I, a, b, c, d, GET(4), 0xf7537e82, 6) 162 | STEP(I, d, a, b, c, GET(11), 0xbd3af235, 10) 163 | STEP(I, c, d, a, b, GET(2), 0x2ad7d2bb, 15) 164 | STEP(I, b, c, d, a, GET(9), 0xeb86d391, 21) 165 | 166 | a += saved_a; 167 | b += saved_b; 168 | c += saved_c; 169 | d += saved_d; 170 | 171 | ptr += 64; 172 | } while (size -= 64); 173 | 174 | ctx->a = a; 175 | ctx->b = b; 176 | ctx->c = c; 177 | ctx->d = d; 178 | 179 | return ptr; 180 | } 181 | 182 | void MD5::MD5Init(void *ctxBuf) 183 | { 184 | MD5_CTX *ctx = (MD5_CTX*)ctxBuf; 185 | ctx->a = 0x67452301; 186 | ctx->b = 0xefcdab89; 187 | ctx->c = 0x98badcfe; 188 | ctx->d = 0x10325476; 189 | 190 | ctx->lo = 0; 191 | ctx->hi = 0; 192 | 193 | memset(ctx->block, 0, sizeof(ctx->block)); 194 | memset(ctx->buffer, 0, sizeof(ctx->buffer)); 195 | } 196 | 197 | void MD5::MD5Update(void *ctxBuf, const void *data, size_t size) 198 | { 199 | MD5_CTX *ctx = (MD5_CTX*)ctxBuf; 200 | MD5_u32plus saved_lo; 201 | MD5_u32plus used, free; 202 | 203 | saved_lo = ctx->lo; 204 | if ((ctx->lo = (saved_lo + size) & 0x1fffffff) < saved_lo) { 205 | ctx->hi++; 206 | } 207 | ctx->hi += size >> 29; 208 | 209 | used = saved_lo & 0x3f; 210 | 211 | if (used) { 212 | free = 64 - used; 213 | 214 | if (size < free) { 215 | memcpy(&ctx->buffer[used], data, size); 216 | return; 217 | } 218 | 219 | memcpy(&ctx->buffer[used], data, free); 220 | data = (unsigned char *)data + free; 221 | size -= free; 222 | body(ctx, ctx->buffer, 64); 223 | } 224 | 225 | if (size >= 64) { 226 | data = body(ctx, data, size & ~(size_t)0x3f); 227 | size &= 0x3f; 228 | } 229 | 230 | memcpy(ctx->buffer, data, size); 231 | } 232 | 233 | void MD5::MD5Final(unsigned char *result, void *ctxBuf) 234 | { 235 | MD5_CTX *ctx = (MD5_CTX*)ctxBuf; 236 | MD5_u32plus used, free; 237 | 238 | used = ctx->lo & 0x3f; 239 | 240 | ctx->buffer[used++] = 0x80; 241 | 242 | free = 64 - used; 243 | 244 | if (free < 8) { 245 | memset(&ctx->buffer[used], 0, free); 246 | body(ctx, ctx->buffer, 64); 247 | used = 0; 248 | free = 64; 249 | } 250 | 251 | memset(&ctx->buffer[used], 0, free - 8); 252 | 253 | ctx->lo <<= 3; 254 | ctx->buffer[56] = ctx->lo; 255 | ctx->buffer[57] = ctx->lo >> 8; 256 | ctx->buffer[58] = ctx->lo >> 16; 257 | ctx->buffer[59] = ctx->lo >> 24; 258 | ctx->buffer[60] = ctx->hi; 259 | ctx->buffer[61] = ctx->hi >> 8; 260 | ctx->buffer[62] = ctx->hi >> 16; 261 | ctx->buffer[63] = ctx->hi >> 24; 262 | 263 | body(ctx, ctx->buffer, 64); 264 | 265 | result[0] = ctx->a; 266 | result[1] = ctx->a >> 8; 267 | result[2] = ctx->a >> 16; 268 | result[3] = ctx->a >> 24; 269 | result[4] = ctx->b; 270 | result[5] = ctx->b >> 8; 271 | result[6] = ctx->b >> 16; 272 | result[7] = ctx->b >> 24; 273 | result[8] = ctx->c; 274 | result[9] = ctx->c >> 8; 275 | result[10] = ctx->c >> 16; 276 | result[11] = ctx->c >> 24; 277 | result[12] = ctx->d; 278 | result[13] = ctx->d >> 8; 279 | result[14] = ctx->d >> 16; 280 | result[15] = ctx->d >> 24; 281 | 282 | memset(ctx, 0, sizeof(*ctx)); 283 | } 284 | unsigned char* MD5::make_hash(char *arg) 285 | { 286 | MD5_CTX context; 287 | unsigned char * hash = (unsigned char *) malloc(16); 288 | MD5Init(&context); 289 | MD5Update(&context, arg, strlen(arg)); 290 | MD5Final(hash, &context); 291 | return hash; 292 | } 293 | unsigned char* MD5::make_hash(char *arg,size_t size) 294 | { 295 | MD5_CTX context; 296 | unsigned char * hash = (unsigned char *) malloc(16); 297 | MD5Init(&context); 298 | MD5Update(&context, arg, size); 299 | MD5Final(hash, &context); 300 | return hash; 301 | } 302 | 303 | String MD5::encrypt(String encrypts) 304 | { 305 | unsigned char* hash=MD5::make_hash(( char *)(encrypts.c_str())); 306 | char *md5str = MD5::make_digest(hash, 16); 307 | String ret=String((char *)md5str); 308 | free(md5str); 309 | free(hash); 310 | return ret; 311 | } 312 | 313 | String MD5::getAuth(SipHeader::Authenticate auth) 314 | { 315 | String a1 = auth.user + ":" + auth.realm + ":" + auth.pwd; 316 | debugL2_println(String(" a1= ")+a1); 317 | String ha1 = encrypt(a1); 318 | debugL2_println(String(" ha1= ")+ha1); 319 | String a2 = auth.types + ":sip:" + getUri(auth); 320 | debugL2_println(String(" a2= ")+a2); 321 | String ha2 = encrypt(a2); 322 | debugL2_println(String(" ha2= ")+ha2); 323 | String a3 = ha1 + ":" + auth.nonce + ":" + auth.nonceCount + ":" + auth.cNonce + ":" + auth.qop + ":" + ha2; 324 | debugL2_println(String(" a3= ")+a3); 325 | String ret=encrypt(a3); 326 | return ret; 327 | } 328 | 329 | String MD5::getUri(SipHeader::Authenticate auth ) 330 | { 331 | 332 | if (auth.telNr.length()==0) 333 | return auth.agent; 334 | return auth.telNr+"@"+auth.agent; 335 | } 336 | 337 | -------------------------------------------------------------------------------- /src/MD5.h: -------------------------------------------------------------------------------- 1 | #ifndef MD5_h 2 | #define MD5_h 3 | 4 | #include "Arduino.h" 5 | #include 6 | #include "SipHeader.h" 7 | 8 | typedef unsigned long MD5_u32plus; 9 | 10 | typedef struct 11 | { 12 | MD5_u32plus lo, hi; 13 | MD5_u32plus a, b, c, d; 14 | char buffer[64]; 15 | MD5_u32plus block[16]; 16 | } MD5_CTX; 17 | 18 | class MD5 19 | { 20 | public: 21 | MD5(); 22 | static unsigned char* make_hash( char *arg); 23 | static unsigned char* make_hash( char *arg,size_t size); 24 | static char* make_digest(const unsigned char *digest, int len); 25 | static const void *body(void *ctxBuf, const void *data, size_t size); 26 | static void MD5Init(void *ctxBuf); 27 | static void MD5Final( unsigned char *result, void *ctxBuf); 28 | static void MD5Update(void *ctxBuf, const void *data, size_t size); 29 | String encrypt(String encrypts); 30 | String getUri(SipHeader::Authenticate auth); 31 | String getAuth(SipHeader::Authenticate auth); 32 | }; 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /src/RTP.cpp: -------------------------------------------------------------------------------- 1 | #include "RTP.h" 2 | 3 | RTP::RTP() 4 | { 5 | is_big = is_big_endian(); 6 | rtpBuffer.version = 2; 7 | rtpBuffer.p = 0; 8 | rtpBuffer.x = 0; 9 | rtpBuffer.cc = 0; 10 | rtpBuffer.m = 0; 11 | rtpBuffer.pt = 8; 12 | setSSRCIdentifier(random(10000000)); 13 | setSequenceNumber(random(1000)); 14 | setTimestamp(random(1000)); 15 | } 16 | bool RTP::is_big_endian(void) 17 | { 18 | union 19 | { 20 | uint32_t i; 21 | char c[4]; 22 | } bint = {0x01020304}; 23 | 24 | return bint.c[0] == 1; 25 | } 26 | void RTP::put(int16_t value) 27 | { 28 | 29 | size_t p = (micros() % 20000) / 125; 30 | rtpBuffer.b[p] = ALaw_Encode(value); 31 | 32 | } 33 | int16_t RTP::get(uint8_t pos) 34 | { 35 | switch (rtpBuffer.pt) 36 | { 37 | case 0: 38 | return MuLaw_Decode(rtpBuffer.b[pos]); 39 | break; 40 | case 8: 41 | return ALaw_Decode(rtpBuffer.b[pos]); 42 | break; 43 | default: 44 | return 0; 45 | break; 46 | } 47 | } 48 | int8_t RTP::ALaw_Encode(int16_t number) 49 | { 50 | const uint16_t ALAW_MAX = 0xFFF; 51 | uint16_t mask = 0x800; 52 | uint8_t sign = 0; 53 | uint8_t position = 11; 54 | uint8_t lsb = 0; 55 | if (number < 0) 56 | { 57 | number = -number; 58 | sign = 0x80; 59 | } 60 | if (number > ALAW_MAX) 61 | { 62 | number = ALAW_MAX; 63 | } 64 | for (; ((number & mask) != mask && position >= 5); mask >>= 1, position--) 65 | ; 66 | lsb = (number >> ((position == 4) ? (1) : (position - 4))) & 0x0f; 67 | return (sign | ((position - 4) << 4) | lsb) ^ 0x55; 68 | } 69 | int16_t RTP::ALaw_Decode(int8_t number) 70 | { 71 | uint8_t sign = 0x00; 72 | uint8_t position = 0; 73 | int16_t decoded = 0; 74 | number ^= 0x55; 75 | if (number & 0x80) 76 | { 77 | number &= ~(1 << 7); 78 | sign = -1; 79 | } 80 | position = ((number & 0xF0) >> 4) + 4; 81 | if (position != 4) 82 | { 83 | decoded = ((1 << position) | ((number & 0x0F) << (position - 4)) | (1 << (position - 5))); 84 | } 85 | else 86 | { 87 | decoded = (number << 1) | 1; 88 | } 89 | return (sign == 0) ? (decoded) : (-decoded); 90 | } 91 | int8_t RTP::MuLaw_Encode(int16_t number) 92 | { 93 | const uint16_t MULAW_MAX = 0x1FFF; 94 | const uint16_t MULAW_BIAS = 33; 95 | uint16_t mask = 0x1000; 96 | uint8_t sign = 0; 97 | uint8_t position = 12; 98 | uint8_t lsb = 0; 99 | if (number < 0) 100 | { 101 | number = -number; 102 | sign = 0x80; 103 | } 104 | number += MULAW_BIAS; 105 | if (number > MULAW_MAX) 106 | { 107 | number = MULAW_MAX; 108 | } 109 | for (; ((number & mask) != mask && position >= 5); mask >>= 1, position--) 110 | ; 111 | lsb = (number >> (position - 4)) & 0x0f; 112 | return (~(sign | ((position - 5) << 4) | lsb)); 113 | } 114 | int16_t RTP::MuLaw_Decode(int8_t number) 115 | { 116 | const uint16_t MULAW_BIAS = 33; 117 | uint8_t sign = 0, position = 0; 118 | int16_t decoded = 0; 119 | number = ~number; 120 | if (number & 0x80) 121 | { 122 | number &= ~(1 << 7); 123 | sign = -1; 124 | } 125 | position = ((number & 0xF0) >> 4) + 5; 126 | decoded = ((1 << position) | ((number & 0x0F) << (position - 4)) | (1 << (position - 5))) - MULAW_BIAS; 127 | return (sign == 0) ? (decoded) : (-(decoded)); 128 | } 129 | void RTP::fft(CArray &x) 130 | { 131 | const size_t N = x.size(); 132 | if (N <= 1) 133 | return; 134 | 135 | // divide 136 | CArray even = x[std::slice(0, N / 2, 2)]; 137 | CArray odd = x[std::slice(1, N / 2, 2)]; 138 | 139 | // conquer 140 | fft(even); 141 | fft(odd); 142 | 143 | // combine 144 | for (size_t k = 0; k < N / 2; ++k) 145 | { 146 | Complex t = std::polar(1.0, -2 * PI * k / N) * odd[k]; 147 | x[k] = even[k] + t; 148 | x[k + N / 2] = even[k] - t; 149 | } 150 | } 151 | char RTP::getDtmf() 152 | { 153 | CArray data(128); 154 | for (uint8_t i = 0; i < 128; i++) 155 | data[i] = get(i); 156 | 157 | fft(data); 158 | double b[] = {(abs(data[19].real()) + abs(data[11].real())), 159 | abs(data[21].real()) + abs(data[11].real()), 160 | abs(data[24].real()) + abs(data[11].real()), 161 | abs(data[19].real()) + abs(data[12].real()), 162 | abs(data[21].real()) + abs(data[12].real()), 163 | abs(data[24].real()) + abs(data[12].real()), 164 | abs(data[19].real()) + abs(data[14].real()), 165 | abs(data[21].real()) + abs(data[14].real()), 166 | abs(data[24].real()) + abs(data[14].real()), 167 | abs(data[19].real()) + abs(data[15].real()), 168 | abs(data[21].real()) + abs(data[15].real()), 169 | abs(data[24].real()) + abs(data[15].real())}; 170 | 171 | char l[] = {'1', '2', '3', '4', '5', '6', '7', '8', '9', '*', '0', '#'}; 172 | 173 | int8_t index = 0; 174 | double max = 0; 175 | 176 | for (uint8_t i = 0; i < 12; i++) 177 | { 178 | if (b[i] > max) 179 | { 180 | max = b[i]; 181 | index = i; 182 | }; 183 | } 184 | if (max > 50000) 185 | return l[index]; 186 | else 187 | return ' '; 188 | } 189 | -------------------------------------------------------------------------------- /src/RTP.h: -------------------------------------------------------------------------------- 1 | #ifndef RTP_H 2 | #define RTP_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include "Debug.h" 8 | #define SWAP_INT32(x) (((x) >> 24) | (((x)&0x00FF0000) >> 8) | (((x)&0x0000FF00) << 8) | ((x) << 24)) 9 | #define SWAP_INT16(x) (((x & 0xff) << 8) | ((x & 0xff00) >> 8)) 10 | 11 | 12 | 13 | class RTP 14 | { 15 | private: 16 | typedef std::complex Complex; 17 | typedef std::valarray CArray; 18 | 19 | 20 | 21 | bool is_big; 22 | int8_t ALaw_Encode(int16_t number); 23 | int16_t ALaw_Decode(int8_t number); 24 | int8_t MuLaw_Encode(int16_t number); 25 | int16_t MuLaw_Decode(int8_t number); 26 | bool is_big_endian(void); 27 | void fft(CArray &x); 28 | 29 | public: 30 | RTP(); 31 | 32 | struct Rtp 33 | { 34 | uint8_t cc : 4; 35 | uint8_t x : 1; 36 | uint8_t p : 1; 37 | uint8_t version : 2; 38 | // byte 0 39 | uint8_t pt : 7; 40 | uint8_t m : 1; 41 | 42 | //byte 1 43 | uint16_t sequenceNumber; 44 | //byte 3 45 | uint32_t timestamp; 46 | //byte 7 47 | uint32_t SSRCIdentifier; 48 | //byte 11 49 | int8_t b[160]; 50 | }; 51 | struct Dtmf 52 | { 53 | uint8_t cc : 4; 54 | uint8_t x : 1; 55 | uint8_t p : 1; 56 | uint8_t version : 2; 57 | // byte 0 58 | uint8_t pt : 7; 59 | uint8_t m : 1; 60 | 61 | //byte 1 62 | uint16_t sequenceNumber; 63 | //byte 3 64 | uint32_t timestamp; 65 | //byte 7 66 | uint32_t SSRCIdentifier; 67 | //byte 11 68 | uint8_t event; 69 | //byte 12 70 | uint8_t volume : 6; 71 | uint8_t r : 1; 72 | uint8_t e : 1; 73 | //byte 13 74 | uint16_t duration; 75 | //byte 15 76 | }; 77 | size_t rtpPos=0; 78 | 79 | Rtp rtpBuffer; 80 | Dtmf dtmfBuffer; 81 | uint16_t getSequenceNumber() 82 | { 83 | return is_big ? rtpBuffer.sequenceNumber : SWAP_INT16(rtpBuffer.sequenceNumber); 84 | }; 85 | uint32_t getTimestamp() 86 | { 87 | return is_big ? rtpBuffer.timestamp : SWAP_INT32(rtpBuffer.timestamp); 88 | }; 89 | uint32_t getSSRCIdentifier() 90 | { 91 | return is_big ? rtpBuffer.SSRCIdentifier : SWAP_INT32(rtpBuffer.SSRCIdentifier); 92 | }; 93 | void setSequenceNumber(uint16_t x) 94 | { 95 | rtpBuffer.sequenceNumber = is_big ? x : SWAP_INT16(x); 96 | }; 97 | void setTimestamp(uint32_t x) 98 | { 99 | rtpBuffer.timestamp = is_big ? x : SWAP_INT32(x); 100 | }; 101 | void setSSRCIdentifier(uint32_t x) 102 | { 103 | rtpBuffer.SSRCIdentifier = is_big ? x : SWAP_INT32(x); 104 | }; 105 | 106 | void put(int16_t value); 107 | int16_t get(uint8_t pos); 108 | char getDtmf(); 109 | }; 110 | 111 | #endif 112 | -------------------------------------------------------------------------------- /src/SdpHeader.cpp: -------------------------------------------------------------------------------- 1 | #include "SdpHeader.h" 2 | #include "Debug.h" 3 | 4 | SdpHeader::SdpHeader() { 5 | o.username="-"; 6 | o.netType="IN"; 7 | o.addrType="IP4"; 8 | c.netType="IN"; 9 | c.addrType="IP4"; 10 | m.media="audio"; 11 | m.proto="RTP/AVP"; 12 | m.fmt="0 127"; 13 | } 14 | void SdpHeader::parse(String in) 15 | { 16 | if (in.startsWith("o=")) 17 | { 18 | in.replace("o=", ""); 19 | o.username = in.substring(0, in.indexOf(" ")); 20 | debugL2_println(String(" o.username ") + String(o.username.c_str())); 21 | in = in.substring(in.indexOf(" ") + 1); 22 | o.sessId = in.substring(0, in.indexOf(" ")); 23 | debugL2_println(String(" o.sessId ") + String(o.sessId.c_str())); 24 | in = in.substring(in.indexOf(" ") + 1); 25 | o.sessVersion = in.substring(0, in.indexOf(" ")); 26 | debugL2_println(String(" o.sessVersion ") + String(o.sessVersion.c_str())); 27 | in = in.substring(in.indexOf(" ") + 1); 28 | o.netType = in.substring(0, in.indexOf(" ")); 29 | debugL2_println(String(" o.netType ") + String(o.netType.c_str())); 30 | in = in.substring(in.indexOf(" ") + 1); 31 | o.addrType = in.substring(0, in.indexOf(" ")); 32 | debugL2_println(String(" o.addrType ") + String(o.addrType.c_str())); 33 | in = in.substring(in.indexOf(" ") + 1); 34 | o.municastAddress = in.substring(0, in.indexOf("\r")); 35 | debugL2_println(String(" o.municastAddress ") + String(o.municastAddress.c_str())); 36 | } 37 | if (in.startsWith("m=")) 38 | { 39 | in.replace("m=", ""); 40 | m.media = in.substring(0, in.indexOf(" ")); 41 | debugL2_println(String(" m.media ") + String(m.media.c_str())); 42 | in = in.substring(in.indexOf(" ") + 1); 43 | m.port = in.substring(0, in.indexOf(" ")); 44 | debugL2_println(String(" m.port ") + String(m.port.c_str())); 45 | in = in.substring(in.indexOf(" ") + 1); 46 | m.proto = in.substring(0, in.indexOf(" ")); 47 | debugL2_println(String(" m.proto ") + String(m.proto.c_str())); 48 | in = in.substring(in.indexOf(" ") + 1); 49 | m.fmt = in.substring(0, in.indexOf("\r")); 50 | debugL2_println(String(" m.fmt ") + String(m.fmt.c_str())); 51 | } 52 | if (in.startsWith("c=")) 53 | { 54 | in.replace("c=", ""); 55 | c.netType = in.substring(0, in.indexOf(" ")); 56 | debugL2_println(String(" c.netType ") + String(c.netType.c_str())); 57 | in = in.substring(in.indexOf(" ") + 1); 58 | c.addrType = in.substring(0, in.indexOf(" ")); 59 | debugL2_println(String(" c.addrType ") + String(c.addrType.c_str())); 60 | in = in.substring(in.indexOf(" ") + 1); 61 | c.connectionAddress = in.substring(0, in.indexOf("\r")); 62 | debugL2_println(String(" c.connectionAddress ") + String(c.connectionAddress.c_str())); 63 | } 64 | } 65 | String SdpHeader::getContent() 66 | { 67 | String ret; 68 | ret = "v=0\r\n"; 69 | ret += "o=" + o.username + " " + o.sessId + " " + o.sessVersion + " " + o.netType + " " + o.addrType + " " + o.municastAddress + "\r\n"; 70 | ret += "s=" + s + "\r\n"; 71 | ret += "c=" + c.netType + " " + c.addrType + " " + c.connectionAddress + "\r\n"; 72 | ret += "t=" + t + "\r\n"; 73 | ret += "m=" + m.media + " " + m.port + " " + m.proto + " " + m.fmt + "\r\n"; 74 | ret += "a=rtpmap:8 PCMA/8000\r\n"; 75 | ret += "a=rtpmap:127 telephone-event/8000"; 76 | return ret; 77 | } 78 | -------------------------------------------------------------------------------- /src/SdpHeader.h: -------------------------------------------------------------------------------- 1 | #ifndef SdpHeader_H 2 | #define SdpHeader_H 3 | 4 | #include 5 | 6 | class SdpHeader 7 | { 8 | public: 9 | struct O 10 | { 11 | String username; 12 | String sessId; 13 | String sessVersion; 14 | String netType; 15 | String addrType; 16 | String municastAddress; 17 | }; 18 | 19 | struct M 20 | { 21 | String media; 22 | String port; 23 | String proto; 24 | String fmt; 25 | }; 26 | struct C 27 | { 28 | String netType; 29 | String addrType; 30 | String connectionAddress; 31 | }; 32 | String v = "0"; 33 | O o; 34 | String s = "-"; 35 | C c; 36 | String t = "0 0"; 37 | M m; 38 | String a = ""; 39 | 40 | int udpPortRead=0; 41 | int udpPortWrite=0; 42 | 43 | void parse(String in); 44 | String getContent(); 45 | SdpHeader(); 46 | 47 | }; 48 | 49 | #endif 50 | -------------------------------------------------------------------------------- /src/SipHeader.cpp: -------------------------------------------------------------------------------- 1 | #include "SipHeader.h" 2 | #include "MD5.h" 3 | #include 4 | #include "Debug.h" 5 | 6 | void SipHeader::parse(String in) 7 | { 8 | String ret = ""; 9 | if (in.indexOf("SIP/2.0 ") > -1) 10 | setResposeCode(in); 11 | if (in.indexOf("From: ") > -1) 12 | setFrom(in); 13 | if (in.indexOf("To: ") > -1) 14 | setTo(in); 15 | if (in.indexOf("Call-ID: ") > -1) 16 | setCallId(in); 17 | if (in.indexOf("CSeq: ") > -1) 18 | setCseq(in); 19 | if (in.indexOf("WWW-Authenticate: ") > -1) 20 | setAuthenticate(in); 21 | if (in.indexOf("Proxy-Authenticate:") > -1) 22 | setAuthenticate(in); 23 | if (in.indexOf("Via: ") > -1) 24 | setVia(in); 25 | if (in.indexOf("Content-Length: ") > -1) 26 | setContentLength(in); 27 | if (in.indexOf("Contact: ") > -1) 28 | setContact(in); 29 | if (in.indexOf("INVITE sip:") > -1) 30 | { 31 | setInvite(in); 32 | responseCodes = 2; 33 | } 34 | if (in.indexOf("ACK sip:") > -1) 35 | { 36 | responseCodes = 0; 37 | } 38 | if (in.indexOf("BYE sip:") > -1) 39 | { 40 | responseCodes = 1; 41 | } 42 | } 43 | SipHeader::Gk SipHeader::parsGk(String in) 44 | { 45 | Gk ret; 46 | ret.ip = ""; 47 | ret.port = ""; 48 | ret.telNr = ""; 49 | ret.transport = ""; 50 | String gks = in.substring(in.indexOf("<") + 1, in.indexOf(">")); 51 | if (gks.indexOf(":") >= 0) 52 | { 53 | gks = gks.substring(gks.indexOf(":") + 1); 54 | } 55 | if (gks.indexOf(";") >= 0) 56 | { 57 | String a = gks.substring(gks.indexOf(";")); 58 | gks = gks.substring(0, gks.indexOf(";")); 59 | ret.transport = a.substring(a.indexOf("=") + 1); 60 | } 61 | if (gks.indexOf("@") >= 0) 62 | { 63 | ret.telNr = gks.substring(0, gks.indexOf("@")); 64 | gks = gks.substring(gks.indexOf("@") + 1); 65 | } 66 | if (gks.indexOf(":") >= 0) 67 | { 68 | ret.port = gks.substring(gks.indexOf(":") + 1); 69 | gks = gks.substring(0, gks.indexOf(":")); 70 | } 71 | ret.ip = gks; 72 | return ret; 73 | } 74 | String SipHeader::find(String x, String in) 75 | { 76 | String ret = ""; 77 | if (in.indexOf(x) >= 0) 78 | { 79 | ret = in.substring(in.indexOf(x) + x.length()); 80 | ret.replace("\r", ""); 81 | ret.replace("\n", ""); 82 | if (ret.indexOf(";") >= 0) 83 | { 84 | ret = ret.substring(0, ret.indexOf(";")); 85 | } 86 | if (ret.indexOf(",") >= 0) 87 | { 88 | ret = ret.substring(0, ret.indexOf(",")); 89 | } 90 | ret.replace("\"", ""); 91 | } 92 | return ret; 93 | } 94 | String SipHeader::getVia() 95 | { 96 | String str; 97 | str = "Via: SIP/2.0/TCP "; 98 | str += via.userClient; 99 | str += ":"; 100 | str += via.port; 101 | str += ";branch="; 102 | str += via.branch; 103 | return str; 104 | } 105 | String SipHeader::getMaxForwards() 106 | { 107 | String str; 108 | str = "Max-Forwards: 70"; 109 | return str; 110 | } 111 | String SipHeader::getTo() 112 | { 113 | String str; 114 | if (to.tagTo.length() > 0) 115 | { 116 | str = "To: 5 | 6 | class SipHeader 7 | { 8 | private: 9 | struct Gk 10 | { 11 | String telNr; 12 | String ip; 13 | String port; 14 | String transport; 15 | }; 16 | Gk parsGk(String in); 17 | String find(String x, String in); 18 | 19 | public: 20 | struct Via 21 | { 22 | String userClient; 23 | int port; 24 | String branch; 25 | }; 26 | struct To 27 | { 28 | String telNr; 29 | String userAgent; 30 | String tagTo; 31 | }; 32 | 33 | struct From 34 | { 35 | String telNr; 36 | String userAgent; 37 | String tagFrom; 38 | }; 39 | 40 | struct CSeq 41 | { 42 | int cSeq; 43 | String typ; 44 | }; 45 | struct CallId 46 | { 47 | String callId; 48 | }; 49 | struct Contact 50 | { 51 | String telNr; 52 | String userClient; 53 | String expires; 54 | }; 55 | struct Authenticate 56 | { 57 | String realm; 58 | String domain; 59 | String nonce; 60 | String stale; 61 | String algorithm; 62 | String qop; 63 | String user; 64 | String uri; 65 | String cNonce; 66 | String response; 67 | String pwd; 68 | String types; 69 | String telNr; 70 | String agent; 71 | String nonceCount; 72 | int nc; 73 | }; 74 | struct Invite 75 | { 76 | String telNr; 77 | String userAgent; 78 | String port; 79 | }; 80 | 81 | Via via; 82 | To to; 83 | From from; 84 | CSeq cSeq; 85 | CallId callId; 86 | Contact contact; 87 | Authenticate authenticate; 88 | Invite invite; 89 | String proxyRegistrar; 90 | int responseCodes; 91 | int contentLength; 92 | void parse(String in); 93 | String getVia(); 94 | String getMaxForwards(); 95 | String getTo(); 96 | String getFrom(); 97 | String getCallID(); 98 | String getCSeq(); 99 | String getContact(); 100 | String getAllow(); 101 | String getContentLength(int contentLength = 0); 102 | String getContenType(); 103 | String getAuthorisation(); 104 | 105 | void setResposeCode(String in); 106 | void setFrom(String in); 107 | void setTo(String in); 108 | void setCallId(String in); 109 | void setCseq(String in); 110 | void setAuthenticate(String in); 111 | void setVia(String in); 112 | void setContentLength(String in); 113 | void setContact(String in); 114 | void setInvite(String in); 115 | }; 116 | 117 | #endif 118 | -------------------------------------------------------------------------------- /src/SipMachine.cpp: -------------------------------------------------------------------------------- 1 | #include "SipMachine.h" 2 | #include "Debug.h" 3 | 4 | SipMachine::SipMachine(String user, String pwd, String telNr, String userAgent, String proxyRegistrar, int port) 5 | { 6 | this->user = user; 7 | this->pwd = pwd; 8 | this->telNr = telNr; 9 | this->userAgent = userAgent; 10 | this->userClient = userClient; 11 | this->proxyRegistrar = proxyRegistrar; 12 | this->port = port; 13 | timeStOut = micros(); 14 | timeStOut = timeStOut / 20000; 15 | timeStOut = timeStOut * 20000; 16 | } 17 | 18 | void SipMachine::setup(String userClient, String proxyServer) 19 | { 20 | this->proxyServer = proxyServer; 21 | this->userClient = userClient; 22 | server.begin(port); 23 | 24 | debug_println(String(" Connect SIP Server ") + " Port " + String(port)); 25 | 26 | udpIpWrite = strToIP(proxyServer); 27 | } 28 | 29 | IPAddress SipMachine::strToIP(String str) 30 | { 31 | byte adr[4]; 32 | adr[0] = str.substring(0, str.indexOf('.')).toInt(); 33 | str = str.substring(str.indexOf('.') + 1); 34 | adr[1] = str.substring(0, str.indexOf('.')).toInt(); 35 | str = str.substring(str.indexOf('.') + 1); 36 | adr[2] = str.substring(0, str.indexOf('.')).toInt(); 37 | str = str.substring(str.indexOf('.') + 1); 38 | adr[3] = str.toInt(); 39 | IPAddress ip(adr[0], adr[1], adr[2], adr[3]); 40 | return ip; 41 | } 42 | 43 | int16_t SipMachine::loop(short pcmOut) 44 | { 45 | int ret; 46 | // write Data to outputbuffer 47 | if (status == call) 48 | { 49 | rtpOut.put(pcmOut); 50 | } 51 | if (timeStOut < micros()) 52 | { 53 | timeStOut += 10000; 54 | if ((status == call) & (timeStOut % 20000 == 0)) 55 | { 56 | ret = udp.parsePacket(); 57 | debugL2_println(String("Nr. of parsePacket") + String(ret)); 58 | if (ret) 59 | { 60 | if (ret == 16) 61 | { 62 | getDtmfData(); 63 | } 64 | else 65 | { 66 | getSpeachData(); 67 | } 68 | } 69 | } 70 | else 71 | { 72 | switch (status) 73 | { 74 | case init: 75 | if (timeExpires < millis()) 76 | { 77 | sipRegister(); 78 | status = reg; 79 | timeExpires = millis() + 5000; 80 | } 81 | break; 82 | case reg: 83 | if (timeExpires < millis()) 84 | { 85 | sock_sip.stop(); 86 | debug_println(String(" Stop SIP Client on IP ") + proxyServer + " Port " + String(port)); 87 | status = init; 88 | timeExpires = millis() + 60000; 89 | } 90 | break; 91 | case idle: 92 | if ((timeExpires - millis() < 0)) 93 | status = init; 94 | break; 95 | case call: 96 | writeSpeachData(); 97 | break; 98 | case ringIn: 99 | break; 100 | case ringOut: 101 | break; 102 | default: 103 | break; 104 | } 105 | if (sock_sip) 106 | { 107 | if (sock_sip.available()) 108 | { 109 | String str = sock_sip.readStringUntil('\n'); //terminator, buffer, sizeof(buffer)); 110 | if (sipHeader.contentLength > 0) 111 | { 112 | sipHeader.contentLength -= (str.length() + 1); 113 | debugL1_println(str.c_str()); 114 | parserSdp(str); 115 | if (sipHeader.contentLength < 0) 116 | { 117 | exec(); 118 | } 119 | } 120 | else 121 | { 122 | debugL1_print("-_ "); 123 | debugL1_println(str.c_str()); 124 | parserSip(str); 125 | if (str.equals("\r") || str.equals("\n")) 126 | exec(); 127 | } 128 | } 129 | } 130 | else 131 | { 132 | sock_sip = server.available(); 133 | if (sock_sip) 134 | { 135 | debug_print("Creat new Sip client from Server on IP "); 136 | debug_print(sock_sip.remoteIP().toString() + " and remote Port "); 137 | debug_println(String(sock_sip.remotePort())); 138 | } 139 | } 140 | } 141 | } 142 | return rtpIn.get((micros() % 20000) / 125); 143 | } 144 | 145 | void SipMachine::parserSdp(String in) 146 | { 147 | sdpHeader.parse(in); 148 | } 149 | 150 | void SipMachine::parserSip(String in) 151 | { 152 | sipHeader.parse(in); 153 | } 154 | 155 | void SipMachine::exec() 156 | { 157 | int ret; 158 | if (!sipHeader.to.telNr.equals(telNr)) 159 | { 160 | tagTo = sipHeader.to.tagTo; 161 | } 162 | else 163 | { 164 | tagFrom = sipHeader.to.tagTo; 165 | } 166 | 167 | if (sipHeader.from.telNr.equals(telNr)) 168 | { 169 | tagFrom = sipHeader.from.tagFrom; 170 | } 171 | else 172 | { 173 | tagTo = sipHeader.from.tagFrom; 174 | } 175 | switch (sipHeader.responseCodes) 176 | { 177 | case 0: 178 | debug_println("Execute ACK"); 179 | sock_sip.stop(); 180 | debug_println(String("sock_sip.stop")); 181 | ret = udp.begin(sdpHeader.udpPortRead); 182 | debug_println(String("Start UDP") + ((ret == 1) ? "TRUE" : "FALSE") + " on Port " + sdpHeader.udpPortRead); 183 | status = call; 184 | break; 185 | case 1: 186 | debug_println("Execute BYE"); 187 | sipOk(); 188 | sock_sip.stop(); 189 | debug_println(String("sock_sip.stop")); 190 | udp.stop(); 191 | debug_println(String("Stop UDP read ")); 192 | status = idle; 193 | break; 194 | case 2: 195 | debug_println("Execute INVITE"); 196 | sdpHeader.udpPortWrite = sdpHeader.m.port.toInt(); 197 | 198 | sdpHeader.udpPortRead = sdpHeader.udpPortWrite + 10; 199 | sipRinging(); 200 | status = ringIn; 201 | break; 202 | case 100: 203 | debug_println("Execute 100 Trying"); 204 | break; 205 | case 180: 206 | debug_println("Execute 180 Ringing"); 207 | status = ringOut; 208 | break; 209 | case 200: 210 | if (sipHeader.cSeq.typ.equals("REGISTER")) 211 | { 212 | debug_println("Execute 200 OK Register"); 213 | timeExpires += sipHeader.contact.expires.toInt() * 1000; 214 | status = idle; 215 | } 216 | else if (sipHeader.cSeq.typ.equals("INVITE")) 217 | { 218 | debug_println("Execute 200 OK INVITE"); 219 | sdpHeader.udpPortWrite = sdpHeader.m.port.toInt(); 220 | sipAck(); 221 | status = call; 222 | udpIpWrite = strToIP(sdpHeader.o.municastAddress); 223 | } 224 | sock_sip.stop(); 225 | debug_println(String("sock_sip.stop")); 226 | break; 227 | case 401: 228 | debug_println("Execute 401 sipRegisterAuth"); 229 | sipRegisterAuth(); 230 | break; 231 | case 403: 232 | debug_println("Execute 403 Forbidden"); 233 | sock_sip.stop(); 234 | debug_println(String("sock_sip.stop")); 235 | udp.stop(); 236 | debug_println(String("Stop UDP read and Write")); 237 | break; 238 | case 404: 239 | debug_println("Execute 404 Not Found"); 240 | sock_sip.stop(); 241 | debug_println(String("sock_sip.stop")); 242 | udp.stop(); 243 | debug_println(String("Stop UDP read and Write")); 244 | break; 245 | case 407: 246 | debug_println("Execute 407 Proxy Authentication Required"); 247 | sipAck(); 248 | sipAuth(); 249 | ret = udp.begin(sdpHeader.udpPortRead); 250 | debug_println(String("Start UDP read ") + ((ret == 1) ? "TRUE" : "FALSE") + " on Port " + sdpHeader.udpPortRead); 251 | break; 252 | case 481: 253 | debug_println(" Execute 481 Call Leg/Transaction Does Not Exist "); 254 | break; 255 | case 486: 256 | debug_println("Execute 486 Busy Here"); 257 | sock_sip.stop(); 258 | debug_println(String("sock_sip.stop")); 259 | udp.stop(); 260 | debug_println(String("Stop UDP read ")); 261 | break; 262 | default: 263 | debug_println(String(sipHeader.responseCodes) + " does not Exists :-)"); 264 | break; 265 | } 266 | } 267 | void SipMachine::writeSIPdata(String message) 268 | { 269 | size_t ret = sock_sip.println(message); 270 | debugL1_print(String(ret) + " "); 271 | debugL1_println(message.c_str()); 272 | if (ret < 0) 273 | debugL1_println(ret); 274 | } 275 | 276 | void SipMachine::sipRegister() 277 | { 278 | int ret = sock_sip.connect(proxyServer.c_str(), port); 279 | debug_println(String(" Connect SIP Client on IP ") + proxyServer + " Port " + String(port) + " ret= " + (ret ? "true" : "false")); 280 | sipHeader.proxyRegistrar = proxyRegistrar; 281 | sipHeader.via.branch = branch; 282 | sipHeader.via.port = port; 283 | sipHeader.via.userClient = userClient; 284 | sipHeader.from.tagFrom = tagFrom; 285 | sipHeader.from.telNr = telNr; 286 | sipHeader.from.userAgent = userAgent; 287 | sipHeader.to.tagTo = tagTo; 288 | sipHeader.to.telNr = telNr; 289 | sipHeader.to.userAgent = userAgent; 290 | sipHeader.callId.callId = callId + "@" + userAgent; 291 | sipHeader.contact.telNr = telNr; 292 | sipHeader.contact.userClient = userClient; 293 | sipHeader.cSeq.cSeq = 0; 294 | sipHeader.cSeq.typ = "REGISTER"; 295 | debug_println("***** Register *****"); 296 | String str; 297 | str = "REGISTER sip:"; 298 | str += sipHeader.proxyRegistrar; 299 | str += " SIP/2.0"; 300 | writeSIPdata(str); 301 | writeSIPdata(sipHeader.getVia()); 302 | writeSIPdata(sipHeader.getMaxForwards()); 303 | writeSIPdata(sipHeader.getFrom()); 304 | writeSIPdata(sipHeader.getTo()); 305 | writeSIPdata(sipHeader.getCallID()); 306 | writeSIPdata(sipHeader.getCSeq()); 307 | writeSIPdata(sipHeader.getContact()); 308 | writeSIPdata(sipHeader.getAllow()); 309 | writeSIPdata(sipHeader.getContentLength()); 310 | writeSIPdata(""); 311 | } 312 | 313 | void SipMachine::sipRinging() 314 | { 315 | debug_println("***** Ringing *****"); 316 | sipHeader.to.tagTo = randomChr(30); 317 | sipHeader.contact.telNr = telNr; 318 | String str; 319 | str = "SIP/2.0 180 Ringing"; 320 | writeSIPdata(str); 321 | writeSIPdata(sipHeader.getVia()); 322 | writeSIPdata(sipHeader.getTo()); 323 | writeSIPdata(sipHeader.getFrom()); 324 | writeSIPdata(sipHeader.getCallID()); 325 | writeSIPdata(sipHeader.getCSeq()); 326 | writeSIPdata(sipHeader.getContact()); 327 | writeSIPdata(sipHeader.getContentLength()); 328 | writeSIPdata(""); 329 | } 330 | 331 | void SipMachine::sipOk() 332 | { 333 | debug_println("***** Ok *****"); 334 | sdpHeader.o.sessId = String(sdpHeader.o.sessId.toInt() + 1); 335 | sdpHeader.o.sessVersion = String(sdpHeader.o.sessVersion.toInt() + 1); 336 | sdpHeader.o.municastAddress = userClient; 337 | sdpHeader.c.connectionAddress = userClient; 338 | sdpHeader.m.port = String(sdpHeader.udpPortRead); 339 | sdpHeader.m.fmt = String("8 127"); 340 | sipHeader.contact.telNr = telNr; 341 | sipHeader.contact.userClient = userClient; 342 | String str; 343 | str = "SIP/2.0 200 OK"; 344 | writeSIPdata(str); 345 | writeSIPdata(sipHeader.getVia()); 346 | writeSIPdata(sipHeader.getTo()); 347 | writeSIPdata(sipHeader.getFrom()); 348 | writeSIPdata(sipHeader.getCallID()); 349 | writeSIPdata(sipHeader.getCSeq()); 350 | writeSIPdata(sipHeader.getContact()); 351 | if (sipHeader.cSeq.typ.equals("INVITE")) 352 | { 353 | writeSIPdata(sipHeader.getContenType()); 354 | writeSIPdata(sipHeader.getContentLength(sdpHeader.getContent().length() + 2)); 355 | writeSIPdata(""); 356 | writeSIPdata(sdpHeader.getContent()); 357 | } 358 | else 359 | { 360 | writeSIPdata(sipHeader.getContentLength()); 361 | writeSIPdata(""); 362 | } 363 | } 364 | 365 | void SipMachine::sipInvite(String telNrTo) 366 | { 367 | debug_println("***** Invite *****"); 368 | int ret = sock_sip.connect(proxyServer.c_str(), port); 369 | debug_println(String(" Connect SIP Client on IP ") + proxyServer + " Port " + String(port) + " ret= " + (ret ? "true" : "false")); 370 | sdpHeader.o.sessId = String(random(90000000)); 371 | sdpHeader.o.sessVersion = String(random(90000000)); 372 | sdpHeader.o.municastAddress = userClient; 373 | sdpHeader.c.connectionAddress = userClient; 374 | sdpHeader.m.port = String(random(10000, 90000)); 375 | sdpHeader.udpPortRead = sdpHeader.m.port.toInt(); 376 | sdpHeader.m.fmt = String("8 127"); 377 | sipHeader.via.branch = branch; 378 | sipHeader.via.port = port; 379 | sipHeader.via.userClient = userClient; 380 | sipHeader.from.tagFrom = tagFrom; 381 | sipHeader.from.telNr = telNr; 382 | sipHeader.from.userAgent = userAgent; 383 | sipHeader.to.telNr = telNrTo; 384 | sipHeader.to.userAgent = userAgent; 385 | sipHeader.to.tagTo = ""; 386 | sipHeader.callId.callId = String(randomChr(7)) + "@" + proxyServer; 387 | sipHeader.cSeq.cSeq = 1; 388 | sipHeader.cSeq.typ = "INVITE"; 389 | authType = "INVITE"; 390 | sipHeader.contact.telNr = telNr; 391 | sipHeader.contact.userClient = userClient; 392 | String str; 393 | str = "INVITE sip:"; 394 | str += telNrTo; 395 | str += "@"; 396 | str += userAgent; 397 | str += " SIP/2.0"; 398 | writeSIPdata(str); 399 | writeSIPdata(sipHeader.getVia()); 400 | writeSIPdata(sipHeader.getTo()); 401 | writeSIPdata(sipHeader.getFrom()); 402 | writeSIPdata(sipHeader.getCallID()); 403 | writeSIPdata(sipHeader.getCSeq()); 404 | writeSIPdata(sipHeader.getContact()); 405 | writeSIPdata(sipHeader.getContenType()); 406 | writeSIPdata(sipHeader.getContentLength(sdpHeader.getContent().length() + 2)); 407 | writeSIPdata(""); 408 | writeSIPdata(sdpHeader.getContent()); 409 | status = ringOut; 410 | } 411 | 412 | void SipMachine::sipAck() 413 | { 414 | debug_println("***** ACK *****"); 415 | sipHeader.cSeq.typ = "ACK"; 416 | String str; 417 | str = "ACK sip:"; 418 | str += telNrTo; 419 | str += "@"; 420 | str += userAgent; 421 | str += " SIP/2.0"; 422 | writeSIPdata(str); 423 | writeSIPdata(sipHeader.getVia()); 424 | writeSIPdata(sipHeader.getTo()); 425 | writeSIPdata(sipHeader.getFrom()); 426 | writeSIPdata(sipHeader.getCallID()); 427 | writeSIPdata(sipHeader.getCSeq()); 428 | writeSIPdata(sipHeader.getContact()); 429 | writeSIPdata(sipHeader.getContentLength()); 430 | writeSIPdata(""); 431 | } 432 | 433 | void SipMachine::sipBye() 434 | { 435 | int ret = sock_sip.connect(proxyServer.c_str(), port); 436 | debug_println(String(" Connect SIP Client on IP ") + proxyServer + " Port " + String(port) + " ret= " + (ret ? "true" : "false")); 437 | debug_println("***** BYE *****"); 438 | branch = "z9hG4bK-" + randomChr(30); 439 | sipHeader.via.branch = branch; 440 | sipHeader.cSeq.typ = "BYE"; 441 | authType = "BYE"; 442 | sipHeader.cSeq.cSeq++; 443 | sipHeader.from.tagFrom = tagFrom; 444 | sipHeader.from.telNr = telNr; 445 | sipHeader.from.userAgent = userAgent; 446 | sipHeader.to.telNr = telNrTo; 447 | sipHeader.to.userAgent = userAgent; 448 | sipHeader.to.tagTo = tagTo; 449 | String str; 450 | str = "BYE sip:"; 451 | str += telNrTo; 452 | str += "@"; 453 | str += userAgent; 454 | str += " SIP/2.0"; 455 | writeSIPdata(str); 456 | writeSIPdata(sipHeader.getVia()); 457 | writeSIPdata(sipHeader.getTo()); 458 | writeSIPdata(sipHeader.getFrom()); 459 | writeSIPdata(sipHeader.getCallID()); 460 | writeSIPdata(sipHeader.getCSeq()); 461 | writeSIPdata(sipHeader.getContentLength()); 462 | writeSIPdata(""); 463 | debug_println("***** BYE *****"); 464 | } 465 | 466 | void SipMachine::sipAuth() 467 | { 468 | debug_print("***** "); 469 | debug_print(authType); 470 | debug_println("in Auth *****"); 471 | sipHeader.cSeq.cSeq++; 472 | sipHeader.cSeq.typ = authType; 473 | sipHeader.authenticate.types = authType; 474 | if (authType.equals("INVITE")) 475 | { 476 | sipHeader.authenticate.telNr = telNrTo; 477 | sipHeader.authenticate.agent = userAgent; 478 | sipHeader.to.tagTo = ""; 479 | sipHeader.contact.telNr = telNr; 480 | sipHeader.contact.userClient = userClient; 481 | } 482 | String str; 483 | str = authType; 484 | str += " sip:"; 485 | str += telNrTo; 486 | str += "@"; 487 | str += userAgent; 488 | str += " SIP/2.0"; 489 | writeSIPdata(str); 490 | writeSIPdata(sipHeader.getVia()); 491 | writeSIPdata(sipHeader.getTo()); 492 | writeSIPdata(sipHeader.getFrom()); 493 | writeSIPdata(sipHeader.getCallID()); 494 | writeSIPdata(sipHeader.getCSeq()); 495 | writeSIPdata(sipHeader.getContact()); 496 | writeSIPdata(sipHeader.getAuthorisation()); 497 | if (authType.equals("INVITE")) 498 | { 499 | writeSIPdata(sipHeader.getContenType()); 500 | writeSIPdata(sipHeader.getContentLength(sdpHeader.getContent().length() + 2)); 501 | writeSIPdata(""); 502 | writeSIPdata(sdpHeader.getContent()); 503 | status = ringOut; 504 | } 505 | else 506 | { 507 | writeSIPdata(sipHeader.getContentLength()); 508 | writeSIPdata(""); 509 | status = idle; 510 | } 511 | } 512 | void SipMachine::sipRegisterAuth() 513 | { 514 | sipHeader.cSeq.cSeq++; 515 | sipHeader.cSeq.typ = "REGISTER"; 516 | sipHeader.to.tagTo = ""; 517 | sipHeader.authenticate.user = user; 518 | sipHeader.authenticate.agent = proxyRegistrar; 519 | sipHeader.authenticate.pwd = pwd; 520 | sipHeader.authenticate.types = "REGISTER"; 521 | sipHeader.authenticate.telNr = ""; 522 | sipHeader.authenticate.nonceCount = "00000001"; 523 | if (sipHeader.cSeq.cSeq < 3) 524 | { 525 | debug_println("***** Register Auth *****"); 526 | String str; 527 | str = "REGISTER sip:"; 528 | str += sipHeader.proxyRegistrar; 529 | str += " SIP/2.0"; 530 | writeSIPdata(str); 531 | writeSIPdata(sipHeader.getVia()); 532 | writeSIPdata(sipHeader.getMaxForwards()); 533 | writeSIPdata(sipHeader.getTo()); 534 | writeSIPdata(sipHeader.getFrom()); 535 | writeSIPdata(sipHeader.getCallID()); 536 | writeSIPdata(sipHeader.getCSeq()); 537 | writeSIPdata(sipHeader.getContact()); 538 | writeSIPdata(sipHeader.getAllow()); 539 | writeSIPdata(sipHeader.getAuthorisation()); 540 | writeSIPdata(sipHeader.getContentLength()); 541 | writeSIPdata(""); 542 | debugL1_println("***** Register Auth out *****"); 543 | } 544 | } 545 | 546 | String SipMachine::randomChr(int size) 547 | { 548 | String ret = ""; 549 | for (int i = 0; i < size; i++) 550 | { 551 | if (i % 3 == 0) 552 | { 553 | ret += (char)random(48, 57); 554 | } 555 | else if (i % 3 == 1) 556 | { 557 | ret += (char)random(65, 90); 558 | } 559 | else if (i % 3 == 2) 560 | { 561 | ret += (char)random(97, 122); 562 | } 563 | } 564 | return ret; 565 | } 566 | 567 | String SipMachine::getTelNrIncomingCall() 568 | { 569 | return sipHeader.from.telNr; 570 | } 571 | void SipMachine::acceptIncomingCall() 572 | { 573 | sipOk(); 574 | status = callAccept; 575 | } 576 | void SipMachine::makeCall(String telNrTo) 577 | { 578 | this->telNrTo = telNrTo; 579 | sipInvite(telNrTo); 580 | } 581 | 582 | void SipMachine::bye() 583 | { 584 | sipBye(); 585 | status = idle; 586 | } 587 | String SipMachine::getKeyPressedLast20() 588 | { 589 | return dtmf; 590 | } 591 | 592 | SipMachine::Status SipMachine::getStatus() 593 | { 594 | return status; 595 | } 596 | 597 | void SipMachine::getDtmfData() 598 | { 599 | if (udp.available()) 600 | { 601 | int ret = udp.readBytes((uint8_t *)&(rtpIn.dtmfBuffer), sizeof(rtpIn.dtmfBuffer)); 602 | debugL1_print(String("UDP DTMF read count ") + String(ret)); 603 | debugL1_print(String(" Sequence Number : ") + String(rtpIn.getSequenceNumber())); 604 | debugL1_print(String(" Timestamp: ") + String(rtpIn.getTimestamp())); 605 | debugL1_print(String(" event ") + String(rtpIn.dtmfBuffer.event)); 606 | debugL1_print(String(" E ") + String(rtpIn.dtmfBuffer.e)); 607 | debugL1_print(String(" R ") + String(rtpIn.dtmfBuffer.r)); 608 | debugL1_print(String(" volume ") + String(rtpIn.dtmfBuffer.volume)); 609 | debugL1_println(String(" duration ") + String(rtpIn.dtmfBuffer.duration)); 610 | if (rtpIn.dtmfBuffer.e == 1) 611 | { 612 | if (dtmf.length() > 20) 613 | dtmf = dtmf.substring(1); 614 | String s = String(rtpIn.dtmfBuffer.event, 10); 615 | if (s.equals("10")) 616 | s = "*"; 617 | if (s.equals("11")) 618 | s = "#"; 619 | dtmf += s; 620 | } 621 | } 622 | } 623 | void SipMachine::getSpeachData() 624 | { 625 | 626 | if (udp.available()) 627 | { 628 | int ret = udp.readBytes((uint8_t *)&(rtpIn.rtpBuffer), sizeof(rtpIn.rtpBuffer)); 629 | debugL2_print(String("UDP read count ") + String(ret)); 630 | debugL2_print(String(" Sequence Number : ") + String(rtpIn.getSequenceNumber())); 631 | debugL2_println(String(" Timestamp: ") + String(rtpIn.getTimestamp())); 632 | if (((rtpIn.getSequenceNumber() % 5) == 0)) 633 | { 634 | char dtm = rtpIn.getDtmf(); 635 | if (dtm != ' ') 636 | { 637 | if (dtmf.length() > 20) 638 | dtmf = dtmf.substring(1); 639 | dtmf += String(dtm); 640 | } 641 | } 642 | } 643 | } 644 | 645 | void SipMachine::writeSpeachData() 646 | { 647 | int ret = 0; 648 | ret = udp.beginPacket(udpIpWrite, sdpHeader.udpPortWrite); 649 | debugL2_print(String("UDP write ") + ((ret == 1) ? "TRUE" : "FALSE")); 650 | rtpOut.setSequenceNumber(rtpOut.getSequenceNumber() + 1); 651 | rtpOut.setTimestamp(rtpOut.getTimestamp() + 160); 652 | ret = udp.write((uint8_t *)&rtpOut.rtpBuffer, sizeof(rtpOut.rtpBuffer)); 653 | debugL2_print(String(" count ") + String(ret)); 654 | ret = udp.endPacket(); 655 | debugL2_print(String(" ") + ((ret == 1) ? "TRUE " : "FALSE ")); 656 | rtpOut.rtpPos = 0; 657 | debugL2_print(String(" Sequence Number : ") + String(rtpOut.getSequenceNumber())); 658 | debugL2_print(String(" Timestamp: ") + String(rtpOut.getTimestamp())); 659 | debugL2_print(String(" ADDR: ") + udpIpWrite.toString() + " on Port " + (sdpHeader.udpPortWrite)); 660 | debugL2_println(""); 661 | } 662 | -------------------------------------------------------------------------------- /src/SipMachine.h: -------------------------------------------------------------------------------- 1 | #ifndef SipMachine_H 2 | #define SipMachine_H 3 | #include 4 | #include "SipHeader.h" 5 | #include "WiFiClient.h" 6 | #include "WiFiServer.h" 7 | #include "SdpHeader.h" 8 | #include "WiFiUdp.h" 9 | #include "RTP.h" 10 | #include "SipStreamIn.h" 11 | 12 | 13 | class SipMachine 14 | { 15 | private: 16 | unsigned long timeExpires = 0; 17 | unsigned long timeStOut=0; 18 | 19 | String user; 20 | String pwd; 21 | String telNr; 22 | String telNrTo; 23 | String userAgent; 24 | String userClient; 25 | String proxyServer; 26 | String proxyRegistrar; 27 | String tagTo; 28 | String authType=""; 29 | int port = 5060; 30 | WiFiClient sock_sip; 31 | WiFiServer server; 32 | WiFiUDP udp; 33 | RTP rtpIn; 34 | RTP rtpOut; 35 | String branch = "z9hG4bK-" + randomChr(30); 36 | String tagFrom = randomChr(30); 37 | String callId = randomChr(7); 38 | String randomChr(int size); 39 | void parserSip(String in); 40 | void parserSdp(String in); 41 | void exec(); 42 | void writeSIPdata(String message); 43 | void sipRegister(); 44 | void sipRegisterAuth(); 45 | void sipRinging(); 46 | void sipOk(); 47 | void sipInvite(String telNrTo); 48 | void sipAuth(); 49 | void sipAck(); 50 | void sipBye(); 51 | void getDtmfData(); 52 | void getSpeachData(); 53 | void writeSpeachData(); 54 | IPAddress strToIP(String str); 55 | SipHeader sipHeader; 56 | SdpHeader sdpHeader; 57 | String dtmf; 58 | IPAddress udpIpWrite; 59 | 60 | public: 61 | typedef enum 62 | { 63 | init, 64 | reg, 65 | idle, 66 | ringIn, 67 | ringOut, 68 | callAccept, 69 | call, 70 | } Status; 71 | SipMachine(String user, String pwd, String telNr, String userAgent, String proxyRegistrar, int port = 5060); 72 | void setup(String userClient, String proxyServer); 73 | int16_t loop(int16_t pcmOut); 74 | String getTelNrIncomingCall(); 75 | void acceptIncomingCall(); 76 | void makeCall(String telNrTo); 77 | void bye(); 78 | String getKeyPressedLast20(); 79 | Status getStatus(); 80 | protected: 81 | Status status = init; 82 | }; 83 | 84 | #endif 85 | -------------------------------------------------------------------------------- /src/SipStreamIn.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "SipStreamIn.h" 3 | 4 | size_t SipStreamIn::write(uint8_t in) 5 | { 6 | size_t f=0; 7 | return f; 8 | } 9 | int SipStreamIn::available() 10 | { 11 | int ret=0; 12 | return ret; 13 | } 14 | int SipStreamIn::read() 15 | { 16 | int ret=0; 17 | return ret; 18 | } 19 | int SipStreamIn::peek() 20 | { 21 | int ret=0; 22 | return ret; 23 | } 24 | void SipStreamIn::flush() {} 25 | -------------------------------------------------------------------------------- /src/SipStreamIn.h: -------------------------------------------------------------------------------- 1 | #ifndef SIPSTREAMIN_H_INCLUDED 2 | #define SIPSTREAMIN_H_INCLUDED 3 | 4 | #include "Stream.h" 5 | 6 | class SipStreamIn: public Stream 7 | { 8 | 9 | public: 10 | size_t write(uint8_t); 11 | int available(); 12 | int read(); 13 | int peek(); 14 | void flush(); 15 | 16 | 17 | }; 18 | 19 | 20 | #endif // SIPSTREAMIN_H_INCLUDED 21 | --------------------------------------------------------------------------------