--- /dev/null
+{
+ "targets": [
+ {
+ "target_name": "nodeaudio",
+ "sources": [ "src/nodeaudio.c", "src/audio_handler.c", "src/frame_buffer.c" ],
+ "include_dirs": [
+ "/usr/local/include"
+ ],
+ "link_settings": {
+ "libraries": [
+ "-lportaudio"
+ ]
+ }
+ }
+ ]
+}
--- /dev/null
+const nodeAudio = require('bindings')('nodeaudio.node');
+console.log("Imported nodeAudio");
+
+const wait = async (callback, seconds) => {
+ await setTimeout(() => {
+ callback();
+ }, seconds);
+}
+
+const recordThenPlay = async (recSeconds) => {
+
+ console.log("Initializing nodeAudio");
+ nodeAudio.initialize();
+
+ nodeAudio.fill_input_buffer();
+
+ console.log(`Recording for ${recSeconds} seconds`);
+ const audio = await wait(nodeAudio.return_input_buffer, recSeconds);
+
+ console.log("Playing audio");
+ nodeAudio.feed_output_buffer(audio);
+
+ console.log("Shutting down audio");
+ nodeAudio.terminate();
+
+}
+
+recordThenPlay(5);
\ No newline at end of file
--- /dev/null
+# We borrow heavily from the kernel build setup, though we are simpler since
+# we don't have Kconfig tweaking settings on us.
+
+# The implicit make rules have it looking for RCS files, among other things.
+# We instead explicitly write all the rules we care about.
+# It's even quicker (saves ~200ms) to pass -r on the command line.
+MAKEFLAGS=-r
+
+# The source directory tree.
+srcdir := ..
+abs_srcdir := $(abspath $(srcdir))
+
+# The name of the builddir.
+builddir_name ?= .
+
+# The V=1 flag on command line makes us verbosely print command lines.
+ifdef V
+ quiet=
+else
+ quiet=quiet_
+endif
+
+# Specify BUILDTYPE=Release on the command line for a release build.
+BUILDTYPE ?= Release
+
+# Directory all our build output goes into.
+# Note that this must be two directories beneath src/ for unit tests to pass,
+# as they reach into the src/ directory for data with relative paths.
+builddir ?= $(builddir_name)/$(BUILDTYPE)
+abs_builddir := $(abspath $(builddir))
+depsdir := $(builddir)/.deps
+
+# Object output directory.
+obj := $(builddir)/obj
+abs_obj := $(abspath $(obj))
+
+# We build up a list of every single one of the targets so we can slurp in the
+# generated dependency rule Makefiles in one pass.
+all_deps :=
+
+
+
+CC.target ?= $(CC)
+CFLAGS.target ?= $(CPPFLAGS) $(CFLAGS)
+CXX.target ?= $(CXX)
+CXXFLAGS.target ?= $(CPPFLAGS) $(CXXFLAGS)
+LINK.target ?= $(LINK)
+LDFLAGS.target ?= $(LDFLAGS)
+AR.target ?= $(AR)
+
+# C++ apps need to be linked with g++.
+LINK ?= $(CXX.target)
+
+# TODO(evan): move all cross-compilation logic to gyp-time so we don't need
+# to replicate this environment fallback in make as well.
+CC.host ?= gcc
+CFLAGS.host ?= $(CPPFLAGS_host) $(CFLAGS_host)
+CXX.host ?= g++
+CXXFLAGS.host ?= $(CPPFLAGS_host) $(CXXFLAGS_host)
+LINK.host ?= $(CXX.host)
+LDFLAGS.host ?=
+AR.host ?= ar
+
+# Define a dir function that can handle spaces.
+# http://www.gnu.org/software/make/manual/make.html#Syntax-of-Functions
+# "leading spaces cannot appear in the text of the first argument as written.
+# These characters can be put into the argument value by variable substitution."
+empty :=
+space := $(empty) $(empty)
+
+# http://stackoverflow.com/questions/1189781/using-make-dir-or-notdir-on-a-path-with-spaces
+replace_spaces = $(subst $(space),?,$1)
+unreplace_spaces = $(subst ?,$(space),$1)
+dirx = $(call unreplace_spaces,$(dir $(call replace_spaces,$1)))
+
+# Flags to make gcc output dependency info. Note that you need to be
+# careful here to use the flags that ccache and distcc can understand.
+# We write to a dep file on the side first and then rename at the end
+# so we can't end up with a broken dep file.
+depfile = $(depsdir)/$(call replace_spaces,$@).d
+DEPFLAGS = -MMD -MF $(depfile).raw
+
+# We have to fixup the deps output in a few ways.
+# (1) the file output should mention the proper .o file.
+# ccache or distcc lose the path to the target, so we convert a rule of
+# the form:
+# foobar.o: DEP1 DEP2
+# into
+# path/to/foobar.o: DEP1 DEP2
+# (2) we want missing files not to cause us to fail to build.
+# We want to rewrite
+# foobar.o: DEP1 DEP2 \
+# DEP3
+# to
+# DEP1:
+# DEP2:
+# DEP3:
+# so if the files are missing, they're just considered phony rules.
+# We have to do some pretty insane escaping to get those backslashes
+# and dollar signs past make, the shell, and sed at the same time.
+# Doesn't work with spaces, but that's fine: .d files have spaces in
+# their names replaced with other characters.
+define fixup_dep
+# The depfile may not exist if the input file didn't have any #includes.
+touch $(depfile).raw
+# Fixup path as in (1).
+sed -e "s|^$(notdir $@)|$@|" $(depfile).raw >> $(depfile)
+# Add extra rules as in (2).
+# We remove slashes and replace spaces with new lines;
+# remove blank lines;
+# delete the first line and append a colon to the remaining lines.
+sed -e 's|\\||' -e 'y| |\n|' $(depfile).raw |\
+ grep -v '^$$' |\
+ sed -e 1d -e 's|$$|:|' \
+ >> $(depfile)
+rm $(depfile).raw
+endef
+
+# Command definitions:
+# - cmd_foo is the actual command to run;
+# - quiet_cmd_foo is the brief-output summary of the command.
+
+quiet_cmd_cc = CC($(TOOLSET)) $@
+cmd_cc = $(CC.$(TOOLSET)) $(GYP_CFLAGS) $(DEPFLAGS) $(CFLAGS.$(TOOLSET)) -c -o $@ $<
+
+quiet_cmd_cxx = CXX($(TOOLSET)) $@
+cmd_cxx = $(CXX.$(TOOLSET)) $(GYP_CXXFLAGS) $(DEPFLAGS) $(CXXFLAGS.$(TOOLSET)) -c -o $@ $<
+
+quiet_cmd_objc = CXX($(TOOLSET)) $@
+cmd_objc = $(CC.$(TOOLSET)) $(GYP_OBJCFLAGS) $(DEPFLAGS) -c -o $@ $<
+
+quiet_cmd_objcxx = CXX($(TOOLSET)) $@
+cmd_objcxx = $(CXX.$(TOOLSET)) $(GYP_OBJCXXFLAGS) $(DEPFLAGS) -c -o $@ $<
+
+# Commands for precompiled header files.
+quiet_cmd_pch_c = CXX($(TOOLSET)) $@
+cmd_pch_c = $(CC.$(TOOLSET)) $(GYP_PCH_CFLAGS) $(DEPFLAGS) $(CXXFLAGS.$(TOOLSET)) -c -o $@ $<
+quiet_cmd_pch_cc = CXX($(TOOLSET)) $@
+cmd_pch_cc = $(CC.$(TOOLSET)) $(GYP_PCH_CXXFLAGS) $(DEPFLAGS) $(CXXFLAGS.$(TOOLSET)) -c -o $@ $<
+quiet_cmd_pch_m = CXX($(TOOLSET)) $@
+cmd_pch_m = $(CC.$(TOOLSET)) $(GYP_PCH_OBJCFLAGS) $(DEPFLAGS) -c -o $@ $<
+quiet_cmd_pch_mm = CXX($(TOOLSET)) $@
+cmd_pch_mm = $(CC.$(TOOLSET)) $(GYP_PCH_OBJCXXFLAGS) $(DEPFLAGS) -c -o $@ $<
+
+# gyp-mac-tool is written next to the root Makefile by gyp.
+# Use $(4) for the command, since $(2) and $(3) are used as flag by do_cmd
+# already.
+quiet_cmd_mac_tool = MACTOOL $(4) $<
+cmd_mac_tool = ./gyp-mac-tool $(4) $< "$@"
+
+quiet_cmd_mac_package_framework = PACKAGE FRAMEWORK $@
+cmd_mac_package_framework = ./gyp-mac-tool package-framework "$@" $(4)
+
+quiet_cmd_infoplist = INFOPLIST $@
+cmd_infoplist = $(CC.$(TOOLSET)) -E -P -Wno-trigraphs -x c $(INFOPLIST_DEFINES) "$<" -o "$@"
+
+quiet_cmd_touch = TOUCH $@
+cmd_touch = touch $@
+
+quiet_cmd_copy = COPY $@
+# send stderr to /dev/null to ignore messages when linking directories.
+cmd_copy = rm -rf "$@" && cp -af "$<" "$@"
+
+quiet_cmd_alink = LIBTOOL-STATIC $@
+cmd_alink = rm -f $@ && ./gyp-mac-tool filter-libtool libtool $(GYP_LIBTOOLFLAGS) -static -o $@ $(filter %.o,$^)
+
+quiet_cmd_link = LINK($(TOOLSET)) $@
+cmd_link = $(LINK.$(TOOLSET)) $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o "$@" $(LD_INPUTS) $(LIBS)
+
+quiet_cmd_solink = SOLINK($(TOOLSET)) $@
+cmd_solink = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o "$@" $(LD_INPUTS) $(LIBS)
+
+quiet_cmd_solink_module = SOLINK_MODULE($(TOOLSET)) $@
+cmd_solink_module = $(LINK.$(TOOLSET)) -bundle $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o $@ $(filter-out FORCE_DO_CMD, $^) $(LIBS)
+
+
+# Define an escape_quotes function to escape single quotes.
+# This allows us to handle quotes properly as long as we always use
+# use single quotes and escape_quotes.
+escape_quotes = $(subst ','\'',$(1))
+# This comment is here just to include a ' to unconfuse syntax highlighting.
+# Define an escape_vars function to escape '$' variable syntax.
+# This allows us to read/write command lines with shell variables (e.g.
+# $LD_LIBRARY_PATH), without triggering make substitution.
+escape_vars = $(subst $$,$$$$,$(1))
+# Helper that expands to a shell command to echo a string exactly as it is in
+# make. This uses printf instead of echo because printf's behaviour with respect
+# to escape sequences is more portable than echo's across different shells
+# (e.g., dash, bash).
+exact_echo = printf '%s\n' '$(call escape_quotes,$(1))'
+
+# Helper to compare the command we're about to run against the command
+# we logged the last time we ran the command. Produces an empty
+# string (false) when the commands match.
+# Tricky point: Make has no string-equality test function.
+# The kernel uses the following, but it seems like it would have false
+# positives, where one string reordered its arguments.
+# arg_check = $(strip $(filter-out $(cmd_$(1)), $(cmd_$@)) \
+# $(filter-out $(cmd_$@), $(cmd_$(1))))
+# We instead substitute each for the empty string into the other, and
+# say they're equal if both substitutions produce the empty string.
+# .d files contain ? instead of spaces, take that into account.
+command_changed = $(or $(subst $(cmd_$(1)),,$(cmd_$(call replace_spaces,$@))),\
+ $(subst $(cmd_$(call replace_spaces,$@)),,$(cmd_$(1))))
+
+# Helper that is non-empty when a prerequisite changes.
+# Normally make does this implicitly, but we force rules to always run
+# so we can check their command lines.
+# $? -- new prerequisites
+# $| -- order-only dependencies
+prereq_changed = $(filter-out FORCE_DO_CMD,$(filter-out $|,$?))
+
+# Helper that executes all postbuilds until one fails.
+define do_postbuilds
+ @E=0;\
+ for p in $(POSTBUILDS); do\
+ eval $$p;\
+ E=$$?;\
+ if [ $$E -ne 0 ]; then\
+ break;\
+ fi;\
+ done;\
+ if [ $$E -ne 0 ]; then\
+ rm -rf "$@";\
+ exit $$E;\
+ fi
+endef
+
+# do_cmd: run a command via the above cmd_foo names, if necessary.
+# Should always run for a given target to handle command-line changes.
+# Second argument, if non-zero, makes it do asm/C/C++ dependency munging.
+# Third argument, if non-zero, makes it do POSTBUILDS processing.
+# Note: We intentionally do NOT call dirx for depfile, since it contains ? for
+# spaces already and dirx strips the ? characters.
+define do_cmd
+$(if $(or $(command_changed),$(prereq_changed)),
+ @$(call exact_echo, $($(quiet)cmd_$(1)))
+ @mkdir -p "$(call dirx,$@)" "$(dir $(depfile))"
+ $(if $(findstring flock,$(word 2,$(cmd_$1))),
+ @$(cmd_$(1))
+ @echo " $(quiet_cmd_$(1)): Finished",
+ @$(cmd_$(1))
+ )
+ @$(call exact_echo,$(call escape_vars,cmd_$(call replace_spaces,$@) := $(cmd_$(1)))) > $(depfile)
+ @$(if $(2),$(fixup_dep))
+ $(if $(and $(3), $(POSTBUILDS)),
+ $(call do_postbuilds)
+ )
+)
+endef
+
+# Declare the "all" target first so it is the default,
+# even though we don't have the deps yet.
+.PHONY: all
+all:
+
+# make looks for ways to re-generate included makefiles, but in our case, we
+# don't have a direct way. Explicitly telling make that it has nothing to do
+# for them makes it go faster.
+%.d: ;
+
+# Use FORCE_DO_CMD to force a target to run. Should be coupled with
+# do_cmd.
+.PHONY: FORCE_DO_CMD
+FORCE_DO_CMD:
+
+TOOLSET := target
+# Suffix rules, putting all outputs into $(obj).
+$(obj).$(TOOLSET)/%.o: $(srcdir)/%.c FORCE_DO_CMD
+ @$(call do_cmd,cc,1)
+$(obj).$(TOOLSET)/%.o: $(srcdir)/%.cc FORCE_DO_CMD
+ @$(call do_cmd,cxx,1)
+$(obj).$(TOOLSET)/%.o: $(srcdir)/%.cpp FORCE_DO_CMD
+ @$(call do_cmd,cxx,1)
+$(obj).$(TOOLSET)/%.o: $(srcdir)/%.cxx FORCE_DO_CMD
+ @$(call do_cmd,cxx,1)
+$(obj).$(TOOLSET)/%.o: $(srcdir)/%.m FORCE_DO_CMD
+ @$(call do_cmd,objc,1)
+$(obj).$(TOOLSET)/%.o: $(srcdir)/%.mm FORCE_DO_CMD
+ @$(call do_cmd,objcxx,1)
+$(obj).$(TOOLSET)/%.o: $(srcdir)/%.S FORCE_DO_CMD
+ @$(call do_cmd,cc,1)
+$(obj).$(TOOLSET)/%.o: $(srcdir)/%.s FORCE_DO_CMD
+ @$(call do_cmd,cc,1)
+
+# Try building from generated source, too.
+$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.c FORCE_DO_CMD
+ @$(call do_cmd,cc,1)
+$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.cc FORCE_DO_CMD
+ @$(call do_cmd,cxx,1)
+$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.cpp FORCE_DO_CMD
+ @$(call do_cmd,cxx,1)
+$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.cxx FORCE_DO_CMD
+ @$(call do_cmd,cxx,1)
+$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.m FORCE_DO_CMD
+ @$(call do_cmd,objc,1)
+$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.mm FORCE_DO_CMD
+ @$(call do_cmd,objcxx,1)
+$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.S FORCE_DO_CMD
+ @$(call do_cmd,cc,1)
+$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.s FORCE_DO_CMD
+ @$(call do_cmd,cc,1)
+
+$(obj).$(TOOLSET)/%.o: $(obj)/%.c FORCE_DO_CMD
+ @$(call do_cmd,cc,1)
+$(obj).$(TOOLSET)/%.o: $(obj)/%.cc FORCE_DO_CMD
+ @$(call do_cmd,cxx,1)
+$(obj).$(TOOLSET)/%.o: $(obj)/%.cpp FORCE_DO_CMD
+ @$(call do_cmd,cxx,1)
+$(obj).$(TOOLSET)/%.o: $(obj)/%.cxx FORCE_DO_CMD
+ @$(call do_cmd,cxx,1)
+$(obj).$(TOOLSET)/%.o: $(obj)/%.m FORCE_DO_CMD
+ @$(call do_cmd,objc,1)
+$(obj).$(TOOLSET)/%.o: $(obj)/%.mm FORCE_DO_CMD
+ @$(call do_cmd,objcxx,1)
+$(obj).$(TOOLSET)/%.o: $(obj)/%.S FORCE_DO_CMD
+ @$(call do_cmd,cc,1)
+$(obj).$(TOOLSET)/%.o: $(obj)/%.s FORCE_DO_CMD
+ @$(call do_cmd,cc,1)
+
+
+ifeq ($(strip $(foreach prefix,$(NO_LOAD),\
+ $(findstring $(join ^,$(prefix)),\
+ $(join ^,nodeaudio.target.mk)))),)
+ include nodeaudio.target.mk
+endif
+
+quiet_cmd_regen_makefile = ACTION Regenerating $@
+cmd_regen_makefile = cd $(srcdir); /usr/local/Cellar/node@14/14.17.0/lib/node_modules/npm/node_modules/node-gyp/gyp/gyp_main.py -fmake --ignore-environment "--toplevel-dir=." -I/Users/adgundersen/Documents/Crimata/nodeaudio/build/config.gypi -I/usr/local/Cellar/node@14/14.17.0/lib/node_modules/npm/node_modules/node-gyp/addon.gypi -I/Users/adgundersen/Library/Caches/node-gyp/14.17.0/include/node/common.gypi "--depth=." "-Goutput_dir=." "--generator-output=build" "-Dlibrary=shared_library" "-Dvisibility=default" "-Dnode_root_dir=/Users/adgundersen/Library/Caches/node-gyp/14.17.0" "-Dnode_gyp_dir=/usr/local/Cellar/node@14/14.17.0/lib/node_modules/npm/node_modules/node-gyp" "-Dnode_lib_file=/Users/adgundersen/Library/Caches/node-gyp/14.17.0/<(target_arch)/node.lib" "-Dmodule_root_dir=/Users/adgundersen/Documents/Crimata/nodeaudio" "-Dnode_engine=v8" binding.gyp
+Makefile: $(srcdir)/../../../Library/Caches/node-gyp/14.17.0/include/node/common.gypi $(srcdir)/../../../../../usr/local/Cellar/node@14/14.17.0/lib/node_modules/npm/node_modules/node-gyp/addon.gypi $(srcdir)/build/config.gypi $(srcdir)/binding.gyp
+ $(call do_cmd,regen_makefile)
+
+# "all" is a concatenation of the "all" targets from all the included
+# sub-makefiles. This is just here to clarify.
+all:
+
+# Add in dependency-tracking rules. $(all_deps) is the list of every single
+# target in our tree. Only consider the ones with .d (dependency) info:
+d_files := $(wildcard $(foreach f,$(all_deps),$(depsdir)/$(f).d))
+ifneq ($(d_files),)
+ include $(d_files)
+endif
--- /dev/null
+cmd_Release/nodeaudio.node := c++ -bundle -undefined dynamic_lookup -Wl,-no_pie -Wl,-search_paths_first -mmacosx-version-min=10.13 -arch x86_64 -L./Release -stdlib=libc++ -o Release/nodeaudio.node Release/obj.target/nodeaudio/src/nodeaudio.o Release/obj.target/nodeaudio/src/audio_handler.o Release/obj.target/nodeaudio/src/frame_buffer.o -lportaudio
--- /dev/null
+cmd_Release/obj.target/nodeaudio/src/audio_handler.o := cc '-DNODE_GYP_MODULE_NAME=nodeaudio' '-DUSING_UV_SHARED=1' '-DUSING_V8_SHARED=1' '-DV8_DEPRECATION_WARNINGS=1' '-DV8_DEPRECATION_WARNINGS' '-DV8_IMMINENT_DEPRECATION_WARNINGS' '-D_DARWIN_USE_64_BIT_INODE=1' '-D_LARGEFILE_SOURCE' '-D_FILE_OFFSET_BITS=64' '-DOPENSSL_NO_PINSHARED' '-DOPENSSL_THREADS' '-DBUILDING_NODE_EXTENSION' -I/Users/adgundersen/Library/Caches/node-gyp/14.17.0/include/node -I/Users/adgundersen/Library/Caches/node-gyp/14.17.0/src -I/Users/adgundersen/Library/Caches/node-gyp/14.17.0/deps/openssl/config -I/Users/adgundersen/Library/Caches/node-gyp/14.17.0/deps/openssl/openssl/include -I/Users/adgundersen/Library/Caches/node-gyp/14.17.0/deps/uv/include -I/Users/adgundersen/Library/Caches/node-gyp/14.17.0/deps/zlib -I/Users/adgundersen/Library/Caches/node-gyp/14.17.0/deps/v8/include -I/usr/local/include -O3 -gdwarf-2 -mmacosx-version-min=10.13 -arch x86_64 -Wall -Wendif-labels -W -Wno-unused-parameter -fno-strict-aliasing -MMD -MF ./Release/.deps/Release/obj.target/nodeaudio/src/audio_handler.o.d.raw -c -o Release/obj.target/nodeaudio/src/audio_handler.o ../src/audio_handler.c
+Release/obj.target/nodeaudio/src/audio_handler.o: ../src/audio_handler.c \
+ /usr/local/include/portaudio.h ../src/audio_handler.h \
+ ../src/frame_buffer.h
+../src/audio_handler.c:
+/usr/local/include/portaudio.h:
+../src/audio_handler.h:
+../src/frame_buffer.h:
--- /dev/null
+cmd_Release/obj.target/nodeaudio/src/frame_buffer.o := cc '-DNODE_GYP_MODULE_NAME=nodeaudio' '-DUSING_UV_SHARED=1' '-DUSING_V8_SHARED=1' '-DV8_DEPRECATION_WARNINGS=1' '-DV8_DEPRECATION_WARNINGS' '-DV8_IMMINENT_DEPRECATION_WARNINGS' '-D_DARWIN_USE_64_BIT_INODE=1' '-D_LARGEFILE_SOURCE' '-D_FILE_OFFSET_BITS=64' '-DOPENSSL_NO_PINSHARED' '-DOPENSSL_THREADS' '-DBUILDING_NODE_EXTENSION' -I/Users/adgundersen/Library/Caches/node-gyp/14.17.0/include/node -I/Users/adgundersen/Library/Caches/node-gyp/14.17.0/src -I/Users/adgundersen/Library/Caches/node-gyp/14.17.0/deps/openssl/config -I/Users/adgundersen/Library/Caches/node-gyp/14.17.0/deps/openssl/openssl/include -I/Users/adgundersen/Library/Caches/node-gyp/14.17.0/deps/uv/include -I/Users/adgundersen/Library/Caches/node-gyp/14.17.0/deps/zlib -I/Users/adgundersen/Library/Caches/node-gyp/14.17.0/deps/v8/include -I/usr/local/include -O3 -gdwarf-2 -mmacosx-version-min=10.13 -arch x86_64 -Wall -Wendif-labels -W -Wno-unused-parameter -fno-strict-aliasing -MMD -MF ./Release/.deps/Release/obj.target/nodeaudio/src/frame_buffer.o.d.raw -c -o Release/obj.target/nodeaudio/src/frame_buffer.o ../src/frame_buffer.c
+Release/obj.target/nodeaudio/src/frame_buffer.o: ../src/frame_buffer.c \
+ ../src/frame_buffer.h
+../src/frame_buffer.c:
+../src/frame_buffer.h:
--- /dev/null
+cmd_Release/obj.target/nodeaudio/src/nodeaudio.o := cc '-DNODE_GYP_MODULE_NAME=nodeaudio' '-DUSING_UV_SHARED=1' '-DUSING_V8_SHARED=1' '-DV8_DEPRECATION_WARNINGS=1' '-DV8_DEPRECATION_WARNINGS' '-DV8_IMMINENT_DEPRECATION_WARNINGS' '-D_DARWIN_USE_64_BIT_INODE=1' '-D_LARGEFILE_SOURCE' '-D_FILE_OFFSET_BITS=64' '-DOPENSSL_NO_PINSHARED' '-DOPENSSL_THREADS' '-DBUILDING_NODE_EXTENSION' -I/Users/adgundersen/Library/Caches/node-gyp/14.17.0/include/node -I/Users/adgundersen/Library/Caches/node-gyp/14.17.0/src -I/Users/adgundersen/Library/Caches/node-gyp/14.17.0/deps/openssl/config -I/Users/adgundersen/Library/Caches/node-gyp/14.17.0/deps/openssl/openssl/include -I/Users/adgundersen/Library/Caches/node-gyp/14.17.0/deps/uv/include -I/Users/adgundersen/Library/Caches/node-gyp/14.17.0/deps/zlib -I/Users/adgundersen/Library/Caches/node-gyp/14.17.0/deps/v8/include -I/usr/local/include -O3 -gdwarf-2 -mmacosx-version-min=10.13 -arch x86_64 -Wall -Wendif-labels -W -Wno-unused-parameter -fno-strict-aliasing -MMD -MF ./Release/.deps/Release/obj.target/nodeaudio/src/nodeaudio.o.d.raw -c -o Release/obj.target/nodeaudio/src/nodeaudio.o ../src/nodeaudio.c
+Release/obj.target/nodeaudio/src/nodeaudio.o: ../src/nodeaudio.c \
+ /Users/adgundersen/Library/Caches/node-gyp/14.17.0/include/node/node_api.h \
+ /Users/adgundersen/Library/Caches/node-gyp/14.17.0/include/node/js_native_api.h \
+ /Users/adgundersen/Library/Caches/node-gyp/14.17.0/include/node/js_native_api_types.h \
+ /Users/adgundersen/Library/Caches/node-gyp/14.17.0/include/node/node_api_types.h \
+ ../src/audio_handler.h
+../src/nodeaudio.c:
+/Users/adgundersen/Library/Caches/node-gyp/14.17.0/include/node/node_api.h:
+/Users/adgundersen/Library/Caches/node-gyp/14.17.0/include/node/js_native_api.h:
+/Users/adgundersen/Library/Caches/node-gyp/14.17.0/include/node/js_native_api_types.h:
+/Users/adgundersen/Library/Caches/node-gyp/14.17.0/include/node/node_api_types.h:
+../src/audio_handler.h:
--- /dev/null
+# This file is generated by gyp; do not edit.
+
+export builddir_name ?= ./build/.
+.PHONY: all
+all:
+ $(MAKE) nodeaudio
--- /dev/null
+# Do not edit. File was generated by node-gyp's "configure" step
+{
+ "target_defaults": {
+ "cflags": [],
+ "default_configuration": "Release",
+ "defines": [],
+ "include_dirs": [],
+ "libraries": []
+ },
+ "variables": {
+ "asan": 0,
+ "build_v8_with_gn": "false",
+ "coverage": "false",
+ "dcheck_always_on": 0,
+ "debug_nghttp2": "false",
+ "debug_node": "false",
+ "enable_lto": "false",
+ "enable_pgo_generate": "false",
+ "enable_pgo_use": "false",
+ "error_on_warn": "false",
+ "force_dynamic_crt": 0,
+ "host_arch": "x64",
+ "icu_gyp_path": "tools/icu/icu-system.gyp",
+ "icu_small": "false",
+ "icu_ver_major": "69",
+ "is_debug": 0,
+ "llvm_version": "12.0",
+ "napi_build_version": "8",
+ "node_byteorder": "little",
+ "node_debug_lib": "false",
+ "node_enable_d8": "false",
+ "node_install_npm": "true",
+ "node_module_version": 83,
+ "node_no_browser_globals": "false",
+ "node_prefix": "/usr/local/Cellar/node@14/14.17.0",
+ "node_release_urlbase": "",
+ "node_shared": "false",
+ "node_shared_brotli": "false",
+ "node_shared_cares": "false",
+ "node_shared_http_parser": "false",
+ "node_shared_libuv": "false",
+ "node_shared_nghttp2": "false",
+ "node_shared_openssl": "false",
+ "node_shared_zlib": "false",
+ "node_tag": "",
+ "node_target_type": "executable",
+ "node_use_bundled_v8": "true",
+ "node_use_dtrace": "true",
+ "node_use_etw": "false",
+ "node_use_node_code_cache": "true",
+ "node_use_node_snapshot": "true",
+ "node_use_openssl": "true",
+ "node_use_v8_platform": "true",
+ "node_with_ltcg": "false",
+ "node_without_node_options": "false",
+ "openssl_fips": "",
+ "openssl_is_fips": "false",
+ "ossfuzz": "false",
+ "shlib_suffix": "83.dylib",
+ "target_arch": "x64",
+ "v8_enable_31bit_smis_on_64bit_arch": 0,
+ "v8_enable_gdbjit": 0,
+ "v8_enable_i18n_support": 1,
+ "v8_enable_inspector": 1,
+ "v8_enable_lite_mode": 0,
+ "v8_enable_object_print": 1,
+ "v8_enable_pointer_compression": 0,
+ "v8_no_strict_aliasing": 1,
+ "v8_optimized_debug": 1,
+ "v8_promise_internal_field_count": 1,
+ "v8_random_seed": 0,
+ "v8_trace_maps": 0,
+ "v8_use_siphash": 1,
+ "want_separate_host_toolset": 0,
+ "xcode_version": "12.0",
+ "nodedir": "/Users/adgundersen/Library/Caches/node-gyp/14.17.0",
+ "standalone_static_library": 1,
+ "dry_run": "",
+ "legacy_bundling": "",
+ "save_dev": "",
+ "browser": "",
+ "commit_hooks": "true",
+ "only": "",
+ "viewer": "man",
+ "also": "",
+ "rollback": "true",
+ "sign_git_commit": "",
+ "audit": "true",
+ "usage": "",
+ "globalignorefile": "/usr/local/etc/npmignore",
+ "init_author_url": "",
+ "maxsockets": "50",
+ "shell": "/bin/zsh",
+ "metrics_registry": "https://registry.npmjs.org/",
+ "parseable": "",
+ "shrinkwrap": "true",
+ "init_license": "ISC",
+ "timing": "",
+ "if_present": "",
+ "cache_max": "Infinity",
+ "init_author_email": "",
+ "sign_git_tag": "",
+ "cert": "",
+ "git_tag_version": "true",
+ "local_address": "",
+ "long": "",
+ "preid": "",
+ "fetch_retries": "2",
+ "registry": "https://registry.npmjs.org/",
+ "key": "",
+ "message": "%s",
+ "versions": "",
+ "globalconfig": "/usr/local/etc/npmrc",
+ "always_auth": "",
+ "logs_max": "10",
+ "prefer_online": "",
+ "cache_lock_retries": "10",
+ "global_style": "",
+ "update_notifier": "true",
+ "audit_level": "low",
+ "heading": "npm",
+ "fetch_retry_mintimeout": "10000",
+ "offline": "",
+ "read_only": "",
+ "searchlimit": "20",
+ "access": "",
+ "json": "",
+ "allow_same_version": "",
+ "description": "true",
+ "engine_strict": "",
+ "https_proxy": "",
+ "init_module": "/Users/adgundersen/.npm-init.js",
+ "userconfig": "/Users/adgundersen/.npmrc",
+ "cidr": "",
+ "node_version": "14.17.0",
+ "user": "",
+ "auth_type": "legacy",
+ "editor": "vi",
+ "ignore_prepublish": "",
+ "save": "true",
+ "script_shell": "",
+ "tag": "latest",
+ "before": "",
+ "global": "",
+ "progress": "true",
+ "ham_it_up": "",
+ "optional": "true",
+ "searchstaleness": "900",
+ "bin_links": "true",
+ "force": "",
+ "save_prod": "",
+ "searchopts": "",
+ "depth": "Infinity",
+ "node_gyp": "/usr/local/Cellar/node@14/14.17.0/lib/node_modules/npm/node_modules/node-gyp/bin/node-gyp.js",
+ "rebuild_bundle": "true",
+ "sso_poll_frequency": "500",
+ "unicode": "true",
+ "fetch_retry_maxtimeout": "60000",
+ "ca": "",
+ "save_prefix": "^",
+ "scripts_prepend_node_path": "warn-only",
+ "sso_type": "oauth",
+ "strict_ssl": "true",
+ "tag_version_prefix": "v",
+ "dev": "",
+ "fetch_retry_factor": "10",
+ "group": "20",
+ "save_exact": "",
+ "cache_lock_stale": "60000",
+ "prefer_offline": "",
+ "version": "",
+ "cache_min": "10",
+ "otp": "",
+ "cache": "/Users/adgundersen/.npm",
+ "searchexclude": "",
+ "color": "true",
+ "package_lock": "true",
+ "fund": "true",
+ "package_lock_only": "",
+ "save_optional": "",
+ "user_agent": "npm/6.14.13 node/v14.17.0 darwin x64",
+ "ignore_scripts": "",
+ "cache_lock_wait": "10000",
+ "production": "",
+ "save_bundle": "",
+ "send_metrics": "",
+ "init_version": "1.0.0",
+ "node_options": "",
+ "umask": "0022",
+ "scope": "",
+ "git": "git",
+ "init_author_name": "",
+ "onload_script": "",
+ "tmp": "/var/folders/8h/5gtb4v414sj09_yzw9rs5z7m0000gq/T",
+ "unsafe_perm": "true",
+ "prefix": "/usr/local",
+ "format_package_lock": "true",
+ "link": ""
+ }
+}
--- /dev/null
+#!/usr/bin/env python
+# Generated by gyp. Do not edit.
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Utility functions to perform Xcode-style build steps.
+
+These functions are executed via gyp-mac-tool when using the Makefile generator.
+"""
+
+from __future__ import print_function
+
+import fcntl
+import fnmatch
+import glob
+import json
+import os
+import plistlib
+import re
+import shutil
+import string
+import subprocess
+import sys
+import tempfile
+
+PY3 = bytes != str
+
+
+def main(args):
+ executor = MacTool()
+ exit_code = executor.Dispatch(args)
+ if exit_code is not None:
+ sys.exit(exit_code)
+
+
+class MacTool(object):
+ """This class performs all the Mac tooling steps. The methods can either be
+ executed directly, or dispatched from an argument list."""
+
+ def Dispatch(self, args):
+ """Dispatches a string command to a method."""
+ if len(args) < 1:
+ raise Exception("Not enough arguments")
+
+ method = "Exec%s" % self._CommandifyName(args[0])
+ return getattr(self, method)(*args[1:])
+
+ def _CommandifyName(self, name_string):
+ """Transforms a tool name like copy-info-plist to CopyInfoPlist"""
+ return name_string.title().replace('-', '')
+
+ def ExecCopyBundleResource(self, source, dest, convert_to_binary):
+ """Copies a resource file to the bundle/Resources directory, performing any
+ necessary compilation on each resource."""
+ extension = os.path.splitext(source)[1].lower()
+ if os.path.isdir(source):
+ # Copy tree.
+ # TODO(thakis): This copies file attributes like mtime, while the
+ # single-file branch below doesn't. This should probably be changed to
+ # be consistent with the single-file branch.
+ if os.path.exists(dest):
+ shutil.rmtree(dest)
+ shutil.copytree(source, dest)
+ elif extension == '.xib':
+ return self._CopyXIBFile(source, dest)
+ elif extension == '.storyboard':
+ return self._CopyXIBFile(source, dest)
+ elif extension == '.strings':
+ self._CopyStringsFile(source, dest, convert_to_binary)
+ else:
+ shutil.copy(source, dest)
+
+ def _CopyXIBFile(self, source, dest):
+ """Compiles a XIB file with ibtool into a binary plist in the bundle."""
+
+ # ibtool sometimes crashes with relative paths. See crbug.com/314728.
+ base = os.path.dirname(os.path.realpath(__file__))
+ if os.path.relpath(source):
+ source = os.path.join(base, source)
+ if os.path.relpath(dest):
+ dest = os.path.join(base, dest)
+
+ args = ['xcrun', 'ibtool', '--errors', '--warnings', '--notices',
+ '--output-format', 'human-readable-text', '--compile', dest, source]
+ ibtool_section_re = re.compile(r'/\*.*\*/')
+ ibtool_re = re.compile(r'.*note:.*is clipping its content')
+ ibtoolout = subprocess.Popen(args, stdout=subprocess.PIPE)
+ current_section_header = None
+ for line in ibtoolout.stdout:
+ if ibtool_section_re.match(line):
+ current_section_header = line
+ elif not ibtool_re.match(line):
+ if current_section_header:
+ sys.stdout.write(current_section_header)
+ current_section_header = None
+ sys.stdout.write(line)
+ return ibtoolout.returncode
+
+ def _ConvertToBinary(self, dest):
+ subprocess.check_call([
+ 'xcrun', 'plutil', '-convert', 'binary1', '-o', dest, dest])
+
+ def _CopyStringsFile(self, source, dest, convert_to_binary):
+ """Copies a .strings file using iconv to reconvert the input into UTF-16."""
+ input_code = self._DetectInputEncoding(source) or "UTF-8"
+
+ # Xcode's CpyCopyStringsFile / builtin-copyStrings seems to call
+ # CFPropertyListCreateFromXMLData() behind the scenes; at least it prints
+ # CFPropertyListCreateFromXMLData(): Old-style plist parser: missing
+ # semicolon in dictionary.
+ # on invalid files. Do the same kind of validation.
+ import CoreFoundation
+ s = open(source, 'rb').read()
+ d = CoreFoundation.CFDataCreate(None, s, len(s))
+ _, error = CoreFoundation.CFPropertyListCreateFromXMLData(None, d, 0, None)
+ if error:
+ return
+
+ fp = open(dest, 'wb')
+ fp.write(s.decode(input_code).encode('UTF-16'))
+ fp.close()
+
+ if convert_to_binary == 'True':
+ self._ConvertToBinary(dest)
+
+ def _DetectInputEncoding(self, file_name):
+ """Reads the first few bytes from file_name and tries to guess the text
+ encoding. Returns None as a guess if it can't detect it."""
+ fp = open(file_name, 'rb')
+ try:
+ header = fp.read(3)
+ except Exception:
+ fp.close()
+ return None
+ fp.close()
+ if header.startswith("\xFE\xFF"):
+ return "UTF-16"
+ elif header.startswith("\xFF\xFE"):
+ return "UTF-16"
+ elif header.startswith("\xEF\xBB\xBF"):
+ return "UTF-8"
+ else:
+ return None
+
+ def ExecCopyInfoPlist(self, source, dest, convert_to_binary, *keys):
+ """Copies the |source| Info.plist to the destination directory |dest|."""
+ # Read the source Info.plist into memory.
+ fd = open(source, 'r')
+ lines = fd.read()
+ fd.close()
+
+ # Insert synthesized key/value pairs (e.g. BuildMachineOSBuild).
+ plist = plistlib.readPlistFromString(lines)
+ if keys:
+ plist = dict(plist.items() + json.loads(keys[0]).items())
+ lines = plistlib.writePlistToString(plist)
+
+ # Go through all the environment variables and replace them as variables in
+ # the file.
+ IDENT_RE = re.compile(r'[/\s]')
+ for key in os.environ:
+ if key.startswith('_'):
+ continue
+ evar = '${%s}' % key
+ evalue = os.environ[key]
+ lines = string.replace(lines, evar, evalue)
+
+ # Xcode supports various suffices on environment variables, which are
+ # all undocumented. :rfc1034identifier is used in the standard project
+ # template these days, and :identifier was used earlier. They are used to
+ # convert non-url characters into things that look like valid urls --
+ # except that the replacement character for :identifier, '_' isn't valid
+ # in a URL either -- oops, hence :rfc1034identifier was born.
+ evar = '${%s:identifier}' % key
+ evalue = IDENT_RE.sub('_', os.environ[key])
+ lines = string.replace(lines, evar, evalue)
+
+ evar = '${%s:rfc1034identifier}' % key
+ evalue = IDENT_RE.sub('-', os.environ[key])
+ lines = string.replace(lines, evar, evalue)
+
+ # Remove any keys with values that haven't been replaced.
+ lines = lines.split('\n')
+ for i in range(len(lines)):
+ if lines[i].strip().startswith("<string>${"):
+ lines[i] = None
+ lines[i - 1] = None
+ lines = '\n'.join(filter(lambda x: x is not None, lines))
+
+ # Write out the file with variables replaced.
+ fd = open(dest, 'w')
+ fd.write(lines)
+ fd.close()
+
+ # Now write out PkgInfo file now that the Info.plist file has been
+ # "compiled".
+ self._WritePkgInfo(dest)
+
+ if convert_to_binary == 'True':
+ self._ConvertToBinary(dest)
+
+ def _WritePkgInfo(self, info_plist):
+ """This writes the PkgInfo file from the data stored in Info.plist."""
+ plist = plistlib.readPlist(info_plist)
+ if not plist:
+ return
+
+ # Only create PkgInfo for executable types.
+ package_type = plist['CFBundlePackageType']
+ if package_type != 'APPL':
+ return
+
+ # The format of PkgInfo is eight characters, representing the bundle type
+ # and bundle signature, each four characters. If that is missing, four
+ # '?' characters are used instead.
+ signature_code = plist.get('CFBundleSignature', '????')
+ if len(signature_code) != 4: # Wrong length resets everything, too.
+ signature_code = '?' * 4
+
+ dest = os.path.join(os.path.dirname(info_plist), 'PkgInfo')
+ fp = open(dest, 'w')
+ fp.write('%s%s' % (package_type, signature_code))
+ fp.close()
+
+ def ExecFlock(self, lockfile, *cmd_list):
+ """Emulates the most basic behavior of Linux's flock(1)."""
+ # Rely on exception handling to report errors.
+ fd = os.open(lockfile, os.O_RDONLY|os.O_NOCTTY|os.O_CREAT, 0o666)
+ fcntl.flock(fd, fcntl.LOCK_EX)
+ return subprocess.call(cmd_list)
+
+ def ExecFilterLibtool(self, *cmd_list):
+ """Calls libtool and filters out '/path/to/libtool: file: foo.o has no
+ symbols'."""
+ libtool_re = re.compile(r'^.*libtool: file: .* has no symbols$')
+ libtool_re5 = re.compile(
+ r'^.*libtool: warning for library: ' +
+ r'.* the table of contents is empty ' +
+ r'\(no object file members in the library define global symbols\)$')
+ env = os.environ.copy()
+ # Ref:
+ # http://www.opensource.apple.com/source/cctools/cctools-809/misc/libtool.c
+ # The problem with this flag is that it resets the file mtime on the file to
+ # epoch=0, e.g. 1970-1-1 or 1969-12-31 depending on timezone.
+ env['ZERO_AR_DATE'] = '1'
+ libtoolout = subprocess.Popen(cmd_list, stderr=subprocess.PIPE, env=env)
+ _, err = libtoolout.communicate()
+ if PY3:
+ err = err.decode('utf-8')
+ for line in err.splitlines():
+ if not libtool_re.match(line) and not libtool_re5.match(line):
+ print(line, file=sys.stderr)
+ # Unconditionally touch the output .a file on the command line if present
+ # and the command succeeded. A bit hacky.
+ if not libtoolout.returncode:
+ for i in range(len(cmd_list) - 1):
+ if cmd_list[i] == "-o" and cmd_list[i+1].endswith('.a'):
+ os.utime(cmd_list[i+1], None)
+ break
+ return libtoolout.returncode
+
+ def ExecPackageFramework(self, framework, version):
+ """Takes a path to Something.framework and the Current version of that and
+ sets up all the symlinks."""
+ # Find the name of the binary based on the part before the ".framework".
+ binary = os.path.basename(framework).split('.')[0]
+
+ CURRENT = 'Current'
+ RESOURCES = 'Resources'
+ VERSIONS = 'Versions'
+
+ if not os.path.exists(os.path.join(framework, VERSIONS, version, binary)):
+ # Binary-less frameworks don't seem to contain symlinks (see e.g.
+ # chromium's out/Debug/org.chromium.Chromium.manifest/ bundle).
+ return
+
+ # Move into the framework directory to set the symlinks correctly.
+ pwd = os.getcwd()
+ os.chdir(framework)
+
+ # Set up the Current version.
+ self._Relink(version, os.path.join(VERSIONS, CURRENT))
+
+ # Set up the root symlinks.
+ self._Relink(os.path.join(VERSIONS, CURRENT, binary), binary)
+ self._Relink(os.path.join(VERSIONS, CURRENT, RESOURCES), RESOURCES)
+
+ # Back to where we were before!
+ os.chdir(pwd)
+
+ def _Relink(self, dest, link):
+ """Creates a symlink to |dest| named |link|. If |link| already exists,
+ it is overwritten."""
+ if os.path.lexists(link):
+ os.remove(link)
+ os.symlink(dest, link)
+
+ def ExecCompileXcassets(self, keys, *inputs):
+ """Compiles multiple .xcassets files into a single .car file.
+
+ This invokes 'actool' to compile all the inputs .xcassets files. The
+ |keys| arguments is a json-encoded dictionary of extra arguments to
+ pass to 'actool' when the asset catalogs contains an application icon
+ or a launch image.
+
+ Note that 'actool' does not create the Assets.car file if the asset
+ catalogs does not contains imageset.
+ """
+ command_line = [
+ 'xcrun', 'actool', '--output-format', 'human-readable-text',
+ '--compress-pngs', '--notices', '--warnings', '--errors',
+ ]
+ is_iphone_target = 'IPHONEOS_DEPLOYMENT_TARGET' in os.environ
+ if is_iphone_target:
+ platform = os.environ['CONFIGURATION'].split('-')[-1]
+ if platform not in ('iphoneos', 'iphonesimulator'):
+ platform = 'iphonesimulator'
+ command_line.extend([
+ '--platform', platform, '--target-device', 'iphone',
+ '--target-device', 'ipad', '--minimum-deployment-target',
+ os.environ['IPHONEOS_DEPLOYMENT_TARGET'], '--compile',
+ os.path.abspath(os.environ['CONTENTS_FOLDER_PATH']),
+ ])
+ else:
+ command_line.extend([
+ '--platform', 'macosx', '--target-device', 'mac',
+ '--minimum-deployment-target', os.environ['MACOSX_DEPLOYMENT_TARGET'],
+ '--compile',
+ os.path.abspath(os.environ['UNLOCALIZED_RESOURCES_FOLDER_PATH']),
+ ])
+ if keys:
+ keys = json.loads(keys)
+ for key, value in keys.items():
+ arg_name = '--' + key
+ if isinstance(value, bool):
+ if value:
+ command_line.append(arg_name)
+ elif isinstance(value, list):
+ for v in value:
+ command_line.append(arg_name)
+ command_line.append(str(v))
+ else:
+ command_line.append(arg_name)
+ command_line.append(str(value))
+ # Note: actool crashes if inputs path are relative, so use os.path.abspath
+ # to get absolute path name for inputs.
+ command_line.extend(map(os.path.abspath, inputs))
+ subprocess.check_call(command_line)
+
+ def ExecMergeInfoPlist(self, output, *inputs):
+ """Merge multiple .plist files into a single .plist file."""
+ merged_plist = {}
+ for path in inputs:
+ plist = self._LoadPlistMaybeBinary(path)
+ self._MergePlist(merged_plist, plist)
+ plistlib.writePlist(merged_plist, output)
+
+ def ExecCodeSignBundle(self, key, resource_rules, entitlements, provisioning):
+ """Code sign a bundle.
+
+ This function tries to code sign an iOS bundle, following the same
+ algorithm as Xcode:
+ 1. copy ResourceRules.plist from the user or the SDK into the bundle,
+ 2. pick the provisioning profile that best match the bundle identifier,
+ and copy it into the bundle as embedded.mobileprovision,
+ 3. copy Entitlements.plist from user or SDK next to the bundle,
+ 4. code sign the bundle.
+ """
+ resource_rules_path = self._InstallResourceRules(resource_rules)
+ substitutions, overrides = self._InstallProvisioningProfile(
+ provisioning, self._GetCFBundleIdentifier())
+ entitlements_path = self._InstallEntitlements(
+ entitlements, substitutions, overrides)
+ subprocess.check_call([
+ 'codesign', '--force', '--sign', key, '--resource-rules',
+ resource_rules_path, '--entitlements', entitlements_path,
+ os.path.join(
+ os.environ['TARGET_BUILD_DIR'],
+ os.environ['FULL_PRODUCT_NAME'])])
+
+ def _InstallResourceRules(self, resource_rules):
+ """Installs ResourceRules.plist from user or SDK into the bundle.
+
+ Args:
+ resource_rules: string, optional, path to the ResourceRules.plist file
+ to use, default to "${SDKROOT}/ResourceRules.plist"
+
+ Returns:
+ Path to the copy of ResourceRules.plist into the bundle.
+ """
+ source_path = resource_rules
+ target_path = os.path.join(
+ os.environ['BUILT_PRODUCTS_DIR'],
+ os.environ['CONTENTS_FOLDER_PATH'],
+ 'ResourceRules.plist')
+ if not source_path:
+ source_path = os.path.join(
+ os.environ['SDKROOT'], 'ResourceRules.plist')
+ shutil.copy2(source_path, target_path)
+ return target_path
+
+ def _InstallProvisioningProfile(self, profile, bundle_identifier):
+ """Installs embedded.mobileprovision into the bundle.
+
+ Args:
+ profile: string, optional, short name of the .mobileprovision file
+ to use, if empty or the file is missing, the best file installed
+ will be used
+ bundle_identifier: string, value of CFBundleIdentifier from Info.plist
+
+ Returns:
+ A tuple containing two dictionary: variables substitutions and values
+ to overrides when generating the entitlements file.
+ """
+ source_path, provisioning_data, team_id = self._FindProvisioningProfile(
+ profile, bundle_identifier)
+ target_path = os.path.join(
+ os.environ['BUILT_PRODUCTS_DIR'],
+ os.environ['CONTENTS_FOLDER_PATH'],
+ 'embedded.mobileprovision')
+ shutil.copy2(source_path, target_path)
+ substitutions = self._GetSubstitutions(bundle_identifier, team_id + '.')
+ return substitutions, provisioning_data['Entitlements']
+
+ def _FindProvisioningProfile(self, profile, bundle_identifier):
+ """Finds the .mobileprovision file to use for signing the bundle.
+
+ Checks all the installed provisioning profiles (or if the user specified
+ the PROVISIONING_PROFILE variable, only consult it) and select the most
+ specific that correspond to the bundle identifier.
+
+ Args:
+ profile: string, optional, short name of the .mobileprovision file
+ to use, if empty or the file is missing, the best file installed
+ will be used
+ bundle_identifier: string, value of CFBundleIdentifier from Info.plist
+
+ Returns:
+ A tuple of the path to the selected provisioning profile, the data of
+ the embedded plist in the provisioning profile and the team identifier
+ to use for code signing.
+
+ Raises:
+ SystemExit: if no .mobileprovision can be used to sign the bundle.
+ """
+ profiles_dir = os.path.join(
+ os.environ['HOME'], 'Library', 'MobileDevice', 'Provisioning Profiles')
+ if not os.path.isdir(profiles_dir):
+ print('cannot find mobile provisioning for %s' % (bundle_identifier), file=sys.stderr)
+ sys.exit(1)
+ provisioning_profiles = None
+ if profile:
+ profile_path = os.path.join(profiles_dir, profile + '.mobileprovision')
+ if os.path.exists(profile_path):
+ provisioning_profiles = [profile_path]
+ if not provisioning_profiles:
+ provisioning_profiles = glob.glob(
+ os.path.join(profiles_dir, '*.mobileprovision'))
+ valid_provisioning_profiles = {}
+ for profile_path in provisioning_profiles:
+ profile_data = self._LoadProvisioningProfile(profile_path)
+ app_id_pattern = profile_data.get(
+ 'Entitlements', {}).get('application-identifier', '')
+ for team_identifier in profile_data.get('TeamIdentifier', []):
+ app_id = '%s.%s' % (team_identifier, bundle_identifier)
+ if fnmatch.fnmatch(app_id, app_id_pattern):
+ valid_provisioning_profiles[app_id_pattern] = (
+ profile_path, profile_data, team_identifier)
+ if not valid_provisioning_profiles:
+ print('cannot find mobile provisioning for %s' % (bundle_identifier), file=sys.stderr)
+ sys.exit(1)
+ # If the user has multiple provisioning profiles installed that can be
+ # used for ${bundle_identifier}, pick the most specific one (ie. the
+ # provisioning profile whose pattern is the longest).
+ selected_key = max(valid_provisioning_profiles, key=lambda v: len(v))
+ return valid_provisioning_profiles[selected_key]
+
+ def _LoadProvisioningProfile(self, profile_path):
+ """Extracts the plist embedded in a provisioning profile.
+
+ Args:
+ profile_path: string, path to the .mobileprovision file
+
+ Returns:
+ Content of the plist embedded in the provisioning profile as a dictionary.
+ """
+ with tempfile.NamedTemporaryFile() as temp:
+ subprocess.check_call([
+ 'security', 'cms', '-D', '-i', profile_path, '-o', temp.name])
+ return self._LoadPlistMaybeBinary(temp.name)
+
+ def _MergePlist(self, merged_plist, plist):
+ """Merge |plist| into |merged_plist|."""
+ for key, value in plist.items():
+ if isinstance(value, dict):
+ merged_value = merged_plist.get(key, {})
+ if isinstance(merged_value, dict):
+ self._MergePlist(merged_value, value)
+ merged_plist[key] = merged_value
+ else:
+ merged_plist[key] = value
+ else:
+ merged_plist[key] = value
+
+ def _LoadPlistMaybeBinary(self, plist_path):
+ """Loads into a memory a plist possibly encoded in binary format.
+
+ This is a wrapper around plistlib.readPlist that tries to convert the
+ plist to the XML format if it can't be parsed (assuming that it is in
+ the binary format).
+
+ Args:
+ plist_path: string, path to a plist file, in XML or binary format
+
+ Returns:
+ Content of the plist as a dictionary.
+ """
+ try:
+ # First, try to read the file using plistlib that only supports XML,
+ # and if an exception is raised, convert a temporary copy to XML and
+ # load that copy.
+ return plistlib.readPlist(plist_path)
+ except:
+ pass
+ with tempfile.NamedTemporaryFile() as temp:
+ shutil.copy2(plist_path, temp.name)
+ subprocess.check_call(['plutil', '-convert', 'xml1', temp.name])
+ return plistlib.readPlist(temp.name)
+
+ def _GetSubstitutions(self, bundle_identifier, app_identifier_prefix):
+ """Constructs a dictionary of variable substitutions for Entitlements.plist.
+
+ Args:
+ bundle_identifier: string, value of CFBundleIdentifier from Info.plist
+ app_identifier_prefix: string, value for AppIdentifierPrefix
+
+ Returns:
+ Dictionary of substitutions to apply when generating Entitlements.plist.
+ """
+ return {
+ 'CFBundleIdentifier': bundle_identifier,
+ 'AppIdentifierPrefix': app_identifier_prefix,
+ }
+
+ def _GetCFBundleIdentifier(self):
+ """Extracts CFBundleIdentifier value from Info.plist in the bundle.
+
+ Returns:
+ Value of CFBundleIdentifier in the Info.plist located in the bundle.
+ """
+ info_plist_path = os.path.join(
+ os.environ['TARGET_BUILD_DIR'],
+ os.environ['INFOPLIST_PATH'])
+ info_plist_data = self._LoadPlistMaybeBinary(info_plist_path)
+ return info_plist_data['CFBundleIdentifier']
+
+ def _InstallEntitlements(self, entitlements, substitutions, overrides):
+ """Generates and install the ${BundleName}.xcent entitlements file.
+
+ Expands variables "$(variable)" pattern in the source entitlements file,
+ add extra entitlements defined in the .mobileprovision file and the copy
+ the generated plist to "${BundlePath}.xcent".
+
+ Args:
+ entitlements: string, optional, path to the Entitlements.plist template
+ to use, defaults to "${SDKROOT}/Entitlements.plist"
+ substitutions: dictionary, variable substitutions
+ overrides: dictionary, values to add to the entitlements
+
+ Returns:
+ Path to the generated entitlements file.
+ """
+ source_path = entitlements
+ target_path = os.path.join(
+ os.environ['BUILT_PRODUCTS_DIR'],
+ os.environ['PRODUCT_NAME'] + '.xcent')
+ if not source_path:
+ source_path = os.path.join(
+ os.environ['SDKROOT'],
+ 'Entitlements.plist')
+ shutil.copy2(source_path, target_path)
+ data = self._LoadPlistMaybeBinary(target_path)
+ data = self._ExpandVariables(data, substitutions)
+ if overrides:
+ for key in overrides:
+ if key not in data:
+ data[key] = overrides[key]
+ plistlib.writePlist(data, target_path)
+ return target_path
+
+ def _ExpandVariables(self, data, substitutions):
+ """Expands variables "$(variable)" in data.
+
+ Args:
+ data: object, can be either string, list or dictionary
+ substitutions: dictionary, variable substitutions to perform
+
+ Returns:
+ Copy of data where each references to "$(variable)" has been replaced
+ by the corresponding value found in substitutions, or left intact if
+ the key was not found.
+ """
+ if isinstance(data, str):
+ for key, value in substitutions.items():
+ data = data.replace('$(%s)' % key, value)
+ return data
+ if isinstance(data, list):
+ return [self._ExpandVariables(v, substitutions) for v in data]
+ if isinstance(data, dict):
+ return {k: self._ExpandVariables(data[k], substitutions) for k in data}
+ return data
+
+if __name__ == '__main__':
+ sys.exit(main(sys.argv[1:]))
--- /dev/null
+# This file is generated by gyp; do not edit.
+
+TOOLSET := target
+TARGET := nodeaudio
+DEFS_Debug := \
+ '-DNODE_GYP_MODULE_NAME=nodeaudio' \
+ '-DUSING_UV_SHARED=1' \
+ '-DUSING_V8_SHARED=1' \
+ '-DV8_DEPRECATION_WARNINGS=1' \
+ '-DV8_DEPRECATION_WARNINGS' \
+ '-DV8_IMMINENT_DEPRECATION_WARNINGS' \
+ '-D_DARWIN_USE_64_BIT_INODE=1' \
+ '-D_LARGEFILE_SOURCE' \
+ '-D_FILE_OFFSET_BITS=64' \
+ '-DOPENSSL_NO_PINSHARED' \
+ '-DOPENSSL_THREADS' \
+ '-DBUILDING_NODE_EXTENSION' \
+ '-DDEBUG' \
+ '-D_DEBUG' \
+ '-DV8_ENABLE_CHECKS'
+
+# Flags passed to all source files.
+CFLAGS_Debug := \
+ -O0 \
+ -gdwarf-2 \
+ -mmacosx-version-min=10.13 \
+ -arch x86_64 \
+ -Wall \
+ -Wendif-labels \
+ -W \
+ -Wno-unused-parameter
+
+# Flags passed to only C files.
+CFLAGS_C_Debug := \
+ -fno-strict-aliasing
+
+# Flags passed to only C++ files.
+CFLAGS_CC_Debug := \
+ -std=gnu++1y \
+ -stdlib=libc++ \
+ -fno-rtti \
+ -fno-exceptions \
+ -fno-strict-aliasing
+
+# Flags passed to only ObjC files.
+CFLAGS_OBJC_Debug :=
+
+# Flags passed to only ObjC++ files.
+CFLAGS_OBJCC_Debug :=
+
+INCS_Debug := \
+ -I/Users/adgundersen/Library/Caches/node-gyp/14.17.0/include/node \
+ -I/Users/adgundersen/Library/Caches/node-gyp/14.17.0/src \
+ -I/Users/adgundersen/Library/Caches/node-gyp/14.17.0/deps/openssl/config \
+ -I/Users/adgundersen/Library/Caches/node-gyp/14.17.0/deps/openssl/openssl/include \
+ -I/Users/adgundersen/Library/Caches/node-gyp/14.17.0/deps/uv/include \
+ -I/Users/adgundersen/Library/Caches/node-gyp/14.17.0/deps/zlib \
+ -I/Users/adgundersen/Library/Caches/node-gyp/14.17.0/deps/v8/include \
+ -I/usr/local/include
+
+DEFS_Release := \
+ '-DNODE_GYP_MODULE_NAME=nodeaudio' \
+ '-DUSING_UV_SHARED=1' \
+ '-DUSING_V8_SHARED=1' \
+ '-DV8_DEPRECATION_WARNINGS=1' \
+ '-DV8_DEPRECATION_WARNINGS' \
+ '-DV8_IMMINENT_DEPRECATION_WARNINGS' \
+ '-D_DARWIN_USE_64_BIT_INODE=1' \
+ '-D_LARGEFILE_SOURCE' \
+ '-D_FILE_OFFSET_BITS=64' \
+ '-DOPENSSL_NO_PINSHARED' \
+ '-DOPENSSL_THREADS' \
+ '-DBUILDING_NODE_EXTENSION'
+
+# Flags passed to all source files.
+CFLAGS_Release := \
+ -O3 \
+ -gdwarf-2 \
+ -mmacosx-version-min=10.13 \
+ -arch x86_64 \
+ -Wall \
+ -Wendif-labels \
+ -W \
+ -Wno-unused-parameter
+
+# Flags passed to only C files.
+CFLAGS_C_Release := \
+ -fno-strict-aliasing
+
+# Flags passed to only C++ files.
+CFLAGS_CC_Release := \
+ -std=gnu++1y \
+ -stdlib=libc++ \
+ -fno-rtti \
+ -fno-exceptions \
+ -fno-strict-aliasing
+
+# Flags passed to only ObjC files.
+CFLAGS_OBJC_Release :=
+
+# Flags passed to only ObjC++ files.
+CFLAGS_OBJCC_Release :=
+
+INCS_Release := \
+ -I/Users/adgundersen/Library/Caches/node-gyp/14.17.0/include/node \
+ -I/Users/adgundersen/Library/Caches/node-gyp/14.17.0/src \
+ -I/Users/adgundersen/Library/Caches/node-gyp/14.17.0/deps/openssl/config \
+ -I/Users/adgundersen/Library/Caches/node-gyp/14.17.0/deps/openssl/openssl/include \
+ -I/Users/adgundersen/Library/Caches/node-gyp/14.17.0/deps/uv/include \
+ -I/Users/adgundersen/Library/Caches/node-gyp/14.17.0/deps/zlib \
+ -I/Users/adgundersen/Library/Caches/node-gyp/14.17.0/deps/v8/include \
+ -I/usr/local/include
+
+OBJS := \
+ $(obj).target/$(TARGET)/src/nodeaudio.o \
+ $(obj).target/$(TARGET)/src/audio_handler.o \
+ $(obj).target/$(TARGET)/src/frame_buffer.o
+
+# Add to the list of files we specially track dependencies for.
+all_deps += $(OBJS)
+
+# CFLAGS et al overrides must be target-local.
+# See "Target-specific Variable Values" in the GNU Make manual.
+$(OBJS): TOOLSET := $(TOOLSET)
+$(OBJS): GYP_CFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE))
+$(OBJS): GYP_CXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE))
+$(OBJS): GYP_OBJCFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE)) $(CFLAGS_OBJC_$(BUILDTYPE))
+$(OBJS): GYP_OBJCXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE)) $(CFLAGS_OBJCC_$(BUILDTYPE))
+
+# Suffix rules, putting all outputs into $(obj).
+
+$(obj).$(TOOLSET)/$(TARGET)/%.o: $(srcdir)/%.c FORCE_DO_CMD
+ @$(call do_cmd,cc,1)
+
+# Try building from generated source, too.
+
+$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj).$(TOOLSET)/%.c FORCE_DO_CMD
+ @$(call do_cmd,cc,1)
+
+$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj)/%.c FORCE_DO_CMD
+ @$(call do_cmd,cc,1)
+
+# End of this set of suffix rules
+### Rules for final target.
+LDFLAGS_Debug := \
+ -undefined dynamic_lookup \
+ -Wl,-no_pie \
+ -Wl,-search_paths_first \
+ -mmacosx-version-min=10.13 \
+ -arch x86_64 \
+ -L$(builddir) \
+ -stdlib=libc++
+
+LIBTOOLFLAGS_Debug := \
+ -undefined dynamic_lookup \
+ -Wl,-no_pie \
+ -Wl,-search_paths_first
+
+LDFLAGS_Release := \
+ -undefined dynamic_lookup \
+ -Wl,-no_pie \
+ -Wl,-search_paths_first \
+ -mmacosx-version-min=10.13 \
+ -arch x86_64 \
+ -L$(builddir) \
+ -stdlib=libc++
+
+LIBTOOLFLAGS_Release := \
+ -undefined dynamic_lookup \
+ -Wl,-no_pie \
+ -Wl,-search_paths_first
+
+LIBS := \
+ -lportaudio
+
+$(builddir)/nodeaudio.node: GYP_LDFLAGS := $(LDFLAGS_$(BUILDTYPE))
+$(builddir)/nodeaudio.node: LIBS := $(LIBS)
+$(builddir)/nodeaudio.node: GYP_LIBTOOLFLAGS := $(LIBTOOLFLAGS_$(BUILDTYPE))
+$(builddir)/nodeaudio.node: TOOLSET := $(TOOLSET)
+$(builddir)/nodeaudio.node: $(OBJS) FORCE_DO_CMD
+ $(call do_cmd,solink_module)
+
+all_deps += $(builddir)/nodeaudio.node
+# Add target alias
+.PHONY: nodeaudio
+nodeaudio: $(builddir)/nodeaudio.node
+
+# Short alias for building this executable.
+.PHONY: nodeaudio.node
+nodeaudio.node: $(builddir)/nodeaudio.node
+
+# Add executable to "all" target.
+.PHONY: all
+all: $(builddir)/nodeaudio.node
+
--- /dev/null
+node-bindings
+=============
+### Helper module for loading your native module's .node file
+
+This is a helper module for authors of Node.js native addon modules.
+It is basically the "swiss army knife" of `require()`ing your native module's
+`.node` file.
+
+Throughout the course of Node's native addon history, addons have ended up being
+compiled in a variety of different places, depending on which build tool and which
+version of node was used. To make matters worse, now the _gyp_ build tool can
+produce either a _Release_ or _Debug_ build, each being built into different
+locations.
+
+This module checks _all_ the possible locations that a native addon would be built
+at, and returns the first one that loads successfully.
+
+
+Installation
+------------
+
+Install with `npm`:
+
+``` bash
+$ npm install bindings
+```
+
+Or add it to the `"dependencies"` section of your _package.json_ file.
+
+
+Example
+-------
+
+`require()`ing the proper bindings file for the current node version, platform
+and architecture is as simple as:
+
+``` js
+var bindings = require('bindings')('binding.node')
+
+// Use your bindings defined in your C files
+bindings.your_c_function()
+```
+
+
+Nice Error Output
+-----------------
+
+When the `.node` file could not be loaded, `node-bindings` throws an Error with
+a nice error message telling you exactly what was tried. You can also check the
+`err.tries` Array property.
+
+```
+Error: Could not load the bindings file. Tried:
+ → /Users/nrajlich/ref/build/binding.node
+ → /Users/nrajlich/ref/build/Debug/binding.node
+ → /Users/nrajlich/ref/build/Release/binding.node
+ → /Users/nrajlich/ref/out/Debug/binding.node
+ → /Users/nrajlich/ref/Debug/binding.node
+ → /Users/nrajlich/ref/out/Release/binding.node
+ → /Users/nrajlich/ref/Release/binding.node
+ → /Users/nrajlich/ref/build/default/binding.node
+ → /Users/nrajlich/ref/compiled/0.8.2/darwin/x64/binding.node
+ at bindings (/Users/nrajlich/ref/node_modules/bindings/bindings.js:84:13)
+ at Object.<anonymous> (/Users/nrajlich/ref/lib/ref.js:5:47)
+ at Module._compile (module.js:449:26)
+ at Object.Module._extensions..js (module.js:467:10)
+ at Module.load (module.js:356:32)
+ at Function.Module._load (module.js:312:12)
+ ...
+```
+
+
+License
+-------
+
+(The MIT License)
+
+Copyright (c) 2012 Nathan Rajlich <nathan@tootallnate.net>
+
+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:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+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.
--- /dev/null
+
+/**
+ * Module dependencies.
+ */
+
+var fs = require('fs')
+ , path = require('path')
+ , join = path.join
+ , dirname = path.dirname
+ , exists = fs.existsSync || path.existsSync
+ , defaults = {
+ arrow: process.env.NODE_BINDINGS_ARROW || ' → '
+ , compiled: process.env.NODE_BINDINGS_COMPILED_DIR || 'compiled'
+ , platform: process.platform
+ , arch: process.arch
+ , version: process.versions.node
+ , bindings: 'bindings.node'
+ , try: [
+ // node-gyp's linked version in the "build" dir
+ [ 'module_root', 'build', 'bindings' ]
+ // node-waf and gyp_addon (a.k.a node-gyp)
+ , [ 'module_root', 'build', 'Debug', 'bindings' ]
+ , [ 'module_root', 'build', 'Release', 'bindings' ]
+ // Debug files, for development (legacy behavior, remove for node v0.9)
+ , [ 'module_root', 'out', 'Debug', 'bindings' ]
+ , [ 'module_root', 'Debug', 'bindings' ]
+ // Release files, but manually compiled (legacy behavior, remove for node v0.9)
+ , [ 'module_root', 'out', 'Release', 'bindings' ]
+ , [ 'module_root', 'Release', 'bindings' ]
+ // Legacy from node-waf, node <= 0.4.x
+ , [ 'module_root', 'build', 'default', 'bindings' ]
+ // Production "Release" buildtype binary (meh...)
+ , [ 'module_root', 'compiled', 'version', 'platform', 'arch', 'bindings' ]
+ ]
+ }
+
+/**
+ * The main `bindings()` function loads the compiled bindings for a given module.
+ * It uses V8's Error API to determine the parent filename that this function is
+ * being invoked from, which is then used to find the root directory.
+ */
+
+function bindings (opts) {
+
+ // Argument surgery
+ if (typeof opts == 'string') {
+ opts = { bindings: opts }
+ } else if (!opts) {
+ opts = {}
+ }
+ opts.__proto__ = defaults
+
+ // Get the module root
+ if (!opts.module_root) {
+ opts.module_root = exports.getRoot(exports.getFileName())
+ }
+
+ // Ensure the given bindings name ends with .node
+ if (path.extname(opts.bindings) != '.node') {
+ opts.bindings += '.node'
+ }
+
+ var tries = []
+ , i = 0
+ , l = opts.try.length
+ , n
+ , b
+ , err
+
+ for (; i<l; i++) {
+ n = join.apply(null, opts.try[i].map(function (p) {
+ return opts[p] || p
+ }))
+ tries.push(n)
+ try {
+ b = opts.path ? require.resolve(n) : require(n)
+ if (!opts.path) {
+ b.path = n
+ }
+ return b
+ } catch (e) {
+ if (!/not find/i.test(e.message)) {
+ throw e
+ }
+ }
+ }
+
+ err = new Error('Could not locate the bindings file. Tried:\n'
+ + tries.map(function (a) { return opts.arrow + a }).join('\n'))
+ err.tries = tries
+ throw err
+}
+module.exports = exports = bindings
+
+
+/**
+ * Gets the filename of the JavaScript file that invokes this function.
+ * Used to help find the root directory of a module.
+ * Optionally accepts an filename argument to skip when searching for the invoking filename
+ */
+
+exports.getFileName = function getFileName (calling_file) {
+ var origPST = Error.prepareStackTrace
+ , origSTL = Error.stackTraceLimit
+ , dummy = {}
+ , fileName
+
+ Error.stackTraceLimit = 10
+
+ Error.prepareStackTrace = function (e, st) {
+ for (var i=0, l=st.length; i<l; i++) {
+ fileName = st[i].getFileName()
+ if (fileName !== __filename) {
+ if (calling_file) {
+ if (fileName !== calling_file) {
+ return
+ }
+ } else {
+ return
+ }
+ }
+ }
+ }
+
+ // run the 'prepareStackTrace' function above
+ Error.captureStackTrace(dummy)
+ dummy.stack
+
+ // cleanup
+ Error.prepareStackTrace = origPST
+ Error.stackTraceLimit = origSTL
+
+ return fileName
+}
+
+/**
+ * Gets the root directory of a module, given an arbitrary filename
+ * somewhere in the module tree. The "root directory" is the directory
+ * containing the `package.json` file.
+ *
+ * In: /home/nate/node-native-module/lib/index.js
+ * Out: /home/nate/node-native-module
+ */
+
+exports.getRoot = function getRoot (file) {
+ var dir = dirname(file)
+ , prev
+ while (true) {
+ if (dir === '.') {
+ // Avoids an infinite loop in rare cases, like the REPL
+ dir = process.cwd()
+ }
+ if (exists(join(dir, 'package.json')) || exists(join(dir, 'node_modules'))) {
+ // Found the 'package.json' file or 'node_modules' dir; we're done
+ return dir
+ }
+ if (prev === dir) {
+ // Got to the top
+ throw new Error('Could not find module root given file: "' + file
+ + '". Do you have a `package.json` file? ')
+ }
+ // Try the parent dir next
+ prev = dir
+ dir = join(dir, '..')
+ }
+}
--- /dev/null
+{
+ "name": "bindings",
+ "description": "Helper module for loading your native module's .node file",
+ "keywords": [
+ "native",
+ "addon",
+ "bindings",
+ "gyp",
+ "waf",
+ "c",
+ "c++"
+ ],
+ "version": "1.2.1",
+ "author": "Nathan Rajlich <nathan@tootallnate.net> (http://tootallnate.net)",
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/TooTallNate/node-bindings.git"
+ },
+ "main": "./bindings.js",
+ "bugs": {
+ "url": "https://github.com/TooTallNate/node-bindings/issues"
+ },
+ "homepage": "https://github.com/TooTallNate/node-bindings",
+ "license": "MIT"
+
+,"_resolved": "https://registry.npmjs.org/bindings/-/bindings-1.2.1.tgz"
+,"_integrity": "sha1-FK1hE4EtLTfXLme0ystLtyZQXxE="
+,"_from": "bindings@1.2.1"
+}
\ No newline at end of file
--- /dev/null
+{
+ "name": "function_arguments",
+ "version": "0.0.0",
+ "lockfileVersion": 1,
+ "requires": true,
+ "dependencies": {
+ "bindings": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.2.1.tgz",
+ "integrity": "sha1-FK1hE4EtLTfXLme0ystLtyZQXxE="
+ }
+ }
+}
--- /dev/null
+{
+ "name": "function_arguments",
+ "version": "0.0.0",
+ "description": "Node.js Addons Example #2",
+ "main": "binding.js",
+ "private": true,
+ "dependencies": {
+ "bindings": "~1.2.1"
+ },
+ "scripts": {
+ "test": "node binding.js"
+ },
+ "gypfile": true
+}
--- /dev/null
+#include <time.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+#include <portaudio.h>
+
+#include "audio_handler.h"
+#include "frame_buffer.h"
+
+bool sys_on;
+
+bool recording = false;
+int write_to_o_buff = 0;
+bool initialized = false;
+
+frame_buffer inputFrameBuffer;
+frame_buffer outputFrameBuffer;
+
+typedef short SAMPLE;
+
+static int min_int (int a, int b) {
+ return (a < b) ? a : b;
+}
+
+#define SAMPLE_RATE (16000)
+#define BUFFER_mSECS (30)
+#define FRAMES_PER_BUFFER (160 * (BUFFER_mSECS/10))
+
+
+/* input -> inputFrameBuffer */
+static int input_callback( const void* input,
+ void* output,
+ unsigned long framesPerBuffer,
+ const PaStreamCallbackTimeInfo* timeInfo,
+ PaStreamCallbackFlags statusFlags,
+ void* frameBuffer )
+{
+ (void) output;
+ char *i_buf = (char *) input;
+ frame_buffer* fb = (frame_buffer*) frameBuffer;
+
+ if (!recording) {
+ rewrite_frames_fb( fb,
+ i_buf,
+ framesPerBuffer*sizeof(SAMPLE) );
+ } else {
+ rewrite_frames_fb( fb,
+ i_buf,
+ framesPerBuffer*sizeof(SAMPLE) );
+ }
+
+ return paContinue;
+
+}
+
+
+/* outputFrameBuffer -> output */
+static int output_callback( const void *input,
+ void* output,
+ unsigned long framesPerBuffer,
+ const PaStreamCallbackTimeInfo* timeInfo,
+ PaStreamCallbackFlags statusFlags,
+ void* frameBuffer )
+{
+
+ (void) input;
+ char* o_buf = (char *) output;
+ frame_buffer* fb = (frame_buffer*) frameBuffer;
+
+ if (write_to_o_buff == 0) {
+
+ write_to_o_buff = 2;
+
+ if (fb->frames_used > 0) {
+
+ int frames_to_read = min_int( framesPerBuffer,
+ fb->frames_used );
+
+ /* read each frame in outputFrameBuffer and write to output */
+ for (int i = 0; i < frames_to_read; i++) {
+ *((SAMPLE *)o_buf) = *((SAMPLE *) read_frame_at_cursor_fb(fb));
+ o_buf += sizeof(SAMPLE);
+ }
+
+ } else {
+ *((SAMPLE *)o_buf) = 0;
+ }
+
+ write_to_o_buff = 0;
+
+ }
+
+ return paContinue;
+}
+
+
+static void setParameters( PaDeviceIndex device,
+ PaStreamParameters* parameters )
+{
+ parameters->device = Pa_GetDefaultInputDevice();
+ parameters->channelCount = 1;
+ parameters->hostApiSpecificStreamInfo = NULL;
+ parameters->suggestedLatency = Pa_GetDeviceInfo(device)->defaultHighInputLatency;
+}
+
+
+static PaError set_stream( int type, // 0 = input, 1 = output
+ PaStream* stream,
+ PaDeviceIndex device,
+ PaStreamCallback* callback,
+ void* frameBuffer )
+{
+ PaError err;
+ PaStreamParameters streamParameters;
+
+ setParameters(device, &streamParameters);
+
+ if (type == 0) {
+ err = Pa_OpenStream( &stream,
+ NULL,
+ &streamParameters,
+ SAMPLE_RATE,
+ FRAMES_PER_BUFFER,
+ paClipOff,
+ callback,
+ frameBuffer );
+ } else {
+ err = Pa_OpenStream( &stream,
+ &streamParameters,
+ NULL,
+ SAMPLE_RATE,
+ FRAMES_PER_BUFFER,
+ paClipOff,
+ callback,
+ frameBuffer );
+ }
+ if (err != paNoError) return err;
+
+ err = Pa_StartStream(stream);
+
+ return err;
+}
+
+
+void AH_initialize()
+{
+ PaError err = paNoError;
+
+ PaDeviceIndex inputDevice;
+ PaDeviceIndex outputDevice;
+ PaDeviceIndex defaultOutputDevice;
+ PaDeviceIndex defaultInputDevice;
+
+ PaStream* inputStream = NULL;
+ PaStream* outputStream = NULL;
+
+ init_fb(&inputFrameBuffer);
+ init_fb(&outputFrameBuffer);
+
+ sys_on = true;
+
+ while (sys_on) {
+
+ Pa_Initialize();
+
+ defaultInputDevice = Pa_GetDefaultInputDevice();
+ defaultOutputDevice = Pa_GetDefaultOutputDevice();
+ printf("Input: %i, Output: %i\n", defaultInputDevice, defaultOutputDevice);
+
+ if (inputDevice != defaultInputDevice) {
+ inputDevice = defaultInputDevice;
+ err = set_stream( 0,
+ inputStream,
+ inputDevice,
+ &input_callback,
+ &inputFrameBuffer );
+ }
+
+ if (outputDevice != defaultOutputDevice) {
+ outputDevice = defaultOutputDevice;
+ err = set_stream( 1,
+ outputStream,
+ outputDevice,
+ &output_callback,
+ &outputFrameBuffer );
+ }
+
+ sleep(1);
+
+ }
+
+ Pa_AbortStream(inputStream);
+ Pa_AbortStream(outputStream);
+
+ delete_fb(&inputFrameBuffer);
+ delete_fb(&outputFrameBuffer);
+
+ Pa_Terminate();
+ initialized = false;
+
+}
+
+void AH_terminate()
+{
+ printf("Terminating PA\n");
+ sys_on = false;
+
+ while(initialized) {
+ struct timespec t;
+ t.tv_sec = 0;
+ t.tv_nsec = 5000;
+ nanosleep(&t, &t);
+ }
+
+}
+
+
+void AH_fillInputBuffer()
+{
+ recording = true;
+}
+
+
+void AH_resetInputBuffer(void* data, size_t* byte_length)
+{
+ size_t len = sizeof(inputFrameBuffer.data);
+ char audioData[len];
+ data = audioData; // points to 0th el of audioData
+ byte_length = &len;
+
+ for(int i = 0; i < (int) len; i++) {
+ audioData[i] = inputFrameBuffer.data[i];
+ }
+
+ recording = false;
+ clear_fb(&inputFrameBuffer);
+}
+
+
+void AH_feedOutputBuffer(void* data, size_t* byte_length)
+{
+
+ // can't intert into buffer while it's being read from
+ while (write_to_o_buff == 2) {
+ struct timespec t;
+ t.tv_sec = 0;
+ t.tv_nsec = 5000;
+ nanosleep(&t, &t);
+ }
+
+ write_to_o_buff = 1;
+ insert_frames_fb(&outputFrameBuffer, data, (int) &byte_length);
+ write_to_o_buff = 0;
+
+}
+
+
--- /dev/null
+#ifndef AUDIO_HANDLER
+#define AUDIO_HANDLER
+
+
+void AH_initialize ();
+
+void AH_fillInputBuffer ();
+
+void AH_resetInputBuffer(void* data, size_t* byte_length);
+
+void AH_feedOutputBuffer(void* data, size_t* byte_length);
+
+void AH_terminate ();
+
+
+#endif
\ No newline at end of file
--- /dev/null
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+
+#include "frame_buffer.h"
+
+#define BYTES_PER_FRAME (2)
+#define INITIAL_FRAME_COUNT (480*100)
+
+
+#define ALPHA (2)
+
+
+
+void init_fb ( frame_buffer *fb ) {
+ fb->frames_used = 0;
+ fb->frames_free = INITIAL_FRAME_COUNT;
+ fb->data = (char *) malloc(BYTES_PER_FRAME*INITIAL_FRAME_COUNT);
+ fb->cursor = fb->data;
+}
+
+
+void delete_fb ( frame_buffer *fb ) {
+ fb->frames_used = 0;
+ fb->frames_free = 0;
+ fb->cursor = NULL;
+ free(fb->data);
+}
+
+
+void clear_fb ( frame_buffer *fb ) {
+ free(fb->data);
+ fb->data = (char *) malloc(BYTES_PER_FRAME*INITIAL_FRAME_COUNT);
+ fb->cursor = fb->data;
+ fb->frames_free = INITIAL_FRAME_COUNT;
+ fb->frames_used = 0;
+}
+
+
+void insert_frames_fb ( frame_buffer *fb, char *frame_data, int frames_len ) {
+
+ int frames = frames_len / BYTES_PER_FRAME;
+
+ int cursor_diff = fb->cursor - fb->data;
+ int data_len = (fb->frames_free+fb->frames_used)*BYTES_PER_FRAME;
+
+ if (frames > fb->frames_free) {
+ fb->data = realloc(fb->data, (data_len+frames_len)*ALPHA);
+ fb->cursor = fb->data+cursor_diff;
+
+ if (fb->frames_used*BYTES_PER_FRAME > data_len-cursor_diff) {
+ memmove(fb->data+data_len, fb->data, (fb->frames_used*BYTES_PER_FRAME)-(data_len-cursor_diff));
+ }
+ fb->frames_used += frames;
+ fb->frames_free = fb->frames_used;
+ }
+
+ data_len = (fb->frames_free+fb->frames_used)*BYTES_PER_FRAME;
+ if (fb->frames_used*BYTES_PER_FRAME > data_len-cursor_diff) {
+ memcpy(fb->data+((fb->frames_used*BYTES_PER_FRAME)-(data_len-cursor_diff)), frame_data, frames_len);
+ fb->frames_free -= frames;
+ fb->frames_used += frames;
+ return;
+ }
+ if (frames_len+(fb->frames_used*BYTES_PER_FRAME) > data_len-cursor_diff) {
+ int non_overlap = data_len - (cursor_diff+(fb->frames_used*BYTES_PER_FRAME));
+ int overlap = frames_len - non_overlap;
+ memcpy(fb->cursor+(fb->frames_used*BYTES_PER_FRAME), frame_data, non_overlap);
+ memcpy(fb->data, &(frame_data[non_overlap]), overlap);
+ fb->frames_free -= frames;
+ fb->frames_used += frames;
+ return;
+ }
+
+ memcpy(fb->cursor+(fb->frames_used*BYTES_PER_FRAME), frame_data, frames_len);
+ fb->frames_free -= frames;
+ fb->frames_used += frames;
+}
+
+
+void rewrite_frames_fb ( frame_buffer *fb, char *frame_data, int frames_len ) {
+ int frames = frames_len / BYTES_PER_FRAME;
+
+ if (frames > (fb->frames_used + fb->frames_free)) {
+ fb->data = realloc(fb->data, frames_len*ALPHA);
+ fb->frames_free = frames;
+ fb->frames_used = frames;
+ } else {
+ fb->frames_free = fb->frames_free + fb->frames_used - frames;
+ fb->frames_used = frames;
+ }
+ memcpy(fb->data, frame_data, frames_len);
+ fb->cursor = fb->data;
+}
+
+
+
+char* read_frame_at_cursor_fb ( frame_buffer *fb ) {
+ char *begin = fb->cursor;
+ int frames_free = fb->frames_free;
+ int frames_used = fb->frames_used;
+ char *data = fb->data;
+
+ if (frames_used == 0) {
+ return NULL;
+ }
+
+ fb->cursor += BYTES_PER_FRAME;
+ if (fb->cursor >= data + ((frames_free+frames_used)*BYTES_PER_FRAME)) {
+ fb->cursor = data;
+ }
+
+ fb->frames_free += 1;
+ fb->frames_used -= 1;
+
+ return begin;
+}
+
+
--- /dev/null
+#ifndef FRAME_BUFFER
+#define FRAME_BUFFER
+
+
+typedef struct {
+ int frames_free, frames_used;
+ char *data, *cursor;
+} frame_buffer;
+
+
+void init_fb ( frame_buffer *fb );
+
+void delete_fb ( frame_buffer *fb );
+
+void clear_fb ( frame_buffer *fb );
+
+void insert_frames_fb ( frame_buffer *fb, char *frame_data, int frames_len );
+
+void rewrite_frames_fb ( frame_buffer *fb, char *frame_data, int frames_len );
+
+char* read_frame_at_cursor_fb ( frame_buffer *fb );
+
+
+#endif
--- /dev/null
+IDIR =../include
+CC=gcc
+CFLAGS=-I$(IDIR)
+
+ODIR=obj
+LDIR =-L/usr/local/lib -L/usr/lib
+
+LIBS=-lportaudio
+
+_DEPS = audio_handler.h frame_buffer.h
+DEPS = $(patsubst %,$(IDIR)/%,$(_DEPS))
+
+_OBJ = audio_handler.o frame_buffer.o
+OBJ = $(patsubst %,$(ODIR)/%,$(_OBJ))
+
+
+$(ODIR)/%.o: %.c $(DEPS)
+ $(CC) -c -o $@ $< $(CFLAGS)
+
+nodeaudio: $(OBJ)
+ $(CC) -o $@ $^ $(CFLAGS) $(LDIR) $(LIBS)
+
+.PHONY: clean
+
+clean:
+ rm -f $(ODIR)/*.o *~ core $(INCDIR)/*~
\ No newline at end of file
--- /dev/null
+#include <assert.h>
+#include <node_api.h>
+#include <stdio.h>
+
+#include "audio_handler.h"
+
+
+#define DECLARE_NAPI_METHOD(name, func) { name, 0, func, 0, 0, 0, napi_default, 0 }
+
+napi_value Initialize(napi_env env, napi_callback_info info)
+{
+ (void) info;
+ AH_initialize();
+ return NULL;
+}
+
+napi_value FillInputBuffer(napi_env env, napi_callback_info info)
+{
+ (void) info;
+ AH_fillInputBuffer();
+ return NULL;
+}
+
+
+napi_value ReturnInputBuffer(napi_env env, napi_callback_info info)
+{
+ (void) info;
+ napi_status status;
+ void* data;
+ size_t byte_length;
+
+ AH_resetInputBuffer(&data, &byte_length);
+
+ napi_value buffer;
+ status = napi_create_arraybuffer( env,
+ byte_length,
+ &data,
+ &buffer );
+ assert(status == napi_ok);
+
+ return buffer;
+}
+
+
+static napi_value FeedOutputBuffer(napi_env env, napi_callback_info info)
+{
+ napi_status status;
+ void* data;
+ size_t byte_length;
+ napi_value arraybuffer;
+
+ size_t argc = 1; /* parse args */
+ napi_value args[1];
+ status = napi_get_cb_info(env, info, &argc, args, NULL, NULL);
+ assert(status == napi_ok);
+
+ arraybuffer = args[0];
+
+ status = napi_get_arraybuffer_info( env,
+ arraybuffer,
+ &data,
+ &byte_length );
+ assert(status == napi_ok);
+
+ AH_feedOutputBuffer(data, &byte_length);
+ return NULL;
+}
+
+
+napi_value Init(napi_env env, napi_value exports)
+{
+ napi_status status;
+
+ napi_property_descriptor desc[] = {
+ DECLARE_NAPI_METHOD("fill_input_buffer", FillInputBuffer),
+ DECLARE_NAPI_METHOD("return_input_buffer", ReturnInputBuffer),
+ DECLARE_NAPI_METHOD("feed_output_buffer", FeedOutputBuffer)
+ };
+
+ status = napi_define_properties(env, exports, 1, desc);
+
+ AH_initialize();
+
+ return exports;
+
+}
+
+
+NAPI_MODULE(NODE_GYP_MODULE_NAME, Init)
+
--- /dev/null
+#include <stdio.h>
+#include <unistd.h>
+#include <pthread.h>
+// #include "audio_handler.h"
+
+#include <portaudio.h>
+
+// int main() {
+// printf("PA init test.\n");
+
+// pthread_t in_th;
+// printf("Creating audio thread.\n");
+// pthread_create(&in_th, NULL, (void *) AH_initialize, NULL);
+
+// sleep(10);
+
+// AH_terminate();
+
+// return 0;
+
+// }
+
+
+int main ()
+{
+
+ printf("Initializing portaudio\n");
+ Pa_Initialize();
+
+ for (int i = 0; i < 10; ++i)
+ {
+ PaHostApiIndex hostApi = Pa_GetDefaultHostApi();
+ const PaHostApiInfo* hostApiInfo = Pa_GetHostApiInfo(hostApi);
+
+ printf("Default input id: %i\n", hostApiInfo->defaultInputDevice);
+
+ sleep(2);
+ }
+
+ Pa_Terminate();
+
+ return 0;
+
+}
\ No newline at end of file