├── .gitignore ├── .npmignore ├── LICENSE ├── README.md ├── binding.gyp ├── examples ├── inputToFile.js ├── smokePlay.js └── smokeSine.js ├── index.ts ├── package.json ├── portaudio ├── bin │ ├── libportaudio.dylib │ ├── libportaudio.so.2 │ ├── portaudio_x64.dll │ └── portaudio_x64.lib ├── bin_armhf │ └── libportaudio.so.2 ├── include │ ├── pa_mac_core.h │ └── portaudio.h └── msvc │ ├── build.bat │ ├── portaudio.def │ ├── portaudio.vcxproj │ └── readme.txt ├── src ├── AudioIn.cc ├── AudioIn.h ├── AudioOut.cc ├── AudioOut.h ├── ChunkQueue.h ├── GetDevices.cc ├── GetDevices.h ├── Memory.h ├── Params.h ├── Persist.h ├── common.cc ├── common.h └── node_pa.cc ├── tsconfig.json ├── tslint.json └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | build 3 | index.js 4 | index.d.ts 5 | node_modules 6 | yarn-error.log 7 | *.wav 8 | *.raw 9 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | build 2 | index.ts 3 | tsconfig.json 4 | tslint.json 5 | yarn-error.log -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2018 Aurora API. 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # node-portaudio 2 | 3 | A [Node.js](http://nodejs.org/) [addon](http://nodejs.org/api/addons.html) that provides a wrapper around the [PortAudio](http://portaudio.com/) library, enabling an application to record and play audio with cross platform support. With this library, you can create [node.js streams](https://nodejs.org/dist/latest-v6.x/docs/api/stream.html) that can be piped to or from other streams, such as files and network connections. This library supports back-pressure. 4 | 5 | This is a fork of [naudiodon](https://github.com/Streampunk/naudiodon), refactored by: 6 | 7 | * porting the entire codebase to TypeScript 8 | * adding better documentation 9 | * adding some more functionality 10 | 11 | See forked repository for credits for corresponding contributions. 12 | 13 | Note: This is a server side library. It is not intended as a means to play and record audio via a browser. 14 | 15 | ## Installation 16 | 17 | Install [Node.js](http://nodejs.org/) for your platform. This software has been developed against the long term stable (LTS) release. For ease of installation with other node packages, this package includes a copy of the dependent PortAudio library and so has no prerequisites. 18 | 19 | `node-portaudio` is designed to be `require`d or `import`ed to use from your own application to provide async processing. For example: 20 | 21 | npm install --save node-portaudio 22 | 23 | For Raspberry Pi users, please note that this library is not intended for use with the internal sound card. Please use an external USB sound card or GPIO breakout board such as the [_Pi-DAC+ Full-HD Audio Card_](https://www.modmypi.com/raspberry-pi/breakout-boards/iqaudio/pi-dac-plus-full-hd-audio-card/?tag=pi-dac). 24 | 25 | ## Using node-portaudio 26 | 27 | If you are using regular Node.js, include the library with: 28 | 29 | ```javascript 30 | const portAudio = require('node-portaudio'); 31 | ``` 32 | 33 | If you are using TypeScript, definitions have been provided and you can import the library with: 34 | 35 | ```typescript 36 | import * as portAudio from 'node-portaudio'; 37 | ``` 38 | 39 | ### Listing devices 40 | 41 | To get list of supported devices, call the `getDevices()` function. 42 | 43 | ```javascript 44 | const portAudio = require('node-portaudio'); 45 | 46 | console.log(portAudio.getDevices()); 47 | ``` 48 | 49 | An example of the output is: 50 | 51 | ```javascript 52 | [ { id: 0, 53 | name: 'Built-in Microph', 54 | maxInputChannels: 2, 55 | maxOutputChannels: 0, 56 | defaultSampleRate: 44100, 57 | defaultLowInputLatency: 0.00199546485260771, 58 | defaultLowOutputLatency: 0.01, 59 | defaultHighInputLatency: 0.012154195011337868, 60 | defaultHighOutputLatency: 0.1, 61 | hostAPIName: 'Core Audio' }, 62 | { id: 1, 63 | name: 'Built-in Input', 64 | maxInputChannels: 2, 65 | maxOutputChannels: 0, 66 | defaultSampleRate: 44100, 67 | defaultLowInputLatency: 0.00199546485260771, 68 | defaultLowOutputLatency: 0.01, 69 | defaultHighInputLatency: 0.012154195011337868, 70 | defaultHighOutputLatency: 0.1, 71 | hostAPIName: 'Core Audio' }, 72 | { id: 2, 73 | name: 'Built-in Output', 74 | maxInputChannels: 0, 75 | maxOutputChannels: 2, 76 | defaultSampleRate: 44100, 77 | defaultLowInputLatency: 0.01, 78 | defaultLowOutputLatency: 0.002108843537414966, 79 | defaultHighInputLatency: 0.1, 80 | defaultHighOutputLatency: 0.012267573696145125, 81 | hostAPIName: 'Core Audio' } ] 82 | ``` 83 | 84 | Note that the device `id` parameter index value can be used as to specify which device to use for playback or recording with optional parameter `deviceId`. 85 | 86 | ### Playing audio 87 | 88 | Playing audio involves streaming audio data to an instance of `AudioOutput`. 89 | 90 | ```javascript 91 | const fs = require('fs'); 92 | const portAudio = require('node-portaudio'); 93 | 94 | // Create an instance of AudioOutput, which is a WriteableStream 95 | const ao = new portAudio.AudioOutput({ 96 | channelCount: 2, 97 | sampleFormat: portAudio.SampleFormat16Bit, 98 | sampleRate: 48000, 99 | deviceId : -1 // Use -1 or omit the deviceId to select the default device 100 | }); 101 | 102 | // handle errors from the AudioOutput 103 | ao.on('error', err => console.error); 104 | 105 | // Create a stream to pipe into the AudioOutput 106 | // Note that this does not strip the WAV header so a click will be heard at the beginning 107 | const rs = fs.createReadStream('steam_48000.wav'); 108 | 109 | // setup to close the output stream at the end of the read stream 110 | rs.on('end', () => ao.end()); 111 | 112 | // Start piping data and start streaming 113 | rs.pipe(ao); 114 | ao.start(); 115 | ``` 116 | 117 | ### Recording audio 118 | 119 | Recording audio invovles reading from an instance of `AudioInput`. 120 | 121 | ```javascript 122 | const fs = require('fs'); 123 | const portAudio = require('node-portaudio'); 124 | 125 | // Create an instance of AudioInput, which is a ReadableStream 126 | const ai = new portAudio.AudioInput({ 127 | channelCount: 2, 128 | sampleFormat: portAudio.SampleFormat16Bit, 129 | sampleRate: 44100 130 | deviceId : -1 // Use -1 or omit the deviceId to select the default device 131 | }); 132 | 133 | // handle errors from the AudioInput 134 | ai.on('error', err => console.error); 135 | 136 | // Create a write stream to write out to a raw audio file 137 | const ws = fs.createWriteStream('rawAudio.raw'); 138 | 139 | //Start streaming 140 | ai.pipe(ws); 141 | ai.start(); 142 | 143 | ``` 144 | 145 | Note that this produces a raw audio file - wav headers would be required to create a wav file. However this basic example produces a file may be read by audio software such as Audacity, using the sample rate and format parameters set when establishing the stream. 146 | 147 | To stop the recording, call `ai.quit()`. For example: 148 | 149 | ```javascript 150 | process.on('SIGINT', () => { 151 | console.log('Received SIGINT. Stopping recording.'); 152 | ai.quit(); 153 | }); 154 | ``` 155 | 156 | ## Troubleshooting 157 | 158 | ### Linux - No Default Device Found 159 | 160 | Ensure that when you compile portaudio that the configure scripts says "ALSA" yes. 161 | 162 | ### Mac - Carbon Component Manager 163 | 164 | You may see or have seen the following message during initilisation of the audio library on MacOS: 165 | 166 | ``` 167 | WARNING: 140: This application, or a library it uses, is using the deprecated Carbon Component Manager 168 | for hosting Audio Units. Support for this will be removed in a future release. Also, this makes the host 169 | incompatible with version 3 audio units. Please transition to the API's in AudioComponent.h. 170 | ``` 171 | 172 | A locally compiled version of the portaudio library is now included with the latest version of `node-portaudio` that uses more up-to-date APIs from Apple. The portaudio team are [aware of this issue](https://app.assembla.com/spaces/portaudio/tickets/218-pa-coreaudio-uses-some--quot-deprecated-quot--apis----this-is-by-design-but-need/details). 173 | 174 | ## Status, support and further development 175 | 176 | This library was created mostly to port to TypeScript and add some additional PortAudio functionality. It may be developed further if more features are requested. Additionally, you can create a PR to add some of your own functionality. 177 | 178 | ## License 179 | 180 | This software uses libraries from the PortAudio project. The [license terms for PortAudio](http://portaudio.com/license.html) are stated to be an [MIT license](http://opensource.org/licenses/mit-license.php). 181 | -------------------------------------------------------------------------------- /binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "node_pa", 5 | "sources": [ 6 | "src/node_pa.cc", 7 | "src/GetDevices.cc", 8 | "src/AudioIn.cc", 9 | "src/AudioOut.cc", 10 | "src/common.cc" 11 | ], 12 | "include_dirs": [ 13 | " ai.quit()); 21 | -------------------------------------------------------------------------------- /examples/smokePlay.js: -------------------------------------------------------------------------------- 1 | /* Copyright 2017 Streampunk Media Ltd. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | // Plays the sound of a steam train from file 'test.wav'. 17 | 18 | var portAudio = require('../index.js'); 19 | var fs = require('fs'); 20 | var file = fs.readFileSync('test.wav'); 21 | 22 | console.log(portAudio.getDevices()); 23 | 24 | var ao = new portAudio.AudioOutput({ 25 | channelCount: 1, 26 | sampleFormat: portAudio.SampleFormat16Bit, 27 | sampleRate: 44100, 28 | deviceId: -1 29 | }); 30 | 31 | ao.on('error', console.error); 32 | ao.start(); 33 | ao.write(file); 34 | ao.end(); 35 | 36 | process.on('SIGINT', () => ao.quit()); 37 | -------------------------------------------------------------------------------- /examples/smokeSine.js: -------------------------------------------------------------------------------- 1 | /* Copyright 2017 Streampunk Media Ltd. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | // Plays a since wave for approx 10 seconds 17 | 18 | const portAudio = require('../index.js'); 19 | 20 | // create a sine wave lookup table 21 | var sampleRate = 44100; 22 | var tableSize = 200; 23 | var buffer = Buffer.allocUnsafe(tableSize * 4); 24 | for (var i = 0; i < tableSize * 4; i++) { 25 | buffer[i] = (Math.sin((i / tableSize) * 3.1415 * 2.0) * 127); 26 | } 27 | 28 | var ao = new portAudio.AudioOutput({ 29 | channelCount: 1, 30 | sampleFormat: portAudio.SampleFormat8Bit, 31 | sampleRate: sampleRate, 32 | deviceId: -1 33 | }); 34 | 35 | function tenSecondsIsh(writer, data, callback) { 36 | var i = 552; 37 | write(); 38 | function write() { 39 | var ok = true; 40 | console.log(i); 41 | do { 42 | i -= 1; 43 | if (i === 0) { 44 | // last time! 45 | writer.end(data, callback); 46 | } else { 47 | // see if we should continue, or wait 48 | // don't pass the callback, because we're not done yet. 49 | ok = writer.write(data); 50 | console.log(ok); 51 | // console.log('Writing data', ok); 52 | } 53 | } while (i > 0 && ok); 54 | if (i > 0) { 55 | // had to stop early! 56 | // write some more once it drains 57 | writer.once('drain', write); 58 | } 59 | } 60 | } 61 | 62 | ao.on('error', console.error); 63 | 64 | tenSecondsIsh(ao, buffer, console.log.bind(null, "Done!")); 65 | ao.start(); 66 | 67 | process.once('SIGINT', () => ao.quit()); 68 | -------------------------------------------------------------------------------- /index.ts: -------------------------------------------------------------------------------- 1 | import bindings from "bindings"; 2 | import { Readable, Writable } from "stream"; 3 | 4 | const NodePA = bindings("node_pa.node"); 5 | 6 | /////////////////////////////////////////////////////////////////////////////// 7 | // Sample format widths // 8 | /////////////////////////////////////////////////////////////////////////////// 9 | 10 | /** Use 8-bit samples to read/write to PortAudio */ 11 | export const SampleFormat8Bit = 8; 12 | /** Use 16-bit samples to read/write to PortAudio */ 13 | export const SampleFormat16Bit = 16; 14 | /** Use 24-bit samples to read/write to PortAudio */ 15 | export const SampleFormat24Bit = 24; 16 | /** Use 32-bit samples to read/write to PortAudio */ 17 | export const SampleFormat32Bit = 32; 18 | 19 | /////////////////////////////////////////////////////////////////////////////// 20 | 21 | /** Get available devices from PortAudio */ 22 | export const getDevices = NodePA.getDevices; 23 | 24 | /** 25 | * Available options to initialize audio input and output 26 | */ 27 | export interface AudioOptions { 28 | /** 29 | * The device ID to use. These correspond to device IDs returned by 30 | * `getDevices`. Omit or set this to -1 to use the default device 31 | */ 32 | deviceId?: number; 33 | /** 34 | * Sample rate to read/write from/to the audio device (samples/sec) 35 | */ 36 | sampleRate?: number; 37 | /** 38 | * Number of channels to read/write audio from/to 39 | */ 40 | channelCount?: number; 41 | /** 42 | * The sample width. Use one of the exported constants (8, 16, 24, or 32) 43 | */ 44 | sampleFormat?: number; 45 | /** 46 | * Enable debug mode. This will print out messages from the C bindings onto 47 | * stderr when an error occurs 48 | */ 49 | debug?: boolean; 50 | } 51 | 52 | /** 53 | * The function signature of the callbacks to various `AudioInput` and 54 | * `AudioOutput` methods. 55 | */ 56 | export type AudioCallback = (error?: Error | null | undefined) => void; 57 | 58 | /** 59 | * AudioInput is a readable stream that records audio from the given device 60 | */ 61 | export class AudioInput extends Readable { 62 | /** audio is an instance of the node_pa PortAudio binding (input stream) */ 63 | private audio: any; 64 | 65 | /** 66 | * Creates the AudioInput instance by initializing the Readable stream 67 | * and initializing the underlying PortAudio instance with the given 68 | * options. 69 | * 70 | * @param options options to pass to PortAudio 71 | */ 72 | constructor(options: AudioOptions) { 73 | super({ 74 | highWaterMark: 16384, 75 | objectMode: false, 76 | }); 77 | this.audio = new NodePA.AudioIn(options); 78 | } 79 | 80 | /** 81 | * Reads some data from PortAudio and pushes it into the stream 82 | * 83 | * @param size number of bytes to read 84 | */ 85 | public _read(size: number = 1024) { 86 | this.audio.read(size, (err: Error, buf: Buffer) => { 87 | if (!err) { 88 | this.push(buf); 89 | } 90 | }); 91 | } 92 | 93 | /** 94 | * Start reading data from the input device 95 | */ 96 | public start() { 97 | this.audio.start(); 98 | } 99 | 100 | /** 101 | * Immediately aborts recording without waiting for the buffers to flush 102 | */ 103 | public abort() { 104 | this.audio.abort(); 105 | } 106 | 107 | /** 108 | * Gracefully stops the recording device, flushing all buffers, and then calls 109 | * the given function. 110 | * 111 | * @param cb callback to call after quit has completed 112 | */ 113 | public quit(cb?: AudioCallback) { 114 | this.audio.quit(() => { 115 | if (cb && typeof cb === "function") { 116 | cb(); 117 | } 118 | }); 119 | } 120 | } 121 | 122 | /** 123 | * AudioOutput is a writeable stream that plays audio on the given device 124 | */ 125 | export class AudioOutput extends Writable { 126 | /** audio is an instance of the node_pa PortAudio binding (output stream) */ 127 | private audio: any; 128 | 129 | /** 130 | * Creates the AudioOutput instance by initializing the Writable stream 131 | * and initializing the underlying PortAudio instance with the given 132 | * options. 133 | * 134 | * @param options options to initialize PortAudio with 135 | */ 136 | constructor(options: AudioOptions) { 137 | super({ 138 | decodeStrings: false, 139 | highWaterMark: 16384, 140 | objectMode: false, 141 | }); 142 | this.audio = new NodePA.AudioOut(options); 143 | this.on("finish", this.quit.bind(this)); 144 | } 145 | 146 | /** 147 | * Write some data to the PortAudio output device and call the given callback 148 | * upon completion. 149 | * 150 | * @param chunk data to write to the device 151 | * @param encoding encoding of the data 152 | * @param cb callback to call after write is completed 153 | */ 154 | public write(chunk: any, encoding?: any, cb: AudioCallback = (() => undefined)) { 155 | this.audio.write(chunk, cb); 156 | return true; 157 | } 158 | 159 | /** 160 | * Start writing data to the output device 161 | */ 162 | public start() { 163 | this.audio.start(); 164 | } 165 | 166 | /** 167 | * Immediately aborts playback without waiting for the buffers to flush 168 | */ 169 | public abort() { 170 | this.audio.abort(); 171 | } 172 | 173 | /** 174 | * Gracefully stops the playback device, flushing all buffers, and then calls 175 | * the given function. 176 | * 177 | * @param cb callback to call after quit has completed 178 | */ 179 | public quit(cb?: AudioCallback) { 180 | this.audio.quit(() => { 181 | if (cb && typeof cb === "function") { 182 | cb(); 183 | } 184 | }); 185 | } 186 | } 187 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "node-portaudio", 3 | "version": "0.4.10", 4 | "description": "Node Stream bindings for PortAudio.", 5 | "main": "./index.js", 6 | "keywords": [ 7 | "portaudio", 8 | "audio", 9 | "play", 10 | "record", 11 | "wav" 12 | ], 13 | "bugs": { 14 | "url": "https://github.com/auroraapi/node-portaudio/issues" 15 | }, 16 | "repository": "git+https://github.com/auroraapi/node-portaudio.git", 17 | "dependencies": { 18 | "bindings": "^1.3.0", 19 | "nan": "^2.10.0" 20 | }, 21 | "devDependencies": { 22 | "@types/bindings": "^1.3.0", 23 | "@types/node": "^8.5.0", 24 | "tape": "^4.9.0", 25 | "tslint": "^5.9.1", 26 | "typescript": "^2.8.3" 27 | }, 28 | "author": "Aurora API", 29 | "license": "MIT", 30 | "scripts": { 31 | "prepublish": "yarn build", 32 | "install": "node-gyp rebuild", 33 | "build": "rm -rf index.js index.d.ts && tsc --pretty --declaration", 34 | "lint": "tslint -c tslint.json -p tsconfig.json -e node_modules --fix", 35 | "clean": "rm -rf index.js index.d.ts build yarn-error.log" 36 | }, 37 | "gypfile": true 38 | } 39 | -------------------------------------------------------------------------------- /portaudio/bin/libportaudio.dylib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/auroraapi/node-portaudio/30361b2ee5f6a873c83b4c20148b7acb51bebc94/portaudio/bin/libportaudio.dylib -------------------------------------------------------------------------------- /portaudio/bin/libportaudio.so.2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/auroraapi/node-portaudio/30361b2ee5f6a873c83b4c20148b7acb51bebc94/portaudio/bin/libportaudio.so.2 -------------------------------------------------------------------------------- /portaudio/bin/portaudio_x64.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/auroraapi/node-portaudio/30361b2ee5f6a873c83b4c20148b7acb51bebc94/portaudio/bin/portaudio_x64.dll -------------------------------------------------------------------------------- /portaudio/bin/portaudio_x64.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/auroraapi/node-portaudio/30361b2ee5f6a873c83b4c20148b7acb51bebc94/portaudio/bin/portaudio_x64.lib -------------------------------------------------------------------------------- /portaudio/bin_armhf/libportaudio.so.2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/auroraapi/node-portaudio/30361b2ee5f6a873c83b4c20148b7acb51bebc94/portaudio/bin_armhf/libportaudio.so.2 -------------------------------------------------------------------------------- /portaudio/include/pa_mac_core.h: -------------------------------------------------------------------------------- 1 | #ifndef PA_MAC_CORE_H 2 | #define PA_MAC_CORE_H 3 | /* 4 | * PortAudio Portable Real-Time Audio Library 5 | * Macintosh Core Audio specific extensions 6 | * portaudio.h should be included before this file. 7 | * 8 | * Copyright (c) 2005-2006 Bjorn Roche 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 public_header 43 | * @brief CoreAudio-specific PortAudio API extension header file. 44 | */ 45 | 46 | #include "portaudio.h" 47 | 48 | #include 49 | #include 50 | 51 | #ifdef __cplusplus 52 | extern "C" { 53 | #endif 54 | 55 | 56 | /** 57 | * A pointer to a paMacCoreStreamInfo may be passed as 58 | * the hostApiSpecificStreamInfo in the PaStreamParameters struct 59 | * when opening a stream or querying the format. Use NULL, for the 60 | * defaults. Note that for duplex streams, flags for input and output 61 | * should be the same or behaviour is undefined. 62 | */ 63 | typedef struct 64 | { 65 | unsigned long size; /**size of whole structure including this header */ 66 | PaHostApiTypeId hostApiType; /**host API for which this data is intended */ 67 | unsigned long version; /**structure version */ 68 | unsigned long flags; /** flags to modify behaviour */ 69 | SInt32 const * channelMap; /** Channel map for HAL channel mapping , if not needed, use NULL;*/ 70 | unsigned long channelMapSize; /** Channel map size for HAL channel mapping , if not needed, use 0;*/ 71 | } PaMacCoreStreamInfo; 72 | 73 | /** 74 | * Functions 75 | */ 76 | 77 | 78 | /** Use this function to initialize a paMacCoreStreamInfo struct 79 | * using the requested flags. Note that channel mapping is turned 80 | * off after a call to this function. 81 | * @param data The datastructure to initialize 82 | * @param flags The flags to initialize the datastructure with. 83 | */ 84 | void PaMacCore_SetupStreamInfo( PaMacCoreStreamInfo *data, unsigned long flags ); 85 | 86 | /** call this after pa_SetupMacCoreStreamInfo to use channel mapping as described in notes.txt. 87 | * @param data The stream info structure to assign a channel mapping to 88 | * @param channelMap The channel map array, as described in notes.txt. This array pointer will be used directly (ie the underlying data will not be copied), so the caller should not free the array until after the stream has been opened. 89 | * @param channelMapSize The size of the channel map array. 90 | */ 91 | void PaMacCore_SetupChannelMap( PaMacCoreStreamInfo *data, const SInt32 * const channelMap, unsigned long channelMapSize ); 92 | 93 | /** 94 | * Retrieve the AudioDeviceID of the input device assigned to an open stream 95 | * 96 | * @param s The stream to query. 97 | * 98 | * @return A valid AudioDeviceID, or NULL if an error occurred. 99 | */ 100 | AudioDeviceID PaMacCore_GetStreamInputDevice( PaStream* s ); 101 | 102 | /** 103 | * Retrieve the AudioDeviceID of the output device assigned to an open stream 104 | * 105 | * @param s The stream to query. 106 | * 107 | * @return A valid AudioDeviceID, or NULL if an error occurred. 108 | */ 109 | AudioDeviceID PaMacCore_GetStreamOutputDevice( PaStream* s ); 110 | 111 | /** 112 | * Returns a statically allocated string with the device's name 113 | * for the given channel. NULL will be returned on failure. 114 | * 115 | * This function's implemenation is not complete! 116 | * 117 | * @param device The PortAudio device index. 118 | * @param channel The channel number who's name is requested. 119 | * @return a statically allocated string with the name of the device. 120 | * Because this string is statically allocated, it must be 121 | * coppied if it is to be saved and used by the user after 122 | * another call to this function. 123 | * 124 | */ 125 | const char *PaMacCore_GetChannelName( int device, int channelIndex, bool input ); 126 | 127 | 128 | /** Retrieve the range of legal native buffer sizes for the specificed device, in sample frames. 129 | 130 | @param device The global index of the PortAudio device about which the query is being made. 131 | @param minBufferSizeFrames A pointer to the location which will receive the minimum buffer size value. 132 | @param maxBufferSizeFrames A pointer to the location which will receive the maximum buffer size value. 133 | 134 | @see kAudioDevicePropertyBufferFrameSizeRange in the CoreAudio SDK. 135 | */ 136 | PaError PaMacCore_GetBufferSizeRange( PaDeviceIndex device, 137 | long *minBufferSizeFrames, long *maxBufferSizeFrames ); 138 | 139 | 140 | /** 141 | * Flags 142 | */ 143 | 144 | /** 145 | * The following flags alter the behaviour of PA on the mac platform. 146 | * they can be ORed together. These should work both for opening and 147 | * checking a device. 148 | */ 149 | 150 | /** Allows PortAudio to change things like the device's frame size, 151 | * which allows for much lower latency, but might disrupt the device 152 | * if other programs are using it, even when you are just Querying 153 | * the device. */ 154 | #define paMacCoreChangeDeviceParameters (0x01) 155 | 156 | /** In combination with the above flag, 157 | * causes the stream opening to fail, unless the exact sample rates 158 | * are supported by the device. */ 159 | #define paMacCoreFailIfConversionRequired (0x02) 160 | 161 | /** These flags set the SR conversion quality, if required. The wierd ordering 162 | * allows Maximum Quality to be the default.*/ 163 | #define paMacCoreConversionQualityMin (0x0100) 164 | #define paMacCoreConversionQualityMedium (0x0200) 165 | #define paMacCoreConversionQualityLow (0x0300) 166 | #define paMacCoreConversionQualityHigh (0x0400) 167 | #define paMacCoreConversionQualityMax (0x0000) 168 | 169 | /** 170 | * Here are some "preset" combinations of flags (above) to get to some 171 | * common configurations. THIS IS OVERKILL, but if more flags are added 172 | * it won't be. 173 | */ 174 | 175 | /**This is the default setting: do as much sample rate conversion as possible 176 | * and as little mucking with the device as possible. */ 177 | #define paMacCorePlayNice (0x00) 178 | /**This setting is tuned for pro audio apps. It allows SR conversion on input 179 | and output, but it tries to set the appropriate SR on the device.*/ 180 | #define paMacCorePro (0x01) 181 | /**This is a setting to minimize CPU usage and still play nice.*/ 182 | #define paMacCoreMinimizeCPUButPlayNice (0x0100) 183 | /**This is a setting to minimize CPU usage, even if that means interrupting the device. */ 184 | #define paMacCoreMinimizeCPU (0x0101) 185 | 186 | 187 | #ifdef __cplusplus 188 | } 189 | #endif /** __cplusplus */ 190 | 191 | #endif /** PA_MAC_CORE_H */ 192 | -------------------------------------------------------------------------------- /portaudio/include/portaudio.h: -------------------------------------------------------------------------------- 1 | #ifndef PORTAUDIO_H 2 | #define PORTAUDIO_H 3 | /* 4 | * $Id: portaudio.h 1859 2012-09-01 00:10:13Z philburk $ 5 | * PortAudio Portable Real-Time Audio Library 6 | * PortAudio API Header File 7 | * Latest version available at: http://www.portaudio.com/ 8 | * 9 | * Copyright (c) 1999-2002 Ross Bencina and 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 public_header 44 | @brief The portable PortAudio API. 45 | */ 46 | 47 | 48 | #ifdef __cplusplus 49 | extern "C" 50 | { 51 | #endif /* __cplusplus */ 52 | 53 | 54 | /** Retrieve the release number of the currently running PortAudio build, 55 | eg 1900. 56 | */ 57 | int Pa_GetVersion( void ); 58 | 59 | 60 | /** Retrieve a textual description of the current PortAudio build, 61 | eg "PortAudio V19-devel 13 October 2002". 62 | */ 63 | const char* Pa_GetVersionText( void ); 64 | 65 | 66 | /** Error codes returned by PortAudio functions. 67 | Note that with the exception of paNoError, all PaErrorCodes are negative. 68 | */ 69 | 70 | typedef int PaError; 71 | typedef enum PaErrorCode 72 | { 73 | paNoError = 0, 74 | 75 | paNotInitialized = -10000, 76 | paUnanticipatedHostError, 77 | paInvalidChannelCount, 78 | paInvalidSampleRate, 79 | paInvalidDevice, 80 | paInvalidFlag, 81 | paSampleFormatNotSupported, 82 | paBadIODeviceCombination, 83 | paInsufficientMemory, 84 | paBufferTooBig, 85 | paBufferTooSmall, 86 | paNullCallback, 87 | paBadStreamPtr, 88 | paTimedOut, 89 | paInternalError, 90 | paDeviceUnavailable, 91 | paIncompatibleHostApiSpecificStreamInfo, 92 | paStreamIsStopped, 93 | paStreamIsNotStopped, 94 | paInputOverflowed, 95 | paOutputUnderflowed, 96 | paHostApiNotFound, 97 | paInvalidHostApi, 98 | paCanNotReadFromACallbackStream, 99 | paCanNotWriteToACallbackStream, 100 | paCanNotReadFromAnOutputOnlyStream, 101 | paCanNotWriteToAnInputOnlyStream, 102 | paIncompatibleStreamHostApi, 103 | paBadBufferPtr 104 | } PaErrorCode; 105 | 106 | 107 | /** Translate the supplied PortAudio error code into a human readable 108 | message. 109 | */ 110 | const char *Pa_GetErrorText( PaError errorCode ); 111 | 112 | 113 | /** Library initialization function - call this before using PortAudio. 114 | This function initializes internal data structures and prepares underlying 115 | host APIs for use. With the exception of Pa_GetVersion(), Pa_GetVersionText(), 116 | and Pa_GetErrorText(), this function MUST be called before using any other 117 | PortAudio API functions. 118 | 119 | If Pa_Initialize() is called multiple times, each successful 120 | call must be matched with a corresponding call to Pa_Terminate(). 121 | Pairs of calls to Pa_Initialize()/Pa_Terminate() may overlap, and are not 122 | required to be fully nested. 123 | 124 | Note that if Pa_Initialize() returns an error code, Pa_Terminate() should 125 | NOT be called. 126 | 127 | @return paNoError if successful, otherwise an error code indicating the cause 128 | of failure. 129 | 130 | @see Pa_Terminate 131 | */ 132 | PaError Pa_Initialize( void ); 133 | 134 | 135 | /** Library termination function - call this when finished using PortAudio. 136 | This function deallocates all resources allocated by PortAudio since it was 137 | initialized by a call to Pa_Initialize(). In cases where Pa_Initialise() has 138 | been called multiple times, each call must be matched with a corresponding call 139 | to Pa_Terminate(). The final matching call to Pa_Terminate() will automatically 140 | close any PortAudio streams that are still open. 141 | 142 | Pa_Terminate() MUST be called before exiting a program which uses PortAudio. 143 | Failure to do so may result in serious resource leaks, such as audio devices 144 | not being available until the next reboot. 145 | 146 | @return paNoError if successful, otherwise an error code indicating the cause 147 | of failure. 148 | 149 | @see Pa_Initialize 150 | */ 151 | PaError Pa_Terminate( void ); 152 | 153 | 154 | 155 | /** The type used to refer to audio devices. Values of this type usually 156 | range from 0 to (Pa_GetDeviceCount()-1), and may also take on the PaNoDevice 157 | and paUseHostApiSpecificDeviceSpecification values. 158 | 159 | @see Pa_GetDeviceCount, paNoDevice, paUseHostApiSpecificDeviceSpecification 160 | */ 161 | typedef int PaDeviceIndex; 162 | 163 | 164 | /** A special PaDeviceIndex value indicating that no device is available, 165 | or should be used. 166 | 167 | @see PaDeviceIndex 168 | */ 169 | #define paNoDevice ((PaDeviceIndex)-1) 170 | 171 | 172 | /** A special PaDeviceIndex value indicating that the device(s) to be used 173 | are specified in the host api specific stream info structure. 174 | 175 | @see PaDeviceIndex 176 | */ 177 | #define paUseHostApiSpecificDeviceSpecification ((PaDeviceIndex)-2) 178 | 179 | 180 | /* Host API enumeration mechanism */ 181 | 182 | /** The type used to enumerate to host APIs at runtime. Values of this type 183 | range from 0 to (Pa_GetHostApiCount()-1). 184 | 185 | @see Pa_GetHostApiCount 186 | */ 187 | typedef int PaHostApiIndex; 188 | 189 | 190 | /** Retrieve the number of available host APIs. Even if a host API is 191 | available it may have no devices available. 192 | 193 | @return A non-negative value indicating the number of available host APIs 194 | or, a PaErrorCode (which are always negative) if PortAudio is not initialized 195 | or an error is encountered. 196 | 197 | @see PaHostApiIndex 198 | */ 199 | PaHostApiIndex Pa_GetHostApiCount( void ); 200 | 201 | 202 | /** Retrieve the index of the default host API. The default host API will be 203 | the lowest common denominator host API on the current platform and is 204 | unlikely to provide the best performance. 205 | 206 | @return A non-negative value ranging from 0 to (Pa_GetHostApiCount()-1) 207 | indicating the default host API index or, a PaErrorCode (which are always 208 | negative) if PortAudio is not initialized or an error is encountered. 209 | */ 210 | PaHostApiIndex Pa_GetDefaultHostApi( void ); 211 | 212 | 213 | /** Unchanging unique identifiers for each supported host API. This type 214 | is used in the PaHostApiInfo structure. The values are guaranteed to be 215 | unique and to never change, thus allowing code to be written that 216 | conditionally uses host API specific extensions. 217 | 218 | New type ids will be allocated when support for a host API reaches 219 | "public alpha" status, prior to that developers should use the 220 | paInDevelopment type id. 221 | 222 | @see PaHostApiInfo 223 | */ 224 | typedef enum PaHostApiTypeId 225 | { 226 | paInDevelopment=0, /* use while developing support for a new host API */ 227 | paDirectSound=1, 228 | paMME=2, 229 | paASIO=3, 230 | paSoundManager=4, 231 | paCoreAudio=5, 232 | paOSS=7, 233 | paALSA=8, 234 | paAL=9, 235 | paBeOS=10, 236 | paWDMKS=11, 237 | paJACK=12, 238 | paWASAPI=13, 239 | paAudioScienceHPI=14 240 | } PaHostApiTypeId; 241 | 242 | 243 | /** A structure containing information about a particular host API. */ 244 | 245 | typedef struct PaHostApiInfo 246 | { 247 | /** this is struct version 1 */ 248 | int structVersion; 249 | /** The well known unique identifier of this host API @see PaHostApiTypeId */ 250 | PaHostApiTypeId type; 251 | /** A textual description of the host API for display on user interfaces. */ 252 | const char *name; 253 | 254 | /** The number of devices belonging to this host API. This field may be 255 | used in conjunction with Pa_HostApiDeviceIndexToDeviceIndex() to enumerate 256 | all devices for this host API. 257 | @see Pa_HostApiDeviceIndexToDeviceIndex 258 | */ 259 | int deviceCount; 260 | 261 | /** The default input device for this host API. The value will be a 262 | device index ranging from 0 to (Pa_GetDeviceCount()-1), or paNoDevice 263 | if no default input device is available. 264 | */ 265 | PaDeviceIndex defaultInputDevice; 266 | 267 | /** The default output device for this host API. The value will be a 268 | device index ranging from 0 to (Pa_GetDeviceCount()-1), or paNoDevice 269 | if no default output device is available. 270 | */ 271 | PaDeviceIndex defaultOutputDevice; 272 | 273 | } PaHostApiInfo; 274 | 275 | 276 | /** Retrieve a pointer to a structure containing information about a specific 277 | host Api. 278 | 279 | @param hostApi A valid host API index ranging from 0 to (Pa_GetHostApiCount()-1) 280 | 281 | @return A pointer to an immutable PaHostApiInfo structure describing 282 | a specific host API. If the hostApi parameter is out of range or an error 283 | is encountered, the function returns NULL. 284 | 285 | The returned structure is owned by the PortAudio implementation and must not 286 | be manipulated or freed. The pointer is only guaranteed to be valid between 287 | calls to Pa_Initialize() and Pa_Terminate(). 288 | */ 289 | const PaHostApiInfo * Pa_GetHostApiInfo( PaHostApiIndex hostApi ); 290 | 291 | 292 | /** Convert a static host API unique identifier, into a runtime 293 | host API index. 294 | 295 | @param type A unique host API identifier belonging to the PaHostApiTypeId 296 | enumeration. 297 | 298 | @return A valid PaHostApiIndex ranging from 0 to (Pa_GetHostApiCount()-1) or, 299 | a PaErrorCode (which are always negative) if PortAudio is not initialized 300 | or an error is encountered. 301 | 302 | The paHostApiNotFound error code indicates that the host API specified by the 303 | type parameter is not available. 304 | 305 | @see PaHostApiTypeId 306 | */ 307 | PaHostApiIndex Pa_HostApiTypeIdToHostApiIndex( PaHostApiTypeId type ); 308 | 309 | 310 | /** Convert a host-API-specific device index to standard PortAudio device index. 311 | This function may be used in conjunction with the deviceCount field of 312 | PaHostApiInfo to enumerate all devices for the specified host API. 313 | 314 | @param hostApi A valid host API index ranging from 0 to (Pa_GetHostApiCount()-1) 315 | 316 | @param hostApiDeviceIndex A valid per-host device index in the range 317 | 0 to (Pa_GetHostApiInfo(hostApi)->deviceCount-1) 318 | 319 | @return A non-negative PaDeviceIndex ranging from 0 to (Pa_GetDeviceCount()-1) 320 | or, a PaErrorCode (which are always negative) if PortAudio is not initialized 321 | or an error is encountered. 322 | 323 | A paInvalidHostApi error code indicates that the host API index specified by 324 | the hostApi parameter is out of range. 325 | 326 | A paInvalidDevice error code indicates that the hostApiDeviceIndex parameter 327 | is out of range. 328 | 329 | @see PaHostApiInfo 330 | */ 331 | PaDeviceIndex Pa_HostApiDeviceIndexToDeviceIndex( PaHostApiIndex hostApi, 332 | int hostApiDeviceIndex ); 333 | 334 | 335 | 336 | /** Structure used to return information about a host error condition. 337 | */ 338 | typedef struct PaHostErrorInfo{ 339 | PaHostApiTypeId hostApiType; /**< the host API which returned the error code */ 340 | long errorCode; /**< the error code returned */ 341 | const char *errorText; /**< a textual description of the error if available, otherwise a zero-length string */ 342 | }PaHostErrorInfo; 343 | 344 | 345 | /** Return information about the last host error encountered. The error 346 | information returned by Pa_GetLastHostErrorInfo() will never be modified 347 | asynchronously by errors occurring in other PortAudio owned threads 348 | (such as the thread that manages the stream callback.) 349 | 350 | This function is provided as a last resort, primarily to enhance debugging 351 | by providing clients with access to all available error information. 352 | 353 | @return A pointer to an immutable structure constraining information about 354 | the host error. The values in this structure will only be valid if a 355 | PortAudio function has previously returned the paUnanticipatedHostError 356 | error code. 357 | */ 358 | const PaHostErrorInfo* Pa_GetLastHostErrorInfo( void ); 359 | 360 | 361 | 362 | /* Device enumeration and capabilities */ 363 | 364 | /** Retrieve the number of available devices. The number of available devices 365 | may be zero. 366 | 367 | @return A non-negative value indicating the number of available devices or, 368 | a PaErrorCode (which are always negative) if PortAudio is not initialized 369 | or an error is encountered. 370 | */ 371 | PaDeviceIndex Pa_GetDeviceCount( void ); 372 | 373 | 374 | /** Retrieve the index of the default input device. The result can be 375 | used in the inputDevice parameter to Pa_OpenStream(). 376 | 377 | @return The default input device index for the default host API, or paNoDevice 378 | if no default input device is available or an error was encountered. 379 | */ 380 | PaDeviceIndex Pa_GetDefaultInputDevice( void ); 381 | 382 | 383 | /** Retrieve the index of the default output device. The result can be 384 | used in the outputDevice parameter to Pa_OpenStream(). 385 | 386 | @return The default output device index for the default host API, or paNoDevice 387 | if no default output device is available or an error was encountered. 388 | 389 | @note 390 | On the PC, the user can specify a default device by 391 | setting an environment variable. For example, to use device #1. 392 |
 393 |  set PA_RECOMMENDED_OUTPUT_DEVICE=1
 394 | 
395 | The user should first determine the available device ids by using 396 | the supplied application "pa_devs". 397 | */ 398 | PaDeviceIndex Pa_GetDefaultOutputDevice( void ); 399 | 400 | 401 | /** The type used to represent monotonic time in seconds. PaTime is 402 | used for the fields of the PaStreamCallbackTimeInfo argument to the 403 | PaStreamCallback and as the result of Pa_GetStreamTime(). 404 | 405 | PaTime values have unspecified origin. 406 | 407 | @see PaStreamCallback, PaStreamCallbackTimeInfo, Pa_GetStreamTime 408 | */ 409 | typedef double PaTime; 410 | 411 | 412 | /** A type used to specify one or more sample formats. Each value indicates 413 | a possible format for sound data passed to and from the stream callback, 414 | Pa_ReadStream and Pa_WriteStream. 415 | 416 | The standard formats paFloat32, paInt16, paInt32, paInt24, paInt8 417 | and aUInt8 are usually implemented by all implementations. 418 | 419 | The floating point representation (paFloat32) uses +1.0 and -1.0 as the 420 | maximum and minimum respectively. 421 | 422 | paUInt8 is an unsigned 8 bit format where 128 is considered "ground" 423 | 424 | The paNonInterleaved flag indicates that audio data is passed as an array 425 | of pointers to separate buffers, one buffer for each channel. Usually, 426 | when this flag is not used, audio data is passed as a single buffer with 427 | all channels interleaved. 428 | 429 | @see Pa_OpenStream, Pa_OpenDefaultStream, PaDeviceInfo 430 | @see paFloat32, paInt16, paInt32, paInt24, paInt8 431 | @see paUInt8, paCustomFormat, paNonInterleaved 432 | */ 433 | typedef unsigned long PaSampleFormat; 434 | 435 | 436 | #define paFloat32 ((PaSampleFormat) 0x00000001) /**< @see PaSampleFormat */ 437 | #define paInt32 ((PaSampleFormat) 0x00000002) /**< @see PaSampleFormat */ 438 | #define paInt24 ((PaSampleFormat) 0x00000004) /**< Packed 24 bit format. @see PaSampleFormat */ 439 | #define paInt16 ((PaSampleFormat) 0x00000008) /**< @see PaSampleFormat */ 440 | #define paInt8 ((PaSampleFormat) 0x00000010) /**< @see PaSampleFormat */ 441 | #define paUInt8 ((PaSampleFormat) 0x00000020) /**< @see PaSampleFormat */ 442 | #define paCustomFormat ((PaSampleFormat) 0x00010000) /**< @see PaSampleFormat */ 443 | 444 | #define paNonInterleaved ((PaSampleFormat) 0x80000000) /**< @see PaSampleFormat */ 445 | 446 | /** A structure providing information and capabilities of PortAudio devices. 447 | Devices may support input, output or both input and output. 448 | */ 449 | typedef struct PaDeviceInfo 450 | { 451 | int structVersion; /* this is struct version 2 */ 452 | const char *name; 453 | PaHostApiIndex hostApi; /**< note this is a host API index, not a type id*/ 454 | 455 | int maxInputChannels; 456 | int maxOutputChannels; 457 | 458 | /** Default latency values for interactive performance. */ 459 | PaTime defaultLowInputLatency; 460 | PaTime defaultLowOutputLatency; 461 | /** Default latency values for robust non-interactive applications (eg. playing sound files). */ 462 | PaTime defaultHighInputLatency; 463 | PaTime defaultHighOutputLatency; 464 | 465 | double defaultSampleRate; 466 | } PaDeviceInfo; 467 | 468 | 469 | /** Retrieve a pointer to a PaDeviceInfo structure containing information 470 | about the specified device. 471 | @return A pointer to an immutable PaDeviceInfo structure. If the device 472 | parameter is out of range the function returns NULL. 473 | 474 | @param device A valid device index in the range 0 to (Pa_GetDeviceCount()-1) 475 | 476 | @note PortAudio manages the memory referenced by the returned pointer, 477 | the client must not manipulate or free the memory. The pointer is only 478 | guaranteed to be valid between calls to Pa_Initialize() and Pa_Terminate(). 479 | 480 | @see PaDeviceInfo, PaDeviceIndex 481 | */ 482 | const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceIndex device ); 483 | 484 | 485 | /** Parameters for one direction (input or output) of a stream. 486 | */ 487 | typedef struct PaStreamParameters 488 | { 489 | /** A valid device index in the range 0 to (Pa_GetDeviceCount()-1) 490 | specifying the device to be used or the special constant 491 | paUseHostApiSpecificDeviceSpecification which indicates that the actual 492 | device(s) to use are specified in hostApiSpecificStreamInfo. 493 | This field must not be set to paNoDevice. 494 | */ 495 | PaDeviceIndex device; 496 | 497 | /** The number of channels of sound to be delivered to the 498 | stream callback or accessed by Pa_ReadStream() or Pa_WriteStream(). 499 | It can range from 1 to the value of maxInputChannels in the 500 | PaDeviceInfo record for the device specified by the device parameter. 501 | */ 502 | int channelCount; 503 | 504 | /** The sample format of the buffer provided to the stream callback, 505 | a_ReadStream() or Pa_WriteStream(). It may be any of the formats described 506 | by the PaSampleFormat enumeration. 507 | */ 508 | PaSampleFormat sampleFormat; 509 | 510 | /** The desired latency in seconds. Where practical, implementations should 511 | configure their latency based on these parameters, otherwise they may 512 | choose the closest viable latency instead. Unless the suggested latency 513 | is greater than the absolute upper limit for the device implementations 514 | should round the suggestedLatency up to the next practical value - ie to 515 | provide an equal or higher latency than suggestedLatency wherever possible. 516 | Actual latency values for an open stream may be retrieved using the 517 | inputLatency and outputLatency fields of the PaStreamInfo structure 518 | returned by Pa_GetStreamInfo(). 519 | @see default*Latency in PaDeviceInfo, *Latency in PaStreamInfo 520 | */ 521 | PaTime suggestedLatency; 522 | 523 | /** An optional pointer to a host api specific data structure 524 | containing additional information for device setup and/or stream processing. 525 | hostApiSpecificStreamInfo is never required for correct operation, 526 | if not used it should be set to NULL. 527 | */ 528 | void *hostApiSpecificStreamInfo; 529 | 530 | } PaStreamParameters; 531 | 532 | 533 | /** Return code for Pa_IsFormatSupported indicating success. */ 534 | #define paFormatIsSupported (0) 535 | 536 | /** Determine whether it would be possible to open a stream with the specified 537 | parameters. 538 | 539 | @param inputParameters A structure that describes the input parameters used to 540 | open a stream. The suggestedLatency field is ignored. See PaStreamParameters 541 | for a description of these parameters. inputParameters must be NULL for 542 | output-only streams. 543 | 544 | @param outputParameters A structure that describes the output parameters used 545 | to open a stream. The suggestedLatency field is ignored. See PaStreamParameters 546 | for a description of these parameters. outputParameters must be NULL for 547 | input-only streams. 548 | 549 | @param sampleRate The required sampleRate. For full-duplex streams it is the 550 | sample rate for both input and output 551 | 552 | @return Returns 0 if the format is supported, and an error code indicating why 553 | the format is not supported otherwise. The constant paFormatIsSupported is 554 | provided to compare with the return value for success. 555 | 556 | @see paFormatIsSupported, PaStreamParameters 557 | */ 558 | PaError Pa_IsFormatSupported( const PaStreamParameters *inputParameters, 559 | const PaStreamParameters *outputParameters, 560 | double sampleRate ); 561 | 562 | 563 | 564 | /* Streaming types and functions */ 565 | 566 | 567 | /** 568 | A single PaStream can provide multiple channels of real-time 569 | streaming audio input and output to a client application. A stream 570 | provides access to audio hardware represented by one or more 571 | PaDevices. Depending on the underlying Host API, it may be possible 572 | to open multiple streams using the same device, however this behavior 573 | is implementation defined. Portable applications should assume that 574 | a PaDevice may be simultaneously used by at most one PaStream. 575 | 576 | Pointers to PaStream objects are passed between PortAudio functions that 577 | operate on streams. 578 | 579 | @see Pa_OpenStream, Pa_OpenDefaultStream, Pa_OpenDefaultStream, Pa_CloseStream, 580 | Pa_StartStream, Pa_StopStream, Pa_AbortStream, Pa_IsStreamActive, 581 | Pa_GetStreamTime, Pa_GetStreamCpuLoad 582 | 583 | */ 584 | typedef void PaStream; 585 | 586 | 587 | /** Can be passed as the framesPerBuffer parameter to Pa_OpenStream() 588 | or Pa_OpenDefaultStream() to indicate that the stream callback will 589 | accept buffers of any size. 590 | */ 591 | #define paFramesPerBufferUnspecified (0) 592 | 593 | 594 | /** Flags used to control the behavior of a stream. They are passed as 595 | parameters to Pa_OpenStream or Pa_OpenDefaultStream. Multiple flags may be 596 | ORed together. 597 | 598 | @see Pa_OpenStream, Pa_OpenDefaultStream 599 | @see paNoFlag, paClipOff, paDitherOff, paNeverDropInput, 600 | paPrimeOutputBuffersUsingStreamCallback, paPlatformSpecificFlags 601 | */ 602 | typedef unsigned long PaStreamFlags; 603 | 604 | /** @see PaStreamFlags */ 605 | #define paNoFlag ((PaStreamFlags) 0) 606 | 607 | /** Disable default clipping of out of range samples. 608 | @see PaStreamFlags 609 | */ 610 | #define paClipOff ((PaStreamFlags) 0x00000001) 611 | 612 | /** Disable default dithering. 613 | @see PaStreamFlags 614 | */ 615 | #define paDitherOff ((PaStreamFlags) 0x00000002) 616 | 617 | /** Flag requests that where possible a full duplex stream will not discard 618 | overflowed input samples without calling the stream callback. This flag is 619 | only valid for full duplex callback streams and only when used in combination 620 | with the paFramesPerBufferUnspecified (0) framesPerBuffer parameter. Using 621 | this flag incorrectly results in a paInvalidFlag error being returned from 622 | Pa_OpenStream and Pa_OpenDefaultStream. 623 | 624 | @see PaStreamFlags, paFramesPerBufferUnspecified 625 | */ 626 | #define paNeverDropInput ((PaStreamFlags) 0x00000004) 627 | 628 | /** Call the stream callback to fill initial output buffers, rather than the 629 | default behavior of priming the buffers with zeros (silence). This flag has 630 | no effect for input-only and blocking read/write streams. 631 | 632 | @see PaStreamFlags 633 | */ 634 | #define paPrimeOutputBuffersUsingStreamCallback ((PaStreamFlags) 0x00000008) 635 | 636 | /** A mask specifying the platform specific bits. 637 | @see PaStreamFlags 638 | */ 639 | #define paPlatformSpecificFlags ((PaStreamFlags)0xFFFF0000) 640 | 641 | /** 642 | Timing information for the buffers passed to the stream callback. 643 | 644 | Time values are expressed in seconds and are synchronised with the time base used by Pa_GetStreamTime() for the associated stream. 645 | 646 | @see PaStreamCallback, Pa_GetStreamTime 647 | */ 648 | typedef struct PaStreamCallbackTimeInfo{ 649 | PaTime inputBufferAdcTime; /**< The time when the first sample of the input buffer was captured at the ADC input */ 650 | PaTime currentTime; /**< The time when the stream callback was invoked */ 651 | PaTime outputBufferDacTime; /**< The time when the first sample of the output buffer will output the DAC */ 652 | } PaStreamCallbackTimeInfo; 653 | 654 | 655 | /** 656 | Flag bit constants for the statusFlags to PaStreamCallback. 657 | 658 | @see paInputUnderflow, paInputOverflow, paOutputUnderflow, paOutputOverflow, 659 | paPrimingOutput 660 | */ 661 | typedef unsigned long PaStreamCallbackFlags; 662 | 663 | /** In a stream opened with paFramesPerBufferUnspecified, indicates that 664 | input data is all silence (zeros) because no real data is available. In a 665 | stream opened without paFramesPerBufferUnspecified, it indicates that one or 666 | more zero samples have been inserted into the input buffer to compensate 667 | for an input underflow. 668 | @see PaStreamCallbackFlags 669 | */ 670 | #define paInputUnderflow ((PaStreamCallbackFlags) 0x00000001) 671 | 672 | /** In a stream opened with paFramesPerBufferUnspecified, indicates that data 673 | prior to the first sample of the input buffer was discarded due to an 674 | overflow, possibly because the stream callback is using too much CPU time. 675 | Otherwise indicates that data prior to one or more samples in the 676 | input buffer was discarded. 677 | @see PaStreamCallbackFlags 678 | */ 679 | #define paInputOverflow ((PaStreamCallbackFlags) 0x00000002) 680 | 681 | /** Indicates that output data (or a gap) was inserted, possibly because the 682 | stream callback is using too much CPU time. 683 | @see PaStreamCallbackFlags 684 | */ 685 | #define paOutputUnderflow ((PaStreamCallbackFlags) 0x00000004) 686 | 687 | /** Indicates that output data will be discarded because no room is available. 688 | @see PaStreamCallbackFlags 689 | */ 690 | #define paOutputOverflow ((PaStreamCallbackFlags) 0x00000008) 691 | 692 | /** Some of all of the output data will be used to prime the stream, input 693 | data may be zero. 694 | @see PaStreamCallbackFlags 695 | */ 696 | #define paPrimingOutput ((PaStreamCallbackFlags) 0x00000010) 697 | 698 | /** 699 | Allowable return values for the PaStreamCallback. 700 | @see PaStreamCallback 701 | */ 702 | typedef enum PaStreamCallbackResult 703 | { 704 | paContinue=0, /**< Signal that the stream should continue invoking the callback and processing audio. */ 705 | paComplete=1, /**< Signal that the stream should stop invoking the callback and finish once all output samples have played. */ 706 | paAbort=2 /**< Signal that the stream should stop invoking the callback and finish as soon as possible. */ 707 | } PaStreamCallbackResult; 708 | 709 | 710 | /** 711 | Functions of type PaStreamCallback are implemented by PortAudio clients. 712 | They consume, process or generate audio in response to requests from an 713 | active PortAudio stream. 714 | 715 | When a stream is running, PortAudio calls the stream callback periodically. 716 | The callback function is responsible for processing buffers of audio samples 717 | passed via the input and output parameters. 718 | 719 | The PortAudio stream callback runs at very high or real-time priority. 720 | It is required to consistently meet its time deadlines. Do not allocate 721 | memory, access the file system, call library functions or call other functions 722 | from the stream callback that may block or take an unpredictable amount of 723 | time to complete. 724 | 725 | In order for a stream to maintain glitch-free operation the callback 726 | must consume and return audio data faster than it is recorded and/or 727 | played. PortAudio anticipates that each callback invocation may execute for 728 | a duration approaching the duration of frameCount audio frames at the stream 729 | sample rate. It is reasonable to expect to be able to utilise 70% or more of 730 | the available CPU time in the PortAudio callback. However, due to buffer size 731 | adaption and other factors, not all host APIs are able to guarantee audio 732 | stability under heavy CPU load with arbitrary fixed callback buffer sizes. 733 | When high callback CPU utilisation is required the most robust behavior 734 | can be achieved by using paFramesPerBufferUnspecified as the 735 | Pa_OpenStream() framesPerBuffer parameter. 736 | 737 | @param input and @param output are either arrays of interleaved samples or; 738 | if non-interleaved samples were requested using the paNonInterleaved sample 739 | format flag, an array of buffer pointers, one non-interleaved buffer for 740 | each channel. 741 | 742 | The format, packing and number of channels used by the buffers are 743 | determined by parameters to Pa_OpenStream(). 744 | 745 | @param frameCount The number of sample frames to be processed by 746 | the stream callback. 747 | 748 | @param timeInfo Timestamps indicating the ADC capture time of the first sample 749 | in the input buffer, the DAC output time of the first sample in the output buffer 750 | and the time the callback was invoked. 751 | See PaStreamCallbackTimeInfo and Pa_GetStreamTime() 752 | 753 | @param statusFlags Flags indicating whether input and/or output buffers 754 | have been inserted or will be dropped to overcome underflow or overflow 755 | conditions. 756 | 757 | @param userData The value of a user supplied pointer passed to 758 | Pa_OpenStream() intended for storing synthesis data etc. 759 | 760 | @return 761 | The stream callback should return one of the values in the 762 | ::PaStreamCallbackResult enumeration. To ensure that the callback continues 763 | to be called, it should return paContinue (0). Either paComplete or paAbort 764 | can be returned to finish stream processing, after either of these values is 765 | returned the callback will not be called again. If paAbort is returned the 766 | stream will finish as soon as possible. If paComplete is returned, the stream 767 | will continue until all buffers generated by the callback have been played. 768 | This may be useful in applications such as soundfile players where a specific 769 | duration of output is required. However, it is not necessary to utilize this 770 | mechanism as Pa_StopStream(), Pa_AbortStream() or Pa_CloseStream() can also 771 | be used to stop the stream. The callback must always fill the entire output 772 | buffer irrespective of its return value. 773 | 774 | @see Pa_OpenStream, Pa_OpenDefaultStream 775 | 776 | @note With the exception of Pa_GetStreamCpuLoad() it is not permissible to call 777 | PortAudio API functions from within the stream callback. 778 | */ 779 | typedef int PaStreamCallback( 780 | const void *input, void *output, 781 | unsigned long frameCount, 782 | const PaStreamCallbackTimeInfo* timeInfo, 783 | PaStreamCallbackFlags statusFlags, 784 | void *userData ); 785 | 786 | 787 | /** Opens a stream for either input, output or both. 788 | 789 | @param stream The address of a PaStream pointer which will receive 790 | a pointer to the newly opened stream. 791 | 792 | @param inputParameters A structure that describes the input parameters used by 793 | the opened stream. See PaStreamParameters for a description of these parameters. 794 | inputParameters must be NULL for output-only streams. 795 | 796 | @param outputParameters A structure that describes the output parameters used by 797 | the opened stream. See PaStreamParameters for a description of these parameters. 798 | outputParameters must be NULL for input-only streams. 799 | 800 | @param sampleRate The desired sampleRate. For full-duplex streams it is the 801 | sample rate for both input and output 802 | 803 | @param framesPerBuffer The number of frames passed to the stream callback 804 | function, or the preferred block granularity for a blocking read/write stream. 805 | The special value paFramesPerBufferUnspecified (0) may be used to request that 806 | the stream callback will receive an optimal (and possibly varying) number of 807 | frames based on host requirements and the requested latency settings. 808 | Note: With some host APIs, the use of non-zero framesPerBuffer for a callback 809 | stream may introduce an additional layer of buffering which could introduce 810 | additional latency. PortAudio guarantees that the additional latency 811 | will be kept to the theoretical minimum however, it is strongly recommended 812 | that a non-zero framesPerBuffer value only be used when your algorithm 813 | requires a fixed number of frames per stream callback. 814 | 815 | @param streamFlags Flags which modify the behavior of the streaming process. 816 | This parameter may contain a combination of flags ORed together. Some flags may 817 | only be relevant to certain buffer formats. 818 | 819 | @param streamCallback A pointer to a client supplied function that is responsible 820 | for processing and filling input and output buffers. If this parameter is NULL 821 | the stream will be opened in 'blocking read/write' mode. In blocking mode, 822 | the client can receive sample data using Pa_ReadStream and write sample data 823 | using Pa_WriteStream, the number of samples that may be read or written 824 | without blocking is returned by Pa_GetStreamReadAvailable and 825 | Pa_GetStreamWriteAvailable respectively. 826 | 827 | @param userData A client supplied pointer which is passed to the stream callback 828 | function. It could for example, contain a pointer to instance data necessary 829 | for processing the audio buffers. This parameter is ignored if streamCallback 830 | is NULL. 831 | 832 | @return 833 | Upon success Pa_OpenStream() returns paNoError and places a pointer to a 834 | valid PaStream in the stream argument. The stream is inactive (stopped). 835 | If a call to Pa_OpenStream() fails, a non-zero error code is returned (see 836 | PaError for possible error codes) and the value of stream is invalid. 837 | 838 | @see PaStreamParameters, PaStreamCallback, Pa_ReadStream, Pa_WriteStream, 839 | Pa_GetStreamReadAvailable, Pa_GetStreamWriteAvailable 840 | */ 841 | PaError Pa_OpenStream( PaStream** stream, 842 | const PaStreamParameters *inputParameters, 843 | const PaStreamParameters *outputParameters, 844 | double sampleRate, 845 | unsigned long framesPerBuffer, 846 | PaStreamFlags streamFlags, 847 | PaStreamCallback *streamCallback, 848 | void *userData ); 849 | 850 | 851 | /** A simplified version of Pa_OpenStream() that opens the default input 852 | and/or output devices. 853 | 854 | @param stream The address of a PaStream pointer which will receive 855 | a pointer to the newly opened stream. 856 | 857 | @param numInputChannels The number of channels of sound that will be supplied 858 | to the stream callback or returned by Pa_ReadStream. It can range from 1 to 859 | the value of maxInputChannels in the PaDeviceInfo record for the default input 860 | device. If 0 the stream is opened as an output-only stream. 861 | 862 | @param numOutputChannels The number of channels of sound to be delivered to the 863 | stream callback or passed to Pa_WriteStream. It can range from 1 to the value 864 | of maxOutputChannels in the PaDeviceInfo record for the default output device. 865 | If 0 the stream is opened as an output-only stream. 866 | 867 | @param sampleFormat The sample format of both the input and output buffers 868 | provided to the callback or passed to and from Pa_ReadStream and Pa_WriteStream. 869 | sampleFormat may be any of the formats described by the PaSampleFormat 870 | enumeration. 871 | 872 | @param sampleRate Same as Pa_OpenStream parameter of the same name. 873 | @param framesPerBuffer Same as Pa_OpenStream parameter of the same name. 874 | @param streamCallback Same as Pa_OpenStream parameter of the same name. 875 | @param userData Same as Pa_OpenStream parameter of the same name. 876 | 877 | @return As for Pa_OpenStream 878 | 879 | @see Pa_OpenStream, PaStreamCallback 880 | */ 881 | PaError Pa_OpenDefaultStream( PaStream** stream, 882 | int numInputChannels, 883 | int numOutputChannels, 884 | PaSampleFormat sampleFormat, 885 | double sampleRate, 886 | unsigned long framesPerBuffer, 887 | PaStreamCallback *streamCallback, 888 | void *userData ); 889 | 890 | 891 | /** Closes an audio stream. If the audio stream is active it 892 | discards any pending buffers as if Pa_AbortStream() had been called. 893 | */ 894 | PaError Pa_CloseStream( PaStream *stream ); 895 | 896 | 897 | /** Functions of type PaStreamFinishedCallback are implemented by PortAudio 898 | clients. They can be registered with a stream using the Pa_SetStreamFinishedCallback 899 | function. Once registered they are called when the stream becomes inactive 900 | (ie once a call to Pa_StopStream() will not block). 901 | A stream will become inactive after the stream callback returns non-zero, 902 | or when Pa_StopStream or Pa_AbortStream is called. For a stream providing audio 903 | output, if the stream callback returns paComplete, or Pa_StopStream is called, 904 | the stream finished callback will not be called until all generated sample data 905 | has been played. 906 | 907 | @param userData The userData parameter supplied to Pa_OpenStream() 908 | 909 | @see Pa_SetStreamFinishedCallback 910 | */ 911 | typedef void PaStreamFinishedCallback( void *userData ); 912 | 913 | 914 | /** Register a stream finished callback function which will be called when the 915 | stream becomes inactive. See the description of PaStreamFinishedCallback for 916 | further details about when the callback will be called. 917 | 918 | @param stream a pointer to a PaStream that is in the stopped state - if the 919 | stream is not stopped, the stream's finished callback will remain unchanged 920 | and an error code will be returned. 921 | 922 | @param streamFinishedCallback a pointer to a function with the same signature 923 | as PaStreamFinishedCallback, that will be called when the stream becomes 924 | inactive. Passing NULL for this parameter will un-register a previously 925 | registered stream finished callback function. 926 | 927 | @return on success returns paNoError, otherwise an error code indicating the cause 928 | of the error. 929 | 930 | @see PaStreamFinishedCallback 931 | */ 932 | PaError Pa_SetStreamFinishedCallback( PaStream *stream, PaStreamFinishedCallback* streamFinishedCallback ); 933 | 934 | 935 | /** Commences audio processing. 936 | */ 937 | PaError Pa_StartStream( PaStream *stream ); 938 | 939 | 940 | /** Terminates audio processing. It waits until all pending 941 | audio buffers have been played before it returns. 942 | */ 943 | PaError Pa_StopStream( PaStream *stream ); 944 | 945 | 946 | /** Terminates audio processing immediately without waiting for pending 947 | buffers to complete. 948 | */ 949 | PaError Pa_AbortStream( PaStream *stream ); 950 | 951 | 952 | /** Determine whether the stream is stopped. 953 | A stream is considered to be stopped prior to a successful call to 954 | Pa_StartStream and after a successful call to Pa_StopStream or Pa_AbortStream. 955 | If a stream callback returns a value other than paContinue the stream is NOT 956 | considered to be stopped. 957 | 958 | @return Returns one (1) when the stream is stopped, zero (0) when 959 | the stream is running or, a PaErrorCode (which are always negative) if 960 | PortAudio is not initialized or an error is encountered. 961 | 962 | @see Pa_StopStream, Pa_AbortStream, Pa_IsStreamActive 963 | */ 964 | PaError Pa_IsStreamStopped( PaStream *stream ); 965 | 966 | 967 | /** Determine whether the stream is active. 968 | A stream is active after a successful call to Pa_StartStream(), until it 969 | becomes inactive either as a result of a call to Pa_StopStream() or 970 | Pa_AbortStream(), or as a result of a return value other than paContinue from 971 | the stream callback. In the latter case, the stream is considered inactive 972 | after the last buffer has finished playing. 973 | 974 | @return Returns one (1) when the stream is active (ie playing or recording 975 | audio), zero (0) when not playing or, a PaErrorCode (which are always negative) 976 | if PortAudio is not initialized or an error is encountered. 977 | 978 | @see Pa_StopStream, Pa_AbortStream, Pa_IsStreamStopped 979 | */ 980 | PaError Pa_IsStreamActive( PaStream *stream ); 981 | 982 | 983 | 984 | /** A structure containing unchanging information about an open stream. 985 | @see Pa_GetStreamInfo 986 | */ 987 | 988 | typedef struct PaStreamInfo 989 | { 990 | /** this is struct version 1 */ 991 | int structVersion; 992 | 993 | /** The input latency of the stream in seconds. This value provides the most 994 | accurate estimate of input latency available to the implementation. It may 995 | differ significantly from the suggestedLatency value passed to Pa_OpenStream(). 996 | The value of this field will be zero (0.) for output-only streams. 997 | @see PaTime 998 | */ 999 | PaTime inputLatency; 1000 | 1001 | /** The output latency of the stream in seconds. This value provides the most 1002 | accurate estimate of output latency available to the implementation. It may 1003 | differ significantly from the suggestedLatency value passed to Pa_OpenStream(). 1004 | The value of this field will be zero (0.) for input-only streams. 1005 | @see PaTime 1006 | */ 1007 | PaTime outputLatency; 1008 | 1009 | /** The sample rate of the stream in Hertz (samples per second). In cases 1010 | where the hardware sample rate is inaccurate and PortAudio is aware of it, 1011 | the value of this field may be different from the sampleRate parameter 1012 | passed to Pa_OpenStream(). If information about the actual hardware sample 1013 | rate is not available, this field will have the same value as the sampleRate 1014 | parameter passed to Pa_OpenStream(). 1015 | */ 1016 | double sampleRate; 1017 | 1018 | } PaStreamInfo; 1019 | 1020 | 1021 | /** Retrieve a pointer to a PaStreamInfo structure containing information 1022 | about the specified stream. 1023 | @return A pointer to an immutable PaStreamInfo structure. If the stream 1024 | parameter is invalid, or an error is encountered, the function returns NULL. 1025 | 1026 | @param stream A pointer to an open stream previously created with Pa_OpenStream. 1027 | 1028 | @note PortAudio manages the memory referenced by the returned pointer, 1029 | the client must not manipulate or free the memory. The pointer is only 1030 | guaranteed to be valid until the specified stream is closed. 1031 | 1032 | @see PaStreamInfo 1033 | */ 1034 | const PaStreamInfo* Pa_GetStreamInfo( PaStream *stream ); 1035 | 1036 | 1037 | /** Returns the current time in seconds for a stream according to the same clock used 1038 | to generate callback PaStreamCallbackTimeInfo timestamps. The time values are 1039 | monotonically increasing and have unspecified origin. 1040 | 1041 | Pa_GetStreamTime returns valid time values for the entire life of the stream, 1042 | from when the stream is opened until it is closed. Starting and stopping the stream 1043 | does not affect the passage of time returned by Pa_GetStreamTime. 1044 | 1045 | This time may be used for synchronizing other events to the audio stream, for 1046 | example synchronizing audio to MIDI. 1047 | 1048 | @return The stream's current time in seconds, or 0 if an error occurred. 1049 | 1050 | @see PaTime, PaStreamCallback, PaStreamCallbackTimeInfo 1051 | */ 1052 | PaTime Pa_GetStreamTime( PaStream *stream ); 1053 | 1054 | 1055 | /** Retrieve CPU usage information for the specified stream. 1056 | The "CPU Load" is a fraction of total CPU time consumed by a callback stream's 1057 | audio processing routines including, but not limited to the client supplied 1058 | stream callback. This function does not work with blocking read/write streams. 1059 | 1060 | This function may be called from the stream callback function or the 1061 | application. 1062 | 1063 | @return 1064 | A floating point value, typically between 0.0 and 1.0, where 1.0 indicates 1065 | that the stream callback is consuming the maximum number of CPU cycles possible 1066 | to maintain real-time operation. A value of 0.5 would imply that PortAudio and 1067 | the stream callback was consuming roughly 50% of the available CPU time. The 1068 | return value may exceed 1.0. A value of 0.0 will always be returned for a 1069 | blocking read/write stream, or if an error occurs. 1070 | */ 1071 | double Pa_GetStreamCpuLoad( PaStream* stream ); 1072 | 1073 | 1074 | /** Read samples from an input stream. The function doesn't return until 1075 | the entire buffer has been filled - this may involve waiting for the operating 1076 | system to supply the data. 1077 | 1078 | @param stream A pointer to an open stream previously created with Pa_OpenStream. 1079 | 1080 | @param buffer A pointer to a buffer of sample frames. The buffer contains 1081 | samples in the format specified by the inputParameters->sampleFormat field 1082 | used to open the stream, and the number of channels specified by 1083 | inputParameters->numChannels. If non-interleaved samples were requested using 1084 | the paNonInterleaved sample format flag, buffer is a pointer to the first element 1085 | of an array of buffer pointers, one non-interleaved buffer for each channel. 1086 | 1087 | @param frames The number of frames to be read into buffer. This parameter 1088 | is not constrained to a specific range, however high performance applications 1089 | will want to match this parameter to the framesPerBuffer parameter used 1090 | when opening the stream. 1091 | 1092 | @return On success PaNoError will be returned, or PaInputOverflowed if input 1093 | data was discarded by PortAudio after the previous call and before this call. 1094 | */ 1095 | PaError Pa_ReadStream( PaStream* stream, 1096 | void *buffer, 1097 | unsigned long frames ); 1098 | 1099 | 1100 | /** Write samples to an output stream. This function doesn't return until the 1101 | entire buffer has been consumed - this may involve waiting for the operating 1102 | system to consume the data. 1103 | 1104 | @param stream A pointer to an open stream previously created with Pa_OpenStream. 1105 | 1106 | @param buffer A pointer to a buffer of sample frames. The buffer contains 1107 | samples in the format specified by the outputParameters->sampleFormat field 1108 | used to open the stream, and the number of channels specified by 1109 | outputParameters->numChannels. If non-interleaved samples were requested using 1110 | the paNonInterleaved sample format flag, buffer is a pointer to the first element 1111 | of an array of buffer pointers, one non-interleaved buffer for each channel. 1112 | 1113 | @param frames The number of frames to be written from buffer. This parameter 1114 | is not constrained to a specific range, however high performance applications 1115 | will want to match this parameter to the framesPerBuffer parameter used 1116 | when opening the stream. 1117 | 1118 | @return On success PaNoError will be returned, or paOutputUnderflowed if 1119 | additional output data was inserted after the previous call and before this 1120 | call. 1121 | */ 1122 | PaError Pa_WriteStream( PaStream* stream, 1123 | const void *buffer, 1124 | unsigned long frames ); 1125 | 1126 | 1127 | /** Retrieve the number of frames that can be read from the stream without 1128 | waiting. 1129 | 1130 | @return Returns a non-negative value representing the maximum number of frames 1131 | that can be read from the stream without blocking or busy waiting or, a 1132 | PaErrorCode (which are always negative) if PortAudio is not initialized or an 1133 | error is encountered. 1134 | */ 1135 | signed long Pa_GetStreamReadAvailable( PaStream* stream ); 1136 | 1137 | 1138 | /** Retrieve the number of frames that can be written to the stream without 1139 | waiting. 1140 | 1141 | @return Returns a non-negative value representing the maximum number of frames 1142 | that can be written to the stream without blocking or busy waiting or, a 1143 | PaErrorCode (which are always negative) if PortAudio is not initialized or an 1144 | error is encountered. 1145 | */ 1146 | signed long Pa_GetStreamWriteAvailable( PaStream* stream ); 1147 | 1148 | 1149 | /* Miscellaneous utilities */ 1150 | 1151 | 1152 | /** Retrieve the size of a given sample format in bytes. 1153 | 1154 | @return The size in bytes of a single sample in the specified format, 1155 | or paSampleFormatNotSupported if the format is not supported. 1156 | */ 1157 | PaError Pa_GetSampleSize( PaSampleFormat format ); 1158 | 1159 | 1160 | /** Put the caller to sleep for at least 'msec' milliseconds. This function is 1161 | provided only as a convenience for authors of portable code (such as the tests 1162 | and examples in the PortAudio distribution.) 1163 | 1164 | The function may sleep longer than requested so don't rely on this for accurate 1165 | musical timing. 1166 | */ 1167 | void Pa_Sleep( long msec ); 1168 | 1169 | 1170 | 1171 | #ifdef __cplusplus 1172 | } 1173 | #endif /* __cplusplus */ 1174 | #endif /* PORTAUDIO_H */ 1175 | -------------------------------------------------------------------------------- /portaudio/msvc/build.bat: -------------------------------------------------------------------------------- 1 | call MSBuild /nologo /p:Configuration=Release portaudio.vcxproj 2 | -------------------------------------------------------------------------------- /portaudio/msvc/portaudio.def: -------------------------------------------------------------------------------- 1 | EXPORTS 2 | 3 | ; 4 | Pa_GetVersion @1 5 | Pa_GetVersionText @2 6 | Pa_GetErrorText @3 7 | Pa_Initialize @4 8 | Pa_Terminate @5 9 | Pa_GetHostApiCount @6 10 | Pa_GetDefaultHostApi @7 11 | Pa_GetHostApiInfo @8 12 | Pa_HostApiTypeIdToHostApiIndex @9 13 | Pa_HostApiDeviceIndexToDeviceIndex @10 14 | Pa_GetLastHostErrorInfo @11 15 | Pa_GetDeviceCount @12 16 | Pa_GetDefaultInputDevice @13 17 | Pa_GetDefaultOutputDevice @14 18 | Pa_GetDeviceInfo @15 19 | Pa_IsFormatSupported @16 20 | Pa_OpenStream @17 21 | Pa_OpenDefaultStream @18 22 | Pa_CloseStream @19 23 | Pa_SetStreamFinishedCallback @20 24 | Pa_StartStream @21 25 | Pa_StopStream @22 26 | Pa_AbortStream @23 27 | Pa_IsStreamStopped @24 28 | Pa_IsStreamActive @25 29 | Pa_GetStreamInfo @26 30 | Pa_GetStreamTime @27 31 | Pa_GetStreamCpuLoad @28 32 | Pa_ReadStream @29 33 | Pa_WriteStream @30 34 | Pa_GetStreamReadAvailable @31 35 | Pa_GetStreamWriteAvailable @32 36 | Pa_GetSampleSize @33 37 | Pa_Sleep @34 38 | ;PaAsio_GetAvailableBufferSizes @50 39 | ;PaAsio_ShowControlPanel @51 40 | PaUtil_InitializeX86PlainConverters @52 41 | ;PaAsio_GetInputChannelName @53 42 | ;PaAsio_GetOutputChannelName @54 43 | PaUtil_SetDebugPrintFunction @55 44 | PaWasapi_GetDeviceDefaultFormat @56 45 | PaWasapi_GetDeviceRole @57 46 | PaWasapi_ThreadPriorityBoost @58 47 | PaWasapi_ThreadPriorityRevert @59 48 | PaWasapi_GetFramesPerHostBuffer @60 49 | PaWasapi_GetJackDescription @61 50 | PaWasapi_GetJackCount @62 -------------------------------------------------------------------------------- /portaudio/msvc/portaudio.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Debug 10 | x64 11 | 12 | 13 | ReleaseMinDependency 14 | Win32 15 | 16 | 17 | ReleaseMinDependency 18 | x64 19 | 20 | 21 | Release 22 | Win32 23 | 24 | 25 | Release 26 | x64 27 | 28 | 29 | 30 | {0A18A071-125E-442F-AFF7-A3F68ABECF99} 31 | portaudio 32 | 8.1 33 | 34 | 35 | 36 | DynamicLibrary 37 | v140 38 | false 39 | 40 | 41 | DynamicLibrary 42 | v140 43 | false 44 | 45 | 46 | DynamicLibrary 47 | v140 48 | false 49 | 50 | 51 | DynamicLibrary 52 | v140 53 | false 54 | 55 | 56 | DynamicLibrary 57 | v140 58 | false 59 | 60 | 61 | DynamicLibrary 62 | v140 63 | false 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | <_ProjectFileVersion>14.0.25123.0 95 | 96 | 97 | $(Platform)\$(Configuration)\ 98 | $(Platform)\$(Configuration)\ 99 | false 100 | 101 | 102 | $(Platform)\$(Configuration)\ 103 | $(Platform)\$(Configuration)\ 104 | false 105 | $(ProjectName)_x64 106 | 107 | 108 | $(Platform)\$(Configuration)\ 109 | $(Platform)\$(Configuration)\ 110 | true 111 | 112 | 113 | $(Platform)\$(Configuration)\ 114 | $(Platform)\$(Configuration)\ 115 | true 116 | 117 | 118 | $(Platform)\$(Configuration)\ 119 | $(Platform)\$(Configuration)\ 120 | false 121 | 122 | 123 | $(Platform)\$(Configuration)\ 124 | $(Platform)\$(Configuration)\ 125 | false 126 | 127 | 128 | 129 | NDEBUG;%(PreprocessorDefinitions) 130 | true 131 | true 132 | Win32 133 | .\Release_x86/portaudio.tlb 134 | 135 | 136 | 137 | MaxSpeed 138 | OnlyExplicitInline 139 | true 140 | Speed 141 | ..\..\src\common;..\..\include;.\;..\..\src\os\win;%(AdditionalIncludeDirectories) 142 | WIN32;NDEBUG;_USRDLL;PA_ENABLE_DEBUG_OUTPUT;_CRT_SECURE_NO_DEPRECATE;PAWIN_USE_WDMKS_DEVICE_INFO;PA_USE_ASIO=0;PA_USE_DS=0;PA_USE_WMME=1;PA_USE_WASAPI=1;PA_USE_WDMKS=1;%(PreprocessorDefinitions) 143 | true 144 | MultiThreadedDLL 145 | true 146 | $(Platform)\$(Configuration)/portaudio.pch 147 | $(Platform)\$(Configuration)\ 148 | $(Platform)\$(Configuration)\ 149 | $(Platform)\$(Configuration)\ 150 | Level3 151 | true 152 | 153 | 154 | NDEBUG;%(PreprocessorDefinitions) 155 | 0x0409 156 | 157 | 158 | ksuser.lib;%(AdditionalDependencies) 159 | $(Platform)\$(Configuration)\portaudio_x86.dll 160 | true 161 | .\portaudio.def 162 | $(Platform)\$(Configuration)\portaudio_x86.pdb 163 | $(Platform)\$(Configuration)\portaudio_x86.lib 164 | MachineX86 165 | 166 | 167 | true 168 | $(Platform)\$(Configuration)\portaudio.bsc 169 | 170 | 171 | 172 | 173 | NDEBUG;%(PreprocessorDefinitions) 174 | true 175 | true 176 | X64 177 | .\Release_x86/portaudio.tlb 178 | 179 | 180 | 181 | MaxSpeed 182 | OnlyExplicitInline 183 | true 184 | Speed 185 | ..\..\src\common;..\..\include;.\;..\..\src\os\win;%(AdditionalIncludeDirectories) 186 | _WIN64;NDEBUG;_USRDLL;PA_ENABLE_DEBUG_OUTPUT;_CRT_SECURE_NO_DEPRECATE;PAWIN_USE_WDMKS_DEVICE_INFO;PA_USE_ASIO=0;PA_USE_DS=0;PA_USE_WMME=1;PA_USE_WASAPI=1;PA_USE_WDMKS=1;%(PreprocessorDefinitions) 187 | true 188 | MultiThreadedDLL 189 | true 190 | $(Platform)\$(Configuration)\portaudio.pch 191 | $(Platform)\$(Configuration)\ 192 | $(Platform)\$(Configuration)\ 193 | $(Platform)\$(Configuration)\ 194 | Level3 195 | true 196 | 197 | 198 | NDEBUG;%(PreprocessorDefinitions) 199 | 0x0409 200 | 201 | 202 | ksuser.lib;%(AdditionalDependencies) 203 | $(Platform)\$(Configuration)\portaudio_x64.dll 204 | true 205 | .\portaudio.def 206 | $(Platform)\$(Configuration)/portaudio_x64.pdb 207 | $(Platform)\$(Configuration)/portaudio_x64.lib 208 | MachineX64 209 | 210 | 211 | true 212 | $(Platform)\$(Configuration)\portaudio_x64.bsc 213 | 214 | 215 | 216 | 217 | _DEBUG;%(PreprocessorDefinitions) 218 | true 219 | true 220 | Win32 221 | .\Debug_x86/portaudio.tlb 222 | 223 | 224 | 225 | Disabled 226 | ..\..\src\common;..\..\include;.\;..\..\src\os\win;%(AdditionalIncludeDirectories) 227 | WIN32;_DEBUG;_USRDLL;PA_ENABLE_DEBUG_OUTPUT;_CRT_SECURE_NO_DEPRECATE;PAWIN_USE_WDMKS_DEVICE_INFO;PA_USE_ASIO=0;PA_USE_DS=0;PA_USE_WMME=1;PA_USE_WASAPI=1;PA_USE_WDMKS=1;%(PreprocessorDefinitions) 228 | true 229 | EnableFastChecks 230 | MultiThreadedDebugDLL 231 | $(Platform)\$(Configuration)/portaudio.pch 232 | $(Platform)\$(Configuration)\ 233 | $(Platform)\$(Configuration)\ 234 | $(Platform)\$(Configuration)\ 235 | Level3 236 | true 237 | EditAndContinue 238 | 239 | 240 | _DEBUG;%(PreprocessorDefinitions) 241 | 0x0409 242 | 243 | 244 | $(Platform)\$(Configuration)\portaudio_x86.dll 245 | true 246 | .\portaudio.def 247 | true 248 | $(Platform)\$(Configuration)\portaudio_x86.pdb 249 | $(Platform)\$(Configuration)\portaudio_x86.lib 250 | MachineX86 251 | 252 | 253 | true 254 | $(Platform)\$(Configuration)\portaudio.bsc 255 | 256 | 257 | 258 | 259 | _DEBUG;%(PreprocessorDefinitions) 260 | true 261 | true 262 | X64 263 | .\Debug_x86/portaudio.tlb 264 | 265 | 266 | 267 | Disabled 268 | ..\..\src\common;..\..\include;.\;..\..\src\os\win;%(AdditionalIncludeDirectories) 269 | _WIN64;_DEBUG;_USRDLL;PA_ENABLE_DEBUG_OUTPUT;_CRT_SECURE_NO_DEPRECATE;PAWIN_USE_WDMKS_DEVICE_INFO;PA_USE_ASIO=0;PA_USE_DS=0;PA_USE_WMME=1;PA_USE_WASAPI=1;PA_USE_WDMKS=1;%(PreprocessorDefinitions) 270 | true 271 | EnableFastChecks 272 | MultiThreadedDebugDLL 273 | $(Platform)\$(Configuration)\portaudio.pch 274 | $(Platform)\$(Configuration)\ 275 | $(Platform)\$(Configuration)\ 276 | $(Platform)\$(Configuration)\ 277 | Level3 278 | true 279 | ProgramDatabase 280 | 281 | 282 | _DEBUG;%(PreprocessorDefinitions) 283 | 0x0409 284 | 285 | 286 | $(Platform)\$(Configuration)\portaudio_x64.dll 287 | true 288 | .\portaudio.def 289 | true 290 | $(Platform)\$(Configuration)/portaudio_x64.pdb 291 | $(Platform)\$(Configuration)\portaudio_x64.lib 292 | MachineX64 293 | 294 | 295 | true 296 | $(Platform)\$(Configuration)/portaudio_x64.bsc 297 | 298 | 299 | 300 | 301 | NDEBUG;%(PreprocessorDefinitions) 302 | true 303 | true 304 | Win32 305 | .\Release_x86/portaudio.tlb 306 | 307 | 308 | 309 | MaxSpeed 310 | OnlyExplicitInline 311 | true 312 | Speed 313 | ..\..\src\common;..\..\include;.\;..\..\src\os\win;%(AdditionalIncludeDirectories) 314 | WIN32;NDEBUG;_USRDLL;PA_ENABLE_DEBUG_OUTPUT;_CRT_SECURE_NO_DEPRECATE;PAWIN_USE_WDMKS_DEVICE_INFO;PA_USE_ASIO=0;PA_USE_DS=0;PA_USE_WMME=1;PA_USE_WASAPI=1;PA_USE_WDMKS=1;%(PreprocessorDefinitions) 315 | true 316 | MultiThreaded 317 | true 318 | $(Platform)\$(Configuration)/portaudio.pch 319 | $(Platform)\$(Configuration)\ 320 | $(Platform)\$(Configuration)\ 321 | $(Platform)\$(Configuration)\ 322 | Level3 323 | true 324 | 325 | 326 | NDEBUG;%(PreprocessorDefinitions) 327 | 0x0409 328 | 329 | 330 | ksuser.lib;%(AdditionalDependencies) 331 | $(Platform)\$(Configuration)\portaudio_x86.dll 332 | true 333 | .\portaudio.def 334 | $(Platform)\$(Configuration)\portaudio_x86.pdb 335 | $(Platform)\$(Configuration)\portaudio_x86.lib 336 | MachineX86 337 | 338 | 339 | true 340 | $(Platform)\$(Configuration)\portaudio.bsc 341 | 342 | 343 | 344 | 345 | NDEBUG;%(PreprocessorDefinitions) 346 | true 347 | true 348 | X64 349 | .\Release_x86/portaudio.tlb 350 | 351 | 352 | 353 | MaxSpeed 354 | OnlyExplicitInline 355 | true 356 | Speed 357 | ..\..\src\common;..\..\include;.\;..\..\src\os\win;%(AdditionalIncludeDirectories) 358 | _WIN64;NDEBUG;_USRDLL;PA_ENABLE_DEBUG_OUTPUT;_CRT_SECURE_NO_DEPRECATE;PAWIN_USE_WDMKS_DEVICE_INFO;PA_USE_ASIO=0;PA_USE_DS=0;PA_USE_WMME=1;PA_USE_WASAPI=1;PA_USE_WDMKS=1;%(PreprocessorDefinitions) 359 | true 360 | MultiThreaded 361 | true 362 | $(Platform)\$(Configuration)\portaudio.pch 363 | $(Platform)\$(Configuration)\ 364 | $(Platform)\$(Configuration)\ 365 | $(Platform)\$(Configuration)\ 366 | Level3 367 | true 368 | 369 | 370 | NDEBUG;%(PreprocessorDefinitions) 371 | 0x0409 372 | 373 | 374 | ksuser.lib;%(AdditionalDependencies) 375 | $(Platform)\$(Configuration)\portaudio_x64.dll 376 | true 377 | .\portaudio.def 378 | $(Platform)\$(Configuration)/portaudio_x64.pdb 379 | $(Platform)\$(Configuration)/portaudio_x64.lib 380 | MachineX64 381 | 382 | 383 | true 384 | $(Platform)\$(Configuration)\portaudio_x64.bsc 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | -------------------------------------------------------------------------------- /portaudio/msvc/readme.txt: -------------------------------------------------------------------------------- 1 | Building portaudio for naudiodon on Windows: 2 | 3 | Copy build.bat, portaudio.vcxproj and portaudio.def into portaudio\build\msvc directory. 4 | Run build.bat 5 | Copy portaudio_x64.dll and portaudio_x64.lib from portaudio\build\msvc\X64\Release to naudiodon\portaudio\bin directory 6 | 7 | -------------------------------------------------------------------------------- /src/AudioIn.cc: -------------------------------------------------------------------------------- 1 | /* Copyright 2017 Streampunk Media Ltd. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | #include 17 | #include "common.h" 18 | #include "AudioIn.h" 19 | #include "Persist.h" 20 | #include "Params.h" 21 | #include "ChunkQueue.h" 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | using namespace v8; 28 | 29 | namespace streampunk { 30 | 31 | extern bool DEBUG; 32 | 33 | static std::map > outstandingAllocs; 34 | static void freeAllocCb(char* data, void* hint) { 35 | std::map >::iterator it = outstandingAllocs.find(data); 36 | if (it != outstandingAllocs.end()) 37 | outstandingAllocs.erase(it); 38 | } 39 | 40 | class InContext { 41 | public: 42 | InContext(std::shared_ptr audioOptions, PaStreamCallback *cb) 43 | : mActive(true), mAudioOptions(audioOptions), mChunkQueue(mAudioOptions->maxQueue()) { 44 | 45 | // Set DEBUG flag based on audio options 46 | DEBUG = audioOptions->debugMode(); 47 | 48 | PaError errCode = Pa_Initialize(); 49 | if (errCode != paNoError) { 50 | std::string err = std::string("Could not initialize PortAudio: ") + Pa_GetErrorText(errCode); 51 | Nan::ThrowError(err.c_str()); 52 | } 53 | 54 | DEBUG_PRINT_ERR("Input %s\n", mAudioOptions->toString().c_str()); 55 | 56 | PaStreamParameters inParams; 57 | memset(&inParams, 0, sizeof(PaStreamParameters)); 58 | 59 | int32_t deviceID = (int32_t)mAudioOptions->deviceID(); 60 | if ((deviceID >= 0) && (deviceID < Pa_GetDeviceCount())) 61 | inParams.device = (PaDeviceIndex)deviceID; 62 | else 63 | inParams.device = Pa_GetDefaultInputDevice(); 64 | if (inParams.device == paNoDevice) 65 | Nan::ThrowError("No default input device"); 66 | DEBUG_PRINT_ERR("Input device name is %s\n", Pa_GetDeviceInfo(inParams.device)->name); 67 | 68 | inParams.channelCount = mAudioOptions->channelCount(); 69 | if (inParams.channelCount > Pa_GetDeviceInfo(inParams.device)->maxInputChannels) 70 | Nan::ThrowError("Channel count exceeds maximum number of input channels for device"); 71 | 72 | uint32_t sampleFormat = mAudioOptions->sampleFormat(); 73 | switch(sampleFormat) { 74 | case 8: inParams.sampleFormat = paInt8; break; 75 | case 16: inParams.sampleFormat = paInt16; break; 76 | case 24: inParams.sampleFormat = paInt24; break; 77 | case 32: inParams.sampleFormat = paInt32; break; 78 | default: Nan::ThrowError("Invalid sampleFormat"); 79 | } 80 | 81 | inParams.suggestedLatency = Pa_GetDeviceInfo(inParams.device)->defaultLowInputLatency; 82 | inParams.hostApiSpecificStreamInfo = NULL; 83 | 84 | double sampleRate = (double)mAudioOptions->sampleRate(); 85 | uint32_t framesPerBuffer = paFramesPerBufferUnspecified; 86 | 87 | #ifdef __arm__ 88 | framesPerBuffer = 256; 89 | inParams.suggestedLatency = Pa_GetDeviceInfo(inParams.device)->defaultHighInputLatency; 90 | #endif 91 | 92 | errCode = Pa_OpenStream(&mStream, &inParams, NULL, sampleRate, 93 | framesPerBuffer, paNoFlag, cb, this); 94 | if (errCode != paNoError) { 95 | std::string err = std::string("Could not open stream: ") + Pa_GetErrorText(errCode); 96 | Nan::ThrowError(err.c_str()); 97 | } 98 | } 99 | 100 | ~InContext() { 101 | Pa_StopStream(mStream); 102 | Pa_Terminate(); 103 | } 104 | 105 | void start() { 106 | PaError errCode = Pa_StartStream(mStream); 107 | if (errCode != paNoError) { 108 | std::string err = std::string("Could not start input stream: ") + Pa_GetErrorText(errCode); 109 | return Nan::ThrowError(err.c_str()); 110 | } 111 | } 112 | 113 | void stop() { 114 | Pa_StopStream(mStream); 115 | Pa_Terminate(); 116 | } 117 | 118 | void abort() { 119 | Pa_AbortStream(mStream); 120 | Pa_Terminate(); 121 | } 122 | 123 | std::shared_ptr readChunk() { 124 | return mChunkQueue.dequeue(); 125 | } 126 | 127 | bool readBuffer(const void *srcBuf, uint32_t frameCount) { 128 | const uint8_t *src = (uint8_t *)srcBuf; 129 | uint32_t bytesAvailable = frameCount * mAudioOptions->channelCount() * mAudioOptions->sampleFormat() / 8; 130 | std::shared_ptr dstBuf = Memory::makeNew(bytesAvailable); 131 | memcpy(dstBuf->buf(), src, bytesAvailable); 132 | mChunkQueue.enqueue(dstBuf); 133 | return mActive; 134 | } 135 | 136 | void checkStatus(uint32_t statusFlags) { 137 | if (statusFlags) { 138 | std::string err = std::string("portAudio status - "); 139 | if (statusFlags & paInputUnderflow) 140 | err += "input underflow "; 141 | if (statusFlags & paInputOverflow) 142 | err += "input overflow "; 143 | 144 | std::lock_guard lk(m); 145 | mErrStr = err; 146 | } 147 | } 148 | 149 | bool getErrStr(std::string& errStr) { 150 | std::lock_guard lk(m); 151 | errStr = mErrStr; 152 | mErrStr = std::string(); 153 | return errStr != std::string(); 154 | } 155 | 156 | void quit() { 157 | std::unique_lock lk(m); 158 | mActive = false; 159 | mChunkQueue.quit(); 160 | } 161 | 162 | private: 163 | bool mActive; 164 | std::shared_ptr mAudioOptions; 165 | ChunkQueue > mChunkQueue; 166 | PaStream* mStream; 167 | std::string mErrStr; 168 | mutable std::mutex m; 169 | std::condition_variable cv; 170 | }; 171 | 172 | int InCallback(const void *input, void *output, unsigned long frameCount, 173 | const PaStreamCallbackTimeInfo *timeInfo, 174 | PaStreamCallbackFlags statusFlags, void *userData) { 175 | InContext *context = (InContext *)userData; 176 | context->checkStatus(statusFlags); 177 | return context->readBuffer(input, frameCount) ? paContinue : paComplete; 178 | } 179 | 180 | class InWorker : public Nan::AsyncWorker { 181 | public: 182 | InWorker(std::shared_ptr InContext, Nan::Callback *callback) 183 | : AsyncWorker(callback), mInContext(InContext) 184 | { } 185 | ~InWorker() {} 186 | 187 | void Execute() { 188 | mInChunk = mInContext->readChunk(); 189 | } 190 | 191 | void HandleOKCallback () { 192 | Nan::HandleScope scope; 193 | 194 | std::string errStr; 195 | if (mInContext->getErrStr(errStr)) { 196 | Local argv[] = { Nan::Error(errStr.c_str()) }; 197 | callback->Call(1, argv, async_resource); 198 | } 199 | 200 | if (mInChunk) { 201 | outstandingAllocs.insert(make_pair((char*)mInChunk->buf(), mInChunk)); 202 | Nan::MaybeLocal maybeBuf = Nan::NewBuffer((char*)mInChunk->buf(), mInChunk->numBytes(), freeAllocCb, 0); 203 | Local argv[] = { Nan::Null(), maybeBuf.ToLocalChecked() }; 204 | callback->Call(2, argv, async_resource); 205 | } else { 206 | Local argv[] = { Nan::Null(), Nan::Null() }; 207 | callback->Call(2, argv, async_resource); 208 | } 209 | } 210 | 211 | private: 212 | std::shared_ptr mInContext; 213 | std::shared_ptr mInChunk; 214 | }; 215 | 216 | class QuitInWorker : public Nan::AsyncWorker { 217 | public: 218 | QuitInWorker(std::shared_ptr InContext, Nan::Callback *callback) 219 | : AsyncWorker(callback), mInContext(InContext) 220 | { } 221 | ~QuitInWorker() {} 222 | 223 | void Execute() { 224 | mInContext->quit(); 225 | } 226 | 227 | void HandleOKCallback () { 228 | Nan::HandleScope scope; 229 | mInContext->stop(); 230 | callback->Call(0, NULL, async_resource); 231 | } 232 | 233 | private: 234 | std::shared_ptr mInContext; 235 | }; 236 | 237 | AudioIn::AudioIn(Local options) { 238 | mInContext = std::make_shared(std::make_shared(options), InCallback); 239 | } 240 | AudioIn::~AudioIn() {} 241 | 242 | void AudioIn::doStart() { mInContext->start(); } 243 | 244 | NAN_METHOD(AudioIn::Start) { 245 | AudioIn* obj = Nan::ObjectWrap::Unwrap(info.Holder()); 246 | obj->doStart(); 247 | info.GetReturnValue().SetUndefined(); 248 | } 249 | 250 | NAN_METHOD(AudioIn::Abort) { 251 | AudioIn* obj = Nan::ObjectWrap::Unwrap(info.Holder()); 252 | obj->mInContext->abort(); 253 | info.GetReturnValue().SetUndefined(); 254 | } 255 | 256 | NAN_METHOD(AudioIn::Read) { 257 | if (info.Length() != 2) 258 | return Nan::ThrowError("AudioIn Read expects 2 arguments"); 259 | if (!info[0]->IsNumber()) 260 | return Nan::ThrowError("AudioIn Read requires a valid advisory size as the first parameter"); 261 | if (!info[1]->IsFunction()) 262 | return Nan::ThrowError("AudioIn Read requires a valid callback as the second parameter"); 263 | 264 | // uint32_t sizeAdv = Nan::To(info[0]).FromJust(); 265 | Local callback = Local::Cast(info[1]); 266 | AudioIn* obj = Nan::ObjectWrap::Unwrap(info.Holder()); 267 | 268 | AsyncQueueWorker(new InWorker(obj->getContext(), new Nan::Callback(callback))); 269 | info.GetReturnValue().SetUndefined(); 270 | } 271 | 272 | NAN_METHOD(AudioIn::Quit) { 273 | if (info.Length() != 1) 274 | return Nan::ThrowError("AudioIn Quit expects 1 argument"); 275 | if (!info[0]->IsFunction()) 276 | return Nan::ThrowError("AudioIn Quit requires a valid callback as the parameter"); 277 | 278 | Local callback = Local::Cast(info[0]); 279 | AudioIn* obj = Nan::ObjectWrap::Unwrap(info.Holder()); 280 | 281 | AsyncQueueWorker(new QuitInWorker(obj->getContext(), new Nan::Callback(callback))); 282 | info.GetReturnValue().SetUndefined(); 283 | } 284 | 285 | NAN_MODULE_INIT(AudioIn::Init) { 286 | Local tpl = Nan::New(New); 287 | tpl->SetClassName(Nan::New("AudioIn").ToLocalChecked()); 288 | tpl->InstanceTemplate()->SetInternalFieldCount(1); 289 | 290 | SetPrototypeMethod(tpl, "start", Start); 291 | SetPrototypeMethod(tpl, "read", Read); 292 | SetPrototypeMethod(tpl, "quit", Quit); 293 | SetPrototypeMethod(tpl, "abort", Abort); 294 | 295 | constructor().Reset(Nan::GetFunction(tpl).ToLocalChecked()); 296 | Nan::Set(target, Nan::New("AudioIn").ToLocalChecked(), 297 | Nan::GetFunction(tpl).ToLocalChecked()); 298 | } 299 | 300 | } // namespace streampunk 301 | -------------------------------------------------------------------------------- /src/AudioIn.h: -------------------------------------------------------------------------------- 1 | /* Copyright 2017 Streampunk Media Ltd. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | #ifndef AUDIOIN_H 17 | #define AUDIOIN_H 18 | 19 | #include "Memory.h" 20 | 21 | namespace streampunk { 22 | 23 | class InContext; 24 | 25 | class AudioIn : public Nan::ObjectWrap { 26 | public: 27 | static NAN_MODULE_INIT(Init); 28 | 29 | std::shared_ptr getContext() const { return mInContext; } 30 | void doStart(); 31 | 32 | private: 33 | explicit AudioIn(v8::Local options); 34 | ~AudioIn(); 35 | 36 | static NAN_METHOD(New) { 37 | if (info.IsConstructCall()) { 38 | if (!((info.Length() == 1) && (info[0]->IsObject()))) 39 | return Nan::ThrowError("AudioIn constructor requires a valid options object as the parameter"); 40 | v8::Local options = v8::Local::Cast(info[0]); 41 | AudioIn *obj = new AudioIn(options); 42 | obj->Wrap(info.This()); 43 | info.GetReturnValue().Set(info.This()); 44 | } else { 45 | const int argc = 1; 46 | v8::Local argv[] = { info[0] }; 47 | v8::Local cons = Nan::New(constructor()); 48 | info.GetReturnValue().Set(cons->NewInstance(Nan::GetCurrentContext(), argc, argv).ToLocalChecked()); 49 | } 50 | } 51 | 52 | static inline Nan::Persistent & constructor() { 53 | static Nan::Persistent my_constructor; 54 | return my_constructor; 55 | } 56 | 57 | static NAN_METHOD(Start); 58 | static NAN_METHOD(Read); 59 | static NAN_METHOD(Quit); 60 | static NAN_METHOD(Abort); 61 | 62 | std::shared_ptr mInContext; 63 | }; 64 | 65 | } // namespace streampunk 66 | 67 | #endif 68 | -------------------------------------------------------------------------------- /src/AudioOut.cc: -------------------------------------------------------------------------------- 1 | /* Copyright 2017 Streampunk Media Ltd. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | #include 17 | #include "common.h" 18 | #include "AudioOut.h" 19 | #include "Persist.h" 20 | #include "Params.h" 21 | #include "ChunkQueue.h" 22 | #include 23 | #include 24 | #include 25 | 26 | using namespace v8; 27 | 28 | namespace streampunk { 29 | 30 | extern bool DEBUG; 31 | 32 | class AudioChunk { 33 | public: 34 | AudioChunk (Local chunk) 35 | : mPersistentChunk(new Persist(chunk)), 36 | mChunk(Memory::makeNew((uint8_t *)node::Buffer::Data(chunk), (uint32_t)node::Buffer::Length(chunk))) 37 | { } 38 | ~AudioChunk() { } 39 | 40 | std::shared_ptr chunk() const { return mChunk; } 41 | 42 | private: 43 | std::unique_ptr mPersistentChunk; 44 | std::shared_ptr mChunk; 45 | }; 46 | 47 | class OutContext { 48 | public: 49 | OutContext(std::shared_ptr audioOptions, PaStreamCallback *cb) 50 | : mAudioOptions(audioOptions), mChunkQueue(mAudioOptions->maxQueue()), 51 | mCurOffset(0), mActive(true), mFinished(false) { 52 | 53 | // set DEBUG flag based on options 54 | DEBUG = audioOptions->debugMode(); 55 | 56 | PaError errCode = Pa_Initialize(); 57 | if (errCode != paNoError) { 58 | std::string err = std::string("Could not initialize PortAudio: ") + Pa_GetErrorText(errCode); 59 | Nan::ThrowError(err.c_str()); 60 | } 61 | 62 | DEBUG_PRINT_ERR("Output %s\n", mAudioOptions->toString().c_str()); 63 | 64 | PaStreamParameters outParams; 65 | memset(&outParams, 0, sizeof(PaStreamParameters)); 66 | 67 | int32_t deviceID = (int32_t)mAudioOptions->deviceID(); 68 | if ((deviceID >= 0) && (deviceID < Pa_GetDeviceCount())) 69 | outParams.device = (PaDeviceIndex)deviceID; 70 | else 71 | outParams.device = Pa_GetDefaultOutputDevice(); 72 | if (outParams.device == paNoDevice) 73 | Nan::ThrowError("No default output device"); 74 | DEBUG_PRINT_ERR("Output device name is %s\n", Pa_GetDeviceInfo(outParams.device)->name); 75 | 76 | outParams.channelCount = mAudioOptions->channelCount(); 77 | if (outParams.channelCount > Pa_GetDeviceInfo(outParams.device)->maxOutputChannels) 78 | Nan::ThrowError("Channel count exceeds maximum number of output channels for device"); 79 | 80 | uint32_t sampleFormat = mAudioOptions->sampleFormat(); 81 | switch(sampleFormat) { 82 | case 8: outParams.sampleFormat = paInt8; break; 83 | case 16: outParams.sampleFormat = paInt16; break; 84 | case 24: outParams.sampleFormat = paInt24; break; 85 | case 32: outParams.sampleFormat = paInt32; break; 86 | default: Nan::ThrowError("Invalid sampleFormat"); 87 | } 88 | 89 | outParams.suggestedLatency = Pa_GetDeviceInfo(outParams.device)->defaultLowOutputLatency; 90 | outParams.hostApiSpecificStreamInfo = NULL; 91 | 92 | double sampleRate = (double)mAudioOptions->sampleRate(); 93 | uint32_t framesPerBuffer = paFramesPerBufferUnspecified; 94 | 95 | #ifdef __arm__ 96 | framesPerBuffer = 256; 97 | outParams.suggestedLatency = Pa_GetDeviceInfo(outParams.device)->defaultHighOutputLatency; 98 | #endif 99 | 100 | errCode = Pa_OpenStream(&mStream, NULL, &outParams, sampleRate, 101 | framesPerBuffer, paNoFlag, cb, this); 102 | if (errCode != paNoError) { 103 | std::string err = std::string("Could not open stream: ") + Pa_GetErrorText(errCode); 104 | Nan::ThrowError(err.c_str()); 105 | } 106 | } 107 | 108 | ~OutContext() { 109 | Pa_StopStream(mStream); 110 | Pa_Terminate(); 111 | } 112 | 113 | void start() { 114 | PaError errCode = Pa_StartStream(mStream); 115 | if (errCode != paNoError) { 116 | std::string err = std::string("Could not start output stream: ") + Pa_GetErrorText(errCode); 117 | return Nan::ThrowError(err.c_str()); 118 | } 119 | } 120 | 121 | void stop() { 122 | Pa_StopStream(mStream); 123 | Pa_Terminate(); 124 | } 125 | 126 | void abort() { 127 | Pa_AbortStream(mStream); 128 | Pa_Terminate(); 129 | } 130 | 131 | void addChunk(std::shared_ptr audioChunk) { 132 | mChunkQueue.enqueue(audioChunk); 133 | } 134 | 135 | bool fillBuffer(void *buf, uint32_t frameCount) { 136 | uint8_t *dst = (uint8_t *)buf; 137 | uint32_t bytesRemaining = frameCount * mAudioOptions->channelCount() * mAudioOptions->sampleFormat() / 8; 138 | 139 | uint32_t active = isActive(); 140 | if (!active && (0 == mChunkQueue.size()) && 141 | (!mCurChunk || (mCurChunk && (bytesRemaining >= mCurChunk->chunk()->numBytes() - mCurOffset)))) { 142 | if (mCurChunk) { 143 | uint32_t bytesCopied = doCopy(mCurChunk->chunk(), dst, bytesRemaining); 144 | uint32_t missingBytes = bytesRemaining - bytesCopied; 145 | if (missingBytes > 0) { 146 | DEBUG_PRINT_ERR("Finishing - %d bytes not available for the last output buffer\n", missingBytes); 147 | memset(dst + bytesCopied, 0, missingBytes); 148 | } 149 | } 150 | std::lock_guard lk(m); 151 | mFinished = true; 152 | cv.notify_one(); 153 | } else { 154 | while (bytesRemaining) { 155 | if (!(mCurChunk && (mCurOffset < mCurChunk->chunk()->numBytes()))) { 156 | mCurChunk = mChunkQueue.dequeue(); 157 | mCurOffset = 0; 158 | } 159 | if (mCurChunk) { 160 | uint32_t bytesCopied = doCopy(mCurChunk->chunk(), dst, bytesRemaining); 161 | bytesRemaining -= bytesCopied; 162 | dst += bytesCopied; 163 | mCurOffset += bytesCopied; 164 | } else { // Deal with termination case of ChunkQueue being kicked and returning null chunk 165 | std::lock_guard lk(m); 166 | mFinished = true; 167 | cv.notify_one(); 168 | break; 169 | } 170 | } 171 | } 172 | 173 | return !mFinished; 174 | } 175 | 176 | void checkStatus(uint32_t statusFlags) { 177 | if (statusFlags) { 178 | std::string err = std::string("portAudio status - "); 179 | if (statusFlags & paOutputUnderflow) 180 | err += "output underflow "; 181 | if (statusFlags & paOutputOverflow) 182 | err += "output overflow "; 183 | if (statusFlags & paPrimingOutput) 184 | err += "priming output "; 185 | 186 | std::lock_guard lk(m); 187 | mErrStr = err; 188 | } 189 | } 190 | 191 | bool getErrStr(std::string& errStr) { 192 | std::lock_guard lk(m); 193 | errStr = mErrStr; 194 | mErrStr = std::string(); 195 | return errStr != std::string(); 196 | } 197 | 198 | void quit() { 199 | std::unique_lock lk(m); 200 | mActive = false; 201 | mChunkQueue.quit(); 202 | while(!mFinished) 203 | cv.wait(lk); 204 | } 205 | 206 | private: 207 | std::shared_ptr mAudioOptions; 208 | ChunkQueue > mChunkQueue; 209 | std::shared_ptr mCurChunk; 210 | PaStream* mStream; 211 | uint32_t mCurOffset; 212 | bool mActive; 213 | bool mFinished; 214 | std::string mErrStr; 215 | mutable std::mutex m; 216 | std::condition_variable cv; 217 | 218 | bool isActive() const { 219 | std::unique_lock lk(m); 220 | return mActive; 221 | } 222 | 223 | uint32_t doCopy(std::shared_ptr chunk, void *dst, uint32_t numBytes) { 224 | uint32_t curChunkBytes = chunk->numBytes() - mCurOffset; 225 | uint32_t thisChunkBytes = std::min(curChunkBytes, numBytes); 226 | memcpy(dst, chunk->buf() + mCurOffset, thisChunkBytes); 227 | return thisChunkBytes; 228 | } 229 | }; 230 | 231 | int OutCallback(const void *input, void *output, unsigned long frameCount, 232 | const PaStreamCallbackTimeInfo *timeInfo, 233 | PaStreamCallbackFlags statusFlags, void *userData) { 234 | OutContext *context = (OutContext *)userData; 235 | context->checkStatus(statusFlags); 236 | return context->fillBuffer(output, frameCount) ? paContinue : paComplete; 237 | } 238 | 239 | class OutWorker : public Nan::AsyncWorker { 240 | public: 241 | OutWorker(std::shared_ptr OutContext, Nan::Callback *callback, std::shared_ptr audioChunk) 242 | : AsyncWorker(callback), mOutContext(OutContext), mAudioChunk(audioChunk) 243 | { } 244 | ~OutWorker() {} 245 | 246 | void Execute() { 247 | mOutContext->addChunk(mAudioChunk); 248 | } 249 | 250 | void HandleOKCallback () { 251 | Nan::HandleScope scope; 252 | std::string errStr; 253 | if (mOutContext->getErrStr(errStr)) { 254 | Local argv[] = { Nan::Error(errStr.c_str()) }; 255 | callback->Call(1, argv, async_resource); 256 | } else { 257 | callback->Call(0, NULL, async_resource); 258 | } 259 | } 260 | 261 | private: 262 | std::shared_ptr mOutContext; 263 | std::shared_ptr mAudioChunk; 264 | }; 265 | 266 | class QuitOutWorker : public Nan::AsyncWorker { 267 | public: 268 | QuitOutWorker(std::shared_ptr OutContext, Nan::Callback *callback) 269 | : AsyncWorker(callback), mOutContext(OutContext) 270 | { } 271 | ~QuitOutWorker() {} 272 | 273 | void Execute() { 274 | mOutContext->quit(); 275 | } 276 | 277 | void HandleOKCallback () { 278 | Nan::HandleScope scope; 279 | mOutContext->stop(); 280 | callback->Call(0, NULL, async_resource); 281 | } 282 | 283 | private: 284 | std::shared_ptr mOutContext; 285 | }; 286 | 287 | AudioOut::AudioOut(Local options) { 288 | mOutContext = std::make_shared(std::make_shared(options), OutCallback); 289 | } 290 | AudioOut::~AudioOut() {} 291 | 292 | void AudioOut::doStart() { mOutContext->start(); } 293 | 294 | NAN_METHOD(AudioOut::Start) { 295 | AudioOut* obj = Nan::ObjectWrap::Unwrap(info.Holder()); 296 | obj->doStart(); 297 | info.GetReturnValue().SetUndefined(); 298 | } 299 | 300 | NAN_METHOD(AudioOut::Abort) { 301 | AudioOut* obj = Nan::ObjectWrap::Unwrap(info.Holder()); 302 | obj->mOutContext->abort(); 303 | info.GetReturnValue().SetUndefined(); 304 | } 305 | 306 | NAN_METHOD(AudioOut::Write) { 307 | if (info.Length() != 2) 308 | return Nan::ThrowError("AudioOut Write expects 2 arguments"); 309 | if (!info[0]->IsObject()) 310 | return Nan::ThrowError("AudioOut Write requires a valid chunk buffer as the first parameter"); 311 | if (!info[1]->IsFunction()) 312 | return Nan::ThrowError("AudioOut Write requires a valid callback as the second parameter"); 313 | 314 | Local chunkObj = Local::Cast(info[0]); 315 | Local callback = Local::Cast(info[1]); 316 | AudioOut* obj = Nan::ObjectWrap::Unwrap(info.Holder()); 317 | 318 | AsyncQueueWorker(new OutWorker(obj->getContext(), new Nan::Callback(callback), std::make_shared(chunkObj))); 319 | info.GetReturnValue().SetUndefined(); 320 | } 321 | 322 | NAN_METHOD(AudioOut::Quit) { 323 | if (info.Length() != 1) 324 | return Nan::ThrowError("AudioOut Quit expects 1 argument"); 325 | if (!info[0]->IsFunction()) 326 | return Nan::ThrowError("AudioOut Quit requires a valid callback as the parameter"); 327 | 328 | Local callback = Local::Cast(info[0]); 329 | AudioOut* obj = Nan::ObjectWrap::Unwrap(info.Holder()); 330 | 331 | AsyncQueueWorker(new QuitOutWorker(obj->getContext(), new Nan::Callback(callback))); 332 | info.GetReturnValue().SetUndefined(); 333 | } 334 | 335 | NAN_MODULE_INIT(AudioOut::Init) { 336 | Local tpl = Nan::New(New); 337 | tpl->SetClassName(Nan::New("AudioOut").ToLocalChecked()); 338 | tpl->InstanceTemplate()->SetInternalFieldCount(1); 339 | 340 | SetPrototypeMethod(tpl, "start", Start); 341 | SetPrototypeMethod(tpl, "write", Write); 342 | SetPrototypeMethod(tpl, "quit", Quit); 343 | SetPrototypeMethod(tpl, "abort", Abort); 344 | 345 | constructor().Reset(Nan::GetFunction(tpl).ToLocalChecked()); 346 | Nan::Set(target, Nan::New("AudioOut").ToLocalChecked(), 347 | Nan::GetFunction(tpl).ToLocalChecked()); 348 | } 349 | 350 | } // namespace streampunk -------------------------------------------------------------------------------- /src/AudioOut.h: -------------------------------------------------------------------------------- 1 | /* Copyright 2017 Streampunk Media Ltd. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | #ifndef AUDIOOUT_H 17 | #define AUDIOOUT_H 18 | 19 | #include "Memory.h" 20 | 21 | namespace streampunk { 22 | 23 | class OutContext; 24 | 25 | class AudioOut : public Nan::ObjectWrap { 26 | public: 27 | static NAN_MODULE_INIT(Init); 28 | 29 | std::shared_ptr getContext() const { return mOutContext; } 30 | void doStart(); 31 | 32 | private: 33 | explicit AudioOut(v8::Local options); 34 | ~AudioOut(); 35 | 36 | static NAN_METHOD(New) { 37 | if (info.IsConstructCall()) { 38 | if (!((info.Length() == 1) && (info[0]->IsObject()))) 39 | return Nan::ThrowError("AudioOut constructor requires a valid options object as the parameter"); 40 | v8::Local options = v8::Local::Cast(info[0]); 41 | AudioOut *obj = new AudioOut(options); 42 | obj->Wrap(info.This()); 43 | info.GetReturnValue().Set(info.This()); 44 | } else { 45 | const int argc = 1; 46 | v8::Local argv[] = { info[0] }; 47 | v8::Local cons = Nan::New(constructor()); 48 | info.GetReturnValue().Set(cons->NewInstance(Nan::GetCurrentContext(), argc, argv).ToLocalChecked()); 49 | } 50 | } 51 | 52 | static inline Nan::Persistent & constructor() { 53 | static Nan::Persistent my_constructor; 54 | return my_constructor; 55 | } 56 | 57 | static NAN_METHOD(Start); 58 | static NAN_METHOD(Write); 59 | static NAN_METHOD(Quit); 60 | static NAN_METHOD(Abort); 61 | 62 | std::shared_ptr mOutContext; 63 | }; 64 | 65 | } // namespace streampunk 66 | 67 | #endif 68 | -------------------------------------------------------------------------------- /src/ChunkQueue.h: -------------------------------------------------------------------------------- 1 | /* Copyright 2017 Streampunk Media Ltd. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | #ifndef CHUNKQUEUE_H 17 | #define CHUNKQUEUE_H 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | namespace streampunk { 25 | 26 | template 27 | class ChunkQueue { 28 | public: 29 | ChunkQueue(uint32_t maxQueue) : mActive(true), mMaxQueue(maxQueue), qu(), m(), cv() {} 30 | ~ChunkQueue() {} 31 | 32 | void enqueue(T t) { 33 | std::unique_lock lk(m); 34 | while(mActive && (qu.size() >= mMaxQueue)) { 35 | cv.wait(lk); 36 | } 37 | qu.push(t); 38 | cv.notify_one(); 39 | } 40 | 41 | T dequeue() { 42 | std::unique_lock lk(m); 43 | while(mActive && qu.empty()) { 44 | cv.wait(lk); 45 | } 46 | T val; 47 | if (mActive) { 48 | val = qu.front(); 49 | qu.pop(); 50 | cv.notify_one(); 51 | } 52 | return val; 53 | } 54 | 55 | size_t size() const { 56 | std::lock_guard lk(m); 57 | return qu.size(); 58 | } 59 | 60 | void quit() { 61 | std::lock_guard lk(m); 62 | if ((0 == qu.size()) || (qu.size() >= mMaxQueue)) { 63 | // ensure release of any blocked thread 64 | mActive = false; 65 | cv.notify_all(); 66 | } 67 | } 68 | 69 | private: 70 | bool mActive; 71 | uint32_t mMaxQueue; 72 | std::queue qu; 73 | mutable std::mutex m; 74 | std::condition_variable cv; 75 | }; 76 | 77 | } // namespace streampunk 78 | 79 | #endif 80 | -------------------------------------------------------------------------------- /src/GetDevices.cc: -------------------------------------------------------------------------------- 1 | /* Copyright 2017 Streampunk Media Ltd. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | #include 17 | #include "GetDevices.h" 18 | // #include 19 | // #include 20 | #include 21 | 22 | namespace streampunk { 23 | 24 | NAN_METHOD(GetDevices) { 25 | uint32_t numDevices; 26 | 27 | PaError errCode = Pa_Initialize(); 28 | if(errCode != paNoError) { 29 | std::string err = std::string("Could not initialize PortAudio: ") + Pa_GetErrorText(errCode); 30 | Nan::ThrowError(err.c_str()); 31 | } 32 | 33 | numDevices = Pa_GetDeviceCount(); 34 | v8::Local result = Nan::New(numDevices); 35 | 36 | for (uint32_t i = 0; i < numDevices; ++i) { 37 | const PaDeviceInfo* deviceInfo = Pa_GetDeviceInfo(i); 38 | v8::Local v8DeviceInfo = Nan::New(); 39 | Nan::Set(v8DeviceInfo, Nan::New("id").ToLocalChecked(), Nan::New(i)); 40 | Nan::Set(v8DeviceInfo, Nan::New("name").ToLocalChecked(), 41 | Nan::New(deviceInfo->name).ToLocalChecked()); 42 | Nan::Set(v8DeviceInfo, Nan::New("maxInputChannels").ToLocalChecked(), 43 | Nan::New(deviceInfo->maxInputChannels)); 44 | Nan::Set(v8DeviceInfo, Nan::New("maxOutputChannels").ToLocalChecked(), 45 | Nan::New(deviceInfo->maxOutputChannels)); 46 | Nan::Set(v8DeviceInfo, Nan::New("defaultSampleRate").ToLocalChecked(), 47 | Nan::New(deviceInfo->defaultSampleRate)); 48 | Nan::Set(v8DeviceInfo, Nan::New("defaultLowInputLatency").ToLocalChecked(), 49 | Nan::New(deviceInfo->defaultLowInputLatency)); 50 | Nan::Set(v8DeviceInfo, Nan::New("defaultLowOutputLatency").ToLocalChecked(), 51 | Nan::New(deviceInfo->defaultLowOutputLatency)); 52 | Nan::Set(v8DeviceInfo, Nan::New("defaultHighInputLatency").ToLocalChecked(), 53 | Nan::New(deviceInfo->defaultHighInputLatency)); 54 | Nan::Set(v8DeviceInfo, Nan::New("defaultHighOutputLatency").ToLocalChecked(), 55 | Nan::New(deviceInfo->defaultHighOutputLatency)); 56 | Nan::Set(v8DeviceInfo, Nan::New("hostAPIName").ToLocalChecked(), 57 | Nan::New(Pa_GetHostApiInfo(deviceInfo->hostApi)->name).ToLocalChecked()); 58 | 59 | Nan::Set(result, i, v8DeviceInfo); 60 | } 61 | 62 | Pa_Terminate(); 63 | info.GetReturnValue().Set(result); 64 | } 65 | 66 | } // namespace streampunk 67 | -------------------------------------------------------------------------------- /src/GetDevices.h: -------------------------------------------------------------------------------- 1 | /* Copyright 2017 Streampunk Media Ltd. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | #ifndef GETDEVICES_H 17 | #define GETDEVICES_H 18 | 19 | namespace streampunk { 20 | 21 | NAN_METHOD(GetDevices); 22 | 23 | } // namespace streampunk 24 | 25 | #endif -------------------------------------------------------------------------------- /src/Memory.h: -------------------------------------------------------------------------------- 1 | /* Copyright 2017 Streampunk Media Ltd. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | #ifndef MEMORY_H 17 | #define MEMORY_H 18 | 19 | #include 20 | 21 | namespace streampunk { 22 | 23 | class Memory { 24 | public: 25 | static std::shared_ptr makeNew(uint32_t srcBytes) { 26 | return std::make_shared(srcBytes); 27 | } 28 | static std::shared_ptr makeNew(uint8_t *buf, uint32_t srcBytes) { 29 | return std::make_shared(buf, srcBytes); 30 | } 31 | 32 | Memory(uint32_t numBytes) 33 | : mOwnAlloc(true), mNumBytes(numBytes), mBuf(new uint8_t[mNumBytes]) {} 34 | Memory(uint8_t *buf, uint32_t numBytes) 35 | : mOwnAlloc(false), mNumBytes(numBytes), mBuf(buf) {} 36 | ~Memory() { if (mOwnAlloc) delete[] mBuf; } 37 | 38 | uint32_t numBytes() const { return mNumBytes; } 39 | uint8_t *buf() const { return mBuf; } 40 | 41 | private: 42 | const bool mOwnAlloc; 43 | const uint32_t mNumBytes; 44 | uint8_t *const mBuf; 45 | }; 46 | 47 | } // namespace streampunk 48 | 49 | #endif -------------------------------------------------------------------------------- /src/Params.h: -------------------------------------------------------------------------------- 1 | /* Copyright 2017 Streampunk Media Ltd. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | #ifndef PARAMS_H 17 | #define PARAMS_H 18 | 19 | #include 20 | #include 21 | 22 | using namespace v8; 23 | 24 | namespace streampunk { 25 | 26 | class Params { 27 | protected: 28 | Params() {} 29 | virtual ~Params() {} 30 | 31 | Local getKey(Local tags, const std::string& key) { 32 | Local val = Nan::Null(); 33 | Local keyStr = Nan::New(key).ToLocalChecked(); 34 | if (Nan::Has(tags, keyStr).FromJust()) 35 | val = Nan::Get(tags, keyStr).ToLocalChecked(); 36 | return val; 37 | } 38 | 39 | std::string unpackValue(Local val) { 40 | Local valueArray = Local::Cast(val); 41 | return *String::Utf8Value(valueArray->Get(0)); 42 | } 43 | 44 | bool unpackBool(Local tags, const std::string& key, bool dflt) { 45 | bool result = dflt; 46 | Local val = getKey(tags, key); 47 | if (Nan::Null() != val) 48 | result = Nan::To(val).FromJust(); 49 | return result; 50 | } 51 | 52 | uint32_t unpackNum(Local tags, const std::string& key, uint32_t dflt) { 53 | uint32_t result = dflt; 54 | Local val = getKey(tags, key); 55 | if (Nan::Null() != val) 56 | result = Nan::To(val).FromJust(); 57 | return result; 58 | } 59 | 60 | std::string unpackStr(Local tags, const std::string& key, std::string dflt) { 61 | std::string result = dflt; 62 | Local val = getKey(tags, key); 63 | if (Nan::Null() != val) 64 | result = *String::Utf8Value(val); 65 | return result; 66 | } 67 | 68 | private: 69 | Params(const Params &); 70 | }; 71 | 72 | 73 | class AudioOptions : public Params { 74 | public: 75 | AudioOptions(Local tags) 76 | : mDeviceID(unpackNum(tags, "deviceId", 0xffffffff)), 77 | mSampleRate(unpackNum(tags, "sampleRate", 44100)), 78 | mChannelCount(unpackNum(tags, "channelCount", 2)), 79 | mSampleFormat(unpackNum(tags, "sampleFormat", 8)), 80 | mMaxQueue(unpackNum(tags, "maxQueue", 2)), 81 | mDebugMode(unpackBool(tags, "debug", false)) 82 | {} 83 | ~AudioOptions() {} 84 | 85 | uint32_t deviceID() const { return mDeviceID; } 86 | uint32_t sampleRate() const { return mSampleRate; } 87 | uint32_t channelCount() const { return mChannelCount; } 88 | uint32_t sampleFormat() const { return mSampleFormat; } 89 | uint32_t maxQueue() const { return mMaxQueue; } 90 | bool debugMode() const { return mDebugMode; } 91 | 92 | std::string toString() const { 93 | std::stringstream ss; 94 | ss << "audio options: "; 95 | if (mDeviceID == 0xffffffff) 96 | ss << "default device, "; 97 | else 98 | ss << "device " << mDeviceID << ", "; 99 | ss << "sample rate " << mSampleRate << ", "; 100 | ss << "channels " << mChannelCount << ", "; 101 | ss << "bits per sample " << mSampleFormat << ", "; 102 | ss << "max queue " << mMaxQueue; 103 | return ss.str(); 104 | } 105 | 106 | private: 107 | uint32_t mDeviceID; 108 | uint32_t mSampleRate; 109 | uint32_t mChannelCount; 110 | uint32_t mSampleFormat; 111 | uint32_t mMaxQueue; 112 | bool mDebugMode; 113 | }; 114 | 115 | } // namespace streampunk 116 | 117 | #endif 118 | -------------------------------------------------------------------------------- /src/Persist.h: -------------------------------------------------------------------------------- 1 | /* Copyright 2017 Streampunk Media Ltd. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | #ifndef PERSIST_H 17 | #define PERSIST_H 18 | 19 | #include 20 | 21 | namespace streampunk { 22 | 23 | class Persist { 24 | public: 25 | Persist(v8::Local object) 26 | : mPersistObj(object) {} 27 | ~Persist() { mPersistObj.Reset(); } 28 | 29 | private: 30 | Nan::Persistent mPersistObj; 31 | }; 32 | 33 | } // namespace streampunk 34 | 35 | #endif -------------------------------------------------------------------------------- /src/common.cc: -------------------------------------------------------------------------------- 1 | /* Copyright 2018 Aurora API. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | #include "common.h" 17 | 18 | namespace streampunk { 19 | 20 | bool DEBUG = false; 21 | 22 | } // namespace streampunk 23 | -------------------------------------------------------------------------------- /src/common.h: -------------------------------------------------------------------------------- 1 | /* Copyright 2018 Aurora API. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | #ifndef COMMON_H 17 | #define COMMON_H 18 | 19 | #include 20 | 21 | #define DEBUG_PRINT_ERR(s, ...) if (streampunk::DEBUG) { \ 22 | fprintf((stderr), (s), __VA_ARGS__); \ 23 | } 24 | 25 | namespace streampunk { 26 | 27 | extern bool DEBUG; 28 | 29 | } // namespace streampunk 30 | 31 | #endif -------------------------------------------------------------------------------- /src/node_pa.cc: -------------------------------------------------------------------------------- 1 | /* Copyright 2017 Streampunk Media Ltd. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | #include 17 | #include "GetDevices.h" 18 | #include "AudioIn.h" 19 | #include "AudioOut.h" 20 | 21 | NAN_MODULE_INIT(Init) { 22 | Nan::Set(target, Nan::New("getDevices").ToLocalChecked(), 23 | Nan::GetFunction(Nan::New(streampunk::GetDevices)).ToLocalChecked()); 24 | 25 | streampunk::AudioIn::Init(target); 26 | streampunk::AudioOut::Init(target); 27 | } 28 | 29 | NODE_MODULE(portAudio, Init); 30 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Basic Options */ 4 | "target": "es2015", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */ 5 | "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */ 6 | // "lib": [], /* Specify library files to be included in the compilation. */ 7 | // "allowJs": true, /* Allow javascript files to be compiled. */ 8 | // "checkJs": true, /* Report errors in .js files. */ 9 | // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ 10 | "declaration": true, /* Generates corresponding '.d.ts' file. */ 11 | // "sourceMap": true, /* Generates corresponding '.map' file. */ 12 | // "outFile": "index.js", /* Concatenate and emit output to single file. */ 13 | // "outDir": "./", /* Redirect output structure to the directory. */ 14 | // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ 15 | "removeComments": true, /* Do not emit comments to output. */ 16 | // "noEmit": true, /* Do not emit outputs. */ 17 | // "importHelpers": true, /* Import emit helpers from 'tslib'. */ 18 | // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ 19 | // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ 20 | 21 | /* Strict Type-Checking Options */ 22 | "strict": true, /* Enable all strict type-checking options. */ 23 | // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ 24 | // "strictNullChecks": true, /* Enable strict null checks. */ 25 | // "strictFunctionTypes": true, /* Enable strict checking of function types. */ 26 | // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ 27 | // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ 28 | // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ 29 | 30 | /* Additional Checks */ 31 | // "noUnusedLocals": true, /* Report errors on unused locals. */ 32 | // "noUnusedParameters": true, /* Report errors on unused parameters. */ 33 | // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ 34 | // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ 35 | 36 | /* Module Resolution Options */ 37 | // "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ 38 | // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ 39 | // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ 40 | // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ 41 | // "typeRoots": [], /* List of folders to include type definitions from. */ 42 | // "types": [], /* Type declaration files to be included in compilation. */ 43 | // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ 44 | "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ 45 | // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ 46 | 47 | /* Source Map Options */ 48 | // "sourceRoot": "./", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ 49 | // "mapRoot": "./", /* Specify the location where debugger should locate map files instead of generated locations. */ 50 | // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ 51 | // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ 52 | 53 | /* Experimental Options */ 54 | // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ 55 | // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ 56 | } 57 | } -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "defaultSeverity": "error", 3 | "extends": [ 4 | "tslint:recommended" 5 | ], 6 | "jsRules": {}, 7 | "rules": { 8 | "interface-name": [true, "never-prefix"], 9 | "max-classes-per-file": [true, 10] 10 | }, 11 | "rulesDirectory": [] 12 | } -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | "@types/bindings@^1.3.0": 6 | version "1.3.0" 7 | resolved "https://registry.yarnpkg.com/@types/bindings/-/bindings-1.3.0.tgz#e9cd75a96d7abc1ecba0dc7eecb09a9f96cd417c" 8 | 9 | "@types/node@^8.5.0": 10 | version "8.10.10" 11 | resolved "https://registry.yarnpkg.com/@types/node/-/node-8.10.10.tgz#fec07bc2ad549d9e6d2f7aa0fb0be3491b83163a" 12 | 13 | ansi-regex@^2.0.0: 14 | version "2.1.1" 15 | resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" 16 | 17 | ansi-styles@^2.2.1: 18 | version "2.2.1" 19 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" 20 | 21 | ansi-styles@^3.2.1: 22 | version "3.2.1" 23 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" 24 | dependencies: 25 | color-convert "^1.9.0" 26 | 27 | argparse@^1.0.7: 28 | version "1.0.10" 29 | resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" 30 | dependencies: 31 | sprintf-js "~1.0.2" 32 | 33 | babel-code-frame@^6.22.0: 34 | version "6.26.0" 35 | resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" 36 | dependencies: 37 | chalk "^1.1.3" 38 | esutils "^2.0.2" 39 | js-tokens "^3.0.2" 40 | 41 | balanced-match@^1.0.0: 42 | version "1.0.0" 43 | resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" 44 | 45 | bindings@^1.3.0: 46 | version "1.3.0" 47 | resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.3.0.tgz#b346f6ecf6a95f5a815c5839fc7cdb22502f1ed7" 48 | 49 | brace-expansion@^1.1.7: 50 | version "1.1.11" 51 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" 52 | dependencies: 53 | balanced-match "^1.0.0" 54 | concat-map "0.0.1" 55 | 56 | builtin-modules@^1.1.1: 57 | version "1.1.1" 58 | resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" 59 | 60 | chalk@^1.1.3: 61 | version "1.1.3" 62 | resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" 63 | dependencies: 64 | ansi-styles "^2.2.1" 65 | escape-string-regexp "^1.0.2" 66 | has-ansi "^2.0.0" 67 | strip-ansi "^3.0.0" 68 | supports-color "^2.0.0" 69 | 70 | chalk@^2.3.0: 71 | version "2.4.1" 72 | resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.1.tgz#18c49ab16a037b6eb0152cc83e3471338215b66e" 73 | dependencies: 74 | ansi-styles "^3.2.1" 75 | escape-string-regexp "^1.0.5" 76 | supports-color "^5.3.0" 77 | 78 | color-convert@^1.9.0: 79 | version "1.9.1" 80 | resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.1.tgz#c1261107aeb2f294ebffec9ed9ecad529a6097ed" 81 | dependencies: 82 | color-name "^1.1.1" 83 | 84 | color-name@^1.1.1: 85 | version "1.1.3" 86 | resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" 87 | 88 | commander@^2.12.1: 89 | version "2.15.1" 90 | resolved "https://registry.yarnpkg.com/commander/-/commander-2.15.1.tgz#df46e867d0fc2aec66a34662b406a9ccafff5b0f" 91 | 92 | concat-map@0.0.1: 93 | version "0.0.1" 94 | resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" 95 | 96 | deep-equal@~1.0.1: 97 | version "1.0.1" 98 | resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.0.1.tgz#f5d260292b660e084eff4cdbc9f08ad3247448b5" 99 | 100 | define-properties@^1.1.2: 101 | version "1.1.2" 102 | resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.2.tgz#83a73f2fea569898fb737193c8f873caf6d45c94" 103 | dependencies: 104 | foreach "^2.0.5" 105 | object-keys "^1.0.8" 106 | 107 | defined@~1.0.0: 108 | version "1.0.0" 109 | resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693" 110 | 111 | diff@^3.2.0: 112 | version "3.5.0" 113 | resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" 114 | 115 | es-abstract@^1.5.0: 116 | version "1.11.0" 117 | resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.11.0.tgz#cce87d518f0496893b1a30cd8461835535480681" 118 | dependencies: 119 | es-to-primitive "^1.1.1" 120 | function-bind "^1.1.1" 121 | has "^1.0.1" 122 | is-callable "^1.1.3" 123 | is-regex "^1.0.4" 124 | 125 | es-to-primitive@^1.1.1: 126 | version "1.1.1" 127 | resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.1.1.tgz#45355248a88979034b6792e19bb81f2b7975dd0d" 128 | dependencies: 129 | is-callable "^1.1.1" 130 | is-date-object "^1.0.1" 131 | is-symbol "^1.0.1" 132 | 133 | escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: 134 | version "1.0.5" 135 | resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" 136 | 137 | esprima@^4.0.0: 138 | version "4.0.0" 139 | resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.0.tgz#4499eddcd1110e0b218bacf2fa7f7f59f55ca804" 140 | 141 | esutils@^2.0.2: 142 | version "2.0.2" 143 | resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" 144 | 145 | for-each@~0.3.2: 146 | version "0.3.2" 147 | resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.2.tgz#2c40450b9348e97f281322593ba96704b9abd4d4" 148 | dependencies: 149 | is-function "~1.0.0" 150 | 151 | foreach@^2.0.5: 152 | version "2.0.5" 153 | resolved "https://registry.yarnpkg.com/foreach/-/foreach-2.0.5.tgz#0bee005018aeb260d0a3af3ae658dd0136ec1b99" 154 | 155 | fs.realpath@^1.0.0: 156 | version "1.0.0" 157 | resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" 158 | 159 | function-bind@^1.0.2, function-bind@^1.1.1, function-bind@~1.1.1: 160 | version "1.1.1" 161 | resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" 162 | 163 | glob@^7.1.1, glob@~7.1.2: 164 | version "7.1.2" 165 | resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" 166 | dependencies: 167 | fs.realpath "^1.0.0" 168 | inflight "^1.0.4" 169 | inherits "2" 170 | minimatch "^3.0.4" 171 | once "^1.3.0" 172 | path-is-absolute "^1.0.0" 173 | 174 | has-ansi@^2.0.0: 175 | version "2.0.0" 176 | resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" 177 | dependencies: 178 | ansi-regex "^2.0.0" 179 | 180 | has-flag@^3.0.0: 181 | version "3.0.0" 182 | resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" 183 | 184 | has@^1.0.1, has@~1.0.1: 185 | version "1.0.1" 186 | resolved "https://registry.yarnpkg.com/has/-/has-1.0.1.tgz#8461733f538b0837c9361e39a9ab9e9704dc2f28" 187 | dependencies: 188 | function-bind "^1.0.2" 189 | 190 | inflight@^1.0.4: 191 | version "1.0.6" 192 | resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" 193 | dependencies: 194 | once "^1.3.0" 195 | wrappy "1" 196 | 197 | inherits@2, inherits@~2.0.3: 198 | version "2.0.3" 199 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" 200 | 201 | is-callable@^1.1.1, is-callable@^1.1.3: 202 | version "1.1.3" 203 | resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.3.tgz#86eb75392805ddc33af71c92a0eedf74ee7604b2" 204 | 205 | is-date-object@^1.0.1: 206 | version "1.0.1" 207 | resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.1.tgz#9aa20eb6aeebbff77fbd33e74ca01b33581d3a16" 208 | 209 | is-function@~1.0.0: 210 | version "1.0.1" 211 | resolved "https://registry.yarnpkg.com/is-function/-/is-function-1.0.1.tgz#12cfb98b65b57dd3d193a3121f5f6e2f437602b5" 212 | 213 | is-regex@^1.0.4: 214 | version "1.0.4" 215 | resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.4.tgz#5517489b547091b0930e095654ced25ee97e9491" 216 | dependencies: 217 | has "^1.0.1" 218 | 219 | is-symbol@^1.0.1: 220 | version "1.0.1" 221 | resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.1.tgz#3cc59f00025194b6ab2e38dbae6689256b660572" 222 | 223 | js-tokens@^3.0.2: 224 | version "3.0.2" 225 | resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" 226 | 227 | js-yaml@^3.7.0: 228 | version "3.11.0" 229 | resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.11.0.tgz#597c1a8bd57152f26d622ce4117851a51f5ebaef" 230 | dependencies: 231 | argparse "^1.0.7" 232 | esprima "^4.0.0" 233 | 234 | minimatch@^3.0.4: 235 | version "3.0.4" 236 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" 237 | dependencies: 238 | brace-expansion "^1.1.7" 239 | 240 | minimist@~1.2.0: 241 | version "1.2.0" 242 | resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" 243 | 244 | nan@^2.10.0: 245 | version "2.10.0" 246 | resolved "https://registry.yarnpkg.com/nan/-/nan-2.10.0.tgz#96d0cd610ebd58d4b4de9cc0c6828cda99c7548f" 247 | 248 | object-inspect@~1.5.0: 249 | version "1.5.0" 250 | resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.5.0.tgz#9d876c11e40f485c79215670281b767488f9bfe3" 251 | 252 | object-keys@^1.0.8: 253 | version "1.0.11" 254 | resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.0.11.tgz#c54601778ad560f1142ce0e01bcca8b56d13426d" 255 | 256 | once@^1.3.0: 257 | version "1.4.0" 258 | resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" 259 | dependencies: 260 | wrappy "1" 261 | 262 | path-is-absolute@^1.0.0: 263 | version "1.0.1" 264 | resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" 265 | 266 | path-parse@^1.0.5: 267 | version "1.0.5" 268 | resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.5.tgz#3c1adf871ea9cd6c9431b6ea2bd74a0ff055c4c1" 269 | 270 | resolve@^1.3.2: 271 | version "1.7.1" 272 | resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.7.1.tgz#aadd656374fd298aee895bc026b8297418677fd3" 273 | dependencies: 274 | path-parse "^1.0.5" 275 | 276 | resolve@~1.5.0: 277 | version "1.5.0" 278 | resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.5.0.tgz#1f09acce796c9a762579f31b2c1cc4c3cddf9f36" 279 | dependencies: 280 | path-parse "^1.0.5" 281 | 282 | resumer@~0.0.0: 283 | version "0.0.0" 284 | resolved "https://registry.yarnpkg.com/resumer/-/resumer-0.0.0.tgz#f1e8f461e4064ba39e82af3cdc2a8c893d076759" 285 | dependencies: 286 | through "~2.3.4" 287 | 288 | semver@^5.3.0: 289 | version "5.5.0" 290 | resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab" 291 | 292 | sprintf-js@~1.0.2: 293 | version "1.0.3" 294 | resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" 295 | 296 | string.prototype.trim@~1.1.2: 297 | version "1.1.2" 298 | resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.1.2.tgz#d04de2c89e137f4d7d206f086b5ed2fae6be8cea" 299 | dependencies: 300 | define-properties "^1.1.2" 301 | es-abstract "^1.5.0" 302 | function-bind "^1.0.2" 303 | 304 | strip-ansi@^3.0.0: 305 | version "3.0.1" 306 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" 307 | dependencies: 308 | ansi-regex "^2.0.0" 309 | 310 | supports-color@^2.0.0: 311 | version "2.0.0" 312 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" 313 | 314 | supports-color@^5.3.0: 315 | version "5.4.0" 316 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.4.0.tgz#1c6b337402c2137605efe19f10fec390f6faab54" 317 | dependencies: 318 | has-flag "^3.0.0" 319 | 320 | tape@^4.9.0: 321 | version "4.9.0" 322 | resolved "https://registry.yarnpkg.com/tape/-/tape-4.9.0.tgz#855c08360395133709d34d3fbf9ef341eb73ca6a" 323 | dependencies: 324 | deep-equal "~1.0.1" 325 | defined "~1.0.0" 326 | for-each "~0.3.2" 327 | function-bind "~1.1.1" 328 | glob "~7.1.2" 329 | has "~1.0.1" 330 | inherits "~2.0.3" 331 | minimist "~1.2.0" 332 | object-inspect "~1.5.0" 333 | resolve "~1.5.0" 334 | resumer "~0.0.0" 335 | string.prototype.trim "~1.1.2" 336 | through "~2.3.8" 337 | 338 | through@~2.3.4, through@~2.3.8: 339 | version "2.3.8" 340 | resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" 341 | 342 | tslib@^1.8.0, tslib@^1.8.1: 343 | version "1.9.0" 344 | resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.0.tgz#e37a86fda8cbbaf23a057f473c9f4dc64e5fc2e8" 345 | 346 | tslint@^5.9.1: 347 | version "5.9.1" 348 | resolved "https://registry.yarnpkg.com/tslint/-/tslint-5.9.1.tgz#1255f87a3ff57eb0b0e1f0e610a8b4748046c9ae" 349 | dependencies: 350 | babel-code-frame "^6.22.0" 351 | builtin-modules "^1.1.1" 352 | chalk "^2.3.0" 353 | commander "^2.12.1" 354 | diff "^3.2.0" 355 | glob "^7.1.1" 356 | js-yaml "^3.7.0" 357 | minimatch "^3.0.4" 358 | resolve "^1.3.2" 359 | semver "^5.3.0" 360 | tslib "^1.8.0" 361 | tsutils "^2.12.1" 362 | 363 | tsutils@^2.12.1: 364 | version "2.26.2" 365 | resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-2.26.2.tgz#a9f9f63434a456a5e0c95a45d9a59181cb32d3bf" 366 | dependencies: 367 | tslib "^1.8.1" 368 | 369 | typescript@^2.8.3: 370 | version "2.8.3" 371 | resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.8.3.tgz#5d817f9b6f31bb871835f4edf0089f21abe6c170" 372 | 373 | wrappy@1: 374 | version "1.0.2" 375 | resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" 376 | --------------------------------------------------------------------------------