├── .gitignore ├── LICENSE ├── Makefile ├── README.md └── src ├── audio.c ├── display.c ├── inc ├── audio.h ├── display.h ├── p2plib.h ├── pa_allocation.h ├── pa_converters.h ├── pa_cpuload.h ├── pa_debugprint.h ├── pa_dither.h ├── pa_endianness.h ├── pa_hostapi.h ├── pa_memorybarrier.h ├── pa_process.h ├── pa_ringbuffer.h ├── pa_stream.h ├── pa_trace.h ├── pa_types.h ├── pa_unix_util.h ├── pa_util.h └── video.h ├── p2plib.c ├── p2pvc.c ├── pa_allocation.c ├── pa_converters.c ├── pa_cpuload.c ├── pa_debugprint.c ├── pa_dither.c ├── pa_front.c ├── pa_process.c ├── pa_ringbuffer.c ├── pa_stream.c ├── pa_trace.c ├── pa_unix_hostapis.c ├── pa_unix_util.c └── video.c /.gitignore: -------------------------------------------------------------------------------- 1 | # Object files 2 | *.o 3 | *.ko 4 | *.obj 5 | *.elf 6 | 7 | # Vim swap files. 8 | *.swp 9 | 10 | 11 | # Precompiled Headers 12 | *.gch 13 | *.pch 14 | 15 | # Libraries 16 | *.lib 17 | *.a 18 | *.la 19 | *.lo 20 | 21 | # Shared objects (inc. Windows DLLs) 22 | *.dll 23 | *.so 24 | *.so.* 25 | *.dylib 26 | 27 | # Executables 28 | *.exe 29 | *.out 30 | *.app 31 | *.i*86 32 | *.x86_64 33 | *.hex 34 | p2pvc 35 | video 36 | audio 37 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Bram Wasti 4 | Copyright (c) 2015 Connell Donaghy 5 | Copyright (c) 2015 Michael O'Farrell 6 | Copyright (c) 2015 Stefan Dasbach 7 | 8 | Permission is hereby granted, free of charge, to any person obtaining a copy 9 | of this software and associated documentation files (the "Software"), to deal 10 | in the Software without restriction, including without limitation the rights 11 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | copies of the Software, and to permit persons to whom the Software is 13 | furnished to do so, subject to the following conditions: 14 | 15 | The above copyright notice and this permission notice shall be included in 16 | all copies or substantial portions of the Software. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | THE SOFTWARE. 25 | 26 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | OBJDIR=objs 2 | SRCDIR=src 3 | INCDIR=$(SRCDIR)/inc 4 | CFLAGS+=-I$(INCDIR) 5 | platform=$(shell uname -s) 6 | 7 | SRCS=$(wildcard $(SRCDIR)/*.c) 8 | OBJS=$(patsubst $(SRCDIR)/%.c,$(OBJDIR)/%.o,$(SRCS)) 9 | 10 | CFLAGS+=-O2 -Wall 11 | ifeq ($(platform), Linux) 12 | CFLAGS+=-DPA_USE_ALSA 13 | else 14 | CFLAGS+=-DPA_USE_COREAUDIO 15 | endif 16 | CFLAGS+=`pkg-config --cflags opencv` 17 | CFLAGS_DEBUG+=-O0 -g3 -Werror -DDEBUG 18 | LDFLAGS+=-lpthread -lncurses -lportaudio -lm 19 | LDFLAGS+=`pkg-config --libs opencv` 20 | 21 | all: p2pvc 22 | 23 | .PHONY: all clean debug 24 | 25 | debug: CC := $(CC) $(CFLAGS_DEBUG) 26 | debug: clean p2pvc 27 | 28 | p2pvc: $(OBJS) 29 | $(CC) $(CFLAGS) $^ -o $@ $(LDFLAGS) 30 | 31 | video: CFLAGS := $(CFLAGS) -DVIDEOONLY 32 | video: $(filter-out objs/p2pvc.o, $(OBJS)) 33 | $(CC) $(CFLAGS) $^ -o $@ $(LDFLAGS) 34 | 35 | audio: CFLAGS := $(CFLAGS) -DAUDIOONLY 36 | audio: $(filter-out objs/p2pvc.o, $(OBJS)) 37 | $(CC) $(CFLAGS) $^ -o $@ $(LDFLAGS) 38 | 39 | $(OBJS): | $(OBJDIR) 40 | $(OBJDIR): 41 | mkdir -p $@ 42 | 43 | $(OBJDIR)/%.o: $(SRCDIR)/%.c $(wildcard $(INCDIR)/*.h) Makefile 44 | $(CC) $(CFLAGS) $< -c -o $@ 45 | 46 | clean: 47 | rm -rf $(OBJDIR) audio video p2pvc 48 | 49 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # p2pvc 2 | A point to point color terminal video chat. 3 | 4 | ![Demo](http://giant.gfycat.com/HideousSpiffyAdder.gif) 5 | 6 | [and here's a still image](http://i.imgur.com/ziRPCWE.png) 7 | 8 | # Installation 9 | 10 | Arch users can install `p2pvc-git` from [the AUR](https://aur.archlinux.org/packages/p2pvc-git/) 11 | 12 | ### Dependencies 13 | 14 | * OpenCV 15 | * PortAudio 16 | * ncurses 17 | 18 | #### Ubuntu: 19 | 20 | sudo apt-get install libncurses-dev libopencv-dev portaudio19-dev 21 | 22 | #### OS X (with Homebrew): 23 | 24 | brew install ncurses portaudio opencv 25 | 26 | #### OS X (with MacPorts): 27 | 28 | sudo port install ncurses portaudio opencv 29 | 30 | ### Compilation 31 | Make the binary. 32 | 33 | make 34 | 35 | Video chat with yourself to test the camera. (Be sure to mute your mic or speakers or you'll get feedback!) 36 | 37 | ./p2pvc 127.0.0.1 -v 38 | 39 | # Usage 40 | 41 | #### Audio only 42 | 43 | ./p2pvc [ip address] 44 | 45 | #### Flags 46 | 47 | `-v` enables video chat. 48 | 49 | ./p2pvc [ip address] -v 50 | 51 | `-d` sets the dimension of the video in `[width]x[height]` format. 52 | 53 | ./p2pvc [ip address] -v -d 200x50 54 | 55 | `-A` and `-V` allow you to specify the port the audio and video run on respectively. 56 | 57 | ./p2pvc [ip address] -v -A 1337 -V 1338 58 | 59 | `-b` displays incoming bandwidth in the top-right of the video display. 60 | 61 | ./p2pvc [ip address] -v -b 62 | 63 | `-e` to print stderr (which is by default routed to /dev/null). 64 | 65 | ./p2pvc [ip address] -e 66 | 67 | `-B` renders in Braille Unicode characters. Note that the dimensions must both be divisible by 4. 68 | 69 | ./p2pvc [ip address] -v -B -d 200x152 70 | 71 | `-I` sets the threshold for turning pixels on (when using the `-B` flag). Ranges from 1 - 99, defaults 25. 72 | 73 | ./p2pvc [ip address] -v -B -I 50 74 | 75 | `-E` sets and edge filter with `[lower]:[upper]` bounds. 76 | 77 | ./p2pvc [ip address] -v -B -E 100:300 78 | 79 | `-c` sets the color of the video. Used in the form `[r]:[g]:[b]`. Each color ranges from 0 - 100. 80 | 81 | ./p2pvc [ip address] -v -c 0:100:0 82 | 83 | `-s` sets the saturation of the colors in the video. 0.0 is greyscale, 2.0 is default. 84 | 85 | ./p2pvc [ip address] -v -s 3.0 86 | 87 | `-a` sets custom ASCII character maps. Repeat characters to weight their frequency. 88 | 89 | ./p2pvc [ip address] -v -a " ......#####" 90 | 91 | `-r` sets the refresh rate. 92 | 93 | ./p2pvc [ip address] -v -r 10 94 | 95 | ![Demo](http://fat.gfycat.com/WideRecklessChinesecrocodilelizard.gif) 96 | # Known problems and resolutions 97 | 98 | #### Black and white 99 | 100 | This happens when p2pvc thinks the terminal doesn't have enough colors to display all 256. Try `export TERM=xterm-256color` or equivalent to get it working. 101 | 102 | #### No connection made 103 | 104 | p2pvc does not get around NAT, so you may need to port forward. It uses ports 55555 and 55556 for audio and video respectively. 105 | -------------------------------------------------------------------------------- /src/audio.c: -------------------------------------------------------------------------------- 1 | /*** 2 | * p2pvc 3 | ***/ 4 | /* 5 | * Permission is hereby granted, free of charge, to any person obtaining 6 | * a copy of this software and associated documentation files 7 | * (the "Software"), to deal in the Software without restriction, 8 | * including without limitation the rights to use, copy, modify, merge, 9 | * publish, distribute, sublicense, and/or sell copies of the Software, 10 | * and to permit persons to whom the Software is furnished to do so, 11 | * subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be 14 | * included in all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR 20 | * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 21 | * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | */ 24 | #include 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | #include 32 | #include 33 | #define PA_USE_ALSA 1 34 | #include 35 | #include "pa_ringbuffer.h" 36 | #include "pa_util.h" 37 | 38 | #define SAMPLE_RATE (44100) 39 | #define FRAMES_PER_BUFFER (512) 40 | #define NUM_CHANNELS (2) 41 | #define NUM_WRITES_PER_BUFFER (4) 42 | 43 | #define SIZE_TO_SEND (1024) 44 | #define MIN_SIZE_TO_SEND (512) 45 | 46 | #define MIN(x, y) ((x) > (y) ? (y) : (x)) 47 | /* Select sample format. */ 48 | #if 0 49 | #define PA_SAMPLE_TYPE paFloat32 50 | typedef float SAMPLE; 51 | #define SAMPLE_SILENCE (0.0f) 52 | #define PRINTF_S_FORMAT "%.8f" 53 | #elif 0 54 | #define PA_SAMPLE_TYPE paInt16 55 | typedef short SAMPLE; 56 | #define SAMPLE_SILENCE (0) 57 | #define PRINTF_S_FORMAT "%d" 58 | #elif 0 59 | #define PA_SAMPLE_TYPE paInt8 60 | typedef char SAMPLE; 61 | #define SAMPLE_SILENCE (0) 62 | #define PRINTF_S_FORMAT "%d" 63 | #else 64 | #define PA_SAMPLE_TYPE paUInt8 65 | typedef unsigned char SAMPLE; 66 | #define SAMPLE_SILENCE (128) 67 | #define PRINTF_S_FORMAT "%d" 68 | #endif 69 | 70 | typedef struct { 71 | SAMPLE *inputRingBufferData; 72 | PaUtilRingBuffer inputRingBuffer; 73 | SAMPLE *outputRingBufferData; 74 | PaUtilRingBuffer outputRingBuffer; 75 | } paTestData; 76 | 77 | static paTestData data; 78 | 79 | /* Connection structure. */ 80 | static connection_t *cons; 81 | static size_t conslen; 82 | static pthread_mutex_t conslock; 83 | 84 | /* This routine will be called by the PortAudio engine when audio is needed. 85 | ** It may be called at interrupt level on some machines so don't do anything 86 | ** that could mess up the system like calling malloc() or free(). 87 | */ 88 | static int readCallback(const void *inputBuffer, void *outputBuffer, 89 | unsigned long framesPerBuffer, 90 | const PaStreamCallbackTimeInfo* timeInfo, 91 | PaStreamCallbackFlags statusFlags, 92 | void *userData) { 93 | paTestData *data = (paTestData*)userData; 94 | ring_buffer_size_t elementsWriteable = PaUtil_GetRingBufferWriteAvailable(&data->inputRingBuffer); 95 | ring_buffer_size_t elementsToWrite = MIN(elementsWriteable, (ring_buffer_size_t)(framesPerBuffer * NUM_CHANNELS)); 96 | const SAMPLE *rptr = (const SAMPLE*)inputBuffer; 97 | 98 | (void) outputBuffer; /* Prevent unused variable warnings. */ 99 | (void) timeInfo; 100 | (void) statusFlags; 101 | (void) userData; 102 | 103 | PaUtil_WriteRingBuffer(&data->inputRingBuffer, rptr, elementsToWrite); 104 | 105 | return paContinue; 106 | } 107 | 108 | /* This routine will be called by the PortAudio engine when audio is needed. 109 | ** It may be called at interrupt level on some machines so don't do anything 110 | ** that could mess up the system like calling malloc() or free(). 111 | */ 112 | static int writeCallback(const void *inputBuffer, void *outputBuffer, 113 | unsigned long framesPerBuffer, 114 | const PaStreamCallbackTimeInfo* timeInfo, 115 | PaStreamCallbackFlags statusFlags, 116 | void *userData) { 117 | paTestData *data = (paTestData*)userData; 118 | ring_buffer_size_t elementsToPlay = PaUtil_GetRingBufferReadAvailable(&data->outputRingBuffer); 119 | ring_buffer_size_t elementsToRead = MIN(elementsToPlay, (ring_buffer_size_t)(framesPerBuffer * NUM_CHANNELS)); 120 | SAMPLE* wptr = (SAMPLE*)outputBuffer; 121 | 122 | memset(wptr, SAMPLE_SILENCE, framesPerBuffer * NUM_CHANNELS * sizeof(SAMPLE)); 123 | 124 | (void) inputBuffer; /* Prevent unused variable warnings. */ 125 | (void) timeInfo; 126 | (void) statusFlags; 127 | (void) userData; 128 | 129 | PaUtil_ReadRingBuffer(&data->outputRingBuffer, wptr, elementsToRead); 130 | 131 | return paContinue; 132 | } 133 | 134 | static void callback(connection_t *con, void *buf, size_t length) { 135 | ring_buffer_size_t elementsWriteable = PaUtil_GetRingBufferWriteAvailable(&data.outputRingBuffer); 136 | ring_buffer_size_t elementsToWrite = MIN(elementsWriteable, length / data.outputRingBuffer.elementSizeBytes); 137 | const SAMPLE *rptr = (const SAMPLE*)buf; 138 | 139 | PaUtil_WriteRingBuffer(&data.outputRingBuffer, rptr, elementsToWrite); 140 | } 141 | 142 | static void new_callback(connection_t *con, void *data, size_t datalen) { 143 | pthread_mutex_lock(&conslock); 144 | conslen++; 145 | cons = realloc(cons, conslen * sizeof(connection_t)); 146 | memcpy(&(cons[conslen-1]), con, sizeof(connection_t)); 147 | pthread_mutex_unlock(&conslock); 148 | } 149 | 150 | static void *dolisten(void *args) { 151 | int socket; 152 | int port = atoi((char *)args); 153 | p2p_init(port, &socket); 154 | p2p_listener((connection_t **)&cons, &conslen, &conslock, &callback, &new_callback, socket, 4096); 155 | return NULL; 156 | } 157 | 158 | static unsigned NextPowerOf2(unsigned val) { 159 | val--; 160 | val = (val >> 1) | val; 161 | val = (val >> 2) | val; 162 | val = (val >> 4) | val; 163 | val = (val >> 8) | val; 164 | val = (val >> 16) | val; 165 | return ++val; 166 | } 167 | 168 | int start_audio(char *peer, char *port) { 169 | PaStreamParameters inputParameters, 170 | outputParameters; 171 | PaStream *inputStream; 172 | PaStream *outputStream; 173 | PaError err = paNoError; 174 | unsigned numSamples; 175 | unsigned numBytes; 176 | 177 | /* Make a ring buffer that will buffer about half a second. Reasonable 178 | * level of latency before droping. 179 | * Make one for both input and output.*/ 180 | numSamples = NextPowerOf2((unsigned)(SAMPLE_RATE * 0.5 * NUM_CHANNELS)); 181 | numBytes = numSamples * sizeof(SAMPLE); 182 | data.inputRingBufferData = (SAMPLE *) PaUtil_AllocateMemory(numBytes); 183 | if (data.inputRingBufferData == NULL) 184 | { 185 | fprintf(stderr, "Could not allocate ring buffer data.\n"); 186 | goto done; 187 | } 188 | 189 | if (PaUtil_InitializeRingBuffer(&data.inputRingBuffer, sizeof(SAMPLE), numSamples, data.inputRingBufferData) < 0) 190 | { 191 | fprintf(stderr, "Failed to initialize ring buffer. Size is not power of 2 ?\n"); 192 | goto done; 193 | } 194 | 195 | data.outputRingBufferData = (SAMPLE *) PaUtil_AllocateMemory(numBytes); 196 | if (data.outputRingBufferData == NULL) 197 | { 198 | fprintf(stderr, "Could not allocate ring buffer data.\n"); 199 | goto done; 200 | } 201 | 202 | if (PaUtil_InitializeRingBuffer(&data.outputRingBuffer, sizeof(SAMPLE), numSamples, data.outputRingBufferData) < 0) 203 | { 204 | fprintf(stderr, "Failed to initialize ring buffer. Size is not power of 2 ?\n"); 205 | goto done; 206 | } 207 | 208 | err = Pa_Initialize(); 209 | if (err != paNoError) goto done; 210 | 211 | /* Set up output stream. */ 212 | outputParameters.device = Pa_GetDefaultOutputDevice(); /* default output device */ 213 | if (outputParameters.device == paNoDevice) { 214 | fprintf(stderr,"Error: No default output device.\n"); 215 | goto done; 216 | } 217 | outputParameters.channelCount = NUM_CHANNELS; 218 | outputParameters.sampleFormat = PA_SAMPLE_TYPE; 219 | outputParameters.suggestedLatency = Pa_GetDeviceInfo(outputParameters.device)->defaultLowOutputLatency; 220 | outputParameters.hostApiSpecificStreamInfo = NULL; 221 | 222 | err = Pa_OpenStream( 223 | &outputStream, 224 | NULL, /* no input */ 225 | &outputParameters, 226 | SAMPLE_RATE, 227 | FRAMES_PER_BUFFER, 228 | paClipOff, 229 | writeCallback, 230 | &data); 231 | if (err != paNoError) goto done; 232 | 233 | /* Set up input stream. */ 234 | 235 | inputParameters.device = Pa_GetDefaultInputDevice(); /* default input device */ 236 | if (inputParameters.device == paNoDevice) { 237 | fprintf(stderr,"Error: No default input device.\n"); 238 | goto done; 239 | } 240 | inputParameters.channelCount = NUM_CHANNELS; 241 | inputParameters.sampleFormat = PA_SAMPLE_TYPE; 242 | inputParameters.suggestedLatency = Pa_GetDeviceInfo(inputParameters.device)->defaultLowInputLatency; 243 | inputParameters.hostApiSpecificStreamInfo = NULL; 244 | 245 | err = Pa_OpenStream( 246 | &inputStream, 247 | &inputParameters, 248 | NULL, 249 | SAMPLE_RATE, 250 | FRAMES_PER_BUFFER, 251 | paClipOff, 252 | readCallback, 253 | &data); 254 | if (err != paNoError) goto done; 255 | 256 | /* Create connection to remote client. */ 257 | pthread_mutex_init(&conslock, NULL); 258 | 259 | cons = calloc(1, sizeof(connection_t)); 260 | if (p2p_connect(peer, port, &(cons[0]))) { 261 | fprintf(stderr, "Unable to connect to server.\n"); 262 | } else { 263 | conslen++; 264 | } 265 | 266 | pthread_t thr; 267 | pthread_create(&thr, NULL, &dolisten, port); 268 | 269 | /* Start the streams. */ 270 | err = Pa_StartStream(inputStream); 271 | if (err != paNoError) goto done; 272 | 273 | err = Pa_StartStream(outputStream); 274 | if (err != paNoError) goto done; 275 | 276 | while (1) { 277 | /* Try to send out data that has been read in. */ 278 | ring_buffer_size_t elementsInBuffer = PaUtil_GetRingBufferReadAvailable(&data.inputRingBuffer); 279 | while (elementsInBuffer * data.inputRingBuffer.elementSizeBytes > MIN_SIZE_TO_SEND) { 280 | uint8_t buf[SIZE_TO_SEND]; 281 | 282 | ring_buffer_size_t elements_read = 283 | PaUtil_ReadRingBuffer(&data.inputRingBuffer, buf, 284 | SIZE_TO_SEND / data.inputRingBuffer.elementSizeBytes); 285 | 286 | p2p_broadcast(&cons, &conslen, &conslock, buf, 287 | elements_read * data.inputRingBuffer.elementSizeBytes); 288 | 289 | elementsInBuffer = PaUtil_GetRingBufferReadAvailable(&data.inputRingBuffer); 290 | } 291 | Pa_Sleep(20); 292 | } 293 | 294 | /* Stop the streams. */ 295 | err = Pa_CloseStream(inputStream); 296 | if (err != paNoError) goto done; 297 | 298 | err = Pa_CloseStream(outputStream); 299 | if (err != paNoError) goto done; 300 | pthread_mutex_destroy(&conslock); 301 | done: 302 | Pa_Terminate(); 303 | if (data.inputRingBufferData) PaUtil_FreeMemory(data.inputRingBufferData); 304 | if (data.outputRingBufferData) PaUtil_FreeMemory(data.outputRingBufferData); 305 | if (err != paNoError) { 306 | fprintf(stderr, "An error occured while using the portaudio stream\n"); 307 | fprintf(stderr, "Error number: %d\n", err); 308 | fprintf(stderr, "Error message: %s\n", Pa_GetErrorText(err)); 309 | err = 1; /* Always return 0 or 1, but no other return codes. */ 310 | } 311 | return err; 312 | } 313 | 314 | #ifdef AUDIOONLY 315 | int main(int argc, char *argv[]) { 316 | if (argc < 2) { 317 | fprintf(stderr, "Must pass client to connect to.\n"); 318 | } 319 | return start_audio(argv[1], "55555"); 320 | } 321 | #endif 322 | 323 | -------------------------------------------------------------------------------- /src/display.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #define min(a,b) ((a)>(b)?(b):(a)) 8 | 9 | WINDOW *main_screen; 10 | static int intensity_threshold = 25; 11 | static double saturation = 2.0; 12 | static char *ascii_values = " ..::--==+++***###%%%%%%%%@@@@@@@"; 13 | static int monochrome = 0; 14 | char gr; char gg; char gb; 15 | 16 | /* private functions */ 17 | void init_colors(void); 18 | 19 | void init_screen(display_options_t *dopt){ 20 | main_screen = initscr(); 21 | keypad(stdscr, TRUE); // keypad enabled 22 | (void) nodelay(main_screen, 1); // no blocking 23 | (void) noecho(); // don't print to screen 24 | (void) curs_set(FALSE); // don't show the cursor 25 | (void) nonl(); // no new lines 26 | init_colors(); 27 | gr = dopt->r; 28 | gg = dopt->g; 29 | gb = dopt->b; 30 | monochrome = dopt->monochrome; 31 | if (dopt->ascii_values) { 32 | ascii_values = dopt->ascii_values; 33 | } 34 | if (dopt->saturation >= 0.0) { 35 | saturation = dopt->saturation; 36 | } 37 | if (dopt->intensity_threshold) { 38 | intensity_threshold = dopt->intensity_threshold; 39 | } 40 | } 41 | 42 | /* 43 | * crazy shifting is to set up every color 44 | */ 45 | void init_colors(void) { 46 | int i; 47 | start_color(); 48 | if (COLORS < 255) { 49 | for (i = 0; i < (1 << 8); i ++) { 50 | init_pair(i, 255, 0); // 0 --> i if you want pure blocks, otherwise ascii 51 | } 52 | } else { 53 | for (i = 0; i < (1 << 8); i ++) { 54 | init_pair(i, i, 0); // 0 --> i if you want pure blocks, otherwise ascii 55 | } 56 | } 57 | return; 58 | } 59 | 60 | void end_screen(void) { 61 | endwin(); 62 | } 63 | 64 | #define PR .299 65 | #define PG .587 66 | #define PB .114 67 | 68 | void saturate(int *r, int *g, int *b, double change) { 69 | double p = sqrt((*r)*(*r)*PR + (*g)*(*g)*PG + (*b)*(*b)*PB); 70 | 71 | *r = abs(p + ((*r) - p) * change); 72 | *g = abs(p + ((*g) - p) * change); 73 | *b = abs(p + ((*b) - p) * change); 74 | } 75 | 76 | /* allow us to directly map to the 216 colors ncurses makes available */ 77 | static inline unsigned int get_color(int r, int g, int b) { 78 | unsigned int f; 79 | if (monochrome) { 80 | f = (16+gr/48*36+gg/48*6+gb/48); 81 | } else { 82 | saturate(&r, &g, &b, saturation); 83 | f = (16+r/48*36+g/48*6+b/48); 84 | } 85 | return f; 86 | } 87 | 88 | chtype to_braille(unsigned char byte) { 89 | return 10240 + ( 90 | ((byte >> 7) & (1 << 0)) | 91 | ((byte >> 3) & (1 << 3)) | 92 | ((byte >> 4) & (1 << 1)) | 93 | ((byte >> 0) & (1 << 4)) | 94 | ((byte >> 1) & (1 << 2)) | 95 | ((byte << 3) & (1 << 5)) | 96 | ((byte << 5) & (1 << 6)) | 97 | ((byte << 7) & (1 << 7)) 98 | ); 99 | } 100 | 101 | unsigned char from_braille(chtype c) { 102 | char byte = (c - 10240) & 0xFF; 103 | return 104 | ((byte << 7) & (1 << 7)) | 105 | ((byte << 3) & (1 << 6)) | 106 | ((byte << 4) & (1 << 5)) | 107 | ((byte << 0) & (1 << 4)) | 108 | ((byte << 1) & (1 << 3)) | 109 | ((byte >> 3) & (1 << 2)) | 110 | ((byte >> 5) & (1 << 1)) | 111 | ((byte >> 7) & (1 << 0)); 112 | } 113 | 114 | /* if on is nonzero it will turn the pixel on, else off */ 115 | chtype add_pixel(chtype c, int row, int col, int on) { 116 | unsigned char byte = from_braille(c); 117 | if (on) { 118 | return to_braille(byte | (1 << (2 * row + col))); 119 | } else { 120 | return to_braille(byte & (~(1 << (2 * row + col)))); 121 | } 122 | } 123 | 124 | int draw_braille(char *data, int width, int y, int channels) { 125 | int j; 126 | int row = y/4; 127 | unsigned char b, g, r; 128 | int intensity; 129 | for (j = 0; j < width; j++) { 130 | b = data[j * channels]; 131 | g = data[j * channels + 1]; 132 | r = data[j * channels + 2]; 133 | intensity = 100 * ((r/255.0 + g/255.0 + b/255.0) / 3); 134 | int color = get_color(r, g, b); 135 | 136 | char braille[2]; 137 | attron(COLOR_PAIR(color)); 138 | if (y % 4 == 0) { 139 | sprintf(braille, "%C", to_braille(0)); 140 | } 141 | if (intensity > intensity_threshold) { 142 | sprintf(braille, "%C", add_pixel(mvinch(row, j / 2), 3 - (y % 4), 1 - (j % 2), 1)); 143 | } else { 144 | sprintf(braille, "%C", add_pixel(mvinch(row, j / 2), 3 - (y % 4), 1 - (j % 2), 0)); 145 | } 146 | mvaddstr(row, j / 2, braille); 147 | } 148 | if (y == 0) { 149 | refresh(); 150 | } 151 | return 0; 152 | } 153 | 154 | int draw_line(char *data, int width, int y, int channels) { 155 | int j; 156 | unsigned char b, g, r; 157 | int intensity; 158 | for (j = 0; j < width; j++){ 159 | b = data[j * channels]; 160 | g = data[j * channels + 1]; 161 | r = data[j * channels + 2]; 162 | intensity = (strlen(ascii_values) - 1) * ((r/255.0 + g/255.0 + b/255.0) / 3); 163 | char val = ascii_values[intensity]; 164 | int color = get_color(r, g, b); 165 | if (COLORS < 255) { 166 | color = 0; 167 | } 168 | mvaddch(y, j, val|COLOR_PAIR(color)); 169 | } 170 | 171 | if (y == 0) { 172 | refresh(); 173 | } 174 | return 0; 175 | } 176 | 177 | int write_bandwidth(char *bandstr, int bandlen, int width, int height) { 178 | int i; 179 | 180 | if (width < bandlen) { 181 | /* can't write it to the screen */ 182 | return -1; 183 | } 184 | 185 | for (i = width - bandlen; i < width; i++) { 186 | mvaddch(0, i, bandstr[i - width + bandlen]); 187 | } 188 | 189 | refresh(); 190 | return 0; 191 | } 192 | -------------------------------------------------------------------------------- /src/inc/audio.h: -------------------------------------------------------------------------------- 1 | #ifndef AUDIO_H 2 | #define AUDIO_H 3 | 4 | int start_audio(char *peer, char *port); 5 | 6 | #endif /* AUDIO_H */ 7 | -------------------------------------------------------------------------------- /src/inc/display.h: -------------------------------------------------------------------------------- 1 | #ifndef DISPLAY_H 2 | #define DISPLAY_H 3 | 4 | #include 5 | 6 | typedef struct { 7 | int intensity_threshold; 8 | double saturation; 9 | char *ascii_values; 10 | int monochrome; 11 | char r; char g; char b; 12 | } display_options_t; 13 | 14 | void init_screen(display_options_t *dopt); 15 | void end_screen(void); 16 | int draw_image(char *data, int width, int height, int step, int channels); 17 | int draw_braille(char *data, int width, int y, int channels); 18 | int draw_line(char *data, int width, int y, int channels); 19 | int write_bandwidth(char *bandstr, int bandlen, int width, int height); 20 | 21 | #endif /* DISPLAY_H */ 22 | -------------------------------------------------------------------------------- /src/inc/p2plib.h: -------------------------------------------------------------------------------- 1 | /* @file inc/p2plib.h 2 | * @brief Defines the interface of p2plib. 3 | */ 4 | 5 | #ifndef P2PLIB_H 6 | #define P2PLIB_H 7 | 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | #define P2P_HEADER 0x17381939 14 | 15 | /* @brief A status for connections. */ 16 | typedef struct { 17 | int socket; 18 | struct sockaddr_in addr; 19 | socklen_t addr_len; 20 | } connection_t; 21 | 22 | /* @brief a type to signify what the p2p data should do */ 23 | typedef enum { 24 | PASS_HEADER, 25 | CONS_HEADER, 26 | } p2p_action_t; 27 | 28 | /* @brief A header for non-user interaction */ 29 | typedef struct { 30 | unsigned int check; 31 | p2p_action_t act; 32 | } p2p_header_t; 33 | 34 | double p2p_bandwidth(); 35 | 36 | int p2p_send_pass(connection_t *con, char *password); 37 | 38 | int p2p_data(connection_t *con, void *data, size_t datalen, connection_t **cons, size_t *conlen); 39 | 40 | int p2p_connect(char *server, char *port, connection_t *con); 41 | 42 | int p2p_send(connection_t *con, const void *buf, size_t buflen); 43 | 44 | int p2p_broadcast(connection_t **cons, size_t *conslen, pthread_mutex_t *consmutex, const void *buf, size_t buflen); 45 | 46 | int p2p_listener(connection_t **cons, size_t *conslen, 47 | pthread_mutex_t *consmutex, 48 | void (*callback)(connection_t *, void *, size_t), 49 | void (*new_callback)(connection_t *, void *, size_t), 50 | int socket, 51 | unsigned long max_packet_size); 52 | 53 | int p2p_init(int port, int *sockfd); 54 | 55 | #endif /* P2PLIB_H */ 56 | -------------------------------------------------------------------------------- /src/inc/pa_allocation.h: -------------------------------------------------------------------------------- 1 | #ifndef PA_ALLOCATION_H 2 | #define PA_ALLOCATION_H 3 | /* 4 | * $Id$ 5 | * Portable Audio I/O Library allocation context header 6 | * memory allocation context for tracking allocation groups 7 | * 8 | * Based on the Open Source API proposed by Ross Bencina 9 | * Copyright (c) 1999-2008 Ross Bencina, Phil Burk 10 | * 11 | * Permission is hereby granted, free of charge, to any person obtaining 12 | * a copy of this software and associated documentation files 13 | * (the "Software"), to deal in the Software without restriction, 14 | * including without limitation the rights to use, copy, modify, merge, 15 | * publish, distribute, sublicense, and/or sell copies of the Software, 16 | * and to permit persons to whom the Software is furnished to do so, 17 | * subject to the following conditions: 18 | * 19 | * The above copyright notice and this permission notice shall be 20 | * included in all copies or substantial portions of the Software. 21 | * 22 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 23 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 24 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 25 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR 26 | * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 27 | * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 28 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 29 | */ 30 | 31 | /* 32 | * The text above constitutes the entire PortAudio license; however, 33 | * the PortAudio community also makes the following non-binding requests: 34 | * 35 | * Any person wishing to distribute modifications to the Software is 36 | * requested to send the modifications to the original developer so that 37 | * they can be incorporated into the canonical version. It is also 38 | * requested that these non-binding requests be included along with the 39 | * license above. 40 | */ 41 | 42 | /** @file 43 | @ingroup common_src 44 | 45 | @brief Allocation Group prototypes. An Allocation Group makes it easy to 46 | allocate multiple blocks of memory and free them all at once. 47 | 48 | An allocation group is useful for keeping track of multiple blocks 49 | of memory which are allocated at the same time (such as during initialization) 50 | and need to be deallocated at the same time. The allocation group maintains 51 | a list of allocated blocks, and can free all allocations at once. This 52 | can be usefull for cleaning up after a partially initialized object fails. 53 | 54 | The allocation group implementation is built on top of the lower 55 | level allocation functions defined in pa_util.h 56 | */ 57 | 58 | 59 | #ifdef __cplusplus 60 | extern "C" 61 | { 62 | #endif /* __cplusplus */ 63 | 64 | 65 | typedef struct 66 | { 67 | long linkCount; 68 | struct PaUtilAllocationGroupLink *linkBlocks; 69 | struct PaUtilAllocationGroupLink *spareLinks; 70 | struct PaUtilAllocationGroupLink *allocations; 71 | }PaUtilAllocationGroup; 72 | 73 | 74 | 75 | /** Create an allocation group. 76 | */ 77 | PaUtilAllocationGroup* PaUtil_CreateAllocationGroup( void ); 78 | 79 | /** Destroy an allocation group, but not the memory allocated through the group. 80 | */ 81 | void PaUtil_DestroyAllocationGroup( PaUtilAllocationGroup* group ); 82 | 83 | /** Allocate a block of memory though an allocation group. 84 | */ 85 | void* PaUtil_GroupAllocateMemory( PaUtilAllocationGroup* group, long size ); 86 | 87 | /** Free a block of memory that was previously allocated though an allocation 88 | group. Calling this function is a relatively time consuming operation. 89 | Under normal circumstances clients should call PaUtil_FreeAllAllocations to 90 | free all allocated blocks simultaneously. 91 | @see PaUtil_FreeAllAllocations 92 | */ 93 | void PaUtil_GroupFreeMemory( PaUtilAllocationGroup* group, void *buffer ); 94 | 95 | /** Free all blocks of memory which have been allocated through the allocation 96 | group. This function doesn't destroy the group itself. 97 | */ 98 | void PaUtil_FreeAllAllocations( PaUtilAllocationGroup* group ); 99 | 100 | 101 | #ifdef __cplusplus 102 | } 103 | #endif /* __cplusplus */ 104 | #endif /* PA_ALLOCATION_H */ 105 | -------------------------------------------------------------------------------- /src/inc/pa_converters.h: -------------------------------------------------------------------------------- 1 | #ifndef PA_CONVERTERS_H 2 | #define PA_CONVERTERS_H 3 | /* 4 | * $Id$ 5 | * Portable Audio I/O Library sample conversion mechanism 6 | * 7 | * Based on the Open Source API proposed by Ross Bencina 8 | * Copyright (c) 1999-2002 Phil Burk, Ross Bencina 9 | * 10 | * Permission is hereby granted, free of charge, to any person obtaining 11 | * a copy of this software and associated documentation files 12 | * (the "Software"), to deal in the Software without restriction, 13 | * including without limitation the rights to use, copy, modify, merge, 14 | * publish, distribute, sublicense, and/or sell copies of the Software, 15 | * and to permit persons to whom the Software is furnished to do so, 16 | * subject to the following conditions: 17 | * 18 | * The above copyright notice and this permission notice shall be 19 | * included in all copies or substantial portions of the Software. 20 | * 21 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 22 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 23 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 24 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR 25 | * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 26 | * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 27 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 28 | */ 29 | 30 | /* 31 | * The text above constitutes the entire PortAudio license; however, 32 | * the PortAudio community also makes the following non-binding requests: 33 | * 34 | * Any person wishing to distribute modifications to the Software is 35 | * requested to send the modifications to the original developer so that 36 | * they can be incorporated into the canonical version. It is also 37 | * requested that these non-binding requests be included along with the 38 | * license above. 39 | */ 40 | 41 | /** @file 42 | @ingroup common_src 43 | 44 | @brief Conversion functions used to convert buffers of samples from one 45 | format to another. 46 | */ 47 | 48 | 49 | #include "portaudio.h" /* for PaSampleFormat */ 50 | 51 | #ifdef __cplusplus 52 | extern "C" 53 | { 54 | #endif /* __cplusplus */ 55 | 56 | 57 | struct PaUtilTriangularDitherGenerator; 58 | 59 | 60 | /** Choose an available sample format which is most appropriate for 61 | representing the requested format. If the requested format is not available 62 | higher quality formats are considered before lower quality formates. 63 | @param availableFormats A variable containing the logical OR of all available 64 | formats. 65 | @param format The desired format. 66 | @return The most appropriate available format for representing the requested 67 | format. 68 | */ 69 | PaSampleFormat PaUtil_SelectClosestAvailableFormat( 70 | PaSampleFormat availableFormats, PaSampleFormat format ); 71 | 72 | 73 | /* high level conversions functions for use by implementations */ 74 | 75 | 76 | /** The generic sample converter prototype. Sample converters convert count 77 | samples from sourceBuffer to destinationBuffer. The actual type of the data 78 | pointed to by these parameters varys for different converter functions. 79 | @param destinationBuffer A pointer to the first sample of the destination. 80 | @param destinationStride An offset between successive destination samples 81 | expressed in samples (not bytes.) It may be negative. 82 | @param sourceBuffer A pointer to the first sample of the source. 83 | @param sourceStride An offset between successive source samples 84 | expressed in samples (not bytes.) It may be negative. 85 | @param count The number of samples to convert. 86 | @param ditherState State information used to calculate dither. Converters 87 | that do not perform dithering will ignore this parameter, in which case 88 | NULL or invalid dither state may be passed. 89 | */ 90 | typedef void PaUtilConverter( 91 | void *destinationBuffer, signed int destinationStride, 92 | void *sourceBuffer, signed int sourceStride, 93 | unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ); 94 | 95 | 96 | /** Find a sample converter function for the given source and destinations 97 | formats and flags (clip and dither.) 98 | @return 99 | A pointer to a PaUtilConverter which will perform the requested 100 | conversion, or NULL if the given format conversion is not supported. 101 | For conversions where clipping or dithering is not necessary, the 102 | clip and dither flags are ignored and a non-clipping or dithering 103 | version is returned. 104 | If the source and destination formats are the same, a function which 105 | copies data of the appropriate size will be returned. 106 | */ 107 | PaUtilConverter* PaUtil_SelectConverter( PaSampleFormat sourceFormat, 108 | PaSampleFormat destinationFormat, PaStreamFlags flags ); 109 | 110 | 111 | /** The generic buffer zeroer prototype. Buffer zeroers copy count zeros to 112 | destinationBuffer. The actual type of the data pointed to varys for 113 | different zeroer functions. 114 | @param destinationBuffer A pointer to the first sample of the destination. 115 | @param destinationStride An offset between successive destination samples 116 | expressed in samples (not bytes.) It may be negative. 117 | @param count The number of samples to zero. 118 | */ 119 | typedef void PaUtilZeroer( 120 | void *destinationBuffer, signed int destinationStride, unsigned int count ); 121 | 122 | 123 | /** Find a buffer zeroer function for the given destination format. 124 | @return 125 | A pointer to a PaUtilZeroer which will perform the requested 126 | zeroing. 127 | */ 128 | PaUtilZeroer* PaUtil_SelectZeroer( PaSampleFormat destinationFormat ); 129 | 130 | /*----------------------------------------------------------------------------*/ 131 | /* low level functions and data structures which may be used for 132 | substituting conversion functions */ 133 | 134 | 135 | /** The type used to store all sample conversion functions. 136 | @see paConverters; 137 | */ 138 | typedef struct{ 139 | PaUtilConverter *Float32_To_Int32; 140 | PaUtilConverter *Float32_To_Int32_Dither; 141 | PaUtilConverter *Float32_To_Int32_Clip; 142 | PaUtilConverter *Float32_To_Int32_DitherClip; 143 | 144 | PaUtilConverter *Float32_To_Int24; 145 | PaUtilConverter *Float32_To_Int24_Dither; 146 | PaUtilConverter *Float32_To_Int24_Clip; 147 | PaUtilConverter *Float32_To_Int24_DitherClip; 148 | 149 | PaUtilConverter *Float32_To_Int16; 150 | PaUtilConverter *Float32_To_Int16_Dither; 151 | PaUtilConverter *Float32_To_Int16_Clip; 152 | PaUtilConverter *Float32_To_Int16_DitherClip; 153 | 154 | PaUtilConverter *Float32_To_Int8; 155 | PaUtilConverter *Float32_To_Int8_Dither; 156 | PaUtilConverter *Float32_To_Int8_Clip; 157 | PaUtilConverter *Float32_To_Int8_DitherClip; 158 | 159 | PaUtilConverter *Float32_To_UInt8; 160 | PaUtilConverter *Float32_To_UInt8_Dither; 161 | PaUtilConverter *Float32_To_UInt8_Clip; 162 | PaUtilConverter *Float32_To_UInt8_DitherClip; 163 | 164 | PaUtilConverter *Int32_To_Float32; 165 | PaUtilConverter *Int32_To_Int24; 166 | PaUtilConverter *Int32_To_Int24_Dither; 167 | PaUtilConverter *Int32_To_Int16; 168 | PaUtilConverter *Int32_To_Int16_Dither; 169 | PaUtilConverter *Int32_To_Int8; 170 | PaUtilConverter *Int32_To_Int8_Dither; 171 | PaUtilConverter *Int32_To_UInt8; 172 | PaUtilConverter *Int32_To_UInt8_Dither; 173 | 174 | PaUtilConverter *Int24_To_Float32; 175 | PaUtilConverter *Int24_To_Int32; 176 | PaUtilConverter *Int24_To_Int16; 177 | PaUtilConverter *Int24_To_Int16_Dither; 178 | PaUtilConverter *Int24_To_Int8; 179 | PaUtilConverter *Int24_To_Int8_Dither; 180 | PaUtilConverter *Int24_To_UInt8; 181 | PaUtilConverter *Int24_To_UInt8_Dither; 182 | 183 | PaUtilConverter *Int16_To_Float32; 184 | PaUtilConverter *Int16_To_Int32; 185 | PaUtilConverter *Int16_To_Int24; 186 | PaUtilConverter *Int16_To_Int8; 187 | PaUtilConverter *Int16_To_Int8_Dither; 188 | PaUtilConverter *Int16_To_UInt8; 189 | PaUtilConverter *Int16_To_UInt8_Dither; 190 | 191 | PaUtilConverter *Int8_To_Float32; 192 | PaUtilConverter *Int8_To_Int32; 193 | PaUtilConverter *Int8_To_Int24; 194 | PaUtilConverter *Int8_To_Int16; 195 | PaUtilConverter *Int8_To_UInt8; 196 | 197 | PaUtilConverter *UInt8_To_Float32; 198 | PaUtilConverter *UInt8_To_Int32; 199 | PaUtilConverter *UInt8_To_Int24; 200 | PaUtilConverter *UInt8_To_Int16; 201 | PaUtilConverter *UInt8_To_Int8; 202 | 203 | PaUtilConverter *Copy_8_To_8; /* copy without any conversion */ 204 | PaUtilConverter *Copy_16_To_16; /* copy without any conversion */ 205 | PaUtilConverter *Copy_24_To_24; /* copy without any conversion */ 206 | PaUtilConverter *Copy_32_To_32; /* copy without any conversion */ 207 | } PaUtilConverterTable; 208 | 209 | 210 | /** A table of pointers to all required converter functions. 211 | PaUtil_SelectConverter() uses this table to lookup the appropriate 212 | conversion functions. The fields of this structure are initialized 213 | with default conversion functions. Fields may be NULL, indicating that 214 | no conversion function is available. User code may substitue optimised 215 | conversion functions by assigning different function pointers to 216 | these fields. 217 | 218 | @note 219 | If the PA_NO_STANDARD_CONVERTERS preprocessor variable is defined, 220 | PortAudio's standard converters will not be compiled, and all fields 221 | of this structure will be initialized to NULL. In such cases, users 222 | should supply their own conversion functions if the require PortAudio 223 | to open a stream that requires sample conversion. 224 | 225 | @see PaUtilConverterTable, PaUtilConverter, PaUtil_SelectConverter 226 | */ 227 | extern PaUtilConverterTable paConverters; 228 | 229 | 230 | /** The type used to store all buffer zeroing functions. 231 | @see paZeroers; 232 | */ 233 | typedef struct{ 234 | PaUtilZeroer *ZeroU8; /* unsigned 8 bit, zero == 128 */ 235 | PaUtilZeroer *Zero8; 236 | PaUtilZeroer *Zero16; 237 | PaUtilZeroer *Zero24; 238 | PaUtilZeroer *Zero32; 239 | } PaUtilZeroerTable; 240 | 241 | 242 | /** A table of pointers to all required zeroer functions. 243 | PaUtil_SelectZeroer() uses this table to lookup the appropriate 244 | conversion functions. The fields of this structure are initialized 245 | with default conversion functions. User code may substitue optimised 246 | conversion functions by assigning different function pointers to 247 | these fields. 248 | 249 | @note 250 | If the PA_NO_STANDARD_ZEROERS preprocessor variable is defined, 251 | PortAudio's standard zeroers will not be compiled, and all fields 252 | of this structure will be initialized to NULL. In such cases, users 253 | should supply their own zeroing functions for the sample sizes which 254 | they intend to use. 255 | 256 | @see PaUtilZeroerTable, PaUtilZeroer, PaUtil_SelectZeroer 257 | */ 258 | extern PaUtilZeroerTable paZeroers; 259 | 260 | #ifdef __cplusplus 261 | } 262 | #endif /* __cplusplus */ 263 | #endif /* PA_CONVERTERS_H */ 264 | -------------------------------------------------------------------------------- /src/inc/pa_cpuload.h: -------------------------------------------------------------------------------- 1 | #ifndef PA_CPULOAD_H 2 | #define PA_CPULOAD_H 3 | /* 4 | * $Id$ 5 | * Portable Audio I/O Library CPU Load measurement functions 6 | * Portable CPU load measurement facility. 7 | * 8 | * Based on the Open Source API proposed by Ross Bencina 9 | * Copyright (c) 2002 Ross Bencina 10 | * 11 | * Permission is hereby granted, free of charge, to any person obtaining 12 | * a copy of this software and associated documentation files 13 | * (the "Software"), to deal in the Software without restriction, 14 | * including without limitation the rights to use, copy, modify, merge, 15 | * publish, distribute, sublicense, and/or sell copies of the Software, 16 | * and to permit persons to whom the Software is furnished to do so, 17 | * subject to the following conditions: 18 | * 19 | * The above copyright notice and this permission notice shall be 20 | * included in all copies or substantial portions of the Software. 21 | * 22 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 23 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 24 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 25 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR 26 | * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 27 | * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 28 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 29 | */ 30 | 31 | /* 32 | * The text above constitutes the entire PortAudio license; however, 33 | * the PortAudio community also makes the following non-binding requests: 34 | * 35 | * Any person wishing to distribute modifications to the Software is 36 | * requested to send the modifications to the original developer so that 37 | * they can be incorporated into the canonical version. It is also 38 | * requested that these non-binding requests be included along with the 39 | * license above. 40 | */ 41 | 42 | /** @file 43 | @ingroup common_src 44 | 45 | @brief Functions to assist in measuring the CPU utilization of a callback 46 | stream. Used to implement the Pa_GetStreamCpuLoad() function. 47 | */ 48 | 49 | 50 | #ifdef __cplusplus 51 | extern "C" 52 | { 53 | #endif /* __cplusplus */ 54 | 55 | 56 | typedef struct { 57 | double samplingPeriod; 58 | double measurementStartTime; 59 | double averageLoad; 60 | } PaUtilCpuLoadMeasurer; /**< @todo need better name than measurer */ 61 | 62 | void PaUtil_InitializeCpuLoadMeasurer( PaUtilCpuLoadMeasurer* measurer, double sampleRate ); 63 | void PaUtil_BeginCpuLoadMeasurement( PaUtilCpuLoadMeasurer* measurer ); 64 | void PaUtil_EndCpuLoadMeasurement( PaUtilCpuLoadMeasurer* measurer, unsigned long framesProcessed ); 65 | void PaUtil_ResetCpuLoadMeasurer( PaUtilCpuLoadMeasurer* measurer ); 66 | double PaUtil_GetCpuLoad( PaUtilCpuLoadMeasurer* measurer ); 67 | 68 | 69 | #ifdef __cplusplus 70 | } 71 | #endif /* __cplusplus */ 72 | #endif /* PA_CPULOAD_H */ 73 | -------------------------------------------------------------------------------- /src/inc/pa_debugprint.h: -------------------------------------------------------------------------------- 1 | #ifndef PA_LOG_H 2 | #define PA_LOG_H 3 | /* 4 | * Log file redirector function 5 | * Copyright (c) 1999-2006 Ross Bencina, Phil Burk 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining 8 | * a copy of this software and associated documentation files 9 | * (the "Software"), to deal in the Software without restriction, 10 | * including without limitation the rights to use, copy, modify, merge, 11 | * publish, distribute, sublicense, and/or sell copies of the Software, 12 | * and to permit persons to whom the Software is furnished to do so, 13 | * subject to the following conditions: 14 | * 15 | * The above copyright notice and this permission notice shall be 16 | * included in all copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 19 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 21 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR 22 | * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 23 | * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 24 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 | */ 26 | 27 | /* 28 | * The text above constitutes the entire PortAudio license; however, 29 | * the PortAudio community also makes the following non-binding requests: 30 | * 31 | * Any person wishing to distribute modifications to the Software is 32 | * requested to send the modifications to the original developer so that 33 | * they can be incorporated into the canonical version. It is also 34 | * requested that these non-binding requests be included along with the 35 | * license above. 36 | */ 37 | 38 | /** @file 39 | @ingroup common_src 40 | */ 41 | 42 | 43 | #ifdef __cplusplus 44 | extern "C" 45 | { 46 | #endif /* __cplusplus */ 47 | 48 | 49 | 50 | void PaUtil_DebugPrint( const char *format, ... ); 51 | 52 | 53 | /* 54 | The basic format for log messages is described below. If you need to 55 | add any log messages, please follow this format. 56 | 57 | Function entry (void function): 58 | 59 | "FunctionName called.\n" 60 | 61 | Function entry (non void function): 62 | 63 | "FunctionName called:\n" 64 | "\tParam1Type param1: param1Value\n" 65 | "\tParam2Type param2: param2Value\n" (etc...) 66 | 67 | 68 | Function exit (no return value): 69 | 70 | "FunctionName returned.\n" 71 | 72 | Function exit (simple return value): 73 | 74 | "FunctionName returned:\n" 75 | "\tReturnType: returnValue\n" 76 | 77 | If the return type is an error code, the error text is displayed in () 78 | 79 | If the return type is not an error code, but has taken a special value 80 | because an error occurred, then the reason for the error is shown in [] 81 | 82 | If the return type is a struct ptr, the struct is dumped. 83 | 84 | See the code below for examples 85 | */ 86 | 87 | /** PA_DEBUG() provides a simple debug message printing facility. The macro 88 | passes it's argument to a printf-like function called PaUtil_DebugPrint() 89 | which prints to stderr and always flushes the stream after printing. 90 | Because preprocessor macros cannot directly accept variable length argument 91 | lists, calls to the macro must include an additional set of parenthesis, eg: 92 | PA_DEBUG(("errorno: %d", 1001 )); 93 | */ 94 | 95 | 96 | #ifdef PA_ENABLE_DEBUG_OUTPUT 97 | #define PA_DEBUG(x) PaUtil_DebugPrint x ; 98 | #else 99 | #define PA_DEBUG(x) 100 | #endif 101 | 102 | 103 | #ifdef PA_LOG_API_CALLS 104 | #define PA_LOGAPI(x) PaUtil_DebugPrint x 105 | 106 | #define PA_LOGAPI_ENTER(functionName) PaUtil_DebugPrint( functionName " called.\n" ) 107 | 108 | #define PA_LOGAPI_ENTER_PARAMS(functionName) PaUtil_DebugPrint( functionName " called:\n" ) 109 | 110 | #define PA_LOGAPI_EXIT(functionName) PaUtil_DebugPrint( functionName " returned.\n" ) 111 | 112 | #define PA_LOGAPI_EXIT_PAERROR( functionName, result ) \ 113 | PaUtil_DebugPrint( functionName " returned:\n" ); \ 114 | PaUtil_DebugPrint("\tPaError: %d ( %s )\n", result, Pa_GetErrorText( result ) ) 115 | 116 | #define PA_LOGAPI_EXIT_T( functionName, resultFormatString, result ) \ 117 | PaUtil_DebugPrint( functionName " returned:\n" ); \ 118 | PaUtil_DebugPrint("\t" resultFormatString "\n", result ) 119 | 120 | #define PA_LOGAPI_EXIT_PAERROR_OR_T_RESULT( functionName, positiveResultFormatString, result ) \ 121 | PaUtil_DebugPrint( functionName " returned:\n" ); \ 122 | if( result > 0 ) \ 123 | PaUtil_DebugPrint("\t" positiveResultFormatString "\n", result ); \ 124 | else \ 125 | PaUtil_DebugPrint("\tPaError: %d ( %s )\n", result, Pa_GetErrorText( result ) ) 126 | #else 127 | #define PA_LOGAPI(x) 128 | #define PA_LOGAPI_ENTER(functionName) 129 | #define PA_LOGAPI_ENTER_PARAMS(functionName) 130 | #define PA_LOGAPI_EXIT(functionName) 131 | #define PA_LOGAPI_EXIT_PAERROR( functionName, result ) 132 | #define PA_LOGAPI_EXIT_T( functionName, resultFormatString, result ) 133 | #define PA_LOGAPI_EXIT_PAERROR_OR_T_RESULT( functionName, positiveResultFormatString, result ) 134 | #endif 135 | 136 | 137 | typedef void (*PaUtilLogCallback ) (const char *log); 138 | 139 | /** 140 | Install user provided log function 141 | */ 142 | void PaUtil_SetDebugPrintFunction(PaUtilLogCallback cb); 143 | 144 | 145 | 146 | #ifdef __cplusplus 147 | } 148 | #endif /* __cplusplus */ 149 | #endif /* PA_LOG_H */ 150 | -------------------------------------------------------------------------------- /src/inc/pa_dither.h: -------------------------------------------------------------------------------- 1 | #ifndef PA_DITHER_H 2 | #define PA_DITHER_H 3 | /* 4 | * $Id$ 5 | * Portable Audio I/O Library triangular dither generator 6 | * 7 | * Based on the Open Source API proposed by Ross Bencina 8 | * Copyright (c) 1999-2002 Phil Burk, Ross Bencina 9 | * 10 | * Permission is hereby granted, free of charge, to any person obtaining 11 | * a copy of this software and associated documentation files 12 | * (the "Software"), to deal in the Software without restriction, 13 | * including without limitation the rights to use, copy, modify, merge, 14 | * publish, distribute, sublicense, and/or sell copies of the Software, 15 | * and to permit persons to whom the Software is furnished to do so, 16 | * subject to the following conditions: 17 | * 18 | * The above copyright notice and this permission notice shall be 19 | * included in all copies or substantial portions of the Software. 20 | * 21 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 22 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 23 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 24 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR 25 | * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 26 | * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 27 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 28 | */ 29 | 30 | /* 31 | * The text above constitutes the entire PortAudio license; however, 32 | * the PortAudio community also makes the following non-binding requests: 33 | * 34 | * Any person wishing to distribute modifications to the Software is 35 | * requested to send the modifications to the original developer so that 36 | * they can be incorporated into the canonical version. It is also 37 | * requested that these non-binding requests be included along with the 38 | * license above. 39 | */ 40 | 41 | /** @file 42 | @ingroup common_src 43 | 44 | @brief Functions for generating dither noise 45 | */ 46 | 47 | #include "pa_types.h" 48 | 49 | 50 | #ifdef __cplusplus 51 | extern "C" 52 | { 53 | #endif /* __cplusplus */ 54 | 55 | /* Note that the linear congruential algorithm requires 32 bit integers 56 | * because it uses arithmetic overflow. So use PaUint32 instead of 57 | * unsigned long so it will work on 64 bit systems. 58 | */ 59 | 60 | /** @brief State needed to generate a dither signal */ 61 | typedef struct PaUtilTriangularDitherGenerator{ 62 | PaUint32 previous; 63 | PaUint32 randSeed1; 64 | PaUint32 randSeed2; 65 | } PaUtilTriangularDitherGenerator; 66 | 67 | 68 | /** @brief Initialize dither state */ 69 | void PaUtil_InitializeTriangularDitherState( PaUtilTriangularDitherGenerator *ditherState ); 70 | 71 | 72 | /** 73 | @brief Calculate 2 LSB dither signal with a triangular distribution. 74 | Ranged for adding to a 1 bit right-shifted 32 bit integer 75 | prior to >>15. eg: 76 |
 77 |     signed long in = *
 78 |     signed long dither = PaUtil_Generate16BitTriangularDither( ditherState );
 79 |     signed short out = (signed short)(((in>>1) + dither) >> 15);
 80 | 
81 | @return 82 | A signed 32-bit integer with a range of +32767 to -32768 83 | */ 84 | PaInt32 PaUtil_Generate16BitTriangularDither( PaUtilTriangularDitherGenerator *ditherState ); 85 | 86 | 87 | /** 88 | @brief Calculate 2 LSB dither signal with a triangular distribution. 89 | Ranged for adding to a pre-scaled float. 90 |
 91 |     float in = *
 92 |     float dither = PaUtil_GenerateFloatTriangularDither( ditherState );
 93 |     // use smaller scaler to prevent overflow when we add the dither
 94 |     signed short out = (signed short)(in*(32766.0f) + dither );
 95 | 
96 | @return 97 | A float with a range of -2.0 to +1.99999. 98 | */ 99 | float PaUtil_GenerateFloatTriangularDither( PaUtilTriangularDitherGenerator *ditherState ); 100 | 101 | 102 | 103 | #ifdef __cplusplus 104 | } 105 | #endif /* __cplusplus */ 106 | #endif /* PA_DITHER_H */ 107 | -------------------------------------------------------------------------------- /src/inc/pa_endianness.h: -------------------------------------------------------------------------------- 1 | #ifndef PA_ENDIANNESS_H 2 | #define PA_ENDIANNESS_H 3 | /* 4 | * $Id$ 5 | * Portable Audio I/O Library current platform endianness macros 6 | * 7 | * Based on the Open Source API proposed by Ross Bencina 8 | * Copyright (c) 1999-2002 Phil Burk, Ross Bencina 9 | * 10 | * Permission is hereby granted, free of charge, to any person obtaining 11 | * a copy of this software and associated documentation files 12 | * (the "Software"), to deal in the Software without restriction, 13 | * including without limitation the rights to use, copy, modify, merge, 14 | * publish, distribute, sublicense, and/or sell copies of the Software, 15 | * and to permit persons to whom the Software is furnished to do so, 16 | * subject to the following conditions: 17 | * 18 | * The above copyright notice and this permission notice shall be 19 | * included in all copies or substantial portions of the Software. 20 | * 21 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 22 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 23 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 24 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR 25 | * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 26 | * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 27 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 28 | */ 29 | 30 | /* 31 | * The text above constitutes the entire PortAudio license; however, 32 | * the PortAudio community also makes the following non-binding requests: 33 | * 34 | * Any person wishing to distribute modifications to the Software is 35 | * requested to send the modifications to the original developer so that 36 | * they can be incorporated into the canonical version. It is also 37 | * requested that these non-binding requests be included along with the 38 | * license above. 39 | */ 40 | 41 | /** @file 42 | @ingroup common_src 43 | 44 | @brief Configure endianness symbols for the target processor. 45 | 46 | Arrange for either the PA_LITTLE_ENDIAN or PA_BIG_ENDIAN preprocessor symbols 47 | to be defined. The one that is defined reflects the endianness of the target 48 | platform and may be used to implement conditional compilation of byte-order 49 | dependent code. 50 | 51 | If either PA_LITTLE_ENDIAN or PA_BIG_ENDIAN is defined already, then no attempt 52 | is made to override that setting. This may be useful if you have a better way 53 | of determining the platform's endianness. The autoconf mechanism uses this for 54 | example. 55 | 56 | A PA_VALIDATE_ENDIANNESS macro is provided to compare the compile time 57 | and runtime endiannes and raise an assertion if they don't match. 58 | */ 59 | 60 | 61 | #ifdef __cplusplus 62 | extern "C" 63 | { 64 | #endif /* __cplusplus */ 65 | 66 | /* If this is an apple, we need to do detect endianness this way */ 67 | #if defined(__APPLE__) 68 | /* we need to do some endian detection that is sensitive to harware arch */ 69 | #if defined(__LITTLE_ENDIAN__) 70 | #if !defined( PA_LITTLE_ENDIAN ) 71 | #define PA_LITTLE_ENDIAN 72 | #endif 73 | #if defined( PA_BIG_ENDIAN ) 74 | #undef PA_BIG_ENDIAN 75 | #endif 76 | #else 77 | #if !defined( PA_BIG_ENDIAN ) 78 | #define PA_BIG_ENDIAN 79 | #endif 80 | #if defined( PA_LITTLE_ENDIAN ) 81 | #undef PA_LITTLE_ENDIAN 82 | #endif 83 | #endif 84 | #else 85 | /* this is not an apple, so first check the existing defines, and, failing that, 86 | detect well-known architechtures. */ 87 | 88 | #if defined(PA_LITTLE_ENDIAN) || defined(PA_BIG_ENDIAN) 89 | /* endianness define has been set externally, such as by autoconf */ 90 | 91 | #if defined(PA_LITTLE_ENDIAN) && defined(PA_BIG_ENDIAN) 92 | #error both PA_LITTLE_ENDIAN and PA_BIG_ENDIAN have been defined externally to pa_endianness.h - only one endianness at a time please 93 | #endif 94 | 95 | #else 96 | /* endianness define has not been set externally */ 97 | 98 | /* set PA_LITTLE_ENDIAN or PA_BIG_ENDIAN by testing well known platform specific defines */ 99 | 100 | #if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__) || defined(LITTLE_ENDIAN) || defined(__i386) || defined(_M_IX86) || defined(__x86_64__) 101 | #define PA_LITTLE_ENDIAN /* win32, assume intel byte order */ 102 | #else 103 | #define PA_BIG_ENDIAN 104 | #endif 105 | #endif 106 | 107 | #if !defined(PA_LITTLE_ENDIAN) && !defined(PA_BIG_ENDIAN) 108 | /* 109 | If the following error is raised, you either need to modify the code above 110 | to automatically determine the endianness from other symbols defined on your 111 | platform, or define either PA_LITTLE_ENDIAN or PA_BIG_ENDIAN externally. 112 | */ 113 | #error pa_endianness.h was unable to automatically determine the endianness of the target platform 114 | #endif 115 | 116 | #endif 117 | 118 | 119 | /* PA_VALIDATE_ENDIANNESS compares the compile time and runtime endianness, 120 | and raises an assertion if they don't match. must be included in 121 | the context in which this macro is used. 122 | */ 123 | #if defined(NDEBUG) 124 | #define PA_VALIDATE_ENDIANNESS 125 | #else 126 | #if defined(PA_LITTLE_ENDIAN) 127 | #define PA_VALIDATE_ENDIANNESS \ 128 | { \ 129 | const long nativeOne = 1; \ 130 | assert( "PortAudio: compile time and runtime endianness don't match" && (((char *)&nativeOne)[0]) == 1 ); \ 131 | } 132 | #elif defined(PA_BIG_ENDIAN) 133 | #define PA_VALIDATE_ENDIANNESS \ 134 | { \ 135 | const long nativeOne = 1; \ 136 | assert( "PortAudio: compile time and runtime endianness don't match" && (((char *)&nativeOne)[0]) == 0 ); \ 137 | } 138 | #endif 139 | #endif 140 | 141 | 142 | #ifdef __cplusplus 143 | } 144 | #endif /* __cplusplus */ 145 | #endif /* PA_ENDIANNESS_H */ 146 | -------------------------------------------------------------------------------- /src/inc/pa_hostapi.h: -------------------------------------------------------------------------------- 1 | #ifndef PA_HOSTAPI_H 2 | #define PA_HOSTAPI_H 3 | /* 4 | * $Id$ 5 | * Portable Audio I/O Library 6 | * host api representation 7 | * 8 | * Based on the Open Source API proposed by Ross Bencina 9 | * Copyright (c) 1999-2008 Ross Bencina, Phil Burk 10 | * 11 | * Permission is hereby granted, free of charge, to any person obtaining 12 | * a copy of this software and associated documentation files 13 | * (the "Software"), to deal in the Software without restriction, 14 | * including without limitation the rights to use, copy, modify, merge, 15 | * publish, distribute, sublicense, and/or sell copies of the Software, 16 | * and to permit persons to whom the Software is furnished to do so, 17 | * subject to the following conditions: 18 | * 19 | * The above copyright notice and this permission notice shall be 20 | * included in all copies or substantial portions of the Software. 21 | * 22 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 23 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 24 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 25 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR 26 | * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 27 | * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 28 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 29 | */ 30 | 31 | /* 32 | * The text above constitutes the entire PortAudio license; however, 33 | * the PortAudio community also makes the following non-binding requests: 34 | * 35 | * Any person wishing to distribute modifications to the Software is 36 | * requested to send the modifications to the original developer so that 37 | * they can be incorporated into the canonical version. It is also 38 | * requested that these non-binding requests be included along with the 39 | * license above. 40 | */ 41 | 42 | /** @file 43 | @ingroup common_src 44 | 45 | @brief Interfaces and representation structures used by pa_front.c 46 | to manage and communicate with host API implementations. 47 | */ 48 | 49 | #include "portaudio.h" 50 | 51 | /** 52 | The PA_NO_* host API macros are now deprecated in favor of PA_USE_* macros. 53 | PA_USE_* indicates whether a particular host API will be initialized by PortAudio. 54 | An undefined or 0 value indicates that the host API will not be used. A value of 1 55 | indicates that the host API will be used. PA_USE_* macros should be left undefined 56 | or defined to either 0 or 1. 57 | 58 | The code below ensures that PA_USE_* macros are always defined and have value 59 | 0 or 1. Undefined symbols are defaulted to 0. Symbols that are neither 0 nor 1 60 | are defaulted to 1. 61 | */ 62 | 63 | #ifndef PA_USE_SKELETON 64 | #define PA_USE_SKELETON 0 65 | #elif (PA_USE_SKELETON != 0) && (PA_USE_SKELETON != 1) 66 | #undef PA_USE_SKELETON 67 | #define PA_USE_SKELETON 1 68 | #endif 69 | 70 | #if defined(PA_NO_ASIO) || defined(PA_NO_DS) || defined(PA_NO_WMME) || defined(PA_NO_WASAPI) || defined(PA_NO_WDMKS) 71 | #error "Portaudio: PA_NO_ is no longer supported, please remove definition and use PA_USE_ instead" 72 | #endif 73 | 74 | #ifndef PA_USE_ASIO 75 | #define PA_USE_ASIO 0 76 | #elif (PA_USE_ASIO != 0) && (PA_USE_ASIO != 1) 77 | #undef PA_USE_ASIO 78 | #define PA_USE_ASIO 1 79 | #endif 80 | 81 | #ifndef PA_USE_DS 82 | #define PA_USE_DS 0 83 | #elif (PA_USE_DS != 0) && (PA_USE_DS != 1) 84 | #undef PA_USE_DS 85 | #define PA_USE_DS 1 86 | #endif 87 | 88 | #ifndef PA_USE_WMME 89 | #define PA_USE_WMME 0 90 | #elif (PA_USE_WMME != 0) && (PA_USE_WMME != 1) 91 | #undef PA_USE_WMME 92 | #define PA_USE_WMME 1 93 | #endif 94 | 95 | #ifndef PA_USE_WASAPI 96 | #define PA_USE_WASAPI 0 97 | #elif (PA_USE_WASAPI != 0) && (PA_USE_WASAPI != 1) 98 | #undef PA_USE_WASAPI 99 | #define PA_USE_WASAPI 1 100 | #endif 101 | 102 | #ifndef PA_USE_WDMKS 103 | #define PA_USE_WDMKS 0 104 | #elif (PA_USE_WDMKS != 0) && (PA_USE_WDMKS != 1) 105 | #undef PA_USE_WDMKS 106 | #define PA_USE_WDMKS 1 107 | #endif 108 | 109 | /* Set default values for Unix based APIs. */ 110 | #if defined(PA_NO_OSS) || defined(PA_NO_ALSA) || defined(PA_NO_JACK) || defined(PA_NO_COREAUDIO) || defined(PA_NO_SGI) || defined(PA_NO_ASIHPI) 111 | #error "Portaudio: PA_NO_ is no longer supported, please remove definition and use PA_USE_ instead" 112 | #endif 113 | 114 | #ifndef PA_USE_OSS 115 | #define PA_USE_OSS 0 116 | #elif (PA_USE_OSS != 0) && (PA_USE_OSS != 1) 117 | #undef PA_USE_OSS 118 | #define PA_USE_OSS 1 119 | #endif 120 | 121 | #ifndef PA_USE_ALSA 122 | #define PA_USE_ALSA 0 123 | #elif (PA_USE_ALSA != 0) && (PA_USE_ALSA != 1) 124 | #undef PA_USE_ALSA 125 | #define PA_USE_ALSA 1 126 | #endif 127 | 128 | #ifndef PA_USE_JACK 129 | #define PA_USE_JACK 0 130 | #elif (PA_USE_JACK != 0) && (PA_USE_JACK != 1) 131 | #undef PA_USE_JACK 132 | #define PA_USE_JACK 1 133 | #endif 134 | 135 | #ifndef PA_USE_SGI 136 | #define PA_USE_SGI 0 137 | #elif (PA_USE_SGI != 0) && (PA_USE_SGI != 1) 138 | #undef PA_USE_SGI 139 | #define PA_USE_SGI 1 140 | #endif 141 | 142 | #ifndef PA_USE_COREAUDIO 143 | #define PA_USE_COREAUDIO 0 144 | #elif (PA_USE_COREAUDIO != 0) && (PA_USE_COREAUDIO != 1) 145 | #undef PA_USE_COREAUDIO 146 | #define PA_USE_COREAUDIO 1 147 | #endif 148 | 149 | #ifndef PA_USE_ASIHPI 150 | #define PA_USE_ASIHPI 0 151 | #elif (PA_USE_ASIHPI != 0) && (PA_USE_ASIHPI != 1) 152 | #undef PA_USE_ASIHPI 153 | #define PA_USE_ASIHPI 1 154 | #endif 155 | 156 | #ifdef __cplusplus 157 | extern "C" 158 | { 159 | #endif /* __cplusplus */ 160 | 161 | 162 | /** **FOR THE USE OF pa_front.c ONLY** 163 | Do NOT use fields in this structure, they my change at any time. 164 | Use functions defined in pa_util.h if you think you need functionality 165 | which can be derived from here. 166 | */ 167 | typedef struct PaUtilPrivatePaFrontHostApiInfo { 168 | 169 | 170 | unsigned long baseDeviceIndex; 171 | }PaUtilPrivatePaFrontHostApiInfo; 172 | 173 | 174 | /** The common header for all data structures whose pointers are passed through 175 | the hostApiSpecificStreamInfo field of the PaStreamParameters structure. 176 | Note that in order to keep the public PortAudio interface clean, this structure 177 | is not used explicitly when declaring hostApiSpecificStreamInfo data structures. 178 | However, some code in pa_front depends on the first 3 members being equivalent 179 | with this structure. 180 | @see PaStreamParameters 181 | */ 182 | typedef struct PaUtilHostApiSpecificStreamInfoHeader 183 | { 184 | unsigned long size; /**< size of whole structure including this header */ 185 | PaHostApiTypeId hostApiType; /**< host API for which this data is intended */ 186 | unsigned long version; /**< structure version */ 187 | } PaUtilHostApiSpecificStreamInfoHeader; 188 | 189 | 190 | 191 | /** A structure representing the interface to a host API. Contains both 192 | concrete data and pointers to functions which implement the interface. 193 | */ 194 | typedef struct PaUtilHostApiRepresentation { 195 | PaUtilPrivatePaFrontHostApiInfo privatePaFrontInfo; 196 | 197 | /** The host api implementation should populate the info field. In the 198 | case of info.defaultInputDevice and info.defaultOutputDevice the 199 | values stored should be 0 based indices within the host api's own 200 | device index range (0 to deviceCount). These values will be converted 201 | to global device indices by pa_front after PaUtilHostApiInitializer() 202 | returns. 203 | */ 204 | PaHostApiInfo info; 205 | 206 | PaDeviceInfo** deviceInfos; 207 | 208 | /** 209 | (*Terminate)() is guaranteed to be called with a valid 210 | parameter, which was previously returned from the same implementation's 211 | initializer. 212 | */ 213 | void (*Terminate)( struct PaUtilHostApiRepresentation *hostApi ); 214 | 215 | /** 216 | The inputParameters and outputParameters pointers should not be saved 217 | as they will not remain valid after OpenStream is called. 218 | 219 | 220 | The following guarantees are made about parameters to (*OpenStream)(): 221 | 222 | [NOTE: the following list up to *END PA FRONT VALIDATIONS* should be 223 | kept in sync with the one for ValidateOpenStreamParameters and 224 | Pa_OpenStream in pa_front.c] 225 | 226 | PaHostApiRepresentation *hostApi 227 | - is valid for this implementation 228 | 229 | PaStream** stream 230 | - is non-null 231 | 232 | - at least one of inputParameters & outputParmeters is valid (not NULL) 233 | 234 | - if inputParameters & outputParmeters are both valid, that 235 | inputParameters->device & outputParmeters->device both use the same host api 236 | 237 | PaDeviceIndex inputParameters->device 238 | - is within range (0 to Pa_CountDevices-1) Or: 239 | - is paUseHostApiSpecificDeviceSpecification and 240 | inputParameters->hostApiSpecificStreamInfo is non-NULL and refers 241 | to a valid host api 242 | 243 | int inputParameters->numChannels 244 | - if inputParameters->device is not paUseHostApiSpecificDeviceSpecification, numInputChannels is > 0 245 | - upper bound is NOT validated against device capabilities 246 | 247 | PaSampleFormat inputParameters->sampleFormat 248 | - is one of the sample formats defined in portaudio.h 249 | 250 | void *inputParameters->hostApiSpecificStreamInfo 251 | - if supplied its hostApi field matches the input device's host Api 252 | 253 | PaDeviceIndex outputParmeters->device 254 | - is within range (0 to Pa_CountDevices-1) 255 | 256 | int outputParmeters->numChannels 257 | - if inputDevice is valid, numInputChannels is > 0 258 | - upper bound is NOT validated against device capabilities 259 | 260 | PaSampleFormat outputParmeters->sampleFormat 261 | - is one of the sample formats defined in portaudio.h 262 | 263 | void *outputParmeters->hostApiSpecificStreamInfo 264 | - if supplied its hostApi field matches the output device's host Api 265 | 266 | double sampleRate 267 | - is not an 'absurd' rate (less than 1000. or greater than 384000.) 268 | - sampleRate is NOT validated against device capabilities 269 | 270 | PaStreamFlags streamFlags 271 | - unused platform neutral flags are zero 272 | - paNeverDropInput is only used for full-duplex callback streams 273 | with variable buffer size (paFramesPerBufferUnspecified) 274 | 275 | [*END PA FRONT VALIDATIONS*] 276 | 277 | 278 | The following validations MUST be performed by (*OpenStream)(): 279 | 280 | - check that input device can support numInputChannels 281 | 282 | - check that input device can support inputSampleFormat, or that 283 | we have the capability to convert from outputSampleFormat to 284 | a native format 285 | 286 | - if inputStreamInfo is supplied, validate its contents, 287 | or return an error if no inputStreamInfo is expected 288 | 289 | - check that output device can support numOutputChannels 290 | 291 | - check that output device can support outputSampleFormat, or that 292 | we have the capability to convert from outputSampleFormat to 293 | a native format 294 | 295 | - if outputStreamInfo is supplied, validate its contents, 296 | or return an error if no outputStreamInfo is expected 297 | 298 | - if a full duplex stream is requested, check that the combination 299 | of input and output parameters is supported 300 | 301 | - check that the device supports sampleRate 302 | 303 | - alter sampleRate to a close allowable rate if necessary 304 | 305 | - validate inputLatency and outputLatency 306 | 307 | - validate any platform specific flags, if flags are supplied they 308 | must be valid. 309 | */ 310 | PaError (*OpenStream)( struct PaUtilHostApiRepresentation *hostApi, 311 | PaStream** stream, 312 | const PaStreamParameters *inputParameters, 313 | const PaStreamParameters *outputParameters, 314 | double sampleRate, 315 | unsigned long framesPerCallback, 316 | PaStreamFlags streamFlags, 317 | PaStreamCallback *streamCallback, 318 | void *userData ); 319 | 320 | 321 | PaError (*IsFormatSupported)( struct PaUtilHostApiRepresentation *hostApi, 322 | const PaStreamParameters *inputParameters, 323 | const PaStreamParameters *outputParameters, 324 | double sampleRate ); 325 | } PaUtilHostApiRepresentation; 326 | 327 | 328 | /** Prototype for the initialization function which must be implemented by every 329 | host API. 330 | 331 | This function should only return an error other than paNoError if it encounters 332 | an unexpected and fatal error (memory allocation error for example). In general, 333 | there may be conditions under which it returns a NULL interface pointer and also 334 | returns paNoError. For example, if the ASIO implementation detects that ASIO is 335 | not installed, it should return a NULL interface, and paNoError. 336 | 337 | @see paHostApiInitializers 338 | */ 339 | typedef PaError PaUtilHostApiInitializer( PaUtilHostApiRepresentation**, PaHostApiIndex ); 340 | 341 | 342 | /** paHostApiInitializers is a NULL-terminated array of host API initialization 343 | functions. These functions are called by pa_front.c to initialize the host APIs 344 | when the client calls Pa_Initialize(). 345 | 346 | The initialization functions are invoked in order. 347 | 348 | The first successfully initialized host API that has a default input *or* output 349 | device is used as the default PortAudio host API. This is based on the logic that 350 | there is only one default host API, and it must contain the default input and output 351 | devices (if defined). 352 | 353 | There is a platform specific file that defines paHostApiInitializers for that 354 | platform, pa_win/pa_win_hostapis.c contains the Win32 definitions for example. 355 | */ 356 | extern PaUtilHostApiInitializer *paHostApiInitializers[]; 357 | 358 | 359 | #ifdef __cplusplus 360 | } 361 | #endif /* __cplusplus */ 362 | #endif /* PA_HOSTAPI_H */ 363 | -------------------------------------------------------------------------------- /src/inc/pa_memorybarrier.h: -------------------------------------------------------------------------------- 1 | /* 2 | * $Id: pa_memorybarrier.h 1240 2007-07-17 13:05:07Z bjornroche $ 3 | * Portable Audio I/O Library 4 | * Memory barrier utilities 5 | * 6 | * Author: Bjorn Roche, XO Audio, LLC 7 | * 8 | * This program uses the PortAudio Portable Audio Library. 9 | * For more information see: http://www.portaudio.com 10 | * Copyright (c) 1999-2000 Ross Bencina and Phil Burk 11 | * 12 | * Permission is hereby granted, free of charge, to any person obtaining 13 | * a copy of this software and associated documentation files 14 | * (the "Software"), to deal in the Software without restriction, 15 | * including without limitation the rights to use, copy, modify, merge, 16 | * publish, distribute, sublicense, and/or sell copies of the Software, 17 | * and to permit persons to whom the Software is furnished to do so, 18 | * subject to the following conditions: 19 | * 20 | * The above copyright notice and this permission notice shall be 21 | * included in all copies or substantial portions of the Software. 22 | * 23 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 24 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 25 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 26 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR 27 | * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 28 | * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 29 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 30 | */ 31 | 32 | /* 33 | * The text above constitutes the entire PortAudio license; however, 34 | * the PortAudio community also makes the following non-binding requests: 35 | * 36 | * Any person wishing to distribute modifications to the Software is 37 | * requested to send the modifications to the original developer so that 38 | * they can be incorporated into the canonical version. It is also 39 | * requested that these non-binding requests be included along with the 40 | * license above. 41 | */ 42 | 43 | /** 44 | @file pa_memorybarrier.h 45 | @ingroup common_src 46 | */ 47 | 48 | /**************** 49 | * Some memory barrier primitives based on the system. 50 | * right now only OS X, FreeBSD, and Linux are supported. In addition to providing 51 | * memory barriers, these functions should ensure that data cached in registers 52 | * is written out to cache where it can be snooped by other CPUs. (ie, the volatile 53 | * keyword should not be required) 54 | * 55 | * the primitives that must be defined are: 56 | * 57 | * PaUtil_FullMemoryBarrier() 58 | * PaUtil_ReadMemoryBarrier() 59 | * PaUtil_WriteMemoryBarrier() 60 | * 61 | ****************/ 62 | 63 | #if defined(__APPLE__) 64 | # include 65 | /* Here are the memory barrier functions. Mac OS X only provides 66 | full memory barriers, so the three types of barriers are the same, 67 | however, these barriers are superior to compiler-based ones. */ 68 | # define PaUtil_FullMemoryBarrier() OSMemoryBarrier() 69 | # define PaUtil_ReadMemoryBarrier() OSMemoryBarrier() 70 | # define PaUtil_WriteMemoryBarrier() OSMemoryBarrier() 71 | #elif defined(__GNUC__) 72 | /* GCC >= 4.1 has built-in intrinsics. We'll use those */ 73 | # if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) 74 | # define PaUtil_FullMemoryBarrier() __sync_synchronize() 75 | # define PaUtil_ReadMemoryBarrier() __sync_synchronize() 76 | # define PaUtil_WriteMemoryBarrier() __sync_synchronize() 77 | /* as a fallback, GCC understands volatile asm and "memory" to mean it 78 | * should not reorder memory read/writes */ 79 | /* Note that it is not clear that any compiler actually defines __PPC__, 80 | * it can probably removed safely. */ 81 | # elif defined( __ppc__ ) || defined( __powerpc__) || defined( __PPC__ ) 82 | # define PaUtil_FullMemoryBarrier() asm volatile("sync":::"memory") 83 | # define PaUtil_ReadMemoryBarrier() asm volatile("sync":::"memory") 84 | # define PaUtil_WriteMemoryBarrier() asm volatile("sync":::"memory") 85 | # elif defined( __i386__ ) || defined( __i486__ ) || defined( __i586__ ) || \ 86 | defined( __i686__ ) || defined( __x86_64__ ) 87 | # define PaUtil_FullMemoryBarrier() asm volatile("mfence":::"memory") 88 | # define PaUtil_ReadMemoryBarrier() asm volatile("lfence":::"memory") 89 | # define PaUtil_WriteMemoryBarrier() asm volatile("sfence":::"memory") 90 | # else 91 | # ifdef ALLOW_SMP_DANGERS 92 | # warning Memory barriers not defined on this system or system unknown 93 | # warning For SMP safety, you should fix this. 94 | # define PaUtil_FullMemoryBarrier() 95 | # define PaUtil_ReadMemoryBarrier() 96 | # define PaUtil_WriteMemoryBarrier() 97 | # else 98 | # error Memory barriers are not defined on this system. You can still compile by defining ALLOW_SMP_DANGERS, but SMP safety will not be guaranteed. 99 | # endif 100 | # endif 101 | #elif (_MSC_VER >= 1400) && !defined(_WIN32_WCE) 102 | # include 103 | # pragma intrinsic(_ReadWriteBarrier) 104 | # pragma intrinsic(_ReadBarrier) 105 | # pragma intrinsic(_WriteBarrier) 106 | /* note that MSVC intrinsics _ReadWriteBarrier(), _ReadBarrier(), _WriteBarrier() are just compiler barriers *not* memory barriers */ 107 | # define PaUtil_FullMemoryBarrier() _ReadWriteBarrier() 108 | # define PaUtil_ReadMemoryBarrier() _ReadBarrier() 109 | # define PaUtil_WriteMemoryBarrier() _WriteBarrier() 110 | #elif defined(_WIN32_WCE) 111 | # define PaUtil_FullMemoryBarrier() 112 | # define PaUtil_ReadMemoryBarrier() 113 | # define PaUtil_WriteMemoryBarrier() 114 | #elif defined(_MSC_VER) || defined(__BORLANDC__) 115 | # define PaUtil_FullMemoryBarrier() _asm { lock add [esp], 0 } 116 | # define PaUtil_ReadMemoryBarrier() _asm { lock add [esp], 0 } 117 | # define PaUtil_WriteMemoryBarrier() _asm { lock add [esp], 0 } 118 | #else 119 | # ifdef ALLOW_SMP_DANGERS 120 | # warning Memory barriers not defined on this system or system unknown 121 | # warning For SMP safety, you should fix this. 122 | # define PaUtil_FullMemoryBarrier() 123 | # define PaUtil_ReadMemoryBarrier() 124 | # define PaUtil_WriteMemoryBarrier() 125 | # else 126 | # error Memory barriers are not defined on this system. You can still compile by defining ALLOW_SMP_DANGERS, but SMP safety will not be guaranteed. 127 | # endif 128 | #endif 129 | -------------------------------------------------------------------------------- /src/inc/pa_ringbuffer.h: -------------------------------------------------------------------------------- 1 | #ifndef PA_RINGBUFFER_H 2 | #define PA_RINGBUFFER_H 3 | /* 4 | * $Id$ 5 | * Portable Audio I/O Library 6 | * Ring Buffer utility. 7 | * 8 | * Author: Phil Burk, http://www.softsynth.com 9 | * modified for SMP safety on OS X by Bjorn Roche. 10 | * also allowed for const where possible. 11 | * modified for multiple-byte-sized data elements by Sven Fischer 12 | * 13 | * Note that this is safe only for a single-thread reader 14 | * and a single-thread writer. 15 | * 16 | * This program is distributed with the PortAudio Portable Audio Library. 17 | * For more information see: http://www.portaudio.com 18 | * Copyright (c) 1999-2000 Ross Bencina and Phil Burk 19 | * 20 | * Permission is hereby granted, free of charge, to any person obtaining 21 | * a copy of this software and associated documentation files 22 | * (the "Software"), to deal in the Software without restriction, 23 | * including without limitation the rights to use, copy, modify, merge, 24 | * publish, distribute, sublicense, and/or sell copies of the Software, 25 | * and to permit persons to whom the Software is furnished to do so, 26 | * subject to the following conditions: 27 | * 28 | * The above copyright notice and this permission notice shall be 29 | * included in all copies or substantial portions of the Software. 30 | * 31 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 32 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 33 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 34 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR 35 | * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 36 | * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 37 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 38 | */ 39 | 40 | /* 41 | * The text above constitutes the entire PortAudio license; however, 42 | * the PortAudio community also makes the following non-binding requests: 43 | * 44 | * Any person wishing to distribute modifications to the Software is 45 | * requested to send the modifications to the original developer so that 46 | * they can be incorporated into the canonical version. It is also 47 | * requested that these non-binding requests be included along with the 48 | * license above. 49 | */ 50 | 51 | /** @file 52 | @ingroup common_src 53 | @brief Single-reader single-writer lock-free ring buffer 54 | 55 | PaUtilRingBuffer is a ring buffer used to transport samples between 56 | different execution contexts (threads, OS callbacks, interrupt handlers) 57 | without requiring the use of any locks. This only works when there is 58 | a single reader and a single writer (ie. one thread or callback writes 59 | to the ring buffer, another thread or callback reads from it). 60 | 61 | The PaUtilRingBuffer structure manages a ring buffer containing N 62 | elements, where N must be a power of two. An element may be any size 63 | (specified in bytes). 64 | 65 | The memory area used to store the buffer elements must be allocated by 66 | the client prior to calling PaUtil_InitializeRingBuffer() and must outlive 67 | the use of the ring buffer. 68 | 69 | @note The ring buffer functions are not normally exposed in the PortAudio libraries. 70 | If you want to call them then you will need to add pa_ringbuffer.c to your application source code. 71 | */ 72 | 73 | #if defined(__APPLE__) 74 | #include 75 | typedef int32_t ring_buffer_size_t; 76 | #elif defined( __GNUC__ ) 77 | typedef long ring_buffer_size_t; 78 | #elif (_MSC_VER >= 1400) 79 | typedef long ring_buffer_size_t; 80 | #elif defined(_MSC_VER) || defined(__BORLANDC__) 81 | typedef long ring_buffer_size_t; 82 | #else 83 | typedef long ring_buffer_size_t; 84 | #endif 85 | 86 | 87 | 88 | #ifdef __cplusplus 89 | extern "C" 90 | { 91 | #endif /* __cplusplus */ 92 | 93 | typedef struct PaUtilRingBuffer 94 | { 95 | ring_buffer_size_t bufferSize; /**< Number of elements in FIFO. Power of 2. Set by PaUtil_InitRingBuffer. */ 96 | volatile ring_buffer_size_t writeIndex; /**< Index of next writable element. Set by PaUtil_AdvanceRingBufferWriteIndex. */ 97 | volatile ring_buffer_size_t readIndex; /**< Index of next readable element. Set by PaUtil_AdvanceRingBufferReadIndex. */ 98 | ring_buffer_size_t bigMask; /**< Used for wrapping indices with extra bit to distinguish full/empty. */ 99 | ring_buffer_size_t smallMask; /**< Used for fitting indices to buffer. */ 100 | ring_buffer_size_t elementSizeBytes; /**< Number of bytes per element. */ 101 | char *buffer; /**< Pointer to the buffer containing the actual data. */ 102 | }PaUtilRingBuffer; 103 | 104 | /** Initialize Ring Buffer to empty state ready to have elements written to it. 105 | 106 | @param rbuf The ring buffer. 107 | 108 | @param elementSizeBytes The size of a single data element in bytes. 109 | 110 | @param elementCount The number of elements in the buffer (must be a power of 2). 111 | 112 | @param dataPtr A pointer to a previously allocated area where the data 113 | will be maintained. It must be elementCount*elementSizeBytes long. 114 | 115 | @return -1 if elementCount is not a power of 2, otherwise 0. 116 | */ 117 | ring_buffer_size_t PaUtil_InitializeRingBuffer( PaUtilRingBuffer *rbuf, ring_buffer_size_t elementSizeBytes, ring_buffer_size_t elementCount, void *dataPtr ); 118 | 119 | /** Reset buffer to empty. Should only be called when buffer is NOT being read or written. 120 | 121 | @param rbuf The ring buffer. 122 | */ 123 | void PaUtil_FlushRingBuffer( PaUtilRingBuffer *rbuf ); 124 | 125 | /** Retrieve the number of elements available in the ring buffer for writing. 126 | 127 | @param rbuf The ring buffer. 128 | 129 | @return The number of elements available for writing. 130 | */ 131 | ring_buffer_size_t PaUtil_GetRingBufferWriteAvailable( const PaUtilRingBuffer *rbuf ); 132 | 133 | /** Retrieve the number of elements available in the ring buffer for reading. 134 | 135 | @param rbuf The ring buffer. 136 | 137 | @return The number of elements available for reading. 138 | */ 139 | ring_buffer_size_t PaUtil_GetRingBufferReadAvailable( const PaUtilRingBuffer *rbuf ); 140 | 141 | /** Write data to the ring buffer. 142 | 143 | @param rbuf The ring buffer. 144 | 145 | @param data The address of new data to write to the buffer. 146 | 147 | @param elementCount The number of elements to be written. 148 | 149 | @return The number of elements written. 150 | */ 151 | ring_buffer_size_t PaUtil_WriteRingBuffer( PaUtilRingBuffer *rbuf, const void *data, ring_buffer_size_t elementCount ); 152 | 153 | /** Read data from the ring buffer. 154 | 155 | @param rbuf The ring buffer. 156 | 157 | @param data The address where the data should be stored. 158 | 159 | @param elementCount The number of elements to be read. 160 | 161 | @return The number of elements read. 162 | */ 163 | ring_buffer_size_t PaUtil_ReadRingBuffer( PaUtilRingBuffer *rbuf, void *data, ring_buffer_size_t elementCount ); 164 | 165 | /** Get address of region(s) to which we can write data. 166 | 167 | @param rbuf The ring buffer. 168 | 169 | @param elementCount The number of elements desired. 170 | 171 | @param dataPtr1 The address where the first (or only) region pointer will be 172 | stored. 173 | 174 | @param sizePtr1 The address where the first (or only) region length will be 175 | stored. 176 | 177 | @param dataPtr2 The address where the second region pointer will be stored if 178 | the first region is too small to satisfy elementCount. 179 | 180 | @param sizePtr2 The address where the second region length will be stored if 181 | the first region is too small to satisfy elementCount. 182 | 183 | @return The room available to be written or elementCount, whichever is smaller. 184 | */ 185 | ring_buffer_size_t PaUtil_GetRingBufferWriteRegions( PaUtilRingBuffer *rbuf, ring_buffer_size_t elementCount, 186 | void **dataPtr1, ring_buffer_size_t *sizePtr1, 187 | void **dataPtr2, ring_buffer_size_t *sizePtr2 ); 188 | 189 | /** Advance the write index to the next location to be written. 190 | 191 | @param rbuf The ring buffer. 192 | 193 | @param elementCount The number of elements to advance. 194 | 195 | @return The new position. 196 | */ 197 | ring_buffer_size_t PaUtil_AdvanceRingBufferWriteIndex( PaUtilRingBuffer *rbuf, ring_buffer_size_t elementCount ); 198 | 199 | /** Get address of region(s) from which we can read data. 200 | 201 | @param rbuf The ring buffer. 202 | 203 | @param elementCount The number of elements desired. 204 | 205 | @param dataPtr1 The address where the first (or only) region pointer will be 206 | stored. 207 | 208 | @param sizePtr1 The address where the first (or only) region length will be 209 | stored. 210 | 211 | @param dataPtr2 The address where the second region pointer will be stored if 212 | the first region is too small to satisfy elementCount. 213 | 214 | @param sizePtr2 The address where the second region length will be stored if 215 | the first region is too small to satisfy elementCount. 216 | 217 | @return The number of elements available for reading. 218 | */ 219 | ring_buffer_size_t PaUtil_GetRingBufferReadRegions( PaUtilRingBuffer *rbuf, ring_buffer_size_t elementCount, 220 | void **dataPtr1, ring_buffer_size_t *sizePtr1, 221 | void **dataPtr2, ring_buffer_size_t *sizePtr2 ); 222 | 223 | /** Advance the read index to the next location to be read. 224 | 225 | @param rbuf The ring buffer. 226 | 227 | @param elementCount The number of elements to advance. 228 | 229 | @return The new position. 230 | */ 231 | ring_buffer_size_t PaUtil_AdvanceRingBufferReadIndex( PaUtilRingBuffer *rbuf, ring_buffer_size_t elementCount ); 232 | 233 | #ifdef __cplusplus 234 | } 235 | #endif /* __cplusplus */ 236 | #endif /* PA_RINGBUFFER_H */ 237 | -------------------------------------------------------------------------------- /src/inc/pa_stream.h: -------------------------------------------------------------------------------- 1 | #ifndef PA_STREAM_H 2 | #define PA_STREAM_H 3 | /* 4 | * $Id$ 5 | * Portable Audio I/O Library 6 | * stream interface 7 | * 8 | * Based on the Open Source API proposed by Ross Bencina 9 | * Copyright (c) 1999-2008 Ross Bencina, Phil Burk 10 | * 11 | * Permission is hereby granted, free of charge, to any person obtaining 12 | * a copy of this software and associated documentation files 13 | * (the "Software"), to deal in the Software without restriction, 14 | * including without limitation the rights to use, copy, modify, merge, 15 | * publish, distribute, sublicense, and/or sell copies of the Software, 16 | * and to permit persons to whom the Software is furnished to do so, 17 | * subject to the following conditions: 18 | * 19 | * The above copyright notice and this permission notice shall be 20 | * included in all copies or substantial portions of the Software. 21 | * 22 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 23 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 24 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 25 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR 26 | * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 27 | * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 28 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 29 | */ 30 | 31 | /* 32 | * The text above constitutes the entire PortAudio license; however, 33 | * the PortAudio community also makes the following non-binding requests: 34 | * 35 | * Any person wishing to distribute modifications to the Software is 36 | * requested to send the modifications to the original developer so that 37 | * they can be incorporated into the canonical version. It is also 38 | * requested that these non-binding requests be included along with the 39 | * license above. 40 | */ 41 | 42 | /** @file 43 | @ingroup common_src 44 | 45 | @brief Stream interfaces, representation structures and helper functions 46 | used to interface between pa_front.c host API implementations. 47 | */ 48 | 49 | 50 | #include "portaudio.h" 51 | 52 | #ifdef __cplusplus 53 | extern "C" 54 | { 55 | #endif /* __cplusplus */ 56 | 57 | 58 | #define PA_STREAM_MAGIC (0x18273645) 59 | 60 | 61 | /** A structure representing an (abstract) interface to a host API. Contains 62 | pointers to functions which implement the interface. 63 | 64 | All PaStreamInterface functions are guaranteed to be called with a non-null, 65 | valid stream parameter. 66 | */ 67 | typedef struct { 68 | PaError (*Close)( PaStream* stream ); 69 | PaError (*Start)( PaStream *stream ); 70 | PaError (*Stop)( PaStream *stream ); 71 | PaError (*Abort)( PaStream *stream ); 72 | PaError (*IsStopped)( PaStream *stream ); 73 | PaError (*IsActive)( PaStream *stream ); 74 | PaTime (*GetTime)( PaStream *stream ); 75 | double (*GetCpuLoad)( PaStream* stream ); 76 | PaError (*Read)( PaStream* stream, void *buffer, unsigned long frames ); 77 | PaError (*Write)( PaStream* stream, const void *buffer, unsigned long frames ); 78 | signed long (*GetReadAvailable)( PaStream* stream ); 79 | signed long (*GetWriteAvailable)( PaStream* stream ); 80 | } PaUtilStreamInterface; 81 | 82 | 83 | /** Initialize the fields of a PaUtilStreamInterface structure. 84 | */ 85 | void PaUtil_InitializeStreamInterface( PaUtilStreamInterface *streamInterface, 86 | PaError (*Close)( PaStream* ), 87 | PaError (*Start)( PaStream* ), 88 | PaError (*Stop)( PaStream* ), 89 | PaError (*Abort)( PaStream* ), 90 | PaError (*IsStopped)( PaStream* ), 91 | PaError (*IsActive)( PaStream* ), 92 | PaTime (*GetTime)( PaStream* ), 93 | double (*GetCpuLoad)( PaStream* ), 94 | PaError (*Read)( PaStream* stream, void *buffer, unsigned long frames ), 95 | PaError (*Write)( PaStream* stream, const void *buffer, unsigned long frames ), 96 | signed long (*GetReadAvailable)( PaStream* stream ), 97 | signed long (*GetWriteAvailable)( PaStream* stream ) ); 98 | 99 | 100 | /** Dummy Read function for use in interfaces to a callback based streams. 101 | Pass to the Read parameter of PaUtil_InitializeStreamInterface. 102 | @return An error code indicating that the function has no effect 103 | because the stream is a callback stream. 104 | */ 105 | PaError PaUtil_DummyRead( PaStream* stream, 106 | void *buffer, 107 | unsigned long frames ); 108 | 109 | 110 | /** Dummy Write function for use in an interfaces to callback based streams. 111 | Pass to the Write parameter of PaUtil_InitializeStreamInterface. 112 | @return An error code indicating that the function has no effect 113 | because the stream is a callback stream. 114 | */ 115 | PaError PaUtil_DummyWrite( PaStream* stream, 116 | const void *buffer, 117 | unsigned long frames ); 118 | 119 | 120 | /** Dummy GetReadAvailable function for use in interfaces to callback based 121 | streams. Pass to the GetReadAvailable parameter of PaUtil_InitializeStreamInterface. 122 | @return An error code indicating that the function has no effect 123 | because the stream is a callback stream. 124 | */ 125 | signed long PaUtil_DummyGetReadAvailable( PaStream* stream ); 126 | 127 | 128 | /** Dummy GetWriteAvailable function for use in interfaces to callback based 129 | streams. Pass to the GetWriteAvailable parameter of PaUtil_InitializeStreamInterface. 130 | @return An error code indicating that the function has no effect 131 | because the stream is a callback stream. 132 | */ 133 | signed long PaUtil_DummyGetWriteAvailable( PaStream* stream ); 134 | 135 | 136 | 137 | /** Dummy GetCpuLoad function for use in an interface to a read/write stream. 138 | Pass to the GetCpuLoad parameter of PaUtil_InitializeStreamInterface. 139 | @return Returns 0. 140 | */ 141 | double PaUtil_DummyGetCpuLoad( PaStream* stream ); 142 | 143 | 144 | /** Non host specific data for a stream. This data is used by pa_front to 145 | forward to the appropriate functions in the streamInterface structure. 146 | */ 147 | typedef struct PaUtilStreamRepresentation { 148 | unsigned long magic; /**< set to PA_STREAM_MAGIC */ 149 | struct PaUtilStreamRepresentation *nextOpenStream; /**< field used by multi-api code */ 150 | PaUtilStreamInterface *streamInterface; 151 | PaStreamCallback *streamCallback; 152 | PaStreamFinishedCallback *streamFinishedCallback; 153 | void *userData; 154 | PaStreamInfo streamInfo; 155 | } PaUtilStreamRepresentation; 156 | 157 | 158 | /** Initialize a PaUtilStreamRepresentation structure. 159 | 160 | @see PaUtil_InitializeStreamRepresentation 161 | */ 162 | void PaUtil_InitializeStreamRepresentation( 163 | PaUtilStreamRepresentation *streamRepresentation, 164 | PaUtilStreamInterface *streamInterface, 165 | PaStreamCallback *streamCallback, 166 | void *userData ); 167 | 168 | 169 | /** Clean up a PaUtilStreamRepresentation structure previously initialized 170 | by a call to PaUtil_InitializeStreamRepresentation. 171 | 172 | @see PaUtil_InitializeStreamRepresentation 173 | */ 174 | void PaUtil_TerminateStreamRepresentation( PaUtilStreamRepresentation *streamRepresentation ); 175 | 176 | 177 | /** Check that the stream pointer is valid. 178 | 179 | @return Returns paNoError if the stream pointer appears to be OK, otherwise 180 | returns an error indicating the cause of failure. 181 | */ 182 | PaError PaUtil_ValidateStreamPointer( PaStream *stream ); 183 | 184 | 185 | /** Cast an opaque stream pointer into a pointer to a PaUtilStreamRepresentation. 186 | 187 | @see PaUtilStreamRepresentation 188 | */ 189 | #define PA_STREAM_REP( stream )\ 190 | ((PaUtilStreamRepresentation*) (stream) ) 191 | 192 | 193 | /** Cast an opaque stream pointer into a pointer to a PaUtilStreamInterface. 194 | 195 | @see PaUtilStreamRepresentation, PaUtilStreamInterface 196 | */ 197 | #define PA_STREAM_INTERFACE( stream )\ 198 | PA_STREAM_REP( (stream) )->streamInterface 199 | 200 | 201 | 202 | #ifdef __cplusplus 203 | } 204 | #endif /* __cplusplus */ 205 | #endif /* PA_STREAM_H */ 206 | -------------------------------------------------------------------------------- /src/inc/pa_trace.h: -------------------------------------------------------------------------------- 1 | #ifndef PA_TRACE_H 2 | #define PA_TRACE_H 3 | /* 4 | * $Id$ 5 | * Portable Audio I/O Library Trace Facility 6 | * Store trace information in real-time for later printing. 7 | * 8 | * Based on the Open Source API proposed by Ross Bencina 9 | * Copyright (c) 1999-2000 Phil Burk 10 | * 11 | * Permission is hereby granted, free of charge, to any person obtaining 12 | * a copy of this software and associated documentation files 13 | * (the "Software"), to deal in the Software without restriction, 14 | * including without limitation the rights to use, copy, modify, merge, 15 | * publish, distribute, sublicense, and/or sell copies of the Software, 16 | * and to permit persons to whom the Software is furnished to do so, 17 | * subject to the following conditions: 18 | * 19 | * The above copyright notice and this permission notice shall be 20 | * included in all copies or substantial portions of the Software. 21 | * 22 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 23 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 24 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 25 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR 26 | * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 27 | * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 28 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 29 | */ 30 | 31 | /* 32 | * The text above constitutes the entire PortAudio license; however, 33 | * the PortAudio community also makes the following non-binding requests: 34 | * 35 | * Any person wishing to distribute modifications to the Software is 36 | * requested to send the modifications to the original developer so that 37 | * they can be incorporated into the canonical version. It is also 38 | * requested that these non-binding requests be included along with the 39 | * license above. 40 | */ 41 | 42 | /** @file 43 | @ingroup common_src 44 | 45 | @brief Real-time safe event trace logging facility for debugging. 46 | 47 | Allows data to be logged to a fixed size trace buffer in a real-time 48 | execution context (such as at interrupt time). Each log entry consists 49 | of a message comprising a string pointer and an int. The trace buffer 50 | may be dumped to stdout later. 51 | 52 | This facility is only active if PA_TRACE_REALTIME_EVENTS is set to 1, 53 | otherwise the trace functions expand to no-ops. 54 | 55 | @fn PaUtil_ResetTraceMessages 56 | @brief Clear the trace buffer. 57 | 58 | @fn PaUtil_AddTraceMessage 59 | @brief Add a message to the trace buffer. A message consists of string and an int. 60 | @param msg The string pointer must remain valid until PaUtil_DumpTraceMessages 61 | is called. As a result, usually only string literals should be passed as 62 | the msg parameter. 63 | 64 | @fn PaUtil_DumpTraceMessages 65 | @brief Print all messages in the trace buffer to stdout and clear the trace buffer. 66 | */ 67 | 68 | #ifndef PA_TRACE_REALTIME_EVENTS 69 | #define PA_TRACE_REALTIME_EVENTS (0) /**< Set to 1 to enable logging using the trace functions defined below */ 70 | #endif 71 | 72 | #ifndef PA_MAX_TRACE_RECORDS 73 | #define PA_MAX_TRACE_RECORDS (2048) /**< Maximum number of records stored in trace buffer */ 74 | #endif 75 | 76 | #ifdef __cplusplus 77 | extern "C" 78 | { 79 | #endif /* __cplusplus */ 80 | 81 | 82 | #if PA_TRACE_REALTIME_EVENTS 83 | 84 | void PaUtil_ResetTraceMessages(); 85 | void PaUtil_AddTraceMessage( const char *msg, int data ); 86 | void PaUtil_DumpTraceMessages(); 87 | 88 | /* Alternative interface */ 89 | 90 | typedef void* LogHandle; 91 | 92 | int PaUtil_InitializeHighSpeedLog(LogHandle* phLog, unsigned maxSizeInBytes); 93 | void PaUtil_ResetHighSpeedLogTimeRef(LogHandle hLog); 94 | int PaUtil_AddHighSpeedLogMessage(LogHandle hLog, const char* fmt, ...); 95 | void PaUtil_DumpHighSpeedLog(LogHandle hLog, const char* fileName); 96 | void PaUtil_DiscardHighSpeedLog(LogHandle hLog); 97 | 98 | #else 99 | 100 | #define PaUtil_ResetTraceMessages() /* noop */ 101 | #define PaUtil_AddTraceMessage(msg,data) /* noop */ 102 | #define PaUtil_DumpTraceMessages() /* noop */ 103 | 104 | #define PaUtil_InitializeHighSpeedLog(phLog, maxSizeInBytes) (0) 105 | #define PaUtil_ResetHighSpeedLogTimeRef(hLog) 106 | #define PaUtil_AddHighSpeedLogMessage(...) (0) 107 | #define PaUtil_DumpHighSpeedLog(hLog, fileName) 108 | #define PaUtil_DiscardHighSpeedLog(hLog) 109 | 110 | #endif 111 | 112 | 113 | #ifdef __cplusplus 114 | } 115 | #endif /* __cplusplus */ 116 | 117 | #endif /* PA_TRACE_H */ 118 | -------------------------------------------------------------------------------- /src/inc/pa_types.h: -------------------------------------------------------------------------------- 1 | #ifndef PA_TYPES_H 2 | #define PA_TYPES_H 3 | 4 | /* 5 | * Portable Audio I/O Library 6 | * integer type definitions 7 | * 8 | * Based on the Open Source API proposed by Ross Bencina 9 | * Copyright (c) 1999-2006 Ross Bencina, Phil Burk 10 | * 11 | * Permission is hereby granted, free of charge, to any person obtaining 12 | * a copy of this software and associated documentation files 13 | * (the "Software"), to deal in the Software without restriction, 14 | * including without limitation the rights to use, copy, modify, merge, 15 | * publish, distribute, sublicense, and/or sell copies of the Software, 16 | * and to permit persons to whom the Software is furnished to do so, 17 | * subject to the following conditions: 18 | * 19 | * The above copyright notice and this permission notice shall be 20 | * included in all copies or substantial portions of the Software. 21 | * 22 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 23 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 24 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 25 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR 26 | * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 27 | * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 28 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 29 | */ 30 | 31 | /* 32 | * The text above constitutes the entire PortAudio license; however, 33 | * the PortAudio community also makes the following non-binding requests: 34 | * 35 | * Any person wishing to distribute modifications to the Software is 36 | * requested to send the modifications to the original developer so that 37 | * they can be incorporated into the canonical version. It is also 38 | * requested that these non-binding requests be included along with the 39 | * license above. 40 | */ 41 | 42 | /** @file 43 | @ingroup common_src 44 | 45 | @brief Definition of 16 and 32 bit integer types (PaInt16, PaInt32 etc) 46 | 47 | SIZEOF_SHORT, SIZEOF_INT and SIZEOF_LONG are set by the configure script 48 | when it is used. Otherwise we default to the common 32 bit values, if your 49 | platform doesn't use configure, and doesn't use the default values below 50 | you will need to explicitly define these symbols in your make file. 51 | 52 | A PA_VALIDATE_SIZES macro is provided to assert that the values set in this 53 | file are correct. 54 | */ 55 | 56 | #ifndef SIZEOF_SHORT 57 | #define SIZEOF_SHORT 2 58 | #endif 59 | 60 | #ifndef SIZEOF_INT 61 | #define SIZEOF_INT 4 62 | #endif 63 | 64 | #ifndef SIZEOF_LONG 65 | #define SIZEOF_LONG 4 66 | #endif 67 | 68 | 69 | #if SIZEOF_SHORT == 2 70 | typedef signed short PaInt16; 71 | typedef unsigned short PaUint16; 72 | #elif SIZEOF_INT == 2 73 | typedef signed int PaInt16; 74 | typedef unsigned int PaUint16; 75 | #else 76 | #error pa_types.h was unable to determine which type to use for 16bit integers on the target platform 77 | #endif 78 | 79 | #if SIZEOF_SHORT == 4 80 | typedef signed short PaInt32; 81 | typedef unsigned short PaUint32; 82 | #elif SIZEOF_INT == 4 83 | typedef signed int PaInt32; 84 | typedef unsigned int PaUint32; 85 | #elif SIZEOF_LONG == 4 86 | typedef signed long PaInt32; 87 | typedef unsigned long PaUint32; 88 | #else 89 | #error pa_types.h was unable to determine which type to use for 32bit integers on the target platform 90 | #endif 91 | 92 | 93 | /* PA_VALIDATE_TYPE_SIZES compares the size of the integer types at runtime to 94 | ensure that PortAudio was configured correctly, and raises an assertion if 95 | they don't match the expected values. must be included in the 96 | context in which this macro is used. 97 | */ 98 | #define PA_VALIDATE_TYPE_SIZES \ 99 | { \ 100 | assert( "PortAudio: type sizes are not correct in pa_types.h" && sizeof( PaUint16 ) == 2 ); \ 101 | assert( "PortAudio: type sizes are not correct in pa_types.h" && sizeof( PaInt16 ) == 2 ); \ 102 | assert( "PortAudio: type sizes are not correct in pa_types.h" && sizeof( PaUint32 ) == 4 ); \ 103 | assert( "PortAudio: type sizes are not correct in pa_types.h" && sizeof( PaInt32 ) == 4 ); \ 104 | } 105 | 106 | 107 | #endif /* PA_TYPES_H */ 108 | -------------------------------------------------------------------------------- /src/inc/pa_unix_util.h: -------------------------------------------------------------------------------- 1 | /* 2 | * $Id$ 3 | * Portable Audio I/O Library 4 | * UNIX platform-specific support functions 5 | * 6 | * Based on the Open Source API proposed by Ross Bencina 7 | * Copyright (c) 1999-2000 Ross Bencina 8 | * 9 | * Permission is hereby granted, free of charge, to any person obtaining 10 | * a copy of this software and associated documentation files 11 | * (the "Software"), to deal in the Software without restriction, 12 | * including without limitation the rights to use, copy, modify, merge, 13 | * publish, distribute, sublicense, and/or sell copies of the Software, 14 | * and to permit persons to whom the Software is furnished to do so, 15 | * subject to the following conditions: 16 | * 17 | * The above copyright notice and this permission notice shall be 18 | * included in all copies or substantial portions of the Software. 19 | * 20 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 22 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 23 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR 24 | * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 25 | * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 26 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 27 | */ 28 | 29 | /* 30 | * The text above constitutes the entire PortAudio license; however, 31 | * the PortAudio community also makes the following non-binding requests: 32 | * 33 | * Any person wishing to distribute modifications to the Software is 34 | * requested to send the modifications to the original developer so that 35 | * they can be incorporated into the canonical version. It is also 36 | * requested that these non-binding requests be included along with the 37 | * license above. 38 | */ 39 | 40 | /** @file 41 | @ingroup unix_src 42 | */ 43 | 44 | #ifndef PA_UNIX_UTIL_H 45 | #define PA_UNIX_UTIL_H 46 | 47 | #include "pa_cpuload.h" 48 | #include 49 | #include 50 | #include 51 | 52 | #ifdef __cplusplus 53 | extern "C" 54 | { 55 | #endif /* __cplusplus */ 56 | 57 | #define PA_MIN(x,y) ( (x) < (y) ? (x) : (y) ) 58 | #define PA_MAX(x,y) ( (x) > (y) ? (x) : (y) ) 59 | 60 | /* Utilize GCC branch prediction for error tests */ 61 | #if defined __GNUC__ && __GNUC__ >= 3 62 | #define UNLIKELY(expr) __builtin_expect( (expr), 0 ) 63 | #else 64 | #define UNLIKELY(expr) (expr) 65 | #endif 66 | 67 | #define STRINGIZE_HELPER(expr) #expr 68 | #define STRINGIZE(expr) STRINGIZE_HELPER(expr) 69 | 70 | #define PA_UNLESS(expr, code) \ 71 | do { \ 72 | if( UNLIKELY( (expr) == 0 ) ) \ 73 | { \ 74 | PaUtil_DebugPrint(( "Expression '" #expr "' failed in '" __FILE__ "', line: " STRINGIZE( __LINE__ ) "\n" )); \ 75 | result = (code); \ 76 | goto error; \ 77 | } \ 78 | } while (0); 79 | 80 | static PaError paUtilErr_; /* Used with PA_ENSURE */ 81 | 82 | /* Check PaError */ 83 | #define PA_ENSURE(expr) \ 84 | do { \ 85 | if( UNLIKELY( (paUtilErr_ = (expr)) < paNoError ) ) \ 86 | { \ 87 | PaUtil_DebugPrint(( "Expression '" #expr "' failed in '" __FILE__ "', line: " STRINGIZE( __LINE__ ) "\n" )); \ 88 | result = paUtilErr_; \ 89 | goto error; \ 90 | } \ 91 | } while (0); 92 | 93 | #define PA_ASSERT_CALL(expr, success) \ 94 | paUtilErr_ = (expr); \ 95 | assert( success == paUtilErr_ ); 96 | 97 | #define PA_ENSURE_SYSTEM(expr, success) \ 98 | do { \ 99 | if( UNLIKELY( (paUtilErr_ = (expr)) != success ) ) \ 100 | { \ 101 | /* PaUtil_SetLastHostErrorInfo should only be used in the main thread */ \ 102 | if( pthread_equal(pthread_self(), paUnixMainThread) ) \ 103 | { \ 104 | PaUtil_SetLastHostErrorInfo( paALSA, paUtilErr_, strerror( paUtilErr_ ) ); \ 105 | } \ 106 | PaUtil_DebugPrint( "Expression '" #expr "' failed in '" __FILE__ "', line: " STRINGIZE( __LINE__ ) "\n" ); \ 107 | result = paUnanticipatedHostError; \ 108 | goto error; \ 109 | } \ 110 | } while( 0 ); 111 | 112 | typedef struct { 113 | pthread_t callbackThread; 114 | } PaUtilThreading; 115 | 116 | PaError PaUtil_InitializeThreading( PaUtilThreading *threading ); 117 | void PaUtil_TerminateThreading( PaUtilThreading *threading ); 118 | PaError PaUtil_StartThreading( PaUtilThreading *threading, void *(*threadRoutine)(void *), void *data ); 119 | PaError PaUtil_CancelThreading( PaUtilThreading *threading, int wait, PaError *exitResult ); 120 | 121 | /* State accessed by utility functions */ 122 | 123 | /* 124 | void PaUnix_SetRealtimeScheduling( int rt ); 125 | 126 | void PaUtil_InitializeThreading( PaUtilThreading *th, PaUtilCpuLoadMeasurer *clm ); 127 | 128 | PaError PaUtil_CreateCallbackThread( PaUtilThreading *th, void *(*CallbackThreadFunc)( void * ), PaStream *s ); 129 | 130 | PaError PaUtil_KillCallbackThread( PaUtilThreading *th, PaError *exitResult ); 131 | 132 | void PaUtil_CallbackUpdate( PaUtilThreading *th ); 133 | */ 134 | 135 | extern pthread_t paUnixMainThread; 136 | 137 | typedef struct 138 | { 139 | pthread_mutex_t mtx; 140 | } PaUnixMutex; 141 | 142 | PaError PaUnixMutex_Initialize( PaUnixMutex* self ); 143 | PaError PaUnixMutex_Terminate( PaUnixMutex* self ); 144 | PaError PaUnixMutex_Lock( PaUnixMutex* self ); 145 | PaError PaUnixMutex_Unlock( PaUnixMutex* self ); 146 | 147 | typedef struct 148 | { 149 | pthread_t thread; 150 | int parentWaiting; 151 | int stopRequested; 152 | int locked; 153 | PaUnixMutex mtx; 154 | pthread_cond_t cond; 155 | volatile sig_atomic_t stopRequest; 156 | } PaUnixThread; 157 | 158 | /** Initialize global threading state. 159 | */ 160 | PaError PaUnixThreading_Initialize(); 161 | 162 | /** Perish, passing on eventual error code. 163 | * 164 | * A thin wrapper around pthread_exit, will automatically pass on any error code to the joining thread. 165 | * If the result indicates an error, i.e. it is not equal to paNoError, this function will automatically 166 | * allocate a pointer so the error is passed on with pthread_exit. If the result indicates that all is 167 | * well however, only a NULL pointer will be handed to pthread_exit. Thus, the joining thread should 168 | * check whether a non-NULL result pointer is obtained from pthread_join and make sure to free it. 169 | * @param result: The error code to pass on to the joining thread. 170 | */ 171 | #define PaUnixThreading_EXIT(result) \ 172 | do { \ 173 | PaError* pres = NULL; \ 174 | if( paNoError != (result) ) \ 175 | { \ 176 | pres = malloc( sizeof (PaError) ); \ 177 | *pres = (result); \ 178 | } \ 179 | pthread_exit( pres ); \ 180 | } while (0); 181 | 182 | /** Spawn a thread. 183 | * 184 | * Intended for spawning the callback thread from the main thread. This function can even block (for a certain 185 | * time or indefinitely) untill notified by the callback thread (using PaUnixThread_NotifyParent), which can be 186 | * useful in order to make sure that callback has commenced before returning from Pa_StartStream. 187 | * @param threadFunc: The function to be executed in the child thread. 188 | * @param waitForChild: If not 0, wait for child thread to call PaUnixThread_NotifyParent. Less than 0 means 189 | * wait for ever, greater than 0 wait for the specified time. 190 | * @param rtSched: Enable realtime scheduling? 191 | * @return: If timed out waiting on child, paTimedOut. 192 | */ 193 | PaError PaUnixThread_New( PaUnixThread* self, void* (*threadFunc)( void* ), void* threadArg, PaTime waitForChild, 194 | int rtSched ); 195 | 196 | /** Terminate thread. 197 | * 198 | * @param wait: If true, request that background thread stop and wait untill it does, else cancel it. 199 | * @param exitResult: If non-null this will upon return contain the exit status of the thread. 200 | */ 201 | PaError PaUnixThread_Terminate( PaUnixThread* self, int wait, PaError* exitResult ); 202 | 203 | /** Prepare to notify waiting parent thread. 204 | * 205 | * An internal lock must be held before the parent is notified in PaUnixThread_NotifyParent, call this to 206 | * acquire it beforehand. 207 | * @return: If parent is not waiting, paInternalError. 208 | */ 209 | PaError PaUnixThread_PrepareNotify( PaUnixThread* self ); 210 | 211 | /** Notify waiting parent thread. 212 | * 213 | * @return: If parent timed out waiting, paTimedOut. If parent was never waiting, paInternalError. 214 | */ 215 | PaError PaUnixThread_NotifyParent( PaUnixThread* self ); 216 | 217 | /** Has the parent thread requested this thread to stop? 218 | */ 219 | int PaUnixThread_StopRequested( PaUnixThread* self ); 220 | 221 | #ifdef __cplusplus 222 | } 223 | #endif /* __cplusplus */ 224 | #endif 225 | -------------------------------------------------------------------------------- /src/inc/pa_util.h: -------------------------------------------------------------------------------- 1 | #ifndef PA_UTIL_H 2 | #define PA_UTIL_H 3 | /* 4 | * $Id$ 5 | * Portable Audio I/O Library implementation utilities header 6 | * common implementation utilities and interfaces 7 | * 8 | * Based on the Open Source API proposed by Ross Bencina 9 | * Copyright (c) 1999-2008 Ross Bencina, Phil Burk 10 | * 11 | * Permission is hereby granted, free of charge, to any person obtaining 12 | * a copy of this software and associated documentation files 13 | * (the "Software"), to deal in the Software without restriction, 14 | * including without limitation the rights to use, copy, modify, merge, 15 | * publish, distribute, sublicense, and/or sell copies of the Software, 16 | * and to permit persons to whom the Software is furnished to do so, 17 | * subject to the following conditions: 18 | * 19 | * The above copyright notice and this permission notice shall be 20 | * included in all copies or substantial portions of the Software. 21 | * 22 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 23 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 24 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 25 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR 26 | * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 27 | * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 28 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 29 | */ 30 | 31 | /* 32 | * The text above constitutes the entire PortAudio license; however, 33 | * the PortAudio community also makes the following non-binding requests: 34 | * 35 | * Any person wishing to distribute modifications to the Software is 36 | * requested to send the modifications to the original developer so that 37 | * they can be incorporated into the canonical version. It is also 38 | * requested that these non-binding requests be included along with the 39 | * license above. 40 | */ 41 | 42 | /** @file 43 | @ingroup common_src 44 | 45 | @brief Prototypes for utility functions used by PortAudio implementations. 46 | 47 | Some functions declared here are defined in pa_front.c while others 48 | are implemented separately for each platform. 49 | */ 50 | 51 | 52 | #include "portaudio.h" 53 | 54 | #ifdef __cplusplus 55 | extern "C" 56 | { 57 | #endif /* __cplusplus */ 58 | 59 | 60 | struct PaUtilHostApiRepresentation; 61 | 62 | 63 | /** Retrieve a specific host API representation. This function can be used 64 | by implementations to retrieve a pointer to their representation in 65 | host api specific extension functions which aren't passed a rep pointer 66 | by pa_front.c. 67 | 68 | @param hostApi A pointer to a host API represenation pointer. Apon success 69 | this will receive the requested representation pointer. 70 | 71 | @param type A valid host API type identifier. 72 | 73 | @returns An error code. If the result is PaNoError then a pointer to the 74 | requested host API representation will be stored in *hostApi. If the host API 75 | specified by type is not found, this function returns paHostApiNotFound. 76 | */ 77 | PaError PaUtil_GetHostApiRepresentation( struct PaUtilHostApiRepresentation **hostApi, 78 | PaHostApiTypeId type ); 79 | 80 | 81 | /** Convert a PortAudio device index into a host API specific device index. 82 | @param hostApiDevice Pointer to a device index, on success this will recieve the 83 | converted device index value. 84 | @param device The PortAudio device index to convert. 85 | @param hostApi The host api which the index should be converted for. 86 | 87 | @returns On success returns PaNoError and places the converted index in the 88 | hostApiDevice parameter. 89 | */ 90 | PaError PaUtil_DeviceIndexToHostApiDeviceIndex( 91 | PaDeviceIndex *hostApiDevice, PaDeviceIndex device, 92 | struct PaUtilHostApiRepresentation *hostApi ); 93 | 94 | 95 | /** Set the host error information returned by Pa_GetLastHostErrorInfo. This 96 | function and the paUnanticipatedHostError error code should be used as a 97 | last resort. Implementors should use existing PA error codes where possible, 98 | or nominate new ones. Note that at it is always better to use 99 | PaUtil_SetLastHostErrorInfo() and paUnanticipatedHostError than to return an 100 | ambiguous or inaccurate PaError code. 101 | 102 | @param hostApiType The host API which encountered the error (ie of the caller) 103 | 104 | @param errorCode The error code returned by the native API function. 105 | 106 | @param errorText A string describing the error. PaUtil_SetLastHostErrorInfo 107 | makes a copy of the string, so it is not necessary for the pointer to remain 108 | valid after the call to PaUtil_SetLastHostErrorInfo() returns. 109 | 110 | */ 111 | void PaUtil_SetLastHostErrorInfo( PaHostApiTypeId hostApiType, long errorCode, 112 | const char *errorText ); 113 | 114 | 115 | 116 | /* the following functions are implemented in a platform platform specific 117 | .c file 118 | */ 119 | 120 | /** Allocate size bytes, guaranteed to be aligned to a FIXME byte boundary */ 121 | void *PaUtil_AllocateMemory( long size ); 122 | 123 | 124 | /** Realease block if non-NULL. block may be NULL */ 125 | void PaUtil_FreeMemory( void *block ); 126 | 127 | 128 | /** Return the number of currently allocated blocks. This function can be 129 | used for detecting memory leaks. 130 | 131 | @note Allocations will only be tracked if PA_TRACK_MEMORY is #defined. If 132 | it isn't, this function will always return 0. 133 | */ 134 | int PaUtil_CountCurrentlyAllocatedBlocks( void ); 135 | 136 | 137 | /** Initialize the clock used by PaUtil_GetTime(). Call this before calling 138 | PaUtil_GetTime. 139 | 140 | @see PaUtil_GetTime 141 | */ 142 | void PaUtil_InitializeClock( void ); 143 | 144 | 145 | /** Return the system time in seconds. Used to implement CPU load functions 146 | 147 | @see PaUtil_InitializeClock 148 | */ 149 | double PaUtil_GetTime( void ); 150 | 151 | 152 | /* void Pa_Sleep( long msec ); must also be implemented in per-platform .c file */ 153 | 154 | 155 | 156 | #ifdef __cplusplus 157 | } 158 | #endif /* __cplusplus */ 159 | #endif /* PA_UTIL_H */ 160 | -------------------------------------------------------------------------------- /src/inc/video.h: -------------------------------------------------------------------------------- 1 | #ifndef VIDEO_H 2 | #define VIDEO_H 3 | 4 | typedef struct { 5 | int width; 6 | int height; 7 | int depth; 8 | int disp_bandwidth; 9 | int render_type; 10 | unsigned long refresh_rate; 11 | int intensity_threshold; 12 | double saturation; 13 | int monochrome; 14 | char r; char g; char b; 15 | char *ascii_values; 16 | int edge_filter; int edge_lower; int edge_upper; 17 | } vid_options_t; 18 | 19 | void video_shutdown(int signal); 20 | 21 | int start_video(char *peer, char *port, vid_options_t *vopt); 22 | 23 | #endif /* VIDEO_H */ 24 | -------------------------------------------------------------------------------- /src/p2plib.c: -------------------------------------------------------------------------------- 1 | /* @file p2plib.c 2 | * @brief Implements p2plib. 3 | */ 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #define UDP_FLAGS 0 18 | #define BANDWIDTH_BUFLEN 1024 19 | 20 | static struct timespec prevPacket, currPacket; 21 | static long delta = -1; 22 | static unsigned int bandwidth_index; 23 | static double bandwidth_buf[BANDWIDTH_BUFLEN]; 24 | 25 | /* @brief gives the bandwidth for a given packet size 26 | * @return a double that represents the bandwidth in bytes/nanoseconds 27 | */ 28 | double p2p_bandwidth() { 29 | double tot = 0; 30 | unsigned int i = 0; 31 | for (i = 0; i < BANDWIDTH_BUFLEN; i++) { 32 | tot += bandwidth_buf[i]; 33 | } 34 | return tot/BANDWIDTH_BUFLEN; 35 | } 36 | 37 | 38 | /* @brief tells if a packet is used for p2p reasons 39 | * @param con who sent the data 40 | * @param data is the data 41 | * @param datasize is data size 42 | * @param cons current peer's connections (to append if CONS_HEADER) 43 | * @param conslen 44 | * @return 1 if its a p2plib packet else 0 45 | */ 46 | int p2p_data(connection_t *con, void *data, size_t datasize, 47 | connection_t **cons, size_t *conslen) { 48 | 49 | if (P2P_HEADER != ((p2p_header_t *)data)->check) { 50 | return 0; 51 | } 52 | 53 | if (((p2p_header_t *)data)->act == PASS_HEADER) { 54 | /*XXX we can just use sum bytes for this as well */ 55 | char msg[32] = "password already sent"; 56 | p2p_send(con, msg, 20); 57 | } else if (((p2p_header_t *)data)->act == CONS_HEADER) { 58 | size_t h_cons, i; 59 | 60 | memcpy(&h_cons, data + sizeof(p2p_header_t), sizeof(size_t)); 61 | 62 | *cons = realloc(*cons, (*conslen + h_cons)); 63 | 64 | /* copy the connection_ts into the library */ 65 | for (i=0; isocket = socket(curr_addr->ai_family, curr_addr->ai_socktype, curr_addr->ai_protocol); 103 | if (con->socket > 0) { 104 | break; 105 | } 106 | curr_addr = curr_addr->ai_next; 107 | } 108 | 109 | if (curr_addr == NULL) { 110 | fprintf(stderr, "unable to find a server in create_client\n"); 111 | freeaddrinfo(possible_addrs); 112 | return (ENOTCONN); 113 | } 114 | 115 | int port; 116 | sscanf(server_port, "%d", &port); 117 | con->addr.sin_family = curr_addr->ai_family; 118 | con->addr.sin_port = htons(port); 119 | 120 | if (curr_addr->ai_family == AF_INET) { 121 | memcpy((void *)&con->addr.sin_addr, &((struct sockaddr_in *)curr_addr->ai_addr)->sin_addr, curr_addr->ai_addrlen); 122 | } else { 123 | fprintf(stderr, "Unable to use ai_family returned."); 124 | freeaddrinfo(possible_addrs); 125 | return (EINVAL); 126 | } 127 | 128 | /* TODO why does this need to be commented out? */ 129 | //freeaddrinfo(possible_addrs); 130 | con->addr_len = sizeof(con->addr); 131 | 132 | return 0; 133 | } 134 | 135 | /* @brief Create a server that can cold up to max_connections. 136 | * @param port The port to initialize on. 137 | * @param sockfd A reference to populate once the socket is initialized. 138 | * @return An errno or 0 on success. 139 | */ 140 | int p2p_init(int port, int *sockfd) { 141 | int _sockfd_local; 142 | struct sockaddr_in me; 143 | 144 | /* create socket */ 145 | if ((_sockfd_local = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) { 146 | fprintf(stderr, "error in opening socket: %s\n", strerror(errno)); 147 | return (errno); 148 | } 149 | 150 | /* If caller wants, populate socket fd */ 151 | 152 | if (sockfd != NULL) { 153 | *sockfd = _sockfd_local; 154 | } 155 | 156 | /* XXX: Make sure these fields are OK, possibly switch to variables.*/ 157 | memset(&me, 0, sizeof(me)); 158 | me.sin_family = AF_INET; 159 | me.sin_port = htons(port); 160 | me.sin_addr.s_addr = htonl(INADDR_ANY); 161 | 162 | if (bind(_sockfd_local, (struct sockaddr *)&me, sizeof(me)) == -1) { 163 | fprintf(stderr, "error in binding socket: %s\n", strerror(errno)); 164 | return (errno); 165 | } 166 | 167 | /* success */ 168 | return 0; 169 | } 170 | 171 | 172 | int p2p_send_pass(connection_t *con, char *password) { 173 | p2p_header_t head; 174 | head.act = PASS_HEADER; 175 | head.check = P2P_HEADER; 176 | 177 | size_t sendbufsize = strlen(password) + 1 + sizeof(p2p_header_t); 178 | void *sendbuf = malloc(sendbufsize); 179 | 180 | memcpy(sendbuf, &head, sizeof(p2p_header_t)); 181 | memcpy(sendbuf + sizeof(p2p_header_t), password, strlen(password) + 1); 182 | 183 | int rv = p2p_send(con, sendbuf, sendbufsize); 184 | 185 | free(sendbuf); 186 | return (rv); 187 | } 188 | 189 | int p2p_send_conns(connection_t *con, connection_t *cons, size_t conslen) { 190 | size_t i; 191 | p2p_header_t head; 192 | head.act = CONS_HEADER; 193 | head.check = P2P_HEADER; 194 | 195 | size_t sendbufsize = sizeof(size_t) + sizeof(p2p_header_t) + conslen * sizeof(connection_t); 196 | void *sendbuf = malloc(sendbufsize); 197 | 198 | memcpy(sendbuf, &head, sizeof(p2p_header_t)); 199 | memcpy(sendbuf + sizeof(p2p_header_t), &conslen, sizeof(size_t)); 200 | 201 | for (i=0; isocket, buf, buflen, UDP_FLAGS, (struct sockaddr *)&con->addr, con->addr_len); 219 | } 220 | 221 | /* @brief Send data to all connections. 222 | * @param cons A reference to a connection array. 223 | * @param conslen A reference to the length of the connection array. 224 | * @param consmutex A mutex to access the connection array. 225 | * @param buf The data to send. 226 | * @param buflen The length of the data to send. 227 | * @return Negative value on error, 0 on success. 228 | */ 229 | int p2p_broadcast(connection_t **cons, size_t *conslen, pthread_mutex_t *consmutex, const void *buf, size_t buflen) { 230 | if(consmutex) { 231 | pthread_mutex_lock(consmutex); 232 | } 233 | 234 | int i; 235 | for (i = 0; i < *conslen; i++) { 236 | p2p_send(&((*cons)[i]), buf, buflen); 237 | } 238 | 239 | if(consmutex) { 240 | pthread_mutex_unlock(consmutex); 241 | } 242 | return 0; 243 | } 244 | 245 | /* @brief Initialize a listener. 246 | * @param cons A reference to a connection array. 247 | * @param conslen A reference to the length of the connection array. 248 | * @param consmutex A mutex to access the connection array. 249 | * Note: The reason there are references is so the array can be updated. 250 | * In the case of a new connection, new_callback will be called. 251 | * @param callback The standard callback, passing in the data and the 252 | * connection associated with the data. 253 | * @param new_callback Called when a new connection is discovered. 254 | * If null nothing happens. 255 | * @return Negative value on error. 256 | */ 257 | int p2p_listener(connection_t **cons, size_t *conslen, 258 | pthread_mutex_t *consmutex, 259 | void (*callback)(connection_t *, void *, size_t), 260 | void (*new_callback)(connection_t *, void *, size_t), 261 | int socket, 262 | unsigned long max_packet_size) { 263 | 264 | /* A stack allocated connection struct to store any data 265 | about the connection we recieve. */ 266 | connection_t con; 267 | char buf[max_packet_size]; 268 | 269 | 270 | /* Loop on recvfrom. */ 271 | while (1) { 272 | memset(buf, 0, max_packet_size); 273 | int recv_len = recvfrom(socket, buf, max_packet_size, UDP_FLAGS, (struct sockaddr *)&(con.addr), &(con.addr_len)); 274 | 275 | #ifdef __linux__ 276 | /* Temporarily disable bandwidth. Broken for OSX. */ 277 | if (delta == -1) { 278 | clock_gettime(CLOCK_MONOTONIC, &prevPacket); 279 | delta = 0; 280 | } else { 281 | clock_gettime(CLOCK_MONOTONIC, &currPacket); 282 | delta = currPacket.tv_nsec - prevPacket.tv_nsec; 283 | clock_gettime(CLOCK_MONOTONIC, &prevPacket); 284 | bandwidth_index = (bandwidth_index + 1) % BANDWIDTH_BUFLEN; 285 | bandwidth_buf[bandwidth_index] = (double)recv_len/delta; 286 | } 287 | #endif 288 | 289 | /* Handle error UDP style (try again). */ 290 | if (recv_len < 0) { 291 | fprintf(stderr, "Recieve failed. errno: %d\n", errno); 292 | continue; 293 | } 294 | 295 | if(consmutex) { 296 | pthread_mutex_lock(consmutex); 297 | } 298 | 299 | /* Check if the connection we recieved from is in our array. */ 300 | int i, new_connection = 1; 301 | for (i = 0; i < *conslen; i++) { 302 | if (con.addr.sin_addr.s_addr == (*cons)[i].addr.sin_addr.s_addr) { 303 | new_connection = 0; 304 | break; 305 | } 306 | } 307 | 308 | if(consmutex) { 309 | pthread_mutex_unlock(consmutex); 310 | } 311 | 312 | /* Now invoke callbacks. */ 313 | if (new_connection) { 314 | /* Ignore new_callback if not defined. */ 315 | if (new_callback) { 316 | (*new_callback)(&con, buf, recv_len); 317 | } 318 | } else { 319 | (*callback)(&con, buf, recv_len); 320 | } 321 | 322 | } 323 | 324 | return -1; 325 | } 326 | 327 | -------------------------------------------------------------------------------- /src/p2pvc.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | 14 | #define DEFAULT_WIDTH 100 15 | #define DEFAULT_HEIGHT 40 16 | 17 | typedef struct { 18 | char *ipaddr; 19 | char *port; 20 | } network_options_t; 21 | 22 | void *spawn_audio_thread(void *args) { 23 | network_options_t *netopts = args; 24 | start_audio(netopts->ipaddr, netopts->port); 25 | return NULL; 26 | } 27 | 28 | void audio_shutdown(int signal) { 29 | kill(getpid(), SIGUSR1); 30 | } 31 | 32 | void all_shutdown(int signal) { 33 | video_shutdown(signal); 34 | audio_shutdown(signal); 35 | kill(getpid(), SIGKILL); 36 | exit(0); 37 | } 38 | 39 | void usage(FILE *stream) { 40 | fprintf(stream, 41 | "Usage: p2pvc [-h] [server] [options]\n" 42 | "A point to point color terminal video chat.\n" 43 | "\n" 44 | " -v Enable video chat.\n" 45 | " -d Dimensions of video in either [width]x[height] or [width]:[height]\n" 46 | " -A Audio port.\n" 47 | " -V Video port.\n" 48 | " -b Display incoming bandwidth in the top-right of the video display.\n" 49 | " -e Print stderr (which is by default routed to /dev/null).\n" 50 | " -c Use a specified color (i.e green is 0:100:0).\n" 51 | " -B Render in Braille.\n" 52 | " -I Set threshold for braille.\n" 53 | " -E Use an edge filter.\n" 54 | " -a Use custom ascii to print the video.\n" 55 | "\n" 56 | "Report bugs to https://github.com/mofarrell/p2pvc/issues.\n" 57 | ); 58 | } 59 | 60 | int main(int argc, char **argv) { 61 | if (argc < 2) { 62 | usage(stderr); 63 | exit(1); 64 | } 65 | 66 | char *peer = argv[1]; 67 | /* Check if the user actually wanted help. */ 68 | if (!strncmp(peer, "-h", 2)) { 69 | usage(stdout); 70 | exit(0); 71 | } 72 | char *audio_port = "55555"; 73 | char *video_port = "55556"; 74 | vid_options_t vopt; 75 | int spawn_video = 0, print_error = 0; 76 | int c; 77 | int width = DEFAULT_WIDTH, height = DEFAULT_HEIGHT; 78 | 79 | setlocale(LC_ALL, ""); 80 | 81 | memset(&vopt, 0, sizeof(vid_options_t)); 82 | vopt.width = DEFAULT_WIDTH; 83 | vopt.height = DEFAULT_HEIGHT; 84 | vopt.render_type = 0; 85 | vopt.refresh_rate = 20; 86 | vopt.saturation = -1.0; 87 | 88 | while ((c = getopt (argc - 1, &(argv[1]), "bvd:A:V:heBI:E:s:c:a:r:")) != -1) { 89 | switch (c) { 90 | case 'v': 91 | spawn_video = 1; 92 | break; 93 | case 'A': 94 | audio_port = optarg; 95 | break; 96 | case 'V': 97 | video_port = optarg; 98 | break; 99 | case 'd': 100 | sscanf(optarg, "%dx%d", &width, &height); 101 | vopt.width = width; 102 | vopt.height = height; 103 | break; 104 | case 'b': 105 | vopt.disp_bandwidth = 1; 106 | break; 107 | case 'r': 108 | sscanf(optarg, "%lu", &vopt.refresh_rate); 109 | break; 110 | case 'B': 111 | vopt.render_type = 1; 112 | break; 113 | case 'I': 114 | sscanf(optarg, "%d", &vopt.intensity_threshold); 115 | break; 116 | case 'E': 117 | vopt.edge_filter = 1; 118 | sscanf(optarg, "%d:%d", &vopt.edge_lower, &vopt.edge_upper); 119 | break; 120 | case 's': 121 | sscanf(optarg, "%lf", &vopt.saturation); 122 | break; 123 | case 'c': 124 | vopt.monochrome = 1; 125 | sscanf(optarg, "%" SCNd8 ":%" SCNd8 ":%" SCNd8, &vopt.r, &vopt.g, &vopt.b); 126 | break; 127 | case 'a': 128 | vopt.ascii_values = optarg; 129 | break; 130 | case 'h': 131 | usage(stdout); 132 | exit(0); 133 | break; 134 | case 'e': 135 | print_error = 1; 136 | break; 137 | default: 138 | break; 139 | } 140 | } 141 | 142 | if (!print_error) { 143 | int fd = open("/dev/null", O_WRONLY); 144 | dup2(fd, STDERR_FILENO); 145 | } 146 | 147 | if (spawn_video) { 148 | signal(SIGINT, all_shutdown); 149 | pthread_t thr; 150 | network_options_t netopts; 151 | netopts.ipaddr = peer; 152 | netopts.port = audio_port; 153 | pthread_create(&thr, NULL, spawn_audio_thread, (void *)&netopts); 154 | start_video(peer, video_port, &vopt); 155 | } else { 156 | signal(SIGINT, audio_shutdown); 157 | start_audio(peer, audio_port); 158 | } 159 | 160 | return 0; 161 | } 162 | 163 | -------------------------------------------------------------------------------- /src/pa_allocation.c: -------------------------------------------------------------------------------- 1 | /* 2 | * $Id$ 3 | * Portable Audio I/O Library allocation group implementation 4 | * memory allocation group for tracking allocation groups 5 | * 6 | * Based on the Open Source API proposed by Ross Bencina 7 | * Copyright (c) 1999-2002 Ross Bencina, Phil Burk 8 | * 9 | * Permission is hereby granted, free of charge, to any person obtaining 10 | * a copy of this software and associated documentation files 11 | * (the "Software"), to deal in the Software without restriction, 12 | * including without limitation the rights to use, copy, modify, merge, 13 | * publish, distribute, sublicense, and/or sell copies of the Software, 14 | * and to permit persons to whom the Software is furnished to do so, 15 | * subject to the following conditions: 16 | * 17 | * The above copyright notice and this permission notice shall be 18 | * included in all copies or substantial portions of the Software. 19 | * 20 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 22 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 23 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR 24 | * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 25 | * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 26 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 27 | */ 28 | 29 | /* 30 | * The text above constitutes the entire PortAudio license; however, 31 | * the PortAudio community also makes the following non-binding requests: 32 | * 33 | * Any person wishing to distribute modifications to the Software is 34 | * requested to send the modifications to the original developer so that 35 | * they can be incorporated into the canonical version. It is also 36 | * requested that these non-binding requests be included along with the 37 | * license above. 38 | */ 39 | 40 | /** @file 41 | @ingroup common_src 42 | 43 | @brief Allocation Group implementation. 44 | */ 45 | 46 | 47 | #include "pa_allocation.h" 48 | #include "pa_util.h" 49 | 50 | 51 | /* 52 | Maintain 3 singly linked lists... 53 | linkBlocks: the buffers used to allocate the links 54 | spareLinks: links available for use in the allocations list 55 | allocations: the buffers currently allocated using PaUtil_ContextAllocateMemory() 56 | 57 | Link block size is doubled every time new links are allocated. 58 | */ 59 | 60 | 61 | #define PA_INITIAL_LINK_COUNT_ 16 62 | 63 | struct PaUtilAllocationGroupLink 64 | { 65 | struct PaUtilAllocationGroupLink *next; 66 | void *buffer; 67 | }; 68 | 69 | /* 70 | Allocate a block of links. The first link will have it's buffer member 71 | pointing to the block, and it's next member set to . The remaining 72 | links will have NULL buffer members, and each link will point to 73 | the next link except the last, which will point to 74 | */ 75 | static struct PaUtilAllocationGroupLink *AllocateLinks( long count, 76 | struct PaUtilAllocationGroupLink *nextBlock, 77 | struct PaUtilAllocationGroupLink *nextSpare ) 78 | { 79 | struct PaUtilAllocationGroupLink *result; 80 | int i; 81 | 82 | result = (struct PaUtilAllocationGroupLink *)PaUtil_AllocateMemory( 83 | sizeof(struct PaUtilAllocationGroupLink) * count ); 84 | if( result ) 85 | { 86 | /* the block link */ 87 | result[0].buffer = result; 88 | result[0].next = nextBlock; 89 | 90 | /* the spare links */ 91 | for( i=1; ilinkCount = PA_INITIAL_LINK_COUNT_; 116 | result->linkBlocks = &links[0]; 117 | result->spareLinks = &links[1]; 118 | result->allocations = 0; 119 | } 120 | else 121 | { 122 | PaUtil_FreeMemory( links ); 123 | } 124 | } 125 | 126 | return result; 127 | } 128 | 129 | 130 | void PaUtil_DestroyAllocationGroup( PaUtilAllocationGroup* group ) 131 | { 132 | struct PaUtilAllocationGroupLink *current = group->linkBlocks; 133 | struct PaUtilAllocationGroupLink *next; 134 | 135 | while( current ) 136 | { 137 | next = current->next; 138 | PaUtil_FreeMemory( current->buffer ); 139 | current = next; 140 | } 141 | 142 | PaUtil_FreeMemory( group ); 143 | } 144 | 145 | 146 | void* PaUtil_GroupAllocateMemory( PaUtilAllocationGroup* group, long size ) 147 | { 148 | struct PaUtilAllocationGroupLink *links, *link; 149 | void *result = 0; 150 | 151 | /* allocate more links if necessary */ 152 | if( !group->spareLinks ) 153 | { 154 | /* double the link count on each block allocation */ 155 | links = AllocateLinks( group->linkCount, group->linkBlocks, group->spareLinks ); 156 | if( links ) 157 | { 158 | group->linkCount += group->linkCount; 159 | group->linkBlocks = &links[0]; 160 | group->spareLinks = &links[1]; 161 | } 162 | } 163 | 164 | if( group->spareLinks ) 165 | { 166 | result = PaUtil_AllocateMemory( size ); 167 | if( result ) 168 | { 169 | link = group->spareLinks; 170 | group->spareLinks = link->next; 171 | 172 | link->buffer = result; 173 | link->next = group->allocations; 174 | 175 | group->allocations = link; 176 | } 177 | } 178 | 179 | return result; 180 | } 181 | 182 | 183 | void PaUtil_GroupFreeMemory( PaUtilAllocationGroup* group, void *buffer ) 184 | { 185 | struct PaUtilAllocationGroupLink *current = group->allocations; 186 | struct PaUtilAllocationGroupLink *previous = 0; 187 | 188 | if( buffer == 0 ) 189 | return; 190 | 191 | /* find the right link and remove it */ 192 | while( current ) 193 | { 194 | if( current->buffer == buffer ) 195 | { 196 | if( previous ) 197 | { 198 | previous->next = current->next; 199 | } 200 | else 201 | { 202 | group->allocations = current->next; 203 | } 204 | 205 | current->buffer = 0; 206 | current->next = group->spareLinks; 207 | group->spareLinks = current; 208 | 209 | break; 210 | } 211 | 212 | previous = current; 213 | current = current->next; 214 | } 215 | 216 | PaUtil_FreeMemory( buffer ); /* free the memory whether we found it in the list or not */ 217 | } 218 | 219 | 220 | void PaUtil_FreeAllAllocations( PaUtilAllocationGroup* group ) 221 | { 222 | struct PaUtilAllocationGroupLink *current = group->allocations; 223 | struct PaUtilAllocationGroupLink *previous = 0; 224 | 225 | /* free all buffers in the allocations list */ 226 | while( current ) 227 | { 228 | PaUtil_FreeMemory( current->buffer ); 229 | current->buffer = 0; 230 | 231 | previous = current; 232 | current = current->next; 233 | } 234 | 235 | /* link the former allocations list onto the front of the spareLinks list */ 236 | if( previous ) 237 | { 238 | previous->next = group->spareLinks; 239 | group->spareLinks = group->allocations; 240 | group->allocations = 0; 241 | } 242 | } 243 | 244 | -------------------------------------------------------------------------------- /src/pa_cpuload.c: -------------------------------------------------------------------------------- 1 | /* 2 | * $Id$ 3 | * Portable Audio I/O Library CPU Load measurement functions 4 | * Portable CPU load measurement facility. 5 | * 6 | * Based on the Open Source API proposed by Ross Bencina 7 | * Copyright (c) 2002 Ross Bencina 8 | * 9 | * Permission is hereby granted, free of charge, to any person obtaining 10 | * a copy of this software and associated documentation files 11 | * (the "Software"), to deal in the Software without restriction, 12 | * including without limitation the rights to use, copy, modify, merge, 13 | * publish, distribute, sublicense, and/or sell copies of the Software, 14 | * and to permit persons to whom the Software is furnished to do so, 15 | * subject to the following conditions: 16 | * 17 | * The above copyright notice and this permission notice shall be 18 | * included in all copies or substantial portions of the Software. 19 | * 20 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 22 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 23 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR 24 | * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 25 | * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 26 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 27 | */ 28 | 29 | /* 30 | * The text above constitutes the entire PortAudio license; however, 31 | * the PortAudio community also makes the following non-binding requests: 32 | * 33 | * Any person wishing to distribute modifications to the Software is 34 | * requested to send the modifications to the original developer so that 35 | * they can be incorporated into the canonical version. It is also 36 | * requested that these non-binding requests be included along with the 37 | * license above. 38 | */ 39 | 40 | /** @file 41 | @ingroup common_src 42 | 43 | @brief Functions to assist in measuring the CPU utilization of a callback 44 | stream. Used to implement the Pa_GetStreamCpuLoad() function. 45 | 46 | @todo Dynamically calculate the coefficients used to smooth the CPU Load 47 | Measurements over time to provide a uniform characterisation of CPU Load 48 | independent of rate at which PaUtil_BeginCpuLoadMeasurement / 49 | PaUtil_EndCpuLoadMeasurement are called. see http://www.portaudio.com/trac/ticket/113 50 | */ 51 | 52 | 53 | #include "pa_cpuload.h" 54 | 55 | #include 56 | 57 | #include "pa_util.h" /* for PaUtil_GetTime() */ 58 | 59 | 60 | void PaUtil_InitializeCpuLoadMeasurer( PaUtilCpuLoadMeasurer* measurer, double sampleRate ) 61 | { 62 | assert( sampleRate > 0 ); 63 | 64 | measurer->samplingPeriod = 1. / sampleRate; 65 | measurer->averageLoad = 0.; 66 | } 67 | 68 | void PaUtil_ResetCpuLoadMeasurer( PaUtilCpuLoadMeasurer* measurer ) 69 | { 70 | measurer->averageLoad = 0.; 71 | } 72 | 73 | void PaUtil_BeginCpuLoadMeasurement( PaUtilCpuLoadMeasurer* measurer ) 74 | { 75 | measurer->measurementStartTime = PaUtil_GetTime(); 76 | } 77 | 78 | 79 | void PaUtil_EndCpuLoadMeasurement( PaUtilCpuLoadMeasurer* measurer, unsigned long framesProcessed ) 80 | { 81 | double measurementEndTime, secondsFor100Percent, measuredLoad; 82 | 83 | if( framesProcessed > 0 ){ 84 | measurementEndTime = PaUtil_GetTime(); 85 | 86 | assert( framesProcessed > 0 ); 87 | secondsFor100Percent = framesProcessed * measurer->samplingPeriod; 88 | 89 | measuredLoad = (measurementEndTime - measurer->measurementStartTime) / secondsFor100Percent; 90 | 91 | /* Low pass filter the calculated CPU load to reduce jitter using a simple IIR low pass filter. */ 92 | /** FIXME @todo these coefficients shouldn't be hardwired see: http://www.portaudio.com/trac/ticket/113 */ 93 | #define LOWPASS_COEFFICIENT_0 (0.9) 94 | #define LOWPASS_COEFFICIENT_1 (0.99999 - LOWPASS_COEFFICIENT_0) 95 | 96 | measurer->averageLoad = (LOWPASS_COEFFICIENT_0 * measurer->averageLoad) + 97 | (LOWPASS_COEFFICIENT_1 * measuredLoad); 98 | } 99 | } 100 | 101 | 102 | double PaUtil_GetCpuLoad( PaUtilCpuLoadMeasurer* measurer ) 103 | { 104 | return measurer->averageLoad; 105 | } 106 | -------------------------------------------------------------------------------- /src/pa_debugprint.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mofarrell/p2pvc/12a5269ce4709eb335d6e4232d3be14f61fac16b/src/pa_debugprint.c -------------------------------------------------------------------------------- /src/pa_dither.c: -------------------------------------------------------------------------------- 1 | /* 2 | * $Id$ 3 | * Portable Audio I/O Library triangular dither generator 4 | * 5 | * Based on the Open Source API proposed by Ross Bencina 6 | * Copyright (c) 1999-2002 Phil Burk, Ross Bencina 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining 9 | * a copy of this software and associated documentation files 10 | * (the "Software"), to deal in the Software without restriction, 11 | * including without limitation the rights to use, copy, modify, merge, 12 | * publish, distribute, sublicense, and/or sell copies of the Software, 13 | * and to permit persons to whom the Software is furnished to do so, 14 | * subject to the following conditions: 15 | * 16 | * The above copyright notice and this permission notice shall be 17 | * included in all copies or substantial portions of the Software. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 20 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 22 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR 23 | * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 24 | * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 25 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 26 | */ 27 | 28 | /* 29 | * The text above constitutes the entire PortAudio license; however, 30 | * the PortAudio community also makes the following non-binding requests: 31 | * 32 | * Any person wishing to distribute modifications to the Software is 33 | * requested to send the modifications to the original developer so that 34 | * they can be incorporated into the canonical version. It is also 35 | * requested that these non-binding requests be included along with the 36 | * license above. 37 | */ 38 | 39 | /** @file 40 | @ingroup common_src 41 | 42 | @brief Functions for generating dither noise 43 | */ 44 | 45 | #include "pa_types.h" 46 | #include "pa_dither.h" 47 | 48 | 49 | /* Note that the linear congruential algorithm requires 32 bit integers 50 | * because it uses arithmetic overflow. So use PaUint32 instead of 51 | * unsigned long so it will work on 64 bit systems. 52 | */ 53 | 54 | #define PA_DITHER_BITS_ (15) 55 | 56 | 57 | void PaUtil_InitializeTriangularDitherState( PaUtilTriangularDitherGenerator *state ) 58 | { 59 | state->previous = 0; 60 | state->randSeed1 = 22222; 61 | state->randSeed2 = 5555555; 62 | } 63 | 64 | 65 | PaInt32 PaUtil_Generate16BitTriangularDither( PaUtilTriangularDitherGenerator *state ) 66 | { 67 | PaInt32 current, highPass; 68 | 69 | /* Generate two random numbers. */ 70 | state->randSeed1 = (state->randSeed1 * 196314165) + 907633515; 71 | state->randSeed2 = (state->randSeed2 * 196314165) + 907633515; 72 | 73 | /* Generate triangular distribution about 0. 74 | * Shift before adding to prevent overflow which would skew the distribution. 75 | * Also shift an extra bit for the high pass filter. 76 | */ 77 | #define DITHER_SHIFT_ ((sizeof(PaInt32)*8 - PA_DITHER_BITS_) + 1) 78 | 79 | current = (((PaInt32)state->randSeed1)>>DITHER_SHIFT_) + 80 | (((PaInt32)state->randSeed2)>>DITHER_SHIFT_); 81 | 82 | /* High pass filter to reduce audibility. */ 83 | highPass = current - state->previous; 84 | state->previous = current; 85 | return highPass; 86 | } 87 | 88 | 89 | /* Multiply by PA_FLOAT_DITHER_SCALE_ to get a float between -2.0 and +1.99999 */ 90 | #define PA_FLOAT_DITHER_SCALE_ (1.0f / ((1<randSeed1 = (state->randSeed1 * 196314165) + 907633515; 99 | state->randSeed2 = (state->randSeed2 * 196314165) + 907633515; 100 | 101 | /* Generate triangular distribution about 0. 102 | * Shift before adding to prevent overflow which would skew the distribution. 103 | * Also shift an extra bit for the high pass filter. 104 | */ 105 | current = (((PaInt32)state->randSeed1)>>DITHER_SHIFT_) + 106 | (((PaInt32)state->randSeed2)>>DITHER_SHIFT_); 107 | 108 | /* High pass filter to reduce audibility. */ 109 | highPass = current - state->previous; 110 | state->previous = current; 111 | return ((float)highPass) * const_float_dither_scale_; 112 | } 113 | 114 | 115 | /* 116 | The following alternate dither algorithms (from musicdsp.org) could be 117 | considered 118 | */ 119 | 120 | /*Noise shaped dither (March 2000) 121 | ------------------- 122 | 123 | This is a simple implementation of highpass triangular-PDF dither with 124 | 2nd-order noise shaping, for use when truncating floating point audio 125 | data to fixed point. 126 | 127 | The noise shaping lowers the noise floor by 11dB below 5kHz (@ 44100Hz 128 | sample rate) compared to triangular-PDF dither. The code below assumes 129 | input data is in the range +1 to -1 and doesn't check for overloads! 130 | 131 | To save time when generating dither for multiple channels you can do 132 | things like this: r3=(r1 & 0x7F)<<8; instead of calling rand() again. 133 | 134 | 135 | 136 | int r1, r2; //rectangular-PDF random numbers 137 | float s1, s2; //error feedback buffers 138 | float s = 0.5f; //set to 0.0f for no noise shaping 139 | float w = pow(2.0,bits-1); //word length (usually bits=16) 140 | float wi= 1.0f/w; 141 | float d = wi / RAND_MAX; //dither amplitude (2 lsb) 142 | float o = wi * 0.5f; //remove dc offset 143 | float in, tmp; 144 | int out; 145 | 146 | 147 | //for each sample... 148 | 149 | r2=r1; //can make HP-TRI dither by 150 | r1=rand(); //subtracting previous rand() 151 | 152 | in += s * (s1 + s1 - s2); //error feedback 153 | tmp = in + o + d * (float)(r1 - r2); //dc offset and dither 154 | 155 | out = (int)(w * tmp); //truncate downwards 156 | if(tmp<0.0f) out--; //this is faster than floor() 157 | 158 | s2 = s1; 159 | s1 = in - wi * (float)out; //error 160 | 161 | 162 | 163 | -- 164 | paul.kellett@maxim.abel.co.uk 165 | http://www.maxim.abel.co.uk 166 | */ 167 | 168 | 169 | /* 170 | 16-to-8-bit first-order dither 171 | 172 | Type : First order error feedforward dithering code 173 | References : Posted by Jon Watte 174 | 175 | Notes : 176 | This is about as simple a dithering algorithm as you can implement, but it's 177 | likely to sound better than just truncating to N bits. 178 | 179 | Note that you might not want to carry forward the full difference for infinity. 180 | It's probably likely that the worst performance hit comes from the saturation 181 | conditionals, which can be avoided with appropriate instructions on many DSPs 182 | and integer SIMD type instructions, or CMOV. 183 | 184 | Last, if sound quality is paramount (such as when going from > 16 bits to 16 185 | bits) you probably want to use a higher-order dither function found elsewhere 186 | on this site. 187 | 188 | 189 | Code : 190 | // This code will down-convert and dither a 16-bit signed short 191 | // mono signal into an 8-bit unsigned char signal, using a first 192 | // order forward-feeding error term dither. 193 | 194 | #define uchar unsigned char 195 | 196 | void dither_one_channel_16_to_8( short * input, uchar * output, int count, int * memory ) 197 | { 198 | int m = *memory; 199 | while( count-- > 0 ) { 200 | int i = *input++; 201 | i += m; 202 | int j = i + 32768 - 128; 203 | uchar o; 204 | if( j < 0 ) { 205 | o = 0; 206 | } 207 | else if( j > 65535 ) { 208 | o = 255; 209 | } 210 | else { 211 | o = (uchar)((j>>8)&0xff); 212 | } 213 | m = ((j-32768+128)-i); 214 | *output++ = o; 215 | } 216 | *memory = m; 217 | } 218 | */ 219 | -------------------------------------------------------------------------------- /src/pa_ringbuffer.c: -------------------------------------------------------------------------------- 1 | /* 2 | * $Id$ 3 | * Portable Audio I/O Library 4 | * Ring Buffer utility. 5 | * 6 | * Author: Phil Burk, http://www.softsynth.com 7 | * modified for SMP safety on Mac OS X by Bjorn Roche 8 | * modified for SMP safety on Linux by Leland Lucius 9 | * also, allowed for const where possible 10 | * modified for multiple-byte-sized data elements by Sven Fischer 11 | * 12 | * Note that this is safe only for a single-thread reader and a 13 | * single-thread writer. 14 | * 15 | * This program uses the PortAudio Portable Audio Library. 16 | * For more information see: http://www.portaudio.com 17 | * Copyright (c) 1999-2000 Ross Bencina and Phil Burk 18 | * 19 | * Permission is hereby granted, free of charge, to any person obtaining 20 | * a copy of this software and associated documentation files 21 | * (the "Software"), to deal in the Software without restriction, 22 | * including without limitation the rights to use, copy, modify, merge, 23 | * publish, distribute, sublicense, and/or sell copies of the Software, 24 | * and to permit persons to whom the Software is furnished to do so, 25 | * subject to the following conditions: 26 | * 27 | * The above copyright notice and this permission notice shall be 28 | * included in all copies or substantial portions of the Software. 29 | * 30 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 31 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 32 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 33 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR 34 | * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 35 | * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 36 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 37 | */ 38 | 39 | /* 40 | * The text above constitutes the entire PortAudio license; however, 41 | * the PortAudio community also makes the following non-binding requests: 42 | * 43 | * Any person wishing to distribute modifications to the Software is 44 | * requested to send the modifications to the original developer so that 45 | * they can be incorporated into the canonical version. It is also 46 | * requested that these non-binding requests be included along with the 47 | * license above. 48 | */ 49 | 50 | /** 51 | @file 52 | @ingroup common_src 53 | */ 54 | 55 | #include 56 | #include 57 | #include 58 | #include "pa_ringbuffer.h" 59 | #include 60 | #include "pa_memorybarrier.h" 61 | 62 | /*************************************************************************** 63 | * Initialize FIFO. 64 | * elementCount must be power of 2, returns -1 if not. 65 | */ 66 | ring_buffer_size_t PaUtil_InitializeRingBuffer( PaUtilRingBuffer *rbuf, ring_buffer_size_t elementSizeBytes, ring_buffer_size_t elementCount, void *dataPtr ) 67 | { 68 | if( ((elementCount-1) & elementCount) != 0) return -1; /* Not Power of two. */ 69 | rbuf->bufferSize = elementCount; 70 | rbuf->buffer = (char *)dataPtr; 71 | PaUtil_FlushRingBuffer( rbuf ); 72 | rbuf->bigMask = (elementCount*2)-1; 73 | rbuf->smallMask = (elementCount)-1; 74 | rbuf->elementSizeBytes = elementSizeBytes; 75 | return 0; 76 | } 77 | 78 | /*************************************************************************** 79 | ** Return number of elements available for reading. */ 80 | ring_buffer_size_t PaUtil_GetRingBufferReadAvailable( const PaUtilRingBuffer *rbuf ) 81 | { 82 | return ( (rbuf->writeIndex - rbuf->readIndex) & rbuf->bigMask ); 83 | } 84 | /*************************************************************************** 85 | ** Return number of elements available for writing. */ 86 | ring_buffer_size_t PaUtil_GetRingBufferWriteAvailable( const PaUtilRingBuffer *rbuf ) 87 | { 88 | return ( rbuf->bufferSize - PaUtil_GetRingBufferReadAvailable(rbuf)); 89 | } 90 | 91 | /*************************************************************************** 92 | ** Clear buffer. Should only be called when buffer is NOT being read or written. */ 93 | void PaUtil_FlushRingBuffer( PaUtilRingBuffer *rbuf ) 94 | { 95 | rbuf->writeIndex = rbuf->readIndex = 0; 96 | } 97 | 98 | /*************************************************************************** 99 | ** Get address of region(s) to which we can write data. 100 | ** If the region is contiguous, size2 will be zero. 101 | ** If non-contiguous, size2 will be the size of second region. 102 | ** Returns room available to be written or elementCount, whichever is smaller. 103 | */ 104 | ring_buffer_size_t PaUtil_GetRingBufferWriteRegions( PaUtilRingBuffer *rbuf, ring_buffer_size_t elementCount, 105 | void **dataPtr1, ring_buffer_size_t *sizePtr1, 106 | void **dataPtr2, ring_buffer_size_t *sizePtr2 ) 107 | { 108 | ring_buffer_size_t index; 109 | ring_buffer_size_t available = PaUtil_GetRingBufferWriteAvailable( rbuf ); 110 | if( elementCount > available ) elementCount = available; 111 | /* Check to see if write is not contiguous. */ 112 | index = rbuf->writeIndex & rbuf->smallMask; 113 | if( (index + elementCount) > rbuf->bufferSize ) 114 | { 115 | /* Write data in two blocks that wrap the buffer. */ 116 | ring_buffer_size_t firstHalf = rbuf->bufferSize - index; 117 | *dataPtr1 = &rbuf->buffer[index*rbuf->elementSizeBytes]; 118 | *sizePtr1 = firstHalf; 119 | *dataPtr2 = &rbuf->buffer[0]; 120 | *sizePtr2 = elementCount - firstHalf; 121 | } 122 | else 123 | { 124 | *dataPtr1 = &rbuf->buffer[index*rbuf->elementSizeBytes]; 125 | *sizePtr1 = elementCount; 126 | *dataPtr2 = NULL; 127 | *sizePtr2 = 0; 128 | } 129 | 130 | if( available ) 131 | PaUtil_FullMemoryBarrier(); /* (write-after-read) => full barrier */ 132 | 133 | return elementCount; 134 | } 135 | 136 | 137 | /*************************************************************************** 138 | */ 139 | ring_buffer_size_t PaUtil_AdvanceRingBufferWriteIndex( PaUtilRingBuffer *rbuf, ring_buffer_size_t elementCount ) 140 | { 141 | /* ensure that previous writes are seen before we update the write index 142 | (write after write) 143 | */ 144 | PaUtil_WriteMemoryBarrier(); 145 | return rbuf->writeIndex = (rbuf->writeIndex + elementCount) & rbuf->bigMask; 146 | } 147 | 148 | /*************************************************************************** 149 | ** Get address of region(s) from which we can read data. 150 | ** If the region is contiguous, size2 will be zero. 151 | ** If non-contiguous, size2 will be the size of second region. 152 | ** Returns room available to be read or elementCount, whichever is smaller. 153 | */ 154 | ring_buffer_size_t PaUtil_GetRingBufferReadRegions( PaUtilRingBuffer *rbuf, ring_buffer_size_t elementCount, 155 | void **dataPtr1, ring_buffer_size_t *sizePtr1, 156 | void **dataPtr2, ring_buffer_size_t *sizePtr2 ) 157 | { 158 | ring_buffer_size_t index; 159 | ring_buffer_size_t available = PaUtil_GetRingBufferReadAvailable( rbuf ); /* doesn't use memory barrier */ 160 | if( elementCount > available ) elementCount = available; 161 | /* Check to see if read is not contiguous. */ 162 | index = rbuf->readIndex & rbuf->smallMask; 163 | if( (index + elementCount) > rbuf->bufferSize ) 164 | { 165 | /* Write data in two blocks that wrap the buffer. */ 166 | ring_buffer_size_t firstHalf = rbuf->bufferSize - index; 167 | *dataPtr1 = &rbuf->buffer[index*rbuf->elementSizeBytes]; 168 | *sizePtr1 = firstHalf; 169 | *dataPtr2 = &rbuf->buffer[0]; 170 | *sizePtr2 = elementCount - firstHalf; 171 | } 172 | else 173 | { 174 | *dataPtr1 = &rbuf->buffer[index*rbuf->elementSizeBytes]; 175 | *sizePtr1 = elementCount; 176 | *dataPtr2 = NULL; 177 | *sizePtr2 = 0; 178 | } 179 | 180 | if( available ) 181 | PaUtil_ReadMemoryBarrier(); /* (read-after-read) => read barrier */ 182 | 183 | return elementCount; 184 | } 185 | /*************************************************************************** 186 | */ 187 | ring_buffer_size_t PaUtil_AdvanceRingBufferReadIndex( PaUtilRingBuffer *rbuf, ring_buffer_size_t elementCount ) 188 | { 189 | /* ensure that previous reads (copies out of the ring buffer) are always completed before updating (writing) the read index. 190 | (write-after-read) => full barrier 191 | */ 192 | PaUtil_FullMemoryBarrier(); 193 | return rbuf->readIndex = (rbuf->readIndex + elementCount) & rbuf->bigMask; 194 | } 195 | 196 | /*************************************************************************** 197 | ** Return elements written. */ 198 | ring_buffer_size_t PaUtil_WriteRingBuffer( PaUtilRingBuffer *rbuf, const void *data, ring_buffer_size_t elementCount ) 199 | { 200 | ring_buffer_size_t size1, size2, numWritten; 201 | void *data1, *data2; 202 | numWritten = PaUtil_GetRingBufferWriteRegions( rbuf, elementCount, &data1, &size1, &data2, &size2 ); 203 | if( size2 > 0 ) 204 | { 205 | 206 | memcpy( data1, data, size1*rbuf->elementSizeBytes ); 207 | data = ((char *)data) + size1*rbuf->elementSizeBytes; 208 | memcpy( data2, data, size2*rbuf->elementSizeBytes ); 209 | } 210 | else 211 | { 212 | memcpy( data1, data, size1*rbuf->elementSizeBytes ); 213 | } 214 | PaUtil_AdvanceRingBufferWriteIndex( rbuf, numWritten ); 215 | return numWritten; 216 | } 217 | 218 | /*************************************************************************** 219 | ** Return elements read. */ 220 | ring_buffer_size_t PaUtil_ReadRingBuffer( PaUtilRingBuffer *rbuf, void *data, ring_buffer_size_t elementCount ) 221 | { 222 | ring_buffer_size_t size1, size2, numRead; 223 | void *data1, *data2; 224 | numRead = PaUtil_GetRingBufferReadRegions( rbuf, elementCount, &data1, &size1, &data2, &size2 ); 225 | if( size2 > 0 ) 226 | { 227 | memcpy( data, data1, size1*rbuf->elementSizeBytes ); 228 | data = ((char *)data) + size1*rbuf->elementSizeBytes; 229 | memcpy( data, data2, size2*rbuf->elementSizeBytes ); 230 | } 231 | else 232 | { 233 | memcpy( data, data1, size1*rbuf->elementSizeBytes ); 234 | } 235 | PaUtil_AdvanceRingBufferReadIndex( rbuf, numRead ); 236 | return numRead; 237 | } 238 | -------------------------------------------------------------------------------- /src/pa_stream.c: -------------------------------------------------------------------------------- 1 | /* 2 | * $Id$ 3 | * Portable Audio I/O Library 4 | * stream interface 5 | * 6 | * Based on the Open Source API proposed by Ross Bencina 7 | * Copyright (c) 2008 Ross Bencina 8 | * 9 | * Permission is hereby granted, free of charge, to any person obtaining 10 | * a copy of this software and associated documentation files 11 | * (the "Software"), to deal in the Software without restriction, 12 | * including without limitation the rights to use, copy, modify, merge, 13 | * publish, distribute, sublicense, and/or sell copies of the Software, 14 | * and to permit persons to whom the Software is furnished to do so, 15 | * subject to the following conditions: 16 | * 17 | * The above copyright notice and this permission notice shall be 18 | * included in all copies or substantial portions of the Software. 19 | * 20 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 22 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 23 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR 24 | * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 25 | * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 26 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 27 | */ 28 | 29 | /* 30 | * The text above constitutes the entire PortAudio license; however, 31 | * the PortAudio community also makes the following non-binding requests: 32 | * 33 | * Any person wishing to distribute modifications to the Software is 34 | * requested to send the modifications to the original developer so that 35 | * they can be incorporated into the canonical version. It is also 36 | * requested that these non-binding requests be included along with the 37 | * license above. 38 | */ 39 | 40 | /** @file 41 | @ingroup common_src 42 | 43 | @brief Stream interfaces, representation structures and helper functions 44 | used to interface between pa_front.c host API implementations. 45 | */ 46 | 47 | 48 | #include "pa_stream.h" 49 | 50 | 51 | void PaUtil_InitializeStreamInterface( PaUtilStreamInterface *streamInterface, 52 | PaError (*Close)( PaStream* ), 53 | PaError (*Start)( PaStream* ), 54 | PaError (*Stop)( PaStream* ), 55 | PaError (*Abort)( PaStream* ), 56 | PaError (*IsStopped)( PaStream* ), 57 | PaError (*IsActive)( PaStream* ), 58 | PaTime (*GetTime)( PaStream* ), 59 | double (*GetCpuLoad)( PaStream* ), 60 | PaError (*Read)( PaStream*, void *, unsigned long ), 61 | PaError (*Write)( PaStream*, const void *, unsigned long ), 62 | signed long (*GetReadAvailable)( PaStream* ), 63 | signed long (*GetWriteAvailable)( PaStream* ) ) 64 | { 65 | streamInterface->Close = Close; 66 | streamInterface->Start = Start; 67 | streamInterface->Stop = Stop; 68 | streamInterface->Abort = Abort; 69 | streamInterface->IsStopped = IsStopped; 70 | streamInterface->IsActive = IsActive; 71 | streamInterface->GetTime = GetTime; 72 | streamInterface->GetCpuLoad = GetCpuLoad; 73 | streamInterface->Read = Read; 74 | streamInterface->Write = Write; 75 | streamInterface->GetReadAvailable = GetReadAvailable; 76 | streamInterface->GetWriteAvailable = GetWriteAvailable; 77 | } 78 | 79 | 80 | void PaUtil_InitializeStreamRepresentation( PaUtilStreamRepresentation *streamRepresentation, 81 | PaUtilStreamInterface *streamInterface, 82 | PaStreamCallback *streamCallback, 83 | void *userData ) 84 | { 85 | streamRepresentation->magic = PA_STREAM_MAGIC; 86 | streamRepresentation->nextOpenStream = 0; 87 | streamRepresentation->streamInterface = streamInterface; 88 | streamRepresentation->streamCallback = streamCallback; 89 | streamRepresentation->streamFinishedCallback = 0; 90 | 91 | streamRepresentation->userData = userData; 92 | 93 | streamRepresentation->streamInfo.inputLatency = 0.; 94 | streamRepresentation->streamInfo.outputLatency = 0.; 95 | streamRepresentation->streamInfo.sampleRate = 0.; 96 | } 97 | 98 | 99 | void PaUtil_TerminateStreamRepresentation( PaUtilStreamRepresentation *streamRepresentation ) 100 | { 101 | streamRepresentation->magic = 0; 102 | } 103 | 104 | 105 | PaError PaUtil_DummyRead( PaStream* stream, 106 | void *buffer, 107 | unsigned long frames ) 108 | { 109 | (void)stream; /* unused parameter */ 110 | (void)buffer; /* unused parameter */ 111 | (void)frames; /* unused parameter */ 112 | 113 | return paCanNotReadFromACallbackStream; 114 | } 115 | 116 | 117 | PaError PaUtil_DummyWrite( PaStream* stream, 118 | const void *buffer, 119 | unsigned long frames ) 120 | { 121 | (void)stream; /* unused parameter */ 122 | (void)buffer; /* unused parameter */ 123 | (void)frames; /* unused parameter */ 124 | 125 | return paCanNotWriteToACallbackStream; 126 | } 127 | 128 | 129 | signed long PaUtil_DummyGetReadAvailable( PaStream* stream ) 130 | { 131 | (void)stream; /* unused parameter */ 132 | 133 | return paCanNotReadFromACallbackStream; 134 | } 135 | 136 | 137 | signed long PaUtil_DummyGetWriteAvailable( PaStream* stream ) 138 | { 139 | (void)stream; /* unused parameter */ 140 | 141 | return paCanNotWriteToACallbackStream; 142 | } 143 | 144 | 145 | double PaUtil_DummyGetCpuLoad( PaStream* stream ) 146 | { 147 | (void)stream; /* unused parameter */ 148 | 149 | return 0.0; 150 | } 151 | -------------------------------------------------------------------------------- /src/pa_trace.c: -------------------------------------------------------------------------------- 1 | /* 2 | * $Id$ 3 | * Portable Audio I/O Library Trace Facility 4 | * Store trace information in real-time for later printing. 5 | * 6 | * Based on the Open Source API proposed by Ross Bencina 7 | * Copyright (c) 1999-2000 Phil Burk 8 | * 9 | * Permission is hereby granted, free of charge, to any person obtaining 10 | * a copy of this software and associated documentation files 11 | * (the "Software"), to deal in the Software without restriction, 12 | * including without limitation the rights to use, copy, modify, merge, 13 | * publish, distribute, sublicense, and/or sell copies of the Software, 14 | * and to permit persons to whom the Software is furnished to do so, 15 | * subject to the following conditions: 16 | * 17 | * The above copyright notice and this permission notice shall be 18 | * included in all copies or substantial portions of the Software. 19 | * 20 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 22 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 23 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR 24 | * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 25 | * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 26 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 27 | */ 28 | 29 | /* 30 | * The text above constitutes the entire PortAudio license; however, 31 | * the PortAudio community also makes the following non-binding requests: 32 | * 33 | * Any person wishing to distribute modifications to the Software is 34 | * requested to send the modifications to the original developer so that 35 | * they can be incorporated into the canonical version. It is also 36 | * requested that these non-binding requests be included along with the 37 | * license above. 38 | */ 39 | 40 | /** @file 41 | @ingroup common_src 42 | 43 | @brief Real-time safe event trace logging facility for debugging. 44 | */ 45 | 46 | 47 | #include 48 | #include 49 | #include 50 | #include 51 | #include 52 | #include "pa_trace.h" 53 | #include "pa_util.h" 54 | #include "pa_debugprint.h" 55 | 56 | #if PA_TRACE_REALTIME_EVENTS 57 | 58 | static char const *traceTextArray[PA_MAX_TRACE_RECORDS]; 59 | static int traceIntArray[PA_MAX_TRACE_RECORDS]; 60 | static int traceIndex = 0; 61 | static int traceBlock = 0; 62 | 63 | /*********************************************************************/ 64 | void PaUtil_ResetTraceMessages() 65 | { 66 | traceIndex = 0; 67 | } 68 | 69 | /*********************************************************************/ 70 | void PaUtil_DumpTraceMessages() 71 | { 72 | int i; 73 | int messageCount = (traceIndex < PA_MAX_TRACE_RECORDS) ? traceIndex : PA_MAX_TRACE_RECORDS; 74 | 75 | printf("DumpTraceMessages: traceIndex = %d\n", traceIndex ); 76 | for( i=0; idata = (char*)PaUtil_AllocateMemory(maxSizeInBytes); 132 | if (pLog->data == 0) 133 | { 134 | PaUtil_FreeMemory(pLog); 135 | return paInsufficientMemory; 136 | } 137 | pLog->magik = kMagik; 138 | pLog->size = maxSizeInBytes; 139 | pLog->refTime = PaUtil_GetTime(); 140 | return paNoError; 141 | } 142 | 143 | void PaUtil_ResetHighSpeedLogTimeRef( LogHandle hLog ) 144 | { 145 | PaHighPerformanceLog* pLog = (PaHighPerformanceLog*)hLog; 146 | assert(pLog->magik == kMagik); 147 | pLog->refTime = PaUtil_GetTime(); 148 | } 149 | 150 | typedef struct __PaLogEntryHeader 151 | { 152 | int size; 153 | double timeStamp; 154 | } PaLogEntryHeader; 155 | 156 | #ifdef __APPLE__ 157 | #define _vsnprintf vsnprintf 158 | #define min(a,b) ((a)<(b)?(a):(b)) 159 | #endif 160 | 161 | 162 | int PaUtil_AddHighSpeedLogMessage( LogHandle hLog, const char* fmt, ... ) 163 | { 164 | va_list l; 165 | int n = 0; 166 | PaHighPerformanceLog* pLog = (PaHighPerformanceLog*)hLog; 167 | if (pLog != 0) 168 | { 169 | PaLogEntryHeader* pHeader; 170 | char* p; 171 | int maxN; 172 | assert(pLog->magik == kMagik); 173 | pHeader = (PaLogEntryHeader*)( pLog->data + pLog->writePtr ); 174 | p = (char*)( pHeader + 1 ); 175 | maxN = pLog->size - pLog->writePtr - 2 * sizeof(PaLogEntryHeader); 176 | 177 | pHeader->timeStamp = PaUtil_GetTime() - pLog->refTime; 178 | if (maxN > 0) 179 | { 180 | if (maxN > 32) 181 | { 182 | va_start(l, fmt); 183 | n = _vsnprintf(p, min(1024, maxN), fmt, l); 184 | va_end(l); 185 | } 186 | else { 187 | n = sprintf(p, "End of log..."); 188 | } 189 | n = ((n + sizeof(unsigned)) & ~(sizeof(unsigned)-1)) + sizeof(PaLogEntryHeader); 190 | pHeader->size = n; 191 | #if 0 192 | PaUtil_DebugPrint("%05u.%03u: %s\n", pHeader->timeStamp/1000, pHeader->timeStamp%1000, p); 193 | #endif 194 | pLog->writePtr += n; 195 | } 196 | } 197 | return n; 198 | } 199 | 200 | void PaUtil_DumpHighSpeedLog( LogHandle hLog, const char* fileName ) 201 | { 202 | FILE* f = (fileName != NULL) ? fopen(fileName, "w") : stdout; 203 | unsigned localWritePtr; 204 | PaHighPerformanceLog* pLog = (PaHighPerformanceLog*)hLog; 205 | assert(pLog->magik == kMagik); 206 | localWritePtr = pLog->writePtr; 207 | while (pLog->readPtr != localWritePtr) 208 | { 209 | const PaLogEntryHeader* pHeader = (const PaLogEntryHeader*)( pLog->data + pLog->readPtr ); 210 | const char* p = (const char*)( pHeader + 1 ); 211 | const PaUint64 ts = (const PaUint64)( pHeader->timeStamp * USEC_PER_SEC ); 212 | assert(pHeader->size < (1024+sizeof(unsigned)+sizeof(PaLogEntryHeader))); 213 | fprintf(f, "%05u.%03u: %s\n", (unsigned)(ts/1000), (unsigned)(ts%1000), p); 214 | pLog->readPtr += pHeader->size; 215 | } 216 | if (f != stdout) 217 | { 218 | fclose(f); 219 | } 220 | } 221 | 222 | void PaUtil_DiscardHighSpeedLog( LogHandle hLog ) 223 | { 224 | PaHighPerformanceLog* pLog = (PaHighPerformanceLog*)hLog; 225 | assert(pLog->magik == kMagik); 226 | PaUtil_FreeMemory(pLog->data); 227 | PaUtil_FreeMemory(pLog); 228 | } 229 | 230 | #else 231 | /* This stub was added so that this file will generate a symbol. 232 | * Otherwise linker/archiver programs will complain. 233 | */ 234 | int PaUtil_TraceStubToSatisfyLinker(void) 235 | { 236 | return 0; 237 | } 238 | #endif /* TRACE_REALTIME_EVENTS */ 239 | -------------------------------------------------------------------------------- /src/pa_unix_hostapis.c: -------------------------------------------------------------------------------- 1 | /* 2 | * $Id$ 3 | * Portable Audio I/O Library UNIX initialization table 4 | * 5 | * Based on the Open Source API proposed by Ross Bencina 6 | * Copyright (c) 1999-2002 Ross Bencina, Phil Burk 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining 9 | * a copy of this software and associated documentation files 10 | * (the "Software"), to deal in the Software without restriction, 11 | * including without limitation the rights to use, copy, modify, merge, 12 | * publish, distribute, sublicense, and/or sell copies of the Software, 13 | * and to permit persons to whom the Software is furnished to do so, 14 | * subject to the following conditions: 15 | * 16 | * The above copyright notice and this permission notice shall be 17 | * included in all copies or substantial portions of the Software. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 20 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 22 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR 23 | * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 24 | * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 25 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 26 | */ 27 | 28 | /* 29 | * The text above constitutes the entire PortAudio license; however, 30 | * the PortAudio community also makes the following non-binding requests: 31 | * 32 | * Any person wishing to distribute modifications to the Software is 33 | * requested to send the modifications to the original developer so that 34 | * they can be incorporated into the canonical version. It is also 35 | * requested that these non-binding requests be included along with the 36 | * license above. 37 | */ 38 | 39 | /** @file 40 | @ingroup unix_src 41 | */ 42 | 43 | #include "pa_hostapi.h" 44 | 45 | PaError PaJack_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index ); 46 | PaError PaAlsa_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index ); 47 | PaError PaOSS_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index ); 48 | /* Added for IRIX, Pieter, oct 2, 2003: */ 49 | PaError PaSGI_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index ); 50 | /* Linux AudioScience HPI */ 51 | PaError PaAsiHpi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index ); 52 | PaError PaMacCore_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index ); 53 | PaError PaSkeleton_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index ); 54 | 55 | /** Note that on Linux, ALSA is placed before OSS so that the former is preferred over the latter. 56 | */ 57 | 58 | PaUtilHostApiInitializer *paHostApiInitializers[] = 59 | { 60 | #ifdef __linux__ 61 | 62 | #if PA_USE_ALSA 63 | PaAlsa_Initialize, 64 | #endif 65 | 66 | #if PA_USE_OSS 67 | PaOSS_Initialize, 68 | #endif 69 | 70 | #else /* __linux__ */ 71 | 72 | #if PA_USE_OSS 73 | PaOSS_Initialize, 74 | #endif 75 | 76 | #if PA_USE_ALSA 77 | PaAlsa_Initialize, 78 | #endif 79 | 80 | #endif /* __linux__ */ 81 | 82 | #if PA_USE_JACK 83 | PaJack_Initialize, 84 | #endif 85 | /* Added for IRIX, Pieter, oct 2, 2003: */ 86 | #if PA_USE_SGI 87 | PaSGI_Initialize, 88 | #endif 89 | 90 | #if PA_USE_ASIHPI 91 | PaAsiHpi_Initialize, 92 | #endif 93 | 94 | #if PA_USE_COREAUDIO 95 | PaMacCore_Initialize, 96 | #endif 97 | 98 | #if PA_USE_SKELETON 99 | PaSkeleton_Initialize, 100 | #endif 101 | 102 | 0 /* NULL terminated array */ 103 | }; 104 | -------------------------------------------------------------------------------- /src/pa_unix_util.c: -------------------------------------------------------------------------------- 1 | /* 2 | * $Id$ 3 | * Portable Audio I/O Library 4 | * UNIX platform-specific support functions 5 | * 6 | * Based on the Open Source API proposed by Ross Bencina 7 | * Copyright (c) 1999-2000 Ross Bencina 8 | * 9 | * Permission is hereby granted, free of charge, to any person obtaining 10 | * a copy of this software and associated documentation files 11 | * (the "Software"), to deal in the Software without restriction, 12 | * including without limitation the rights to use, copy, modify, merge, 13 | * publish, distribute, sublicense, and/or sell copies of the Software, 14 | * and to permit persons to whom the Software is furnished to do so, 15 | * subject to the following conditions: 16 | * 17 | * The above copyright notice and this permission notice shall be 18 | * included in all copies or substantial portions of the Software. 19 | * 20 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 22 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 23 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR 24 | * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 25 | * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 26 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 27 | */ 28 | 29 | /* 30 | * The text above constitutes the entire PortAudio license; however, 31 | * the PortAudio community also makes the following non-binding requests: 32 | * 33 | * Any person wishing to distribute modifications to the Software is 34 | * requested to send the modifications to the original developer so that 35 | * they can be incorporated into the canonical version. It is also 36 | * requested that these non-binding requests be included along with the 37 | * license above. 38 | */ 39 | 40 | /** @file 41 | @ingroup unix_src 42 | */ 43 | 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include 49 | #include 50 | #include /* For memset */ 51 | #include 52 | #include 53 | 54 | #if defined(__APPLE__) && !defined(HAVE_MACH_ABSOLUTE_TIME) 55 | #define HAVE_MACH_ABSOLUTE_TIME 56 | #endif 57 | #ifdef HAVE_MACH_ABSOLUTE_TIME 58 | #include 59 | #endif 60 | 61 | #include "pa_util.h" 62 | #include "pa_unix_util.h" 63 | #include "pa_debugprint.h" 64 | 65 | /* 66 | Track memory allocations to avoid leaks. 67 | */ 68 | 69 | #if PA_TRACK_MEMORY 70 | static int numAllocations_ = 0; 71 | #endif 72 | 73 | 74 | void *PaUtil_AllocateMemory( long size ) 75 | { 76 | void *result = malloc( size ); 77 | 78 | #if PA_TRACK_MEMORY 79 | if( result != NULL ) numAllocations_ += 1; 80 | #endif 81 | return result; 82 | } 83 | 84 | 85 | void PaUtil_FreeMemory( void *block ) 86 | { 87 | if( block != NULL ) 88 | { 89 | free( block ); 90 | #if PA_TRACK_MEMORY 91 | numAllocations_ -= 1; 92 | #endif 93 | 94 | } 95 | } 96 | 97 | 98 | int PaUtil_CountCurrentlyAllocatedBlocks( void ) 99 | { 100 | #if PA_TRACK_MEMORY 101 | return numAllocations_; 102 | #else 103 | return 0; 104 | #endif 105 | } 106 | 107 | 108 | void Pa_Sleep( long msec ) 109 | { 110 | #ifdef HAVE_NANOSLEEP 111 | struct timespec req = {0}, rem = {0}; 112 | PaTime time = msec / 1.e3; 113 | req.tv_sec = (time_t)time; 114 | assert(time - req.tv_sec < 1.0); 115 | req.tv_nsec = (long)((time - req.tv_sec) * 1.e9); 116 | nanosleep(&req, &rem); 117 | /* XXX: Try sleeping the remaining time (contained in rem) if interrupted by a signal? */ 118 | #else 119 | while( msec > 999 ) /* For OpenBSD and IRIX, argument */ 120 | { /* to usleep must be < 1000000. */ 121 | usleep( 999000 ); 122 | msec -= 999; 123 | } 124 | usleep( msec * 1000 ); 125 | #endif 126 | } 127 | 128 | #ifdef HAVE_MACH_ABSOLUTE_TIME 129 | /* 130 | Discussion on the CoreAudio mailing list suggests that calling 131 | gettimeofday (or anything else in the BSD layer) is not real-time 132 | safe, so we use mach_absolute_time on OSX. This implementation is 133 | based on these two links: 134 | 135 | Technical Q&A QA1398 - Mach Absolute Time Units 136 | http://developer.apple.com/mac/library/qa/qa2004/qa1398.html 137 | 138 | Tutorial: Performance and Time. 139 | http://www.macresearch.org/tutorial_performance_and_time 140 | */ 141 | 142 | /* Scaler to convert the result of mach_absolute_time to seconds */ 143 | static double machSecondsConversionScaler_ = 0.0; 144 | #endif 145 | 146 | void PaUtil_InitializeClock( void ) 147 | { 148 | #ifdef HAVE_MACH_ABSOLUTE_TIME 149 | mach_timebase_info_data_t info; 150 | kern_return_t err = mach_timebase_info( &info ); 151 | if( err == 0 ) 152 | machSecondsConversionScaler_ = 1e-9 * (double) info.numer / (double) info.denom; 153 | #endif 154 | } 155 | 156 | 157 | PaTime PaUtil_GetTime( void ) 158 | { 159 | #ifdef HAVE_MACH_ABSOLUTE_TIME 160 | return mach_absolute_time() * machSecondsConversionScaler_; 161 | #elif defined(HAVE_CLOCK_GETTIME) 162 | struct timespec tp; 163 | clock_gettime(CLOCK_REALTIME, &tp); 164 | return (PaTime)(tp.tv_sec + tp.tv_nsec * 1e-9); 165 | #else 166 | struct timeval tv; 167 | gettimeofday( &tv, NULL ); 168 | return (PaTime) tv.tv_usec * 1e-6 + tv.tv_sec; 169 | #endif 170 | } 171 | 172 | PaError PaUtil_InitializeThreading( PaUtilThreading *threading ) 173 | { 174 | (void) paUtilErr_; 175 | return paNoError; 176 | } 177 | 178 | void PaUtil_TerminateThreading( PaUtilThreading *threading ) 179 | { 180 | } 181 | 182 | PaError PaUtil_StartThreading( PaUtilThreading *threading, void *(*threadRoutine)(void *), void *data ) 183 | { 184 | pthread_create( &threading->callbackThread, NULL, threadRoutine, data ); 185 | return paNoError; 186 | } 187 | 188 | PaError PaUtil_CancelThreading( PaUtilThreading *threading, int wait, PaError *exitResult ) 189 | { 190 | PaError result = paNoError; 191 | void *pret; 192 | 193 | if( exitResult ) 194 | *exitResult = paNoError; 195 | 196 | /* If pthread_cancel is not supported (Android platform) whole this function can lead to indefinite waiting if 197 | working thread (callbackThread) has'n received any stop signals from outside, please keep 198 | this in mind when considering using PaUtil_CancelThreading 199 | */ 200 | #ifdef PTHREAD_CANCELED 201 | /* Only kill the thread if it isn't in the process of stopping (flushing adaptation buffers) */ 202 | if( !wait ) 203 | pthread_cancel( threading->callbackThread ); /* XXX: Safe to call this if the thread has exited on its own? */ 204 | #endif 205 | pthread_join( threading->callbackThread, &pret ); 206 | 207 | #ifdef PTHREAD_CANCELED 208 | if( pret && PTHREAD_CANCELED != pret ) 209 | #else 210 | /* !wait means the thread may have been canceled */ 211 | if( pret && wait ) 212 | #endif 213 | { 214 | if( exitResult ) 215 | *exitResult = *(PaError *) pret; 216 | free( pret ); 217 | } 218 | 219 | return result; 220 | } 221 | 222 | /* Threading */ 223 | /* paUnixMainThread 224 | * We have to be a bit careful with defining this global variable, 225 | * as explained below. */ 226 | #ifdef __APPLE__ 227 | /* apple/gcc has a "problem" with global vars and dynamic libs. 228 | Initializing it seems to fix the problem. 229 | Described a bit in this thread: 230 | http://gcc.gnu.org/ml/gcc/2005-06/msg00179.html 231 | */ 232 | pthread_t paUnixMainThread = 0; 233 | #else 234 | /*pthreads are opaque. We don't know that asigning it an int value 235 | always makes sense, so we don't initialize it unless we have to.*/ 236 | pthread_t paUnixMainThread = 0; 237 | #endif 238 | 239 | PaError PaUnixThreading_Initialize() 240 | { 241 | paUnixMainThread = pthread_self(); 242 | return paNoError; 243 | } 244 | 245 | static PaError BoostPriority( PaUnixThread* self ) 246 | { 247 | PaError result = paNoError; 248 | struct sched_param spm = { 0 }; 249 | /* Priority should only matter between contending FIFO threads? */ 250 | spm.sched_priority = 1; 251 | 252 | assert( self ); 253 | 254 | if( pthread_setschedparam( self->thread, SCHED_FIFO, &spm ) != 0 ) 255 | { 256 | PA_UNLESS( errno == EPERM, paInternalError ); /* Lack permission to raise priority */ 257 | PA_DEBUG(( "Failed bumping priority\n" )); 258 | result = 0; 259 | } 260 | else 261 | { 262 | result = 1; /* Success */ 263 | } 264 | error: 265 | return result; 266 | } 267 | 268 | PaError PaUnixThread_New( PaUnixThread* self, void* (*threadFunc)( void* ), void* threadArg, PaTime waitForChild, 269 | int rtSched ) 270 | { 271 | PaError result = paNoError; 272 | pthread_attr_t attr; 273 | int started = 0; 274 | 275 | memset( self, 0, sizeof (PaUnixThread) ); 276 | PaUnixMutex_Initialize( &self->mtx ); 277 | PA_ASSERT_CALL( pthread_cond_init( &self->cond, NULL ), 0 ); 278 | 279 | self->parentWaiting = 0 != waitForChild; 280 | 281 | /* Spawn thread */ 282 | 283 | /* Temporarily disabled since we should test during configuration for presence of required mman.h header */ 284 | #if 0 285 | #if defined _POSIX_MEMLOCK && (_POSIX_MEMLOCK != -1) 286 | if( rtSched ) 287 | { 288 | if( mlockall( MCL_CURRENT | MCL_FUTURE ) < 0 ) 289 | { 290 | int savedErrno = errno; /* In case errno gets overwritten */ 291 | assert( savedErrno != EINVAL ); /* Most likely a programmer error */ 292 | PA_UNLESS( (savedErrno == EPERM), paInternalError ); 293 | PA_DEBUG(( "%s: Failed locking memory\n", __FUNCTION__ )); 294 | } 295 | else 296 | PA_DEBUG(( "%s: Successfully locked memory\n", __FUNCTION__ )); 297 | } 298 | #endif 299 | #endif 300 | 301 | PA_UNLESS( !pthread_attr_init( &attr ), paInternalError ); 302 | /* Priority relative to other processes */ 303 | PA_UNLESS( !pthread_attr_setscope( &attr, PTHREAD_SCOPE_SYSTEM ), paInternalError ); 304 | 305 | PA_UNLESS( !pthread_create( &self->thread, &attr, threadFunc, threadArg ), paInternalError ); 306 | started = 1; 307 | 308 | if( rtSched ) 309 | { 310 | #if 0 311 | if( self->useWatchdog ) 312 | { 313 | int err; 314 | struct sched_param wdSpm = { 0 }; 315 | /* Launch watchdog, watchdog sets callback thread priority */ 316 | int prio = PA_MIN( self->rtPrio + 4, sched_get_priority_max( SCHED_FIFO ) ); 317 | wdSpm.sched_priority = prio; 318 | 319 | PA_UNLESS( !pthread_attr_init( &attr ), paInternalError ); 320 | PA_UNLESS( !pthread_attr_setinheritsched( &attr, PTHREAD_EXPLICIT_SCHED ), paInternalError ); 321 | PA_UNLESS( !pthread_attr_setscope( &attr, PTHREAD_SCOPE_SYSTEM ), paInternalError ); 322 | PA_UNLESS( !pthread_attr_setschedpolicy( &attr, SCHED_FIFO ), paInternalError ); 323 | PA_UNLESS( !pthread_attr_setschedparam( &attr, &wdSpm ), paInternalError ); 324 | if( (err = pthread_create( &self->watchdogThread, &attr, &WatchdogFunc, self )) ) 325 | { 326 | PA_UNLESS( err == EPERM, paInternalError ); 327 | /* Permission error, go on without realtime privileges */ 328 | PA_DEBUG(( "Failed bumping priority\n" )); 329 | } 330 | else 331 | { 332 | int policy; 333 | self->watchdogRunning = 1; 334 | PA_ENSURE_SYSTEM( pthread_getschedparam( self->watchdogThread, &policy, &wdSpm ), 0 ); 335 | /* Check if priority is right, policy could potentially differ from SCHED_FIFO (but that's alright) */ 336 | if( wdSpm.sched_priority != prio ) 337 | { 338 | PA_DEBUG(( "Watchdog priority not set correctly (%d)\n", wdSpm.sched_priority )); 339 | PA_ENSURE( paInternalError ); 340 | } 341 | } 342 | } 343 | else 344 | #endif 345 | PA_ENSURE( BoostPriority( self ) ); 346 | 347 | { 348 | int policy; 349 | struct sched_param spm; 350 | pthread_getschedparam(self->thread, &policy, &spm); 351 | } 352 | } 353 | 354 | if( self->parentWaiting ) 355 | { 356 | PaTime till; 357 | struct timespec ts; 358 | int res = 0; 359 | PaTime now; 360 | 361 | PA_ENSURE( PaUnixMutex_Lock( &self->mtx ) ); 362 | 363 | /* Wait for stream to be started */ 364 | now = PaUtil_GetTime(); 365 | till = now + waitForChild; 366 | 367 | while( self->parentWaiting && !res ) 368 | { 369 | if( waitForChild > 0 ) 370 | { 371 | ts.tv_sec = (time_t) floor( till ); 372 | ts.tv_nsec = (long) ((till - floor( till )) * 1e9); 373 | res = pthread_cond_timedwait( &self->cond, &self->mtx.mtx, &ts ); 374 | } 375 | else 376 | { 377 | res = pthread_cond_wait( &self->cond, &self->mtx.mtx ); 378 | } 379 | } 380 | 381 | PA_ENSURE( PaUnixMutex_Unlock( &self->mtx ) ); 382 | 383 | PA_UNLESS( !res || ETIMEDOUT == res, paInternalError ); 384 | PA_DEBUG(( "%s: Waited for %g seconds for stream to start\n", __FUNCTION__, PaUtil_GetTime() - now )); 385 | if( ETIMEDOUT == res ) 386 | { 387 | PA_ENSURE( paTimedOut ); 388 | } 389 | } 390 | 391 | end: 392 | return result; 393 | error: 394 | if( started ) 395 | { 396 | PaUnixThread_Terminate( self, 0, NULL ); 397 | } 398 | 399 | goto end; 400 | } 401 | 402 | PaError PaUnixThread_Terminate( PaUnixThread* self, int wait, PaError* exitResult ) 403 | { 404 | PaError result = paNoError; 405 | void* pret; 406 | 407 | if( exitResult ) 408 | { 409 | *exitResult = paNoError; 410 | } 411 | #if 0 412 | if( watchdogExitResult ) 413 | *watchdogExitResult = paNoError; 414 | 415 | if( th->watchdogRunning ) 416 | { 417 | pthread_cancel( th->watchdogThread ); 418 | PA_ENSURE_SYSTEM( pthread_join( th->watchdogThread, &pret ), 0 ); 419 | 420 | if( pret && pret != PTHREAD_CANCELED ) 421 | { 422 | if( watchdogExitResult ) 423 | *watchdogExitResult = *(PaError *) pret; 424 | free( pret ); 425 | } 426 | } 427 | #endif 428 | 429 | /* Only kill the thread if it isn't in the process of stopping (flushing adaptation buffers) */ 430 | /* TODO: Make join time out */ 431 | self->stopRequested = wait; 432 | if( !wait ) 433 | { 434 | PA_DEBUG(( "%s: Canceling thread %d\n", __FUNCTION__, self->thread )); 435 | /* XXX: Safe to call this if the thread has exited on its own? */ 436 | #ifdef PTHREAD_CANCELED 437 | pthread_cancel( self->thread ); 438 | #endif 439 | } 440 | PA_DEBUG(( "%s: Joining thread %d\n", __FUNCTION__, self->thread )); 441 | PA_ENSURE_SYSTEM( pthread_join( self->thread, &pret ), 0 ); 442 | 443 | #ifdef PTHREAD_CANCELED 444 | if( pret && PTHREAD_CANCELED != pret ) 445 | #else 446 | /* !wait means the thread may have been canceled */ 447 | if( pret && wait ) 448 | #endif 449 | { 450 | if( exitResult ) 451 | { 452 | *exitResult = *(PaError*)pret; 453 | } 454 | free( pret ); 455 | } 456 | 457 | error: 458 | PA_ASSERT_CALL( PaUnixMutex_Terminate( &self->mtx ), paNoError ); 459 | PA_ASSERT_CALL( pthread_cond_destroy( &self->cond ), 0 ); 460 | 461 | return result; 462 | } 463 | 464 | PaError PaUnixThread_PrepareNotify( PaUnixThread* self ) 465 | { 466 | PaError result = paNoError; 467 | PA_UNLESS( self->parentWaiting, paInternalError ); 468 | 469 | PA_ENSURE( PaUnixMutex_Lock( &self->mtx ) ); 470 | self->locked = 1; 471 | 472 | error: 473 | return result; 474 | } 475 | 476 | PaError PaUnixThread_NotifyParent( PaUnixThread* self ) 477 | { 478 | PaError result = paNoError; 479 | PA_UNLESS( self->parentWaiting, paInternalError ); 480 | 481 | if( !self->locked ) 482 | { 483 | PA_ENSURE( PaUnixMutex_Lock( &self->mtx ) ); 484 | self->locked = 1; 485 | } 486 | self->parentWaiting = 0; 487 | pthread_cond_signal( &self->cond ); 488 | PA_ENSURE( PaUnixMutex_Unlock( &self->mtx ) ); 489 | self->locked = 0; 490 | 491 | error: 492 | return result; 493 | } 494 | 495 | int PaUnixThread_StopRequested( PaUnixThread* self ) 496 | { 497 | return self->stopRequested; 498 | } 499 | 500 | PaError PaUnixMutex_Initialize( PaUnixMutex* self ) 501 | { 502 | PaError result = paNoError; 503 | PA_ASSERT_CALL( pthread_mutex_init( &self->mtx, NULL ), 0 ); 504 | return result; 505 | } 506 | 507 | PaError PaUnixMutex_Terminate( PaUnixMutex* self ) 508 | { 509 | PaError result = paNoError; 510 | PA_ASSERT_CALL( pthread_mutex_destroy( &self->mtx ), 0 ); 511 | return result; 512 | } 513 | 514 | /** Lock mutex. 515 | * 516 | * We're disabling thread cancellation while the thread is holding a lock, so mutexes are 517 | * properly unlocked at termination time. 518 | */ 519 | PaError PaUnixMutex_Lock( PaUnixMutex* self ) 520 | { 521 | PaError result = paNoError; 522 | 523 | #ifdef PTHREAD_CANCEL 524 | int oldState; 525 | PA_ENSURE_SYSTEM( pthread_setcancelstate( PTHREAD_CANCEL_DISABLE, &oldState ), 0 ); 526 | #endif 527 | PA_ENSURE_SYSTEM( pthread_mutex_lock( &self->mtx ), 0 ); 528 | 529 | error: 530 | return result; 531 | } 532 | 533 | /** Unlock mutex. 534 | * 535 | * Thread cancellation is enabled again after the mutex is properly unlocked. 536 | */ 537 | PaError PaUnixMutex_Unlock( PaUnixMutex* self ) 538 | { 539 | PaError result = paNoError; 540 | 541 | PA_ENSURE_SYSTEM( pthread_mutex_unlock( &self->mtx ), 0 ); 542 | #ifdef PTHREAD_CANCEL 543 | int oldState; 544 | PA_ENSURE_SYSTEM( pthread_setcancelstate( PTHREAD_CANCEL_ENABLE, &oldState ), 0 ); 545 | #endif 546 | 547 | error: 548 | return result; 549 | } 550 | 551 | 552 | #if 0 553 | static void OnWatchdogExit( void *userData ) 554 | { 555 | PaAlsaThreading *th = (PaAlsaThreading *) userData; 556 | struct sched_param spm = { 0 }; 557 | assert( th ); 558 | 559 | PA_ASSERT_CALL( pthread_setschedparam( th->callbackThread, SCHED_OTHER, &spm ), 0 ); /* Lower before exiting */ 560 | PA_DEBUG(( "Watchdog exiting\n" )); 561 | } 562 | 563 | static void *WatchdogFunc( void *userData ) 564 | { 565 | PaError result = paNoError, *pres = NULL; 566 | int err; 567 | PaAlsaThreading *th = (PaAlsaThreading *) userData; 568 | unsigned intervalMsec = 500; 569 | const PaTime maxSeconds = 3.; /* Max seconds between callbacks */ 570 | PaTime timeThen = PaUtil_GetTime(), timeNow, timeElapsed, cpuTimeThen, cpuTimeNow, cpuTimeElapsed; 571 | double cpuLoad, avgCpuLoad = 0.; 572 | int throttled = 0; 573 | 574 | assert( th ); 575 | 576 | /* Execute OnWatchdogExit when exiting */ 577 | pthread_cleanup_push( &OnWatchdogExit, th ); 578 | 579 | /* Boost priority of callback thread */ 580 | PA_ENSURE( result = BoostPriority( th ) ); 581 | if( !result ) 582 | { 583 | /* Boost failed, might as well exit */ 584 | pthread_exit( NULL ); 585 | } 586 | 587 | cpuTimeThen = th->callbackCpuTime; 588 | { 589 | int policy; 590 | struct sched_param spm = { 0 }; 591 | pthread_getschedparam( pthread_self(), &policy, &spm ); 592 | PA_DEBUG(( "%s: Watchdog priority is %d\n", __FUNCTION__, spm.sched_priority )); 593 | } 594 | 595 | while( 1 ) 596 | { 597 | double lowpassCoeff = 0.9, lowpassCoeff1 = 0.99999 - lowpassCoeff; 598 | 599 | /* Test before and after in case whatever underlying sleep call isn't interrupted by pthread_cancel */ 600 | pthread_testcancel(); 601 | Pa_Sleep( intervalMsec ); 602 | pthread_testcancel(); 603 | 604 | if( PaUtil_GetTime() - th->callbackTime > maxSeconds ) 605 | { 606 | PA_DEBUG(( "Watchdog: Terminating callback thread\n" )); 607 | /* Tell thread to terminate */ 608 | err = pthread_kill( th->callbackThread, SIGKILL ); 609 | pthread_exit( NULL ); 610 | } 611 | 612 | PA_DEBUG(( "%s: PortAudio reports CPU load: %g\n", __FUNCTION__, PaUtil_GetCpuLoad( th->cpuLoadMeasurer ) )); 613 | 614 | /* Check if we should throttle, or unthrottle :P */ 615 | cpuTimeNow = th->callbackCpuTime; 616 | cpuTimeElapsed = cpuTimeNow - cpuTimeThen; 617 | cpuTimeThen = cpuTimeNow; 618 | 619 | timeNow = PaUtil_GetTime(); 620 | timeElapsed = timeNow - timeThen; 621 | timeThen = timeNow; 622 | cpuLoad = cpuTimeElapsed / timeElapsed; 623 | avgCpuLoad = avgCpuLoad * lowpassCoeff + cpuLoad * lowpassCoeff1; 624 | /* 625 | if( throttled ) 626 | PA_DEBUG(( "Watchdog: CPU load: %g, %g\n", avgCpuLoad, cpuTimeElapsed )); 627 | */ 628 | if( PaUtil_GetCpuLoad( th->cpuLoadMeasurer ) > .925 ) 629 | { 630 | static int policy; 631 | static struct sched_param spm = { 0 }; 632 | static const struct sched_param defaultSpm = { 0 }; 633 | PA_DEBUG(( "%s: Throttling audio thread, priority %d\n", __FUNCTION__, spm.sched_priority )); 634 | 635 | pthread_getschedparam( th->callbackThread, &policy, &spm ); 636 | if( !pthread_setschedparam( th->callbackThread, SCHED_OTHER, &defaultSpm ) ) 637 | { 638 | throttled = 1; 639 | } 640 | else 641 | PA_DEBUG(( "Watchdog: Couldn't lower priority of audio thread: %s\n", strerror( errno ) )); 642 | 643 | /* Give other processes a go, before raising priority again */ 644 | PA_DEBUG(( "%s: Watchdog sleeping for %lu msecs before unthrottling\n", __FUNCTION__, th->throttledSleepTime )); 645 | Pa_Sleep( th->throttledSleepTime ); 646 | 647 | /* Reset callback priority */ 648 | if( pthread_setschedparam( th->callbackThread, SCHED_FIFO, &spm ) != 0 ) 649 | { 650 | PA_DEBUG(( "%s: Couldn't raise priority of audio thread: %s\n", __FUNCTION__, strerror( errno ) )); 651 | } 652 | 653 | if( PaUtil_GetCpuLoad( th->cpuLoadMeasurer ) >= .99 ) 654 | intervalMsec = 50; 655 | else 656 | intervalMsec = 100; 657 | 658 | /* 659 | lowpassCoeff = .97; 660 | lowpassCoeff1 = .99999 - lowpassCoeff; 661 | */ 662 | } 663 | else if( throttled && avgCpuLoad < .8 ) 664 | { 665 | intervalMsec = 500; 666 | throttled = 0; 667 | 668 | /* 669 | lowpassCoeff = .9; 670 | lowpassCoeff1 = .99999 - lowpassCoeff; 671 | */ 672 | } 673 | } 674 | 675 | pthread_cleanup_pop( 1 ); /* Execute cleanup on exit */ 676 | 677 | error: 678 | /* Shouldn't get here in the normal case */ 679 | 680 | /* Pass on error code */ 681 | pres = malloc( sizeof (PaError) ); 682 | *pres = result; 683 | 684 | pthread_exit( pres ); 685 | } 686 | 687 | static void CallbackUpdate( PaAlsaThreading *th ) 688 | { 689 | th->callbackTime = PaUtil_GetTime(); 690 | th->callbackCpuTime = PaUtil_GetCpuLoad( th->cpuLoadMeasurer ); 691 | } 692 | 693 | /* 694 | static void *CanaryFunc( void *userData ) 695 | { 696 | const unsigned intervalMsec = 1000; 697 | PaUtilThreading *th = (PaUtilThreading *) userData; 698 | 699 | while( 1 ) 700 | { 701 | th->canaryTime = PaUtil_GetTime(); 702 | 703 | pthread_testcancel(); 704 | Pa_Sleep( intervalMsec ); 705 | } 706 | 707 | pthread_exit( NULL ); 708 | } 709 | */ 710 | #endif 711 | -------------------------------------------------------------------------------- /src/video.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #define GET_HEIGHT(h) (h) 10 | #define GET_WIDTH(w) (((w)/8)*8) 11 | 12 | #define COLOR_DEPTH 3 13 | #define BANDWIDTH_BUFLEN 64 14 | 15 | static connection_t *cons; 16 | static size_t conslen; 17 | static pthread_mutex_t conslock; 18 | static CvCapture* cv_cap; 19 | static int disp_bandwidth = 0; 20 | static int width; 21 | static int height; 22 | static int depth = COLOR_DEPTH; 23 | static int render_type; /* 0 default, 1 braille */ 24 | 25 | static void callback(connection_t *con, void *data, size_t length) { 26 | unsigned long index = ntohl(((unsigned long*)data)[0]); 27 | int y = index; 28 | 29 | if (render_type == 1) { 30 | draw_braille(&(((char*)data)[(sizeof(unsigned long))]), length - (sizeof(unsigned long)), y, depth); 31 | } else { 32 | draw_line(&(((char*)data)[(sizeof(unsigned long))]), length - (sizeof(unsigned long)), y, depth); 33 | } 34 | 35 | if (disp_bandwidth) { 36 | char bandstr[BANDWIDTH_BUFLEN]; 37 | memset(bandstr, 0, BANDWIDTH_BUFLEN); 38 | sprintf(bandstr, " Bandwidth : %f MB/s", 1000 * p2p_bandwidth()); 39 | write_bandwidth(bandstr, strlen(bandstr), width, height); 40 | } 41 | } 42 | 43 | static void new_callback(connection_t *con, void *data, size_t datalen) { 44 | pthread_mutex_lock(&conslock); 45 | conslen++; 46 | cons = realloc(cons, conslen * sizeof(connection_t)); 47 | memcpy(&(cons[conslen-1]), con, sizeof(connection_t)); 48 | pthread_mutex_unlock(&conslock); 49 | } 50 | 51 | void video_shutdown(int signal) { 52 | cvReleaseCapture( &cv_cap ); 53 | end_screen(); 54 | } 55 | 56 | static void *dolisten(void *args) { 57 | int socket; 58 | int port = atoi((char *)args); 59 | p2p_init(port, &socket); 60 | p2p_listener((connection_t **)&cons, &conslen, &conslock, &callback, &new_callback, socket, width * height * depth); 61 | return NULL; 62 | } 63 | 64 | int start_video(char *peer, char *port, vid_options_t *vopt) { 65 | width = GET_WIDTH(vopt->width); 66 | height = GET_HEIGHT(vopt->height); 67 | render_type = vopt->render_type; 68 | disp_bandwidth = vopt->disp_bandwidth; 69 | 70 | display_options_t dopt; 71 | memset(&dopt, 0, sizeof(display_options_t)); 72 | 73 | dopt.intensity_threshold = vopt->intensity_threshold; 74 | dopt.saturation = vopt->saturation; 75 | dopt.monochrome = vopt->monochrome; 76 | dopt.r = vopt->r; 77 | dopt.g = vopt->g; 78 | dopt.b = vopt->b; 79 | dopt.ascii_values = vopt->ascii_values; 80 | 81 | init_screen(&dopt); 82 | curs_set(0); 83 | pthread_mutex_init(&conslock, NULL); 84 | 85 | cons = calloc(1, sizeof(connection_t)); 86 | if (p2p_connect(peer, port, &(cons[0]))) { 87 | fprintf(stderr, "Unable to connect to server.\n"); 88 | } else { 89 | conslen++; 90 | } 91 | 92 | pthread_t thr; 93 | pthread_create(&thr, NULL, &dolisten, (void *)port); 94 | 95 | IplImage* color_img; 96 | IplImage* resize_img = cvCreateImage(cvSize(width, height), 8, 3); 97 | IplImage* edge = cvCreateImage(cvGetSize(resize_img), IPL_DEPTH_8U, 1); 98 | 99 | cv_cap = cvCaptureFromCAM(0); 100 | char line_buffer[sizeof(unsigned long) + width * depth]; 101 | struct timespec tim, actual_tim; 102 | tim.tv_sec = 0; 103 | tim.tv_nsec = (1000000000 - 1) / vopt->refresh_rate; 104 | int kernel = 7; 105 | while (1) { 106 | /* Get each frame */ 107 | color_img = cvQueryFrame(cv_cap); 108 | if(color_img && resize_img) { 109 | cvResize(color_img, resize_img, CV_INTER_AREA); 110 | if (vopt->edge_filter) { 111 | cvCvtColor(resize_img, edge, CV_BGR2GRAY); 112 | cvCanny(edge, edge, vopt->edge_lower * kernel * kernel, vopt->edge_upper * kernel * kernel, kernel); 113 | cvCvtColor(edge, resize_img, CV_GRAY2BGR); 114 | } 115 | unsigned long line_index; 116 | for (line_index = 0; line_index < (resize_img->imageSize / (width * depth)); line_index++) { 117 | memset(line_buffer, 0, sizeof(line_buffer)); 118 | unsigned long send_index = htonl(line_index); 119 | memcpy(line_buffer, &send_index, sizeof(unsigned long)); 120 | memcpy(&(line_buffer[sizeof(unsigned long)]), resize_img->imageData + (line_index * width * depth), width * depth); 121 | p2p_broadcast(&cons, &conslen, &conslock, line_buffer, + sizeof(line_buffer)); 122 | } 123 | nanosleep(&tim, &actual_tim); 124 | } 125 | } 126 | 127 | /* Housekeeping */ 128 | cvReleaseCapture(&cv_cap); 129 | end_screen(); 130 | return 0; 131 | } 132 | 133 | #ifdef VIDEOONLY 134 | int main(int argc, char *argv[]) { 135 | vid_options_t vopt; 136 | memset(&vopt, 0, sizeof(vid_options_t)); 137 | vopt.width = 100; 138 | vopt.height = 40; 139 | vopt.disp_bandwidth = 0; 140 | return start_video(argv[1], "55556", &vopt); 141 | } 142 | #endif 143 | 144 | --------------------------------------------------------------------------------