initial commit
This commit is contained in:
commit
1d75db5bde
33 changed files with 2327 additions and 0 deletions
BIN
.DS_Store
vendored
Normal file
BIN
.DS_Store
vendored
Normal file
Binary file not shown.
16
binding.gyp
Normal file
16
binding.gyp
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"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"
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
28
binding.js
Normal file
28
binding.js
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
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);
|
||||
342
build/Makefile
Normal file
342
build/Makefile
Normal file
|
|
@ -0,0 +1,342 @@
|
|||
# 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
|
||||
1
build/Release/.deps/Release/nodeaudio.node.d
Normal file
1
build/Release/.deps/Release/nodeaudio.node.d
Normal file
|
|
@ -0,0 +1 @@
|
|||
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
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
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:
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
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:
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
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:
|
||||
BIN
build/Release/nodeaudio.node
Executable file
BIN
build/Release/nodeaudio.node
Executable file
Binary file not shown.
BIN
build/Release/obj.target/nodeaudio/src/audio_handler.o
Normal file
BIN
build/Release/obj.target/nodeaudio/src/audio_handler.o
Normal file
Binary file not shown.
BIN
build/Release/obj.target/nodeaudio/src/frame_buffer.o
Normal file
BIN
build/Release/obj.target/nodeaudio/src/frame_buffer.o
Normal file
Binary file not shown.
BIN
build/Release/obj.target/nodeaudio/src/nodeaudio.o
Normal file
BIN
build/Release/obj.target/nodeaudio/src/nodeaudio.o
Normal file
Binary file not shown.
6
build/binding.Makefile
Normal file
6
build/binding.Makefile
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
# This file is generated by gyp; do not edit.
|
||||
|
||||
export builddir_name ?= ./build/.
|
||||
.PHONY: all
|
||||
all:
|
||||
$(MAKE) nodeaudio
|
||||
200
build/config.gypi
Normal file
200
build/config.gypi
Normal file
|
|
@ -0,0 +1,200 @@
|
|||
# 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": ""
|
||||
}
|
||||
}
|
||||
615
build/gyp-mac-tool
Executable file
615
build/gyp-mac-tool
Executable file
|
|
@ -0,0 +1,615 @@
|
|||
#!/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:]))
|
||||
195
build/nodeaudio.target.mk
Normal file
195
build/nodeaudio.target.mk
Normal file
|
|
@ -0,0 +1,195 @@
|
|||
# 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
|
||||
|
||||
97
node_modules/bindings/README.md
generated
vendored
Normal file
97
node_modules/bindings/README.md
generated
vendored
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
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.
|
||||
166
node_modules/bindings/bindings.js
generated
vendored
Normal file
166
node_modules/bindings/bindings.js
generated
vendored
Normal file
|
|
@ -0,0 +1,166 @@
|
|||
|
||||
/**
|
||||
* 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, '..')
|
||||
}
|
||||
}
|
||||
29
node_modules/bindings/package.json
generated
vendored
Normal file
29
node_modules/bindings/package.json
generated
vendored
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
{
|
||||
"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"
|
||||
}
|
||||
13
package-lock.json
generated
Normal file
13
package-lock.json
generated
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"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="
|
||||
}
|
||||
}
|
||||
}
|
||||
14
package.json
Normal file
14
package.json
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"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
|
||||
}
|
||||
BIN
src/.DS_Store
vendored
Normal file
BIN
src/.DS_Store
vendored
Normal file
Binary file not shown.
BIN
src/a.out
Executable file
BIN
src/a.out
Executable file
Binary file not shown.
259
src/audio_handler.c
Normal file
259
src/audio_handler.c
Normal file
|
|
@ -0,0 +1,259 @@
|
|||
#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;
|
||||
|
||||
}
|
||||
|
||||
|
||||
16
src/audio_handler.h
Normal file
16
src/audio_handler.h
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
#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
|
||||
BIN
src/audio_handler.o
Normal file
BIN
src/audio_handler.o
Normal file
Binary file not shown.
120
src/frame_buffer.c
Normal file
120
src/frame_buffer.c
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
#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;
|
||||
}
|
||||
|
||||
|
||||
24
src/frame_buffer.h
Normal file
24
src/frame_buffer.h
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
#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
|
||||
BIN
src/frame_buffer.o
Normal file
BIN
src/frame_buffer.o
Normal file
Binary file not shown.
26
src/makefile
Normal file
26
src/makefile
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
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)/*~
|
||||
BIN
src/nodeaudio
Executable file
BIN
src/nodeaudio
Executable file
Binary file not shown.
90
src/nodeaudio.c
Normal file
90
src/nodeaudio.c
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
#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)
|
||||
|
||||
44
src/test.c
Normal file
44
src/test.c
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
#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;
|
||||
|
||||
}
|
||||
Loading…
Reference in a new issue