#if 0 /*─────────────────────────────────────────────────────────────────╗ │ To the extent possible under law, Justine Tunney has waived │ │ all copyright and related or neighboring rights to this file, │ │ as it is written in the following disclaimers: │ │ • http://unlicense.org/ │ │ • http://creativecommons.org/publicdomain/zero/1.0/ │ ╚─────────────────────────────────────────────────────────────────*/ #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "loudness.h" /** * @fileoverview sends audio from microphone to remote computer * @see dsp/prog/recvaudio.c */ #define SAMPLING_RATE 44100 #define FRAMES_PER_SECOND 60 #define DEBUG_LOG 0 #define PORT 9834 #define CHUNK_FRAMES (SAMPLING_RATE / FRAMES_PER_SECOND) static_assert(CHUNK_FRAMES * sizeof(short) < 1472, "audio chunks won't fit in udp ethernet packet"); sig_atomic_t g_done; void onsig(int sig) { g_done = 1; } short toshort(float x) { return fmaxf(-1, fminf(1, x)) * 32767; } float tofloat(short x) { return x / 32768.f; } uint32_t host2ip(const char* host) { uint32_t ip; if ((ip = inet_addr(host)) != -1u) return ip; int rc; struct addrinfo* ai = NULL; struct addrinfo hint = {AI_NUMERICSERV, AF_INET, SOCK_STREAM, IPPROTO_TCP}; if ((rc = getaddrinfo(host, "0", &hint, &ai))) { fprintf(stderr, "%s: %s\n", host, gai_strerror(rc)); exit(50 + rc); } ip = ntohl(((struct sockaddr_in*)ai->ai_addr)->sin_addr.s_addr); freeaddrinfo(ai); return ip; } int main(int argc, char* argv[]) { if (argc != 2) { fprintf(stderr, "%s: missing host argument\n", argv[0]); return 1; } // get host argument const char* remote_host = argv[1]; uint32_t ip = host2ip(remote_host); // connect to server int client; if ((client = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { perror(remote_host); return 3; } struct sockaddr_in addr = {.sin_family = AF_INET, .sin_port = htons(PORT), .sin_addr.s_addr = htonl(ip)}; if (connect(client, (struct sockaddr*)&addr, sizeof(addr))) { perror(remote_host); return 4; } // setup signals struct sigaction sa; sa.sa_flags = 0; sa.sa_handler = onsig; sigemptyset(&sa.sa_mask); sigaction(SIGINT, &sa, 0); // configure cosmo audio struct CosmoAudioOpenOptions cao = {0}; cao.sizeofThis = sizeof(struct CosmoAudioOpenOptions); cao.deviceType = kCosmoAudioDeviceTypeCapture; cao.sampleRate = SAMPLING_RATE; cao.bufferFrames = CHUNK_FRAMES * 2; cao.debugLog = DEBUG_LOG; cao.channels = 1; // connect to microphone and speaker int status; struct CosmoAudio* ca; status = cosmoaudio_open(&ca, &cao); if (status != COSMOAUDIO_SUCCESS) { fprintf(stderr, "failed to open audio: %d\n", status); return 5; } while (!g_done) { // read from microphone float buf32[CHUNK_FRAMES]; cosmoaudio_poll(ca, (int[]){CHUNK_FRAMES}, 0); cosmoaudio_read(ca, buf32, CHUNK_FRAMES); short buf16[CHUNK_FRAMES]; for (int i = 0; i < CHUNK_FRAMES; ++i) buf16[i] = toshort(buf32[i]); // send to server if (write(client, buf16, CHUNK_FRAMES * sizeof(short)) == -1) { if (errno == EINTR && g_done) break; perror(remote_host); return 7; } // print loudness in ascii char meter[21]; double db = rms_to_db(rms(buf32, CHUNK_FRAMES)); format_decibel_meter(meter, 20, db); printf("\r%s| %+6.2f dB", meter, db); fflush(stdout); } // clean up resources cosmoaudio_close(ca); close(client); }