├── app
├── .gitignore
├── src
│ └── main
│ │ ├── res
│ │ ├── values
│ │ │ ├── strings.xml
│ │ │ ├── colors.xml
│ │ │ └── styles.xml
│ │ ├── mipmap-hdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_round.png
│ │ ├── mipmap-mdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_round.png
│ │ ├── mipmap-xhdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxhdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxxhdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_round.png
│ │ ├── mipmap-anydpi-v26
│ │ │ ├── ic_launcher.xml
│ │ │ └── ic_launcher_round.xml
│ │ ├── drawable-v24
│ │ │ └── ic_launcher_foreground.xml
│ │ └── drawable
│ │ │ └── ic_launcher_background.xml
│ │ ├── AndroidManifest.xml
│ │ └── java
│ │ └── com
│ │ └── spotify
│ │ └── nfdrivertest_android
│ │ └── MainActivity.java
├── proguard-rules.pro
└── build.gradle
├── ci
├── ci.json
├── osx.sh
├── windows.ps1
├── README.md
├── windows.py
├── ios.py
├── androidwindows.py
├── linux.sh
├── android.py
├── osx.py
├── androidlinux.py
├── nfbuildlinux.py
├── linux.py
├── nfbuildwindows.py
├── nfbuild.py
├── build_options.py
└── nfbuildosx.py
├── NFDriver.png
├── .gitmodules
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── libraries
├── lame.pch.h
└── CMakeLists.txt
├── appveyor.yml
├── CHANGELOG.md
├── CONTRIBUTING.md
├── gradle.properties
├── settings.gradle
├── .gitignore
├── source
├── cli
│ ├── CMakeLists.txt
│ └── NFDriverCLI.cpp
├── NFDriverFileAACImplementation.h
├── NFDriverFileMP3Implementation.h
├── NFDriverFileImplementation.h
├── NFDriverAdapter.h
├── CMakeLists.txt
├── NFDriver.cpp
├── NFDriverFileImplementation.cpp
├── NFDriverFileMP3Implementation.cpp
├── NFDriverFileAACImplementation.cpp
├── NFDriverAdapter.cpp
└── NFDriver_Windows.cpp
├── tools
└── generate-version.py
├── .circleci
└── config.yml
├── gradlew.bat
├── CMakeLists.txt
├── gradlew
├── include
└── NFDriver
│ └── NFDriver.h
├── .clang-format
├── README.md
└── LICENSE
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 | /.externalNativeBuild
3 |
--------------------------------------------------------------------------------
/ci/ci.json:
--------------------------------------------------------------------------------
1 | {
2 | "static_analyzer_exceptions": []
3 | }
--------------------------------------------------------------------------------
/NFDriver.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nativeformat/NFDriver/HEAD/NFDriver.png
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "libraries/lame"]
2 | path = libraries/lame
3 | url = https://github.com/ffmpegwasm/lame.git
4 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nativeformat/NFDriver/HEAD/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | NFDriverTest_Android
3 |
4 |
--------------------------------------------------------------------------------
/libraries/lame.pch.h:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | typedef int A_INT32_T;
5 | typedef float ieee754_float32_t;
6 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nativeformat/NFDriver/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nativeformat/NFDriver/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nativeformat/NFDriver/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nativeformat/NFDriver/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nativeformat/NFDriver/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nativeformat/NFDriver/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nativeformat/NFDriver/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nativeformat/NFDriver/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nativeformat/NFDriver/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nativeformat/NFDriver/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/appveyor.yml:
--------------------------------------------------------------------------------
1 | image:
2 | - Visual Studio 2017
3 |
4 | build_script:
5 | - git submodule update --init --recursive
6 | - ps: ci/windows.ps1
7 |
8 | artifacts:
9 | - path: build/output/libNFDriver.zip
10 | name: libNFDriver.zip
11 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 |
7 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Wed Feb 07 11:47:58 CET 2018
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip
7 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Change Log
2 | All notable changes to this project will be documented in this file. NFDriver adheres to [Semantic Versioning](http://semver.org/).
3 |
4 | --
5 |
6 | ## [1.0.0](https://github.com/spotify/NFDriver/releases/tag/1.0.0)
7 | _Released on 2018-07-30._
8 |
9 | ### Added
10 | * Initial release of NFDriver.
11 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing
2 | Contributions are welcomed. Open a pull-request or an issue.
3 |
4 | ## Code of conduct
5 | This project adheres to the [Open Code of Conduct][code-of-conduct]. By participating, you are expected to honor this code.
6 |
7 | [code-of-conduct]: https://github.com/spotify/code-of-conduct/blob/master/code-of-conduct.md
8 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | org.gradle.jvmargs=-Xmx1536m
13 |
14 | # When configured, Gradle will run in incubating parallel mode.
15 | # This option should only be used with decoupled projects. More details, visit
16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
17 | # org.gradle.parallel=true
18 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018 Spotify AB.
3 | *
4 | * Licensed to the Apache Software Foundation (ASF) under one
5 | * or more contributor license agreements. See the NOTICE file
6 | * distributed with this work for additional information
7 | * regarding copyright ownership. The ASF licenses this file
8 | * to you under the Apache License, Version 2.0 (the
9 | * "License"); you may not use this file except in compliance
10 | * with the License. You may obtain a copy of the License at
11 | *
12 | * http://www.apache.org/licenses/LICENSE-2.0
13 | *
14 | * Unless required by applicable law or agreed to in writing,
15 | * software distributed under the License is distributed on an
16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17 | * KIND, either express or implied. See the License for the
18 | * specific language governing permissions and limitations
19 | * under the License.
20 | */
21 | include ':app'
22 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Environment normalization:
2 | /.bundle
3 | /vendor/bundle
4 |
5 | # Xcode
6 | #
7 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
8 |
9 | ## Build generated
10 | build/
11 | DerivedData
12 |
13 | ## Various settings
14 | *.pbxuser
15 | !default.pbxuser
16 | *.mode1v3
17 | !default.mode1v3
18 | *.mode2v3
19 | !default.mode2v3
20 | *.perspectivev3
21 | !default.perspectivev3
22 | xcuserdata
23 | project.xcworkspace
24 |
25 | ## Other
26 | *.xccheckout
27 | *.moved-aside
28 | *.xcuserstate
29 | *.xcscmblueprint
30 | .DS_Store
31 |
32 | ## Obj-C/Swift specific
33 | *.hmap
34 | *.ipa
35 |
36 | # Carthage
37 | Carthage/Build
38 |
39 | # Ignore changes to our project.xcconfig that gets overridden by the build system
40 | project.xcconfig
41 |
42 | # Python
43 | *.egg*
44 | *.pyc
45 | nfdriver_env
46 |
47 | # Example Projects
48 | nfdrivertest
49 | NFDriverTest_Windows/Debug
50 | NFDriverTest_Windows/Release
51 | NFDriverTest_Windows/.vs
52 | NFDriverTest_Android/build
53 | NFDriverTest_Android/app/build
54 | NFDriverTest_Android/app/.externalNativeBuild
55 |
56 | /.gradle
--------------------------------------------------------------------------------
/libraries/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/lame/libmp3lame LAME_SOURCE_LIB)
2 | aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/lame/libmp3lame/vector/ LAME_SOURCE_LIB)
3 | aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/lame/mpglib LAME_SOURCE_LIB)
4 |
5 | if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin" AND NOT IOS AND NOT ANDROID)
6 | set(lame_CONFIG_FILE ${CMAKE_CURRENT_BINARY_DIR}/lame/config.h)
7 | #configure_file(${CMAKE_CURRENT_SOURCE_DIR}/lame/config.h.in ${lame_CONFIG_FILE})
8 | add_library(mp3lame SHARED ${LAME_SOURCE_LIB})
9 | target_compile_definitions(mp3lame PRIVATE HAVE_STDINT_H=1 HAVE_MPGLIB=1 DECODE_ON_THE_FLY=1 USE_FAST_LOG=1 TAKEHIRO_IEEE754_HACK=1 HAVE_MEMCPY=1)
10 | target_include_directories(mp3lame PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/lame/libmp3lame" "${CMAKE_CURRENT_SOURCE_DIR}/lame/mpglib" "${CMAKE_CURRENT_SOURCE_DIR}/lame")
11 | target_include_directories(mp3lame PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/lame/include")
12 | target_precompile_headers(mp3lame PRIVATE lame.pch.h)
13 | target_compile_options(mp3lame PRIVATE "-Wno-absolute-value" "-Wno-shift-negative-value" "-Wno-tautological-pointer-compare")
14 | set_target_properties(mp3lame PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lame")
15 | endif()
16 |
--------------------------------------------------------------------------------
/source/cli/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2018 Spotify AB.
2 | #
3 | # Licensed to the Apache Software Foundation (ASF) under one
4 | # or more contributor license agreements. See the NOTICE file
5 | # distributed with this work for additional information
6 | # regarding copyright ownership. The ASF licenses this file
7 | # to you under the Apache License, Version 2.0 (the
8 | # "License"); you may not use this file except in compliance
9 | # with the License. You may obtain a copy of the License at
10 | #
11 | # http://www.apache.org/licenses/LICENSE-2.0
12 | #
13 | # Unless required by applicable law or agreed to in writing,
14 | # software distributed under the License is distributed on an
15 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 | # KIND, either express or implied. See the License for the
17 | # specific language governing permissions and limitations
18 | # under the License.
19 | if(IOS)
20 | add_executable(NFDriverApp
21 | ${APP_TYPE}
22 | NFDriverCLI.cpp)
23 | set_target_properties(NFDriverApp
24 | PROPERTIES
25 | XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "iPhone Developer: My Name")
26 | target_link_libraries(NFDriverApp NFDriver)
27 | elseif(ANDROID_APP)
28 | add_library(NFDriverApp SHARED NFDriverCLI.cpp)
29 | target_link_libraries(NFDriverApp
30 | log
31 | android
32 | OpenSLES)
33 | else()
34 | add_executable(NFDriverCLI NFDriverCLI.cpp)
35 | target_link_libraries(NFDriverCLI NFDriver)
36 | endif()
37 |
--------------------------------------------------------------------------------
/app/src/main/java/com/spotify/nfdrivertest_android/MainActivity.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018 Spotify AB.
3 | *
4 | * Licensed to the Apache Software Foundation (ASF) under one
5 | * or more contributor license agreements. See the NOTICE file
6 | * distributed with this work for additional information
7 | * regarding copyright ownership. The ASF licenses this file
8 | * to you under the Apache License, Version 2.0 (the
9 | * "License"); you may not use this file except in compliance
10 | * with the License. You may obtain a copy of the License at
11 | *
12 | * http://www.apache.org/licenses/LICENSE-2.0
13 | *
14 | * Unless required by applicable law or agreed to in writing,
15 | * software distributed under the License is distributed on an
16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17 | * KIND, either express or implied. See the License for the
18 | * specific language governing permissions and limitations
19 | * under the License.
20 | */
21 | package com.spotify.nfdrivertest_android;
22 |
23 | import android.support.v7.app.AppCompatActivity;
24 | import android.os.Bundle;
25 |
26 | public class MainActivity extends AppCompatActivity {
27 | static {
28 | System.loadLibrary("NFDriverApp");
29 | }
30 |
31 | @Override
32 | protected void onCreate(Bundle savedInstanceState) {
33 | super.onCreate(savedInstanceState);
34 |
35 | nativeMain();
36 | }
37 |
38 | // Check the cpp folder for the native (C++) code. Nothing happens here in Java.
39 | public native void nativeMain();
40 | }
41 |
--------------------------------------------------------------------------------
/ci/osx.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | # Copyright (c) 2021 Spotify AB.
3 | #
4 | # Licensed to the Apache Software Foundation (ASF) under one
5 | # or more contributor license agreements. See the NOTICE file
6 | # distributed with this work for additional information
7 | # regarding copyright ownership. The ASF licenses this file
8 | # to you under the Apache License, Version 2.0 (the
9 | # "License"); you may not use this file except in compliance
10 | # with the License. You may obtain a copy of the License at
11 | #
12 | # http://www.apache.org/licenses/LICENSE-2.0
13 | #
14 | # Unless required by applicable law or agreed to in writing,
15 | # software distributed under the License is distributed on an
16 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17 | # KIND, either express or implied. See the License for the
18 | # specific language governing permissions and limitations
19 | # under the License.
20 |
21 | # Exit on any non-zero status
22 | set -e
23 |
24 | # Update submodules
25 | git submodule sync
26 | git submodule update --init --recursive
27 |
28 | # Install system dependencies
29 | brew install clang-format
30 | brew install ninja
31 | brew install cmake
32 |
33 | # Install virtualenv
34 | python3 -m venv nfdriver_env
35 | source nfdriver_env/bin/activate
36 |
37 | # Install Python Packages
38 | pip3 install pyyaml
39 | pip3 install flake8
40 | pip3 install cmakelint
41 |
42 | # Execute our python build tools
43 | if [ -n "$BUILD_IOS" ]; then
44 | python ci/ios.py "$@"
45 | else
46 | if [ -n "$BUILD_ANDROID" ]; then
47 | brew install android-ndk
48 |
49 | python ci/android.py "$@"
50 | else
51 | python ci/osx.py "$@"
52 | fi
53 | fi
54 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018 Spotify AB.
3 | *
4 | * Licensed to the Apache Software Foundation (ASF) under one
5 | * or more contributor license agreements. See the NOTICE file
6 | * distributed with this work for additional information
7 | * regarding copyright ownership. The ASF licenses this file
8 | * to you under the Apache License, Version 2.0 (the
9 | * "License"); you may not use this file except in compliance
10 | * with the License. You may obtain a copy of the License at
11 | *
12 | * http://www.apache.org/licenses/LICENSE-2.0
13 | *
14 | * Unless required by applicable law or agreed to in writing,
15 | * software distributed under the License is distributed on an
16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17 | * KIND, either express or implied. See the License for the
18 | * specific language governing permissions and limitations
19 | * under the License.
20 | */
21 | apply plugin: 'com.android.application'
22 |
23 | android {
24 | compileSdkVersion 26
25 | defaultConfig {
26 | applicationId "com.spotify.nfdrivertest_android"
27 | minSdkVersion 19
28 | targetSdkVersion 26
29 | versionCode 1
30 | versionName "1.0"
31 | externalNativeBuild {
32 | cmake {
33 | cppFlags ""
34 | arguments "-DANDROID_APP=1 -DANDROID=1"
35 | }
36 | }
37 | }
38 |
39 | sourceSets {
40 | main {
41 | jniLibs.srcDirs = ['src/main/cpp']
42 | }
43 | }
44 |
45 | externalNativeBuild {
46 | cmake {
47 | path "../CMakeLists.txt"
48 | }
49 | }
50 | }
51 |
52 | dependencies {
53 | implementation fileTree(dir: 'libs', include: ['*.jar'])
54 | implementation 'com.android.support:appcompat-v7:26.1.0'
55 | }
56 |
--------------------------------------------------------------------------------
/ci/windows.ps1:
--------------------------------------------------------------------------------
1 | <#
2 | * Copyright (c) 2018 Spotify AB.
3 | *
4 | * Licensed to the Apache Software Foundation (ASF) under one
5 | * or more contributor license agreements. See the NOTICE file
6 | * distributed with this work for additional information
7 | * regarding copyright ownership. The ASF licenses this file
8 | * to you under the Apache License, Version 2.0 (the
9 | * "License"); you may not use this file except in compliance
10 | * with the License. You may obtain a copy of the License at
11 | *
12 | * http://www.apache.org/licenses/LICENSE-2.0
13 | *
14 | * Unless required by applicable law or agreed to in writing,
15 | * software distributed under the License is distributed on an
16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17 | * KIND, either express or implied. See the License for the
18 | * specific language governing permissions and limitations
19 | * under the License.
20 | #>
21 | param (
22 | [string]$build = "windows"
23 | )
24 |
25 | Write-Host "NFDriver build process starting..."
26 | Write-Host $build
27 |
28 | try
29 | {
30 | # Upgrade pip or else the CI will complain
31 | c:\python27\python.exe -m pip install --upgrade pip
32 |
33 | # Start virtualenv
34 | pip install virtualenv
35 | virtualenv nfdriver_env
36 |
37 | & ./nfdriver_env/Scripts/activate.bat
38 |
39 | # Install Python Packages
40 | & nfdriver_env/Scripts/pip.exe install urllib3 `
41 | pyyaml `
42 | flake8 `
43 | cmakelint
44 |
45 | if($build -eq "android"){
46 | & nfdriver_env/Scripts/python.exe ci/androidwindows.py
47 | } else {
48 | & nfdriver_env/Scripts/python.exe ci/windows.py build
49 | }
50 |
51 | if($LASTEXITCODE -ne 0){
52 | exit $LASTEXITCODE
53 | }
54 |
55 | & ./nfdriver_env/Scripts/deactivate.bat
56 | }
57 | catch
58 | {
59 | echo $_.Exception|format-list -force
60 | exit 1
61 | }
62 |
--------------------------------------------------------------------------------
/tools/generate-version.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | '''
3 | * Copyright (c) 2018 Spotify AB.
4 | *
5 | * Licensed to the Apache Software Foundation (ASF) under one
6 | * or more contributor license agreements. See the NOTICE file
7 | * distributed with this work for additional information
8 | * regarding copyright ownership. The ASF licenses this file
9 | * to you under the Apache License, Version 2.0 (the
10 | * "License"); you may not use this file except in compliance
11 | * with the License. You may obtain a copy of the License at
12 | *
13 | * http://www.apache.org/licenses/LICENSE-2.0
14 | *
15 | * Unless required by applicable law or agreed to in writing,
16 | * software distributed under the License is distributed on an
17 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18 | * KIND, either express or implied. See the License for the
19 | * specific language governing permissions and limitations
20 | * under the License.
21 | '''
22 |
23 | from __future__ import print_function
24 |
25 | import os
26 | import subprocess
27 | import sys
28 |
29 |
30 | def main():
31 | output_dir = os.path.join(os.path.join('build', 'output'))
32 | if len(sys.argv) > 1:
33 | output_dir = sys.argv[1]
34 | if not os.path.exists(output_dir):
35 | os.makedirs(output_dir)
36 | print('Generating nfdriver_generated_header.h in ' + output_dir)
37 | generated_header_filename = os.path.join(output_dir, 'nfdriver_generated_header.h')
38 | generated_header = open(generated_header_filename, 'w')
39 | generated_header.write('// This is a generated header from generate-version.py\n')
40 | cwd = os.getcwd()
41 | git_count = subprocess.check_output(['git', 'rev-list', '--count', 'HEAD'], cwd = cwd).decode()
42 | git_describe = subprocess.check_output(['git', 'describe', '--always'], cwd = cwd).decode()
43 | generated_header.write('#define NFDRIVER_VERSION "' + str(git_count.strip()) + '-' + str(git_describe.strip()) + '"\n')
44 |
45 |
46 | if __name__ == "__main__":
47 | main()
48 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
12 |
13 |
19 |
22 |
25 |
26 |
27 |
28 |
34 |
35 |
--------------------------------------------------------------------------------
/source/NFDriverFileAACImplementation.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2021 Spotify AB.
3 | *
4 | * Licensed to the Apache Software Foundation (ASF) under one
5 | * or more contributor license agreements. See the NOTICE file
6 | * distributed with this work for additional information
7 | * regarding copyright ownership. The ASF licenses this file
8 | * to you under the Apache License, Version 2.0 (the
9 | * "License"); you may not use this file except in compliance
10 | * with the License. You may obtain a copy of the License at
11 | *
12 | * http://www.apache.org/licenses/LICENSE-2.0
13 | *
14 | * Unless required by applicable law or agreed to in writing,
15 | * software distributed under the License is distributed on an
16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17 | * KIND, either express or implied. See the License for the
18 | * specific language governing permissions and limitations
19 | * under the License.
20 | */
21 | #pragma once
22 |
23 | #include
24 |
25 | #include
26 | #include
27 | #include
28 |
29 | namespace nativeformat {
30 | namespace driver {
31 |
32 | class NFDriverFileAACImplementation : public NFDriver {
33 | public:
34 | bool isPlaying() const;
35 | void setPlaying(bool playing);
36 |
37 | NFDriverFileAACImplementation(void *clientdata,
38 | NF_STUTTER_CALLBACK stutter_callback,
39 | NF_RENDER_CALLBACK render_callback,
40 | NF_ERROR_CALLBACK error_callback,
41 | NF_WILL_RENDER_CALLBACK will_render_callback,
42 | NF_DID_RENDER_CALLBACK did_render_callback,
43 | const char *output_destination,
44 | int bitrate);
45 | ~NFDriverFileAACImplementation();
46 |
47 | private:
48 | void *_clientdata;
49 | const NF_STUTTER_CALLBACK _stutter_callback;
50 | const NF_RENDER_CALLBACK _render_callback;
51 | const NF_ERROR_CALLBACK _error_callback;
52 | const NF_WILL_RENDER_CALLBACK _will_render_callback;
53 | const NF_DID_RENDER_CALLBACK _did_render_callback;
54 | const std::string _output_destination;
55 | const int _bitrate;
56 |
57 | std::shared_ptr _thread;
58 | std::atomic _run;
59 |
60 | static void run(NFDriverFileAACImplementation *driver);
61 | };
62 |
63 | } // namespace driver
64 | } // namespace nativeformat
65 |
--------------------------------------------------------------------------------
/source/NFDriverFileMP3Implementation.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018 Spotify AB.
3 | *
4 | * Licensed to the Apache Software Foundation (ASF) under one
5 | * or more contributor license agreements. See the NOTICE file
6 | * distributed with this work for additional information
7 | * regarding copyright ownership. The ASF licenses this file
8 | * to you under the Apache License, Version 2.0 (the
9 | * "License"); you may not use this file except in compliance
10 | * with the License. You may obtain a copy of the License at
11 | *
12 | * http://www.apache.org/licenses/LICENSE-2.0
13 | *
14 | * Unless required by applicable law or agreed to in writing,
15 | * software distributed under the License is distributed on an
16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17 | * KIND, either express or implied. See the License for the
18 | * specific language governing permissions and limitations
19 | * under the License.
20 | */
21 | #pragma once
22 |
23 | #include
24 |
25 | #include
26 | #include
27 | #include
28 |
29 | namespace nativeformat {
30 | namespace driver {
31 |
32 | class NFDriverFileMP3Implementation : public NFDriver {
33 | public:
34 | bool isPlaying() const;
35 | void setPlaying(bool playing);
36 |
37 | NFDriverFileMP3Implementation(void *clientdata,
38 | NF_STUTTER_CALLBACK stutter_callback,
39 | NF_RENDER_CALLBACK render_callback,
40 | NF_ERROR_CALLBACK error_callback,
41 | NF_WILL_RENDER_CALLBACK will_render_callback,
42 | NF_DID_RENDER_CALLBACK did_render_callback,
43 | const char *output_destination,
44 | int bitrate);
45 | ~NFDriverFileMP3Implementation();
46 |
47 | private:
48 | void *_clientdata;
49 | const NF_STUTTER_CALLBACK _stutter_callback;
50 | const NF_RENDER_CALLBACK _render_callback;
51 | const NF_ERROR_CALLBACK _error_callback;
52 | const NF_WILL_RENDER_CALLBACK _will_render_callback;
53 | const NF_DID_RENDER_CALLBACK _did_render_callback;
54 | const std::string _output_destination;
55 | const int _bitrate;
56 |
57 | std::shared_ptr _thread;
58 | std::atomic _run;
59 |
60 | static void run(NFDriverFileMP3Implementation *driver);
61 | };
62 |
63 | } // namespace driver
64 | } // namespace nativeformat
65 |
--------------------------------------------------------------------------------
/ci/README.md:
--------------------------------------------------------------------------------
1 | # Continuous Integration
2 | Every pull request and merge to master trigger a set of CircleCI builds. See [config.yml](../.circleci/config.yml) for a complete list of builds.
3 |
4 | ## CI Build Scripts
5 | Each CircleCI build is configured to run one of the scripts in this directory, sometimes with additional command line arguments. See the individual CircleCI build configurations to view or edit the exact build pipeline commands. In general, each platform has a shell script that acts as an entry point (e.g. [osx.sh](osx.sh)) and invokes the appropriate python script (e.g. [osx.py](osx.py)). All of the platform-specific python scripts create build objects derived from [nfbuild.py](nfbuild.py). Some of the methods in the `NFBuild` python class are overriden for platform-specific functionality in the other `nfbuild*.py` files.
6 |
7 | ## Using CI Scripts Locally
8 | The ci scripts can be used to download dependencies, generate build files with CMake, compile targets, and run tests in local build environments as well.
9 |
10 | On OS X, the following commands may be useful. They all assume you have already cloned the project and all of its submodules.
11 |
12 | ### Build-in Help
13 |
14 | For a full-list of supported cmdline command, enter:
15 |
16 | ```
17 | sh ci/osx.sh --help
18 | ```
19 |
20 | ### Running the linter
21 | This will flag any style errors in python and CMake files, and edit C++ source files in place. It will not compile or run any targets.
22 | ```
23 | sh ci/osx.sh lint
24 | ```
25 |
26 | ### Running integration tests
27 | This will run the integration tests locally.
28 | If you want to skip project generation, add `-generateProject=0`.
29 | This command will not destroy the contents of your `cpp/build` folder.
30 | ```
31 | sh ci/osx.sh local_it
32 | ```
33 |
34 | ### Custom builds
35 | The CI scripts allow enabling/disabling any step of the build process.
36 | Options groups (or workflows) are specified without a preceding dash, and will activate a group of build steps.
37 | Additionally individual build steps can be turned on or off. For example, the command below runs the address sanitizer
38 | without wiping the build directory:
39 | ```
40 | sh ci/osx.sh address_sanitizer -makeBuildDirectory=0
41 | ```
42 |
43 | New build options can be added to the ci script by calling `buildOptions.addOption(optionName, optionHelpDescription)`.
44 |
45 | New workflows can be added by calling `buildOptions.addWorkflow(workflow_name, workflow_help_description, array_of_optionName)`.
46 |
47 | By convention, options should be in camel case, while workflows should use underscores.
--------------------------------------------------------------------------------
/source/NFDriverFileImplementation.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018 Spotify AB.
3 | *
4 | * Licensed to the Apache Software Foundation (ASF) under one
5 | * or more contributor license agreements. See the NOTICE file
6 | * distributed with this work for additional information
7 | * regarding copyright ownership. The ASF licenses this file
8 | * to you under the Apache License, Version 2.0 (the
9 | * "License"); you may not use this file except in compliance
10 | * with the License. You may obtain a copy of the License at
11 | *
12 | * http://www.apache.org/licenses/LICENSE-2.0
13 | *
14 | * Unless required by applicable law or agreed to in writing,
15 | * software distributed under the License is distributed on an
16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17 | * KIND, either express or implied. See the License for the
18 | * specific language governing permissions and limitations
19 | * under the License.
20 | */
21 | #pragma once
22 |
23 | #include
24 |
25 | #include
26 | #include
27 | #include
28 |
29 | namespace nativeformat {
30 | namespace driver {
31 |
32 | typedef enum : short {
33 | NFDriverFileWAVHeaderAudioFormatPCM = 1,
34 | NFDriverFileWAVHeaderAudioFormatIEEEFloat = 3
35 | } NFDriverFileWAVHeaderAudioFormat;
36 |
37 | class NFDriverFileImplementation : public NFDriver {
38 | public:
39 | bool isPlaying() const;
40 | void setPlaying(bool playing);
41 |
42 | NFDriverFileImplementation(void *clientdata,
43 | NF_STUTTER_CALLBACK stutter_callback,
44 | NF_RENDER_CALLBACK render_callback,
45 | NF_ERROR_CALLBACK error_callback,
46 | NF_WILL_RENDER_CALLBACK will_render_callback,
47 | NF_DID_RENDER_CALLBACK did_render_callback,
48 | const char *output_destination,
49 | NFDriverFileWAVHeaderAudioFormat wav_format);
50 | ~NFDriverFileImplementation();
51 |
52 | private:
53 | void *_clientdata;
54 | const NF_STUTTER_CALLBACK _stutter_callback;
55 | const NF_RENDER_CALLBACK _render_callback;
56 | const NF_ERROR_CALLBACK _error_callback;
57 | const NF_WILL_RENDER_CALLBACK _will_render_callback;
58 | const NF_DID_RENDER_CALLBACK _did_render_callback;
59 | const std::string _output_destination;
60 | const NFDriverFileWAVHeaderAudioFormat _wav_format;
61 |
62 | std::shared_ptr _thread;
63 | std::atomic _run;
64 |
65 | static void run(NFDriverFileImplementation *driver);
66 | };
67 |
68 | } // namespace driver
69 | } // namespace nativeformat
70 |
--------------------------------------------------------------------------------
/.circleci/config.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | jobs:
3 | buildlinuxclang:
4 | docker:
5 | - image: ubuntu:bionic
6 | steps:
7 | - checkout
8 | - run:
9 | name: Build Linux with clang
10 | command: sh ci/linux.sh clang_build
11 | - store_artifacts:
12 | path: build/output/libNFDriver.zip
13 | destination: libNFDriver.zip
14 | buildlinuxgcc:
15 | docker:
16 | - image: ubuntu:bionic
17 | steps:
18 | - checkout
19 | - run:
20 | name: Build Linux with gcc
21 | command: sh ci/linux.sh gcc_build
22 | - store_artifacts:
23 | path: build/output/libNFDriver.zip
24 | destination: libNFDriver.zip
25 | buildlinuxandroid:
26 | docker:
27 | - image: ubuntu:bionic
28 | steps:
29 | - checkout
30 | - run:
31 | name: Build Android
32 | command: BUILD_ANDROID=1 sh ci/linux.sh build
33 | - store_artifacts:
34 | path: libNFDriver-androidx86.zip
35 | destination: libNFDriver-androidx86.zip
36 | - store_artifacts:
37 | path: libNFDriver-androidArm64.zip
38 | destination: libNFDriver-androidArm64.zip
39 | buildmac:
40 | macos:
41 | xcode: "11.5.0"
42 | steps:
43 | - checkout
44 | - run:
45 | name: Build OSX
46 | command: sh ci/osx.sh build
47 | - store_artifacts:
48 | path: build/output/libNFDriver.zip
49 | destination: libNFDriver.zip
50 | buildmacios:
51 | macos:
52 | xcode: "11.5.0"
53 | steps:
54 | - checkout
55 | - run:
56 | name: Build iOS
57 | command: BUILD_IOS=1 sh ci/osx.sh build
58 | - store_artifacts:
59 | path: build/output/libNFDriver.zip
60 | destination: libNFDriver.zip
61 | buildmacandroid:
62 | macos:
63 | xcode: "11.5.0"
64 | steps:
65 | - checkout
66 | - run: brew update
67 | - run: git submodule sync
68 | - run: git submodule update --init --recursive
69 | # Android NDK does not pass.
70 | - run: sudo spctl --master-disable
71 | - run:
72 | name: Build Android
73 | command: BUILD_ANDROID=1 sh ci/osx.sh build
74 | - store_artifacts:
75 | path: libNFDriver-androidx86.zip
76 | destination: libNFDriver-androidx86.zip
77 | - store_artifacts:
78 | path: libNFDriver-androidArm64.zip
79 | destination: libNFDriver-androidArm64.zip
80 |
81 | workflows:
82 | version: 2
83 | build:
84 | jobs:
85 | - buildlinuxclang
86 | - buildlinuxgcc
87 | - buildlinuxandroid
88 | - buildmac
89 | - buildmacios
90 | - buildmacandroid
91 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/ci/windows.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | '''
3 | * Copyright (c) 2018 Spotify AB.
4 | *
5 | * Licensed to the Apache Software Foundation (ASF) under one
6 | * or more contributor license agreements. See the NOTICE file
7 | * distributed with this work for additional information
8 | * regarding copyright ownership. The ASF licenses this file
9 | * to you under the Apache License, Version 2.0 (the
10 | * "License"); you may not use this file except in compliance
11 | * with the License. You may obtain a copy of the License at
12 | *
13 | * http://www.apache.org/licenses/LICENSE-2.0
14 | *
15 | * Unless required by applicable law or agreed to in writing,
16 | * software distributed under the License is distributed on an
17 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18 | * KIND, either express or implied. See the License for the
19 | * specific language governing permissions and limitations
20 | * under the License.
21 | '''
22 |
23 | import sys
24 |
25 | from nfbuildwindows import NFBuildWindows
26 | from build_options import BuildOptions
27 |
28 |
29 | def main():
30 | buildOptions = BuildOptions()
31 | buildOptions.addOption("installDependencies", "Install dependencies")
32 | buildOptions.addOption("makeBuildDirectory",
33 | "Wipe existing build directory")
34 | buildOptions.addOption("generateProject", "Regenerate project")
35 | buildOptions.addOption("buildTargetCLI",
36 | "Build Target: CLI")
37 | buildOptions.addOption("buildTargetLibrary", "Build Target: Library")
38 | buildOptions.addOption("packageArtifacts", "Package the binary artifacts")
39 | buildOptions.setDefaultWorkflow("Empty workflow", [])
40 |
41 | buildOptions.addWorkflow("build", "Production Build", [
42 | 'installDependencies',
43 | 'makeBuildDirectory',
44 | 'generateProject',
45 | 'buildTargetCLI',
46 | 'buildTargetLibrary',
47 | 'packageArtifacts'
48 | ])
49 |
50 | options = buildOptions.parseArgs()
51 | buildOptions.verbosePrintBuildOptions(options)
52 |
53 | library_target = 'NFDriver'
54 | cli_target = 'NFDriverCLI'
55 | nfbuild = NFBuildWindows()
56 |
57 | if buildOptions.checkOption(options, 'installDependencies'):
58 | nfbuild.installDependencies()
59 |
60 | if buildOptions.checkOption(options, 'makeBuildDirectory'):
61 | nfbuild.makeBuildDirectory()
62 |
63 | if buildOptions.checkOption(options, 'generateProject'):
64 | nfbuild.generateProject(ios=True)
65 |
66 | if buildOptions.checkOption(options, 'buildTargetLibrary'):
67 | nfbuild.buildTarget(library_target)
68 |
69 | if buildOptions.checkOption(options, 'buildTargetCLI'):
70 | nfbuild.buildTarget(cli_target)
71 |
72 | if buildOptions.checkOption(options, "packageArtifacts"):
73 | nfbuild.packageArtifacts()
74 |
75 |
76 | if __name__ == "__main__":
77 | main()
78 |
--------------------------------------------------------------------------------
/ci/ios.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | '''
3 | * Copyright (c) 2018 Spotify AB.
4 | *
5 | * Licensed to the Apache Software Foundation (ASF) under one
6 | * or more contributor license agreements. See the NOTICE file
7 | * distributed with this work for additional information
8 | * regarding copyright ownership. The ASF licenses this file
9 | * to you under the Apache License, Version 2.0 (the
10 | * "License"); you may not use this file except in compliance
11 | * with the License. You may obtain a copy of the License at
12 | *
13 | * http://www.apache.org/licenses/LICENSE-2.0
14 | *
15 | * Unless required by applicable law or agreed to in writing,
16 | * software distributed under the License is distributed on an
17 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18 | * KIND, either express or implied. See the License for the
19 | * specific language governing permissions and limitations
20 | * under the License.
21 | '''
22 |
23 | import sys
24 |
25 | from nfbuildosx import NFBuildOSX
26 |
27 | from build_options import BuildOptions
28 |
29 |
30 | def main():
31 | buildOptions = BuildOptions()
32 | buildOptions.addOption("installDependencies", "Install dependencies")
33 | buildOptions.addOption("makeBuildDirectory",
34 | "Wipe existing build directory")
35 | buildOptions.addOption("generateProject", "Regenerate xcode project")
36 | buildOptions.addOption("buildTargetIphoneSimulator",
37 | "Build Target: iPhone Simulator")
38 | buildOptions.addOption("buildTargetIphoneOS", "Build Target: iPhone OS")
39 | buildOptions.addOption("staticAnalysis", "Run Static Analysis")
40 | buildOptions.addOption("packageArtifacts", "Package the artifacts produced by the build")
41 | buildOptions.setDefaultWorkflow("Empty workflow", [])
42 |
43 | buildOptions.addWorkflow("build", "Production Build", [
44 | 'installDependencies',
45 | 'makeBuildDirectory',
46 | 'generateProject',
47 | 'buildTargetIphoneSimulator',
48 | 'buildTargetIphoneOS',
49 | 'staticAnalysis',
50 | 'packageArtifacts'
51 | ])
52 |
53 | options = buildOptions.parseArgs()
54 | buildOptions.verbosePrintBuildOptions(options)
55 |
56 | library_target = 'NFDriver'
57 | nfbuild = NFBuildOSX()
58 |
59 | if buildOptions.checkOption(options, 'installDependencies'):
60 | nfbuild.installDependencies()
61 |
62 | if buildOptions.checkOption(options, 'makeBuildDirectory'):
63 | nfbuild.makeBuildDirectory()
64 |
65 | if buildOptions.checkOption(options, 'generateProject'):
66 | nfbuild.generateProject(ios=True)
67 |
68 | if buildOptions.checkOption(options, 'buildTargetIphoneSimulator'):
69 | nfbuild.buildTarget(library_target,
70 | sdk='iphonesimulator',
71 | arch='x86_64')
72 |
73 | if buildOptions.checkOption(options, 'buildTargetIphoneOS'):
74 | nfbuild.buildTarget(library_target, sdk='iphoneos', arch='arm64')
75 |
76 | if buildOptions.checkOption(options, 'staticAnalysis'):
77 | nfbuild.staticallyAnalyse(library_target,
78 | include_regex='source/.*')
79 | if buildOptions.checkOption(options, "packageArtifacts"):
80 | nfbuild.packageArtifacts()
81 |
82 |
83 | if __name__ == "__main__":
84 | main()
85 |
--------------------------------------------------------------------------------
/source/NFDriverAdapter.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018 Spotify AB.
3 | *
4 | * Licensed to the Apache Software Foundation (ASF) under one
5 | * or more contributor license agreements. See the NOTICE file
6 | * distributed with this work for additional information
7 | * regarding copyright ownership. The ASF licenses this file
8 | * to you under the Apache License, Version 2.0 (the
9 | * "License"); you may not use this file except in compliance
10 | * with the License. You may obtain a copy of the License at
11 | *
12 | * http://www.apache.org/licenses/LICENSE-2.0
13 | *
14 | * Unless required by applicable law or agreed to in writing,
15 | * software distributed under the License is distributed on an
16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17 | * KIND, either express or implied. See the License for the
18 | * specific language governing permissions and limitations
19 | * under the License.
20 | */
21 | #pragma once
22 |
23 | #include
24 |
25 | namespace nativeformat {
26 | namespace driver {
27 |
28 | struct NFDriverAdapterInternals;
29 |
30 | // This class connects audio I/O to the audio provider (the player for example).
31 | // It will always ask the audio provider for 2 channels interleaved audio, with
32 | // fixed buffer size and fixed samplerate (in NFDriver.h). The class performs
33 | // buffering, resampling and deinterleaving automatically as needed.
34 |
35 | class NFDriverAdapter {
36 | public:
37 | NFDriverAdapter(void *clientdata,
38 | NF_STUTTER_CALLBACK stutter_callback,
39 | NF_RENDER_CALLBACK render_callback,
40 | NF_ERROR_CALLBACK error_callback,
41 | NF_WILL_RENDER_CALLBACK will_render_callback,
42 | NF_DID_RENDER_CALLBACK did_render_callback);
43 | ~NFDriverAdapter();
44 |
45 | static int getOptimalNumberOfFrames(int samplerate); // Returns with the ideal
46 | // number of frames for
47 | // the specific
48 | // samplerate for minimal
49 | // buffering and latency.
50 |
51 | void setSamplerate(int samplerate); // Thread-safe, can be called in any thread.
52 | bool getFrames(float *outputLeft,
53 | float *outputRight,
54 | int numFrames,
55 | int numChannels); // Should be called in the audio
56 | // processing/rendering callback of the audio
57 | // I/O.
58 |
59 | private:
60 | NFDriverAdapterInternals *internals;
61 | };
62 |
63 | struct NFSoundCardDriverInternals;
64 |
65 | class NFSoundCardDriver : public NFDriver {
66 | public:
67 | bool isPlaying() const;
68 | void setPlaying(bool playing);
69 |
70 | NFSoundCardDriver(void *clientdata,
71 | NF_STUTTER_CALLBACK stutter_callback,
72 | NF_RENDER_CALLBACK render_callback,
73 | NF_ERROR_CALLBACK error_callback,
74 | NF_WILL_RENDER_CALLBACK will_render_callback,
75 | NF_DID_RENDER_CALLBACK did_render_callback);
76 | ~NFSoundCardDriver();
77 |
78 | private:
79 | NFSoundCardDriverInternals *internals;
80 | };
81 |
82 | } // namespace driver
83 | } // namespace nativeformat
84 |
--------------------------------------------------------------------------------
/source/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2018 Spotify AB.
2 | #
3 | # Licensed to the Apache Software Foundation (ASF) under one
4 | # or more contributor license agreements. See the NOTICE file
5 | # distributed with this work for additional information
6 | # regarding copyright ownership. The ASF licenses this file
7 | # to you under the Apache License, Version 2.0 (the
8 | # "License"); you may not use this file except in compliance
9 | # with the License. You may obtain a copy of the License at
10 | #
11 | # http://www.apache.org/licenses/LICENSE-2.0
12 | #
13 | # Unless required by applicable law or agreed to in writing,
14 | # software distributed under the License is distributed on an
15 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 | # KIND, either express or implied. See the License for the
17 | # specific language governing permissions and limitations
18 | # under the License.
19 | set(SOURCE_FILES
20 | ../include/NFDriver/NFDriver.h
21 | NFDriverAdapter.h
22 | NFDriverAdapter.cpp
23 | NFDriver.cpp
24 | NFDriverFileImplementation.h
25 | NFDriverFileImplementation.cpp)
26 | set(LINK_LIBRARIES)
27 |
28 | if(${CMAKE_SYSTEM_NAME} MATCHES "Linux" AND NOT ANDROID)
29 | list(APPEND
30 | SOURCE_FILES
31 | NFDriver_Linux.cpp
32 | NFDriverFileMP3Implementation.h
33 | NFDriverFileMP3Implementation.cpp)
34 | find_package(ALSA REQUIRED)
35 | set(THREADS_PREFER_PTHREAD_FLAG ON)
36 | find_package(Threads REQUIRED)
37 | list(APPEND
38 | LINK_LIBRARIES
39 | ${ALSA_LIBRARIES}
40 | ${CMAKE_THREAD_LIBS_INIT}
41 | ${CMAKE_DL_LIBS})
42 | endif()
43 |
44 | if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin" AND NOT IOS AND NOT ANDROID)
45 | list(APPEND
46 | SOURCE_FILES
47 | NFDriver_MacOSX.cpp
48 | NFDriverFileMP3Implementation.h
49 | NFDriverFileMP3Implementation.cpp
50 | NFDriverFileAACImplementation.h
51 | NFDriverFileAACImplementation.cpp)
52 | find_library(AUDIO_UNIT AudioUnit)
53 | find_library(CORE_AUDIO CoreAudio)
54 | find_library(AUDIO_TOOLBOX AudioToolbox)
55 | find_library(CORE_FOUNDATION CoreFoundation)
56 | list(APPEND
57 | LINK_LIBRARIES
58 | ${AUDIO_UNIT}
59 | ${CORE_AUDIO}
60 | ${AUDIO_TOOLBOX}
61 | ${CORE_FOUNDATION})
62 | endif()
63 |
64 | if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin" AND IOS AND NOT ANDROID)
65 | list(APPEND
66 | SOURCE_FILES
67 | NFDriver_iOS.mm
68 | NFDriverFileAACImplementation.h
69 | NFDriverFileAACImplementation.cpp)
70 | find_library(AVFOUNDATION AVFoundation)
71 | find_library(CORE_AUDIO CoreAudio)
72 | find_library(AUDIO_TOOLBOX AudioToolbox)
73 | list(APPEND
74 | LINK_LIBRARIES
75 | ${AVFOUNDATION}
76 | ${CORE_AUDIO}
77 | ${AUDIO_TOOLBOX})
78 | endif()
79 |
80 | if(WIN32 AND NOT ANDROID)
81 | list(APPEND
82 | SOURCE_FILES
83 | NFDriver_Windows.cpp)
84 | list(APPEND
85 | LINK_LIBRARIES
86 | dxva2.lib
87 | evr.lib
88 | mf.lib
89 | mfplat.lib
90 | mfplay.lib
91 | mfreadwrite.lib
92 | mfuuid.lib
93 | mmdevapi.lib)
94 | endif()
95 |
96 | if(ANDROID)
97 | list(APPEND
98 | SOURCE_FILES
99 | NFDriver_Android.cpp)
100 | endif()
101 |
102 | add_library(NFDriver STATIC ${SOURCE_FILES})
103 | target_include_directories(NFDriver
104 | PUBLIC
105 | ../include
106 | ${CMAKE_BINARY_DIR}/output
107 | ../libraries/lame/include)
108 | target_link_libraries(NFDriver ${LINK_LIBRARIES})
109 |
110 | if(NOT ANDROID)
111 | add_subdirectory(cli)
112 | endif()
113 |
--------------------------------------------------------------------------------
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2018 Spotify AB.
2 | #
3 | # Licensed to the Apache Software Foundation (ASF) under one
4 | # or more contributor license agreements. See the NOTICE file
5 | # distributed with this work for additional information
6 | # regarding copyright ownership. The ASF licenses this file
7 | # to you under the Apache License, Version 2.0 (the
8 | # "License"); you may not use this file except in compliance
9 | # with the License. You may obtain a copy of the License at
10 | #
11 | # http://www.apache.org/licenses/LICENSE-2.0
12 | #
13 | # Unless required by applicable law or agreed to in writing,
14 | # software distributed under the License is distributed on an
15 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 | # KIND, either express or implied. See the License for the
17 | # specific language governing permissions and limitations
18 | # under the License.
19 | cmake_minimum_required(VERSION 3.6)
20 |
21 | project(NFDriver)
22 |
23 | set(CMAKE_CXX_STANDARD 11)
24 | set(CMAKE_CXX_STANDARD_REQUIRED ON)
25 |
26 | if(LLVM_STDLIB)
27 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")
28 | endif()
29 |
30 | if(IOS)
31 | set(CMAKE_OSX_SYSROOT iphoneos)
32 | set(CMAKE_OSX_ARCHITECTURES $(ARCHS_STANDARD))
33 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -x objective-c++")
34 | link_directories(\${HOME}/\${SDKROOT}/lib)
35 | set(MACOSX_BUNDLE_GUI_IDENTIFIER "com.spotify.\${PRODUCT_NAME:identifier}")
36 | set(APP_TYPE MACOSX_BUNDLE)
37 | set(CMAKE_EXE_LINKER_FLAGS "-framework UIKit")
38 | endif()
39 |
40 | if(WIN32)
41 | set(WINDOWS_FLAGS "/W3")
42 | set(WINDOWS_FLAGS "${WINDOWS_FLAGS} /WX")
43 | set(WINDOWS_FLAGS "${WINDOWS_FLAGS} /bigobj")
44 | set(WINDOWS_FLAGS "${WINDOWS_FLAGS} /D_CRT_SECURE_NO_WARNINGS=1")
45 | set(WINDOWS_FLAGS "${WINDOWS_FLAGS} /wd4003")
46 | set(WINDOWS_FLAGS "${WINDOWS_FLAGS} /wd4018")
47 | set(WINDOWS_FLAGS "${WINDOWS_FLAGS} /wd4091")
48 | set(WINDOWS_FLAGS "${WINDOWS_FLAGS} /wd4200")
49 | set(WINDOWS_FLAGS "${WINDOWS_FLAGS} /wd4250")
50 | set(WINDOWS_FLAGS "${WINDOWS_FLAGS} /wd4275")
51 | set(WINDOWS_FLAGS "${WINDOWS_FLAGS} /wd4355")
52 | set(WINDOWS_FLAGS "${WINDOWS_FLAGS} /wd4520")
53 | set(WINDOWS_FLAGS "${WINDOWS_FLAGS} /wd4530")
54 | set(WINDOWS_FLAGS "${WINDOWS_FLAGS} /wd4996")
55 | set(WINDOWS_FLAGS "${WINDOWS_FLAGS} /wd4146")
56 | set(WINDOWS_FLAGS "${WINDOWS_FLAGS} /we4053")
57 | set(WINDOWS_FLAGS "${WINDOWS_FLAGS} /we4063")
58 | set(WINDOWS_FLAGS "${WINDOWS_FLAGS} /we4064")
59 | set(WINDOWS_FLAGS "${WINDOWS_FLAGS} /EHsc")
60 | set(WINDOWS_FLAGS "${WINDOWS_FLAGS} /wd4503")
61 | set(WINDOWS_FLAGS "${WINDOWS_FLAGS} /DWIN32")
62 | set(WINDOWS_FLAGS "${WINDOWS_FLAGS} /DUNICODE")
63 | set(WINDOWS_FLAGS "${WINDOWS_FLAGS} /D_UNICODE")
64 | set(WINDOWS_FLAGS "${WINDOWS_FLAGS} /D_WINDOWS")
65 | set(WINDOWS_FLAGS "${WINDOWS_FLAGS} /DNOMINMAX")
66 | set(WINDOWS_FLAGS "${WINDOWS_FLAGS} /D_WIN32_IE=0x0700")
67 | set(WINDOWS_FLAGS "${WINDOWS_FLAGS} /D_WIN32_WINNT=0xA00")
68 | set(WINDOWS_FLAGS "${WINDOWS_FLAGS} /ZW")
69 | set(WINDOWS_FLAGS "${WINDOWS_FLAGS} /wd4447")
70 | set(WINDOWS_LINKER_FLAGS "${WINDOWS_LINKER_FLAGS} /INCREMENTAL:NO")
71 | set(WINDOWS_LINKER_FLAGS "${WINDOWS_LINKER_FLAGS} /OPT:ICF")
72 | set(WINDOWS_LINKER_FLAGS "${WINDOWS_LINKER_FLAGS} /OPT:REF")
73 | set(CMAKE_C_FLAGS
74 | "${CMAKE_C_FLAGS} ${WINDOWS_FLAGS}")
75 | set(CMAKE_CXX_FLAGS
76 | "${CMAKE_CXX_FLAGS} ${WINDOWS_FLAGS}")
77 | set(CMAKE_EXE_LINKER_FLAGS
78 | "${CMAKE_EXE_LINKER_FLAGS} ${WINDOWS_LINKER_FLAGS}")
79 | endif()
80 |
81 | add_subdirectory(source)
82 | add_subdirectory(libraries)
83 |
84 | execute_process(COMMAND python
85 | "${CMAKE_CURRENT_SOURCE_DIR}/tools/generate-version.py"
86 | ${CMAKE_BINARY_DIR}/output
87 | WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
88 |
--------------------------------------------------------------------------------
/ci/androidwindows.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | '''
3 | * Copyright (c) 2018 Spotify AB.
4 | *
5 | * Licensed to the Apache Software Foundation (ASF) under one
6 | * or more contributor license agreements. See the NOTICE file
7 | * distributed with this work for additional information
8 | * regarding copyright ownership. The ASF licenses this file
9 | * to you under the Apache License, Version 2.0 (the
10 | * "License"); you may not use this file except in compliance
11 | * with the License. You may obtain a copy of the License at
12 | *
13 | * http://www.apache.org/licenses/LICENSE-2.0
14 | *
15 | * Unless required by applicable law or agreed to in writing,
16 | * software distributed under the License is distributed on an
17 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18 | * KIND, either express or implied. See the License for the
19 | * specific language governing permissions and limitations
20 | * under the License.
21 | '''
22 |
23 | import sys
24 |
25 | from nfbuildwindows import NFBuildWindows
26 | from build_options import BuildOptions
27 |
28 |
29 | def main():
30 | buildOptions = BuildOptions()
31 | buildOptions.addOption("installDependencies", "Install dependencies")
32 |
33 | buildOptions.addOption("makeBuildDirectoryX86",
34 | "Wipe existing build directory for X86 build.")
35 | buildOptions.addOption("generateProjectX86", "Regenerate project for X86 build")
36 |
37 | buildOptions.addOption("buildTargetLibraryX86", "Build Target: Library (X86)")
38 |
39 | buildOptions.addOption("makeBuildDirectoryArm64",
40 | "Wipe existing build directory for ARM64 build.")
41 | buildOptions.addOption("generateProjectArm64", "Regenerate project for ARM64 build")
42 |
43 | buildOptions.addOption("buildTargetLibraryArm64", "Build Target: Library (ARM64)")
44 |
45 | buildOptions.setDefaultWorkflow("Empty workflow", [])
46 |
47 | buildOptions.addWorkflow("build", "Production Build", [
48 | 'installDependencies',
49 | 'makeBuildDirectoryX86',
50 | 'generateProjectX86',
51 | 'buildTargetLibraryX86',
52 | 'makeBuildDirectoryArm64',
53 | 'generateProjectArm64',
54 | 'buildTargetLibraryArm64'
55 | ])
56 |
57 | buildOptions.addWorkflow("buildX86", "Production Build (X86)", [
58 | 'installDependencies',
59 | 'makeBuildDirectoryX86',
60 | 'generateProjectX86',
61 | 'buildTargetLibraryX86'
62 | ])
63 |
64 | buildOptions.addWorkflow("buildArm64", "Production Build (ARM64)", [
65 | 'installDependencies',
66 | 'makeBuildDirectoryArm64',
67 | 'generateProjectArm64',
68 | 'buildTargetLibraryArm64'
69 | ])
70 |
71 |
72 | options = buildOptions.parseArgs()
73 | buildOptions.verbosePrintBuildOptions(options)
74 |
75 | library_target = 'NFDriver'
76 | nfbuild = NFBuildWindows()
77 |
78 | if buildOptions.checkOption(options, 'installDependencies'):
79 | nfbuild.installDependencies(android=True)
80 |
81 | if buildOptions.checkOption(options, 'makeBuildDirectoryX86'):
82 | nfbuild.makeBuildDirectory()
83 |
84 | if buildOptions.checkOption(options, 'generateProjectX86'):
85 | nfbuild.generateProject(android=True, android_arm=False)
86 |
87 | if buildOptions.checkOption(options, 'buildTargetLibraryX86'):
88 | nfbuild.buildTarget(library_target)
89 |
90 | if buildOptions.checkOption(options, 'makeBuildDirectoryArm64'):
91 | nfbuild.makeBuildDirectory()
92 |
93 | if buildOptions.checkOption(options, 'generateProjectArm64'):
94 | nfbuild.generateProject(android=False, android_arm=True)
95 |
96 | if buildOptions.checkOption(options, 'buildTargetLibraryArm64'):
97 | nfbuild.buildTarget(library_target)
98 |
99 |
100 | if __name__ == "__main__":
101 | main()
102 |
103 |
104 |
--------------------------------------------------------------------------------
/ci/linux.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | # Copyright (c) 2021 Spotify AB.
3 | #
4 | # Licensed to the Apache Software Foundation (ASF) under one
5 | # or more contributor license agreements. See the NOTICE file
6 | # distributed with this work for additional information
7 | # regarding copyright ownership. The ASF licenses this file
8 | # to you under the Apache License, Version 2.0 (the
9 | # "License"); you may not use this file except in compliance
10 | # with the License. You may obtain a copy of the License at
11 | #
12 | # http://www.apache.org/licenses/LICENSE-2.0
13 | #
14 | # Unless required by applicable law or agreed to in writing,
15 | # software distributed under the License is distributed on an
16 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17 | # KIND, either express or implied. See the License for the
18 | # specific language governing permissions and limitations
19 | # under the License.
20 |
21 | # Exit on any non-zero status
22 | set -e
23 | pwd
24 |
25 | # Install basics
26 | apt-get -q update
27 | apt-get install sudo
28 |
29 | # Install system dependencies
30 | export PYTHON_VERSION="3.7.3"
31 | sudo apt-get update
32 | sudo apt-get install -y --no-install-recommends apt-utils software-properties-common
33 | sudo apt-get install -y --no-install-recommends build-essential \
34 | zlib1g-dev \
35 | libncurses5-dev \
36 | libgdbm-dev \
37 | libnss3-dev \
38 | libssl-dev \
39 | libreadline-dev \
40 | libffi-dev \
41 | wget \
42 | libbz2-dev \
43 | libsqlite3-dev \
44 | liblzma-dev
45 | wget --tries=5 "https://www.python.org/ftp/python/$PYTHON_VERSION/Python-$PYTHON_VERSION.tgz"
46 | tar -xf "Python-$PYTHON_VERSION.tgz"
47 | (
48 | cd "Python-$PYTHON_VERSION"
49 | ./configure --enable-loadable-sqlite-extensions
50 | make -j 8
51 | sudo make altinstall
52 | )
53 | sudo apt-get install -y --no-install-recommends python3-setuptools \
54 | libasound2-dev \
55 | clang-format-3.9 \
56 | ninja-build \
57 | clang-3.9 \
58 | libc++-dev \
59 | python-virtualenv \
60 | wget \
61 | libyaml-dev \
62 | python-dev \
63 | python3-dev \
64 | git \
65 | unzip \
66 | cmake \
67 | git \
68 | libc++abi-dev
69 | sudo apt-get install -y --reinstall binutils
70 |
71 | # Update submodules
72 | git submodule sync
73 | git submodule update --init --recursive
74 |
75 | # Install virtualenv
76 | python3.7 -m venv nfdriver_env
77 | . nfdriver_env/bin/activate
78 |
79 | # Install Python Packages
80 | pip3 install pyyaml \
81 | flake8 \
82 | cmakelint
83 |
84 | # Execute our python build tools
85 | if [ -n "$BUILD_ANDROID" ]; then
86 | # Install Android NDK
87 | wget https://dl.google.com/android/repository/android-ndk-r17b-linux-x86_64.zip
88 | unzip -q android-ndk-r17b-linux-x86_64.zip
89 | mv android-ndk-r17b ~/ndk
90 | chmod +x -R ~/ndk
91 |
92 | python ci/androidlinux.py "$@"
93 | else
94 | python ci/linux.py "$@"
95 | fi
96 |
--------------------------------------------------------------------------------
/source/cli/NFDriverCLI.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2021 Spotify AB.
3 | *
4 | * Licensed to the Apache Software Foundation (ASF) under one
5 | * or more contributor license agreements. See the NOTICE file
6 | * distributed with this work for additional information
7 | * regarding copyright ownership. The ASF licenses this file
8 | * to you under the Apache License, Version 2.0 (the
9 | * "License"); you may not use this file except in compliance
10 | * with the License. You may obtain a copy of the License at
11 | *
12 | * http://www.apache.org/licenses/LICENSE-2.0
13 | *
14 | * Unless required by applicable law or agreed to in writing,
15 | * software distributed under the License is distributed on an
16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17 | * KIND, either express or implied. See the License for the
18 | * specific language governing permissions and limitations
19 | * under the License.
20 | */
21 | #include
22 |
23 | #define _USE_MATH_DEFINES
24 | #include
25 | #include
26 | #include
27 |
28 | #if __APPLE__
29 | #include
30 |
31 | #include "TargetConditionals.h"
32 | #endif
33 |
34 | #ifdef __ANDROID__
35 | #include
36 | #include
37 | #endif
38 |
39 | #ifndef M_PI
40 | #define M_PI 3.14159265358979323846
41 | #endif
42 |
43 | static void stutterCallback(void *clientdata) {
44 | printf("stutter\n");
45 | }
46 |
47 | static void errorCallback(void *clientdata, const char *errorMessage, int errorCode) {
48 | printf("error %i: %s\n", errorCode, errorMessage);
49 | }
50 |
51 | static int renderCallback(void *clientdata, float *frames, int numberOfFrames) {
52 | const float *samplerate = reinterpret_cast(clientdata);
53 | const float multiplier =
54 | (2.0f * static_cast(M_PI) * *samplerate) / static_cast(NF_DRIVER_SAMPLERATE);
55 | static unsigned int sinewave = 0;
56 | float audio;
57 |
58 | for (int n = 0; n < numberOfFrames; n++) {
59 | audio = sinf(multiplier * sinewave++);
60 | *frames++ = audio;
61 | *frames++ = audio;
62 | }
63 |
64 | return numberOfFrames;
65 | }
66 |
67 | static void willRenderCallback(void *clientdata) {}
68 |
69 | static void didRenderCallback(void *clientdata) {}
70 |
71 | #ifdef __ANDROID__
72 | extern "C" JNIEXPORT void JNICALL
73 | Java_com_spotify_nfdrivertest_1android_MainActivity_nativeMain(JNIEnv *env, jobject self) {
74 | #else
75 | int main(int argc, const char *argv[]) {
76 | #endif
77 |
78 | std::cout << "NativeFormat Driver Command Line Interface " << nativeformat::driver::version()
79 | << std::endl;
80 |
81 | #ifdef __ANDROID__
82 | NFDriver::onAppLaunch(env, self, NULL, errorCallback);
83 | #endif
84 |
85 | #if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE || ANDROID
86 | const std::string samplerate_string = "44100.0";
87 | #else
88 | if (argc < 2) {
89 | std::cout << "Invalid number of arguments: ./NFDriver [samplerate]" << std::endl;
90 | return 1;
91 | }
92 | const std::string samplerate_string = argv[1];
93 | #endif
94 |
95 | float samplerate = std::stof(samplerate_string);
96 |
97 | nativeformat::driver::NFDriver *driver =
98 | nativeformat::driver::NFDriver::createNFDriver(&samplerate,
99 | stutterCallback,
100 | renderCallback,
101 | errorCallback,
102 | willRenderCallback,
103 | didRenderCallback,
104 | nativeformat::driver::OutputTypeSoundCard);
105 | driver->setPlaying(true);
106 |
107 | #if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
108 | while (true) {
109 | CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, true);
110 | }
111 | #elif !ANDROID
112 | std::cout << std::endl << "Press a key to exit...";
113 | std::cin.get();
114 | #endif
115 |
116 | driver->setPlaying(false);
117 |
118 | #ifndef __ANDROID__
119 | return 0;
120 | #endif
121 | }
122 |
--------------------------------------------------------------------------------
/ci/android.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | '''
3 | * Copyright (c) 2018 Spotify AB.
4 | *
5 | * Licensed to the Apache Software Foundation (ASF) under one
6 | * or more contributor license agreements. See the NOTICE file
7 | * distributed with this work for additional information
8 | * regarding copyright ownership. The ASF licenses this file
9 | * to you under the Apache License, Version 2.0 (the
10 | * "License"); you may not use this file except in compliance
11 | * with the License. You may obtain a copy of the License at
12 | *
13 | * http://www.apache.org/licenses/LICENSE-2.0
14 | *
15 | * Unless required by applicable law or agreed to in writing,
16 | * software distributed under the License is distributed on an
17 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18 | * KIND, either express or implied. See the License for the
19 | * specific language governing permissions and limitations
20 | * under the License.
21 | '''
22 |
23 | import sys
24 |
25 | from nfbuildosx import NFBuildOSX
26 | from build_options import BuildOptions
27 |
28 |
29 | def main():
30 | buildOptions = BuildOptions()
31 | buildOptions.addOption("installDependencies", "Install dependencies")
32 |
33 | buildOptions.addOption("makeBuildDirectoryX86",
34 | "Wipe existing build directory for X86 build.")
35 | buildOptions.addOption("generateProjectX86", "Regenerate project for X86 build")
36 |
37 | buildOptions.addOption("buildTargetLibraryX86", "Build Target: Library (X86)")
38 |
39 | buildOptions.addOption("makeBuildDirectoryArm64",
40 | "Wipe existing build directory for ARM64 build.")
41 | buildOptions.addOption("generateProjectArm64", "Regenerate project for ARM64 build")
42 | buildOptions.addOption("packageArtifacts", "Package the artifacts produced by the build")
43 | buildOptions.addOption("buildTargetLibraryArm64", "Build Target: Library (ARM64)")
44 |
45 | buildOptions.setDefaultWorkflow("Empty workflow", [])
46 |
47 | buildOptions.addWorkflow("build", "Production Build", [
48 | 'installDependencies',
49 | 'makeBuildDirectoryX86',
50 | 'generateProjectX86',
51 | 'buildTargetLibraryX86',
52 | 'packageArtifacts',
53 | 'makeBuildDirectoryArm64',
54 | 'generateProjectArm64',
55 | 'buildTargetLibraryArm64',
56 | 'packageArtifacts'
57 | ])
58 |
59 | buildOptions.addWorkflow("buildX86", "Production Build (X86)", [
60 | 'installDependencies',
61 | 'makeBuildDirectoryX86',
62 | 'generateProjectX86',
63 | 'buildTargetLibraryX86',
64 | 'packageArtifacts'
65 | ])
66 |
67 | buildOptions.addWorkflow("buildArm64", "Production Build (ARM64)", [
68 | 'installDependencies',
69 | 'makeBuildDirectoryArm64',
70 | 'generateProjectArm64',
71 | 'buildTargetLibraryArm64',
72 | 'packageArtifacts'
73 | ])
74 |
75 |
76 | options = buildOptions.parseArgs()
77 | buildOptions.verbosePrintBuildOptions(options)
78 |
79 | library_target = 'NFDriver'
80 | nfbuild = NFBuildOSX()
81 |
82 | if buildOptions.checkOption(options, 'installDependencies'):
83 | nfbuild.installDependencies(android=True)
84 |
85 | if buildOptions.checkOption(options, 'makeBuildDirectoryX86'):
86 | nfbuild.makeBuildDirectory()
87 |
88 | if buildOptions.checkOption(options, 'generateProjectX86'):
89 | nfbuild.generateProject(android=True, android_arm=False)
90 |
91 | if buildOptions.checkOption(options, 'buildTargetLibraryX86'):
92 | nfbuild.buildTarget(library_target)
93 |
94 | if buildOptions.checkOption(options, 'packageArtifacts'):
95 | nfbuild.packageArtifacts()
96 |
97 | if buildOptions.checkOption(options, 'makeBuildDirectoryArm64'):
98 | nfbuild.makeBuildDirectory()
99 |
100 | if buildOptions.checkOption(options, 'generateProjectArm64'):
101 | nfbuild.generateProject(android=True, android_arm=True)
102 |
103 | if buildOptions.checkOption(options, 'buildTargetLibraryArm64'):
104 | nfbuild.buildTarget(library_target)
105 |
106 | if buildOptions.checkOption(options, 'packageArtifacts'):
107 | nfbuild.packageArtifacts()
108 |
109 |
110 | if __name__ == "__main__":
111 | main()
112 |
--------------------------------------------------------------------------------
/ci/osx.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | '''
3 | * Copyright (c) 2018 Spotify AB.
4 | *
5 | * Licensed to the Apache Software Foundation (ASF) under one
6 | * or more contributor license agreements. See the NOTICE file
7 | * distributed with this work for additional information
8 | * regarding copyright ownership. The ASF licenses this file
9 | * to you under the Apache License, Version 2.0 (the
10 | * "License"); you may not use this file except in compliance
11 | * with the License. You may obtain a copy of the License at
12 | *
13 | * http://www.apache.org/licenses/LICENSE-2.0
14 | *
15 | * Unless required by applicable law or agreed to in writing,
16 | * software distributed under the License is distributed on an
17 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18 | * KIND, either express or implied. See the License for the
19 | * specific language governing permissions and limitations
20 | * under the License.
21 | '''
22 |
23 | import sys
24 |
25 | from nfbuildosx import NFBuildOSX
26 | from build_options import BuildOptions
27 |
28 |
29 | def main():
30 | buildOptions = BuildOptions()
31 | buildOptions.addOption("installDependencies", "Install dependencies")
32 |
33 | buildOptions.addOption("lintCmake", "Lint cmake files")
34 | buildOptions.addOption("lintCpp", "Lint CPP Files")
35 | buildOptions.addOption("lintCppWithInlineChange",
36 | "Lint CPP Files and fix them")
37 |
38 | buildOptions.addOption("makeBuildDirectory",
39 | "Wipe existing build directory")
40 | buildOptions.addOption("generateProject", "Regenerate xcode project")
41 |
42 | buildOptions.addOption("buildTargetCLI", "Build Target: CLI")
43 | buildOptions.addOption("buildTargetLibrary", "Build Target: Library")
44 |
45 | buildOptions.addOption("staticAnalysis", "Run Static Analysis")
46 |
47 | buildOptions.addOption("makeCLI", "Deploy CLI Binary")
48 | buildOptions.addOption("packageArtifacts", "Package the artifacts produced by the build")
49 |
50 | buildOptions.setDefaultWorkflow("Empty workflow", [])
51 |
52 | buildOptions.addWorkflow("lint", "Run lint workflow", [
53 | 'installDependencies',
54 | 'lintCmake',
55 | 'lintCppWithInlineChange'
56 | ])
57 |
58 | buildOptions.addWorkflow("build", "Production Build", [
59 | 'installDependencies',
60 | 'lintCmake',
61 | 'lintCpp',
62 | 'makeBuildDirectory',
63 | 'generateProject',
64 | 'buildTargetCLI',
65 | 'buildTargetLibrary',
66 | 'staticAnalysis',
67 | 'packageArtifacts'
68 | ])
69 |
70 | options = buildOptions.parseArgs()
71 | buildOptions.verbosePrintBuildOptions(options)
72 |
73 | nfbuild = NFBuildOSX()
74 | library_target = 'NFDriver'
75 | cli_target = 'NFDriverCLI'
76 |
77 | if buildOptions.checkOption(options, 'installDependencies'):
78 | nfbuild.installDependencies()
79 |
80 | if buildOptions.checkOption(options, 'lintCmake'):
81 | nfbuild.lintCmake()
82 |
83 | if buildOptions.checkOption(options, 'lintCppWithInlineChange'):
84 | nfbuild.lintCPP(make_inline_changes=True)
85 | elif buildOptions.checkOption(options, 'lintCpp'):
86 | nfbuild.lintCPP(make_inline_changes=False)
87 |
88 | if buildOptions.checkOption(options, 'makeBuildDirectory'):
89 | nfbuild.makeBuildDirectory()
90 |
91 | if buildOptions.checkOption(options, 'generateProject'):
92 | nfbuild.generateProject()
93 |
94 | if buildOptions.checkOption(options, 'buildTargetLibrary'):
95 | nfbuild.buildTarget(library_target)
96 | if buildOptions.checkOption(options, 'staticAnalysis'):
97 | nfbuild.staticallyAnalyse(library_target,
98 | include_regex='source/.*')
99 |
100 | if buildOptions.checkOption(options, 'buildTargetCLI'):
101 | nfbuild.buildTarget(cli_target)
102 | if buildOptions.checkOption(options, 'staticAnalysis'):
103 | nfbuild.staticallyAnalyse(cli_target,
104 | include_regex='source/.*')
105 | if buildOptions.checkOption(options, "packageArtifacts"):
106 | nfbuild.packageArtifacts()
107 |
108 |
109 | if __name__ == "__main__":
110 | main()
111 |
--------------------------------------------------------------------------------
/ci/androidlinux.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | '''
3 | * Copyright (c) 2018 Spotify AB.
4 | *
5 | * Licensed to the Apache Software Foundation (ASF) under one
6 | * or more contributor license agreements. See the NOTICE file
7 | * distributed with this work for additional information
8 | * regarding copyright ownership. The ASF licenses this file
9 | * to you under the Apache License, Version 2.0 (the
10 | * "License"); you may not use this file except in compliance
11 | * with the License. You may obtain a copy of the License at
12 | *
13 | * http://www.apache.org/licenses/LICENSE-2.0
14 | *
15 | * Unless required by applicable law or agreed to in writing,
16 | * software distributed under the License is distributed on an
17 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18 | * KIND, either express or implied. See the License for the
19 | * specific language governing permissions and limitations
20 | * under the License.
21 | '''
22 |
23 | import sys
24 |
25 | from nfbuildlinux import NFBuildLinux
26 | from build_options import BuildOptions
27 |
28 |
29 | def main():
30 | buildOptions = BuildOptions()
31 | buildOptions.addOption("installDependencies", "Install dependencies")
32 |
33 | buildOptions.addOption("makeBuildDirectoryX86",
34 | "Wipe existing build directory for X86 build.")
35 | buildOptions.addOption("generateProjectX86", "Regenerate project for X86 build")
36 |
37 | buildOptions.addOption("buildTargetLibraryX86", "Build Target: Library (X86)")
38 |
39 | buildOptions.addOption("makeBuildDirectoryArm64",
40 | "Wipe existing build directory for ARM64 build.")
41 | buildOptions.addOption("generateProjectArm64", "Regenerate project for ARM64 build")
42 | buildOptions.addOption("packageArtifacts", "Package the artifacts produced by the build")
43 | buildOptions.addOption("buildTargetLibraryArm64", "Build Target: Library (ARM64)")
44 |
45 | buildOptions.setDefaultWorkflow("Empty workflow", [])
46 |
47 | buildOptions.addWorkflow("build", "Production Build", [
48 | 'installDependencies',
49 | 'makeBuildDirectoryX86',
50 | 'generateProjectX86',
51 | 'buildTargetLibraryX86',
52 | 'packageArtifacts',
53 | 'makeBuildDirectoryArm64',
54 | 'generateProjectArm64',
55 | 'buildTargetLibraryArm64',
56 | 'packageArtifacts'
57 | ])
58 |
59 | buildOptions.addWorkflow("buildX86", "Production Build (X86)", [
60 | 'installDependencies',
61 | 'makeBuildDirectoryX86',
62 | 'generateProjectX86',
63 | 'buildTargetLibraryX86',
64 | 'packageArtifacts'
65 | ])
66 |
67 | buildOptions.addWorkflow("buildArm64", "Production Build (ARM64)", [
68 | 'installDependencies',
69 | 'makeBuildDirectoryArm64',
70 | 'generateProjectArm64',
71 | 'buildTargetLibraryArm64',
72 | 'packageArtifacts'
73 | ])
74 |
75 |
76 | options = buildOptions.parseArgs()
77 | buildOptions.verbosePrintBuildOptions(options)
78 |
79 | library_target = 'NFDriver'
80 | nfbuild = NFBuildLinux()
81 |
82 | if buildOptions.checkOption(options, 'installDependencies'):
83 | nfbuild.installDependencies(android=True)
84 |
85 | if buildOptions.checkOption(options, 'makeBuildDirectoryX86'):
86 | nfbuild.makeBuildDirectory()
87 |
88 | if buildOptions.checkOption(options, 'generateProjectX86'):
89 | nfbuild.generateProject(android=True, android_arm=False)
90 |
91 | if buildOptions.checkOption(options, 'buildTargetLibraryX86'):
92 | nfbuild.buildTarget(library_target)
93 |
94 | if buildOptions.checkOption(options, 'packageArtifacts'):
95 | nfbuild.packageArtifacts()
96 |
97 | if buildOptions.checkOption(options, 'makeBuildDirectoryArm64'):
98 | nfbuild.makeBuildDirectory()
99 |
100 | if buildOptions.checkOption(options, 'generateProjectArm64'):
101 | nfbuild.generateProject(android=True, android_arm=True)
102 |
103 | if buildOptions.checkOption(options, 'buildTargetLibraryArm64'):
104 | nfbuild.buildTarget(library_target)
105 |
106 | if buildOptions.checkOption(options, 'packageArtifacts'):
107 | nfbuild.packageArtifacts()
108 |
109 |
110 | if __name__ == "__main__":
111 | main()
112 |
--------------------------------------------------------------------------------
/ci/nfbuildlinux.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | '''
3 | * Copyright (c) 2018 Spotify AB.
4 | *
5 | * Licensed to the Apache Software Foundation (ASF) under one
6 | * or more contributor license agreements. See the NOTICE file
7 | * distributed with this work for additional information
8 | * regarding copyright ownership. The ASF licenses this file
9 | * to you under the Apache License, Version 2.0 (the
10 | * "License"); you may not use this file except in compliance
11 | * with the License. You may obtain a copy of the License at
12 | *
13 | * http://www.apache.org/licenses/LICENSE-2.0
14 | *
15 | * Unless required by applicable law or agreed to in writing,
16 | * software distributed under the License is distributed on an
17 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18 | * KIND, either express or implied. See the License for the
19 | * specific language governing permissions and limitations
20 | * under the License.
21 | '''
22 |
23 | import fnmatch
24 | import os
25 | import plistlib
26 | import re
27 | import shutil
28 | import subprocess
29 | import sys
30 |
31 | from distutils import dir_util
32 | from nfbuild import NFBuild
33 |
34 |
35 | class NFBuildLinux(NFBuild):
36 | clang_format_binary = 'clang-format-3.9'
37 |
38 | def __init__(self):
39 | super(self.__class__, self).__init__()
40 | self.project_file = 'build.ninja'
41 | self.cmake_binary = 'cmake'
42 | self.android_ndk_folder = '~/ndk'
43 | self.android = False
44 | self.android_arm = False
45 |
46 | def generateProject(self,
47 | ios=False,
48 | android=False,
49 | android_arm=False,
50 | gcc=False):
51 | self.android = android
52 | self.android_arm = android_arm
53 | cmake_call = [
54 | self.cmake_binary,
55 | '..',
56 | '-GNinja']
57 | if android or android_arm:
58 | android_abi = 'x86_64'
59 | android_toolchain_name = 'x86_64-llvm'
60 | if android_arm:
61 | android_abi = 'arm64-v8a'
62 | android_toolchain_name = 'arm64-llvm'
63 | cmake_call.extend([
64 | '-DANDROID=1',
65 | '-DCMAKE_TOOLCHAIN_FILE=' + self.android_ndk_folder + '/build/cmake/android.toolchain.cmake',
66 | '-DANDROID_NDK=' + self.android_ndk_folder,
67 | '-DANDROID_ABI=' + android_abi,
68 | '-DANDROID_NATIVE_API_LEVEL=21',
69 | '-DANDROID_TOOLCHAIN_NAME=' + android_toolchain_name])
70 | if gcc:
71 | cmake_call.extend(['-DLLVM_STDLIB=0'])
72 | else:
73 | cmake_call.extend(['-DLLVM_STDLIB=1'])
74 |
75 | cmake_result = subprocess.call(cmake_call, cwd=self.build_directory)
76 | if cmake_result != 0:
77 | sys.exit(cmake_result)
78 |
79 | def buildTarget(self, target, sdk='linux', arch='x87_64'):
80 | result = subprocess.call([
81 | 'ninja',
82 | '-C',
83 | self.build_directory,
84 | '-f',
85 | self.project_file,
86 | target])
87 | if result != 0:
88 | sys.exit(result)
89 |
90 | def packageArtifacts(self):
91 | lib_name = 'libNFDriver.a'
92 | cli_name = 'NFDriverCLI'
93 | output_folder = os.path.join(self.build_directory, 'output')
94 | artifacts_folder = os.path.join(output_folder, 'NFDriver')
95 | shutil.copytree('include', os.path.join(artifacts_folder, 'include'))
96 | source_folder = os.path.join(self.build_directory, 'source')
97 | lib_matches = self.find_file(source_folder, lib_name)
98 | cli_matches = self.find_file(source_folder, cli_name)
99 | shutil.copyfile(lib_matches[0], os.path.join(artifacts_folder, lib_name))
100 | if not self.android:
101 | shutil.copyfile(cli_matches[0], os.path.join(artifacts_folder, cli_name))
102 | output_zip = os.path.join(output_folder, 'libNFDriver.zip')
103 | self.make_archive(artifacts_folder, output_zip)
104 | if self.android:
105 | final_zip_name = 'libNFDriver-androidx86.zip'
106 | if self.android_arm:
107 | final_zip_name = 'libNFDriver-androidArm64.zip'
108 | shutil.copyfile(output_zip, final_zip_name)
109 |
--------------------------------------------------------------------------------
/ci/linux.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | '''
3 | * Copyright (c) 2021 Spotify AB.
4 | *
5 | * Licensed to the Apache Software Foundation (ASF) under one
6 | * or more contributor license agreements. See the NOTICE file
7 | * distributed with this work for additional information
8 | * regarding copyright ownership. The ASF licenses this file
9 | * to you under the Apache License, Version 2.0 (the
10 | * "License"); you may not use this file except in compliance
11 | * with the License. You may obtain a copy of the License at
12 | *
13 | * http://www.apache.org/licenses/LICENSE-2.0
14 | *
15 | * Unless required by applicable law or agreed to in writing,
16 | * software distributed under the License is distributed on an
17 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18 | * KIND, either express or implied. See the License for the
19 | * specific language governing permissions and limitations
20 | * under the License.
21 | '''
22 |
23 | import os
24 | import sys
25 |
26 | from nfbuildlinux import NFBuildLinux
27 | from build_options import BuildOptions
28 |
29 |
30 | def main():
31 | buildOptions = BuildOptions()
32 | buildOptions.addOption("installDependencies", "Install dependencies")
33 | buildOptions.addOption("lintCmake", "Lint cmake files")
34 | buildOptions.addOption("lintCppWithInlineChange",
35 | "Lint CPP Files and fix them")
36 |
37 | buildOptions.addOption("makeBuildDirectory",
38 | "Wipe existing build directory")
39 | buildOptions.addOption("generateProject", "Regenerate project")
40 |
41 | buildOptions.addOption("buildTargetCLI", "Build Target: CLI")
42 | buildOptions.addOption("buildTargetLibrary", "Build Target: Library")
43 | buildOptions.addOption("packageArtifacts", "Package the binary artifacts")
44 | buildOptions.addOption("gnuToolchain", "Build with gcc and libstdc++")
45 | buildOptions.addOption("llvmToolchain", "Build with clang and libc++")
46 |
47 | buildOptions.setDefaultWorkflow("Empty workflow", [])
48 |
49 | buildOptions.addWorkflow("lint", "Run lint workflow", [
50 | 'installDependencies',
51 | 'lintCmake',
52 | 'lintCppWithInlineChange'
53 | ])
54 |
55 | buildOptions.addWorkflow("clang_build", "Production build with clang", [
56 | 'llvmToolchain',
57 | 'installDependencies',
58 | 'lintCmake',
59 | 'makeBuildDirectory',
60 | 'generateProject',
61 | 'buildTargetLibrary',
62 | 'buildTargetCLI',
63 | 'packageArtifacts'
64 | ])
65 |
66 | buildOptions.addWorkflow("gcc_build", "Production build with gcc", [
67 | 'gnuToolchain',
68 | 'installDependencies',
69 | 'lintCmake',
70 | 'makeBuildDirectory',
71 | 'generateProject',
72 | 'buildTargetLibrary',
73 | 'buildTargetCLI',
74 | 'packageArtifacts'
75 | ])
76 |
77 | options = buildOptions.parseArgs()
78 | buildOptions.verbosePrintBuildOptions(options)
79 |
80 | library_target = 'NFDriver'
81 | cli_target = 'NFDriverCLI'
82 | nfbuild = NFBuildLinux()
83 |
84 | if buildOptions.checkOption(options, 'installDependencies'):
85 | nfbuild.installDependencies()
86 |
87 | if buildOptions.checkOption(options, 'lintCmake'):
88 | nfbuild.lintCmake()
89 |
90 | if buildOptions.checkOption(options, 'lintCppWithInlineChange'):
91 | nfbuild.lintCPP(make_inline_changes=True)
92 |
93 | if buildOptions.checkOption(options, 'makeBuildDirectory'):
94 | nfbuild.makeBuildDirectory()
95 |
96 | if buildOptions.checkOption(options, 'generateProject'):
97 | if buildOptions.checkOption(options, 'gnuToolchain'):
98 | os.environ['CC'] = 'gcc'
99 | os.environ['CXX'] = 'g++'
100 | nfbuild.generateProject(gcc=True)
101 | elif buildOptions.checkOption(options, 'llvmToolchain'):
102 | os.environ['CC'] = 'clang-3.9'
103 | os.environ['CXX'] = 'clang++-3.9'
104 | nfbuild.generateProject(gcc=False)
105 | else:
106 | nfbuild.generateProject()
107 |
108 | if buildOptions.checkOption(options, 'buildTargetCLI'):
109 | nfbuild.buildTarget(cli_target)
110 |
111 | if buildOptions.checkOption(options, 'buildTargetLibrary'):
112 | nfbuild.buildTarget(library_target)
113 |
114 | if buildOptions.checkOption(options, 'packageArtifacts'):
115 | nfbuild.packageArtifacts()
116 |
117 | if __name__ == "__main__":
118 | main()
119 |
--------------------------------------------------------------------------------
/ci/nfbuildwindows.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | '''
3 | * Copyright (c) 2018 Spotify AB.
4 | *
5 | * Licensed to the Apache Software Foundation (ASF) under one
6 | * or more contributor license agreements. See the NOTICE file
7 | * distributed with this work for additional information
8 | * regarding copyright ownership. The ASF licenses this file
9 | * to you under the Apache License, Version 2.0 (the
10 | * "License"); you may not use this file except in compliance
11 | * with the License. You may obtain a copy of the License at
12 | *
13 | * http://www.apache.org/licenses/LICENSE-2.0
14 | *
15 | * Unless required by applicable law or agreed to in writing,
16 | * software distributed under the License is distributed on an
17 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18 | * KIND, either express or implied. See the License for the
19 | * specific language governing permissions and limitations
20 | * under the License.
21 | '''
22 |
23 | import fnmatch
24 | import os
25 | import plistlib
26 | import re
27 | import shutil
28 | import subprocess
29 | import sys
30 |
31 | from distutils import dir_util
32 | from nfbuild import NFBuild
33 |
34 |
35 | class NFBuildWindows(NFBuild):
36 | def __init__(self):
37 | super(self.__class__, self).__init__()
38 | self.project_file = 'NFDriver.sln'
39 | self.cmake_binary = 'cmake'
40 | self.android = False
41 |
42 | def generateProject(self,
43 | ios=False,
44 | android=False,
45 | android_arm=False):
46 | cmake_call = [
47 | self.cmake_binary,
48 | '..',
49 | '-G']
50 | if android or android_arm:
51 | self.android = True
52 | self.build_project = 'build.ninja'
53 | android_abi = 'x86_64'
54 | android_toolchain_name = 'x86_64-llvm'
55 | if android_arm:
56 | android_abi = 'arm64-v8a'
57 | android_toolchain_name = 'arm64-llvm'
58 | cmake_call.extend([
59 | 'Ninja',
60 | '-DANDROID=1',
61 | '-DCMAKE_TOOLCHAIN_FILE=' + self.android_ndk_folder + '/build/cmake/android.toolchain.cmake',
62 | '-DANDROID_NDK=' + self.android_ndk_folder,
63 | '-DANDROID_ABI=' + android_abi,
64 | '-DANDROID_NATIVE_API_LEVEL=21',
65 | '-DANDROID_TOOLCHAIN_NAME=' + android_toolchain_name])
66 | else:
67 | cl_exe = 'cl.exe'
68 | rc_exe = 'rc.exe'
69 | link_exe = 'link.exe'
70 | cmake_call.extend([
71 | 'Visual Studio 15 2017 Win64',
72 | '-DCMAKE_SYSTEM_NAME=WindowsStore',
73 | '-DCMAKE_SYSTEM_VERSION=10.0'])
74 | cmake_result = subprocess.call(cmake_call, cwd=self.build_directory)
75 | if cmake_result != 0:
76 | sys.exit(cmake_result)
77 |
78 | def buildTarget(self, target, sdk='macosx', arch='x86_64'):
79 | result = 0
80 | if self.android:
81 | result = subprocess.call([
82 | self.ninja_binary,
83 | '-C',
84 | self.build_directory,
85 | '-f',
86 | self.project_file,
87 | target])
88 | else:
89 | result = subprocess.call([
90 | 'msbuild.exe',
91 | os.path.join(self.build_directory, 'NFDriver.sln'),
92 | '/t:NFDriver;' + target])
93 | if result != 0:
94 | sys.exit(result)
95 |
96 | def packageArtifacts(self):
97 | lib_name = 'NFDriver.lib'
98 | cli_name = 'NFDriverCLI.exe'
99 | output_folder = os.path.join(self.build_directory, 'output')
100 | artifacts_folder = os.path.join(output_folder, 'NFDriver')
101 | shutil.copytree('include', os.path.join(artifacts_folder, 'include'))
102 | source_folder = os.path.join(self.build_directory, 'source')
103 | lib_matches = self.find_file(source_folder, lib_name)
104 | cli_matches = self.find_file(source_folder, cli_name)
105 | shutil.copyfile(lib_matches[0], os.path.join(artifacts_folder, lib_name))
106 | if not self.android:
107 | shutil.copyfile(cli_matches[0], os.path.join(artifacts_folder, cli_name))
108 | output_zip = os.path.join(output_folder, 'libNFDriver.zip')
109 | self.make_archive(artifacts_folder, output_zip)
110 | if self.android:
111 | final_zip_name = 'libNFDriver-androidx86.zip'
112 | if self.android_arm:
113 | final_zip_name = 'libNFDriver-androidArm64.zip'
114 | shutil.copyfile(output_zip, final_zip_name)
115 |
--------------------------------------------------------------------------------
/source/NFDriver.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2021 Spotify AB.
3 | *
4 | * Licensed to the Apache Software Foundation (ASF) under one
5 | * or more contributor license agreements. See the NOTICE file
6 | * distributed with this work for additional information
7 | * regarding copyright ownership. The ASF licenses this file
8 | * to you under the Apache License, Version 2.0 (the
9 | * "License"); you may not use this file except in compliance
10 | * with the License. You may obtain a copy of the License at
11 | *
12 | * http://www.apache.org/licenses/LICENSE-2.0
13 | *
14 | * Unless required by applicable law or agreed to in writing,
15 | * software distributed under the License is distributed on an
16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17 | * KIND, either express or implied. See the License for the
18 | * specific language governing permissions and limitations
19 | * under the License.
20 | */
21 | #include
22 |
23 | #include
24 |
25 | #include "NFDriverAdapter.h"
26 | #include "NFDriverFileAACImplementation.h"
27 | #include "NFDriverFileImplementation.h"
28 | #include "NFDriverFileMP3Implementation.h"
29 | #include "nfdriver_generated_header.h"
30 |
31 | namespace nativeformat {
32 | namespace driver {
33 |
34 | const char *version() {
35 | return NFDRIVER_VERSION;
36 | }
37 |
38 | extern const std::string NF_DRIVER_BITRATE_KEY = "bitrate";
39 | extern const std::string NF_DRIVER_WAV_SIZE_KEY = "wavsize";
40 |
41 | int bitrateOption(const std::map &options) {
42 | if (options.count(NF_DRIVER_BITRATE_KEY)) {
43 | return std::stoi(options.at(NF_DRIVER_BITRATE_KEY));
44 | }
45 | return 128;
46 | }
47 |
48 | NFDriverFileWAVHeaderAudioFormat wavsizeOption(const std::map &options) {
49 | if (options.count(NF_DRIVER_WAV_SIZE_KEY)) {
50 | switch (std::stoi(options.at(NF_DRIVER_WAV_SIZE_KEY))) {
51 | case 16:
52 | return NFDriverFileWAVHeaderAudioFormatPCM;
53 | case 32:
54 | return NFDriverFileWAVHeaderAudioFormatIEEEFloat;
55 | default:
56 | assert(false && "Invalid wav size option, must be 16 or 32");
57 | }
58 | }
59 | return NFDriverFileWAVHeaderAudioFormatIEEEFloat;
60 | }
61 |
62 | NFDriver *NFDriver::createNFDriver(void *clientdata,
63 | NF_STUTTER_CALLBACK stutter_callback,
64 | NF_RENDER_CALLBACK render_callback,
65 | NF_ERROR_CALLBACK error_callback,
66 | NF_WILL_RENDER_CALLBACK will_render_callback,
67 | NF_DID_RENDER_CALLBACK did_render_callback,
68 | OutputType output_type,
69 | const char *output_destination,
70 | std::map options) {
71 | switch (output_type) {
72 | case OutputTypeSoundCard:
73 | return new NFSoundCardDriver(clientdata,
74 | stutter_callback,
75 | render_callback,
76 | error_callback,
77 | will_render_callback,
78 | did_render_callback);
79 | case OutputTypeFile:
80 | return new NFDriverFileImplementation(clientdata,
81 | stutter_callback,
82 | render_callback,
83 | error_callback,
84 | will_render_callback,
85 | did_render_callback,
86 | output_destination,
87 | wavsizeOption(options));
88 | case OutputTypeMP3File:
89 | #if _WIN32
90 | assert(false && "No support for MP3 file driver on windows.");
91 | #else
92 | return new NFDriverFileMP3Implementation(clientdata,
93 | stutter_callback,
94 | render_callback,
95 | error_callback,
96 | will_render_callback,
97 | did_render_callback,
98 | output_destination,
99 | bitrateOption(options));
100 | #endif
101 | case OutputTypeAACFile:
102 | #if __APPLE__
103 | return new NFDriverFileAACImplementation(clientdata,
104 | stutter_callback,
105 | render_callback,
106 | error_callback,
107 | will_render_callback,
108 | did_render_callback,
109 | output_destination,
110 | bitrateOption(options));
111 | #else
112 | assert(false && "No support for AAC file driver on this platform.");
113 | #endif
114 | }
115 | return 0;
116 | }
117 |
118 | } // namespace driver
119 | } // namespace nativeformat
120 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # Attempt to set APP_HOME
46 | # Resolve links: $0 may be a link
47 | PRG="$0"
48 | # Need this for relative symlinks.
49 | while [ -h "$PRG" ] ; do
50 | ls=`ls -ld "$PRG"`
51 | link=`expr "$ls" : '.*-> \(.*\)$'`
52 | if expr "$link" : '/.*' > /dev/null; then
53 | PRG="$link"
54 | else
55 | PRG=`dirname "$PRG"`"/$link"
56 | fi
57 | done
58 | SAVED="`pwd`"
59 | cd "`dirname \"$PRG\"`/" >/dev/null
60 | APP_HOME="`pwd -P`"
61 | cd "$SAVED" >/dev/null
62 |
63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
64 |
65 | # Determine the Java command to use to start the JVM.
66 | if [ -n "$JAVA_HOME" ] ; then
67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
68 | # IBM's JDK on AIX uses strange locations for the executables
69 | JAVACMD="$JAVA_HOME/jre/sh/java"
70 | else
71 | JAVACMD="$JAVA_HOME/bin/java"
72 | fi
73 | if [ ! -x "$JAVACMD" ] ; then
74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
75 |
76 | Please set the JAVA_HOME variable in your environment to match the
77 | location of your Java installation."
78 | fi
79 | else
80 | JAVACMD="java"
81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
82 |
83 | Please set the JAVA_HOME variable in your environment to match the
84 | location of your Java installation."
85 | fi
86 |
87 | # Increase the maximum file descriptors if we can.
88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
89 | MAX_FD_LIMIT=`ulimit -H -n`
90 | if [ $? -eq 0 ] ; then
91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
92 | MAX_FD="$MAX_FD_LIMIT"
93 | fi
94 | ulimit -n $MAX_FD
95 | if [ $? -ne 0 ] ; then
96 | warn "Could not set maximum file descriptor limit: $MAX_FD"
97 | fi
98 | else
99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
100 | fi
101 | fi
102 |
103 | # For Darwin, add options to specify how the application appears in the dock
104 | if $darwin; then
105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
106 | fi
107 |
108 | # For Cygwin, switch paths to Windows format before running java
109 | if $cygwin ; then
110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
112 | JAVACMD=`cygpath --unix "$JAVACMD"`
113 |
114 | # We build the pattern for arguments to be converted via cygpath
115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
116 | SEP=""
117 | for dir in $ROOTDIRSRAW ; do
118 | ROOTDIRS="$ROOTDIRS$SEP$dir"
119 | SEP="|"
120 | done
121 | OURCYGPATTERN="(^($ROOTDIRS))"
122 | # Add a user-defined pattern to the cygpath arguments
123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
125 | fi
126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
127 | i=0
128 | for arg in "$@" ; do
129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
131 |
132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
134 | else
135 | eval `echo args$i`="\"$arg\""
136 | fi
137 | i=$((i+1))
138 | done
139 | case $i in
140 | (0) set -- ;;
141 | (1) set -- "$args0" ;;
142 | (2) set -- "$args0" "$args1" ;;
143 | (3) set -- "$args0" "$args1" "$args2" ;;
144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
150 | esac
151 | fi
152 |
153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
154 | function splitJvmOpts() {
155 | JVM_OPTS=("$@")
156 | }
157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
159 |
160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
161 |
--------------------------------------------------------------------------------
/ci/nfbuild.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | '''
3 | * Copyright (c) 2018 Spotify AB.
4 | *
5 | * Licensed to the Apache Software Foundation (ASF) under one
6 | * or more contributor license agreements. See the NOTICE file
7 | * distributed with this work for additional information
8 | * regarding copyright ownership. The ASF licenses this file
9 | * to you under the Apache License, Version 2.0 (the
10 | * "License"); you may not use this file except in compliance
11 | * with the License. You may obtain a copy of the License at
12 | *
13 | * http://www.apache.org/licenses/LICENSE-2.0
14 | *
15 | * Unless required by applicable law or agreed to in writing,
16 | * software distributed under the License is distributed on an
17 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18 | * KIND, either express or implied. See the License for the
19 | * specific language governing permissions and limitations
20 | * under the License.
21 | '''
22 |
23 | import fnmatch
24 | import json
25 | import os
26 | import pprint
27 | import shutil
28 | import subprocess
29 | import sys
30 |
31 |
32 | class NFBuild(object):
33 | def __init__(self):
34 | ci_json_file = os.path.join('ci', 'ci.json')
35 | self.build_configuration = json.load(open(ci_json_file))
36 | self.pretty_printer = pprint.PrettyPrinter(indent=4)
37 | self.current_working_directory = os.getcwd()
38 | self.build_directory = 'build'
39 | self.output_directory = os.path.join(self.build_directory, 'output')
40 | self.statically_analyzed_files = []
41 | self.android = False
42 |
43 | def build_print(self, print_string):
44 | print(print_string)
45 | sys.stdout.flush()
46 |
47 | def makeBuildDirectory(self):
48 | if os.path.exists(self.build_directory):
49 | shutil.rmtree(self.build_directory)
50 | os.makedirs(self.build_directory)
51 | os.makedirs(self.output_directory)
52 |
53 | def installDependencies(self, android=False):
54 | self.android = android
55 |
56 | def generateProject(self,
57 | ios=False,
58 | android=False,
59 | android_arm=False):
60 | assert True, "generateProject should be overridden by subclass"
61 |
62 | def buildTarget(self, target, sdk='macosx'):
63 | assert True, "buildTarget should be overridden by subclass"
64 |
65 | def lintCPPFile(self, filepath, make_inline_changes=False):
66 | current_source = open(filepath, 'r').read()
67 | clang_format_call = [self.clang_format_binary]
68 | if make_inline_changes:
69 | clang_format_call.append('-i')
70 | clang_format_call.append(filepath)
71 | new_source = subprocess.check_output(clang_format_call).decode()
72 | if current_source != new_source and not make_inline_changes:
73 | self.build_print(
74 | filepath + " failed C++ lint, file should look like:")
75 | self.build_print(new_source)
76 | return False
77 | return True
78 |
79 | def lintCPPDirectory(self, directory, make_inline_changes=False):
80 | passed = True
81 | for root, dirnames, filenames in os.walk(directory):
82 | for filename in filenames:
83 | if not filename.endswith(('.cpp', '.h', '.m', '.mm')):
84 | continue
85 | full_filepath = os.path.join(root, filename)
86 | if not self.lintCPPFile(full_filepath, make_inline_changes):
87 | passed = False
88 | return passed
89 |
90 | def lintCPP(self, make_inline_changes=False):
91 | lint_result = self.lintCPPDirectory('source', make_inline_changes)
92 | lint_result &= self.lintCPPDirectory('include', make_inline_changes)
93 | if not lint_result:
94 | sys.exit(1)
95 |
96 | def lintCmakeFile(self, filepath):
97 | self.build_print("Linting: " + filepath)
98 | return subprocess.call(['cmakelint', filepath]) == 0
99 |
100 | def lintCmakeDirectory(self, directory):
101 | passed = True
102 | for root, dirnames, filenames in os.walk(directory):
103 | for filename in filenames:
104 | if not filename.endswith('CMakeLists.txt'):
105 | continue
106 | full_filepath = os.path.join(root, filename)
107 | if not self.lintCmakeFile(full_filepath):
108 | passed = False
109 | return passed
110 |
111 | def lintCmake(self):
112 | lint_result = self.lintCmakeFile('CMakeLists.txt')
113 | lint_result &= self.lintCmakeDirectory('source')
114 | if not lint_result:
115 | sys.exit(1)
116 |
117 | def staticallyAnalyse(self, target, include_regex=None):
118 | assert True, "staticallyAnalyse should be overridden by subclass"
119 |
120 | def buildGradle(self):
121 | exit_code = subprocess.call(['./gradlew', 'assemble'])
122 | if exit_code != 0:
123 | sys.exit(exit_code)
124 |
125 | def packageArtifacts(self):
126 | assert True, "packageArtifacts should be overridden by subclass"
127 |
128 | def make_archive(self, source, destination):
129 | base = os.path.basename(destination)
130 | name = base.split('.')[0]
131 | format = base.split('.')[1]
132 | archive_from = os.path.dirname(source)
133 | archive_to = os.path.basename(source.strip(os.sep))
134 | print(source, destination, archive_from, archive_to)
135 | shutil.make_archive(name, format, archive_from, archive_to)
136 | shutil.move('%s.%s'%(name,format), destination)
137 |
138 | def find_file(self, directory, file_name, multiple_files=False):
139 | matches = []
140 | for root, dirnames, filenames in os.walk(directory):
141 | for filename in fnmatch.filter(filenames, file_name):
142 | matches.append(os.path.join(root, filename))
143 | if not multiple_files:
144 | break
145 | if not multiple_files and len(matches) > 0:
146 | break
147 | return matches
148 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
15 |
20 |
25 |
30 |
35 |
40 |
45 |
50 |
55 |
60 |
65 |
70 |
75 |
80 |
85 |
90 |
95 |
100 |
105 |
110 |
115 |
120 |
125 |
130 |
135 |
140 |
145 |
150 |
155 |
160 |
165 |
170 |
171 |
--------------------------------------------------------------------------------
/source/NFDriverFileImplementation.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018 Spotify AB.
3 | *
4 | * Licensed to the Apache Software Foundation (ASF) under one
5 | * or more contributor license agreements. See the NOTICE file
6 | * distributed with this work for additional information
7 | * regarding copyright ownership. The ASF licenses this file
8 | * to you under the Apache License, Version 2.0 (the
9 | * "License"); you may not use this file except in compliance
10 | * with the License. You may obtain a copy of the License at
11 | *
12 | * http://www.apache.org/licenses/LICENSE-2.0
13 | *
14 | * Unless required by applicable law or agreed to in writing,
15 | * software distributed under the License is distributed on an
16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17 | * KIND, either express or implied. See the License for the
18 | * specific language governing permissions and limitations
19 | * under the License.
20 | */
21 | #include "NFDriverFileImplementation.h"
22 |
23 | #include
24 | #include
25 |
26 | namespace nativeformat {
27 | namespace driver {
28 |
29 | int bytesPerFormat(NFDriverFileWAVHeaderAudioFormat wav_format) {
30 | switch (wav_format) {
31 | case NFDriverFileWAVHeaderAudioFormatPCM:
32 | return sizeof(short);
33 | case NFDriverFileWAVHeaderAudioFormatIEEEFloat:
34 | return sizeof(float);
35 | }
36 | return sizeof(float);
37 | }
38 |
39 | NFDriverFileImplementation::NFDriverFileImplementation(void *clientdata,
40 | NF_STUTTER_CALLBACK stutter_callback,
41 | NF_RENDER_CALLBACK render_callback,
42 | NF_ERROR_CALLBACK error_callback,
43 | NF_WILL_RENDER_CALLBACK will_render_callback,
44 | NF_DID_RENDER_CALLBACK did_render_callback,
45 | const char *output_destination,
46 | NFDriverFileWAVHeaderAudioFormat wav_format)
47 | : _clientdata(clientdata),
48 | _stutter_callback(stutter_callback),
49 | _render_callback(render_callback),
50 | _error_callback(error_callback),
51 | _will_render_callback(will_render_callback),
52 | _did_render_callback(did_render_callback),
53 | _output_destination(output_destination),
54 | _wav_format(wav_format),
55 | _thread(nullptr) {}
56 |
57 | NFDriverFileImplementation::~NFDriverFileImplementation() {
58 | if (isPlaying()) {
59 | setPlaying(false);
60 | }
61 | }
62 |
63 | bool NFDriverFileImplementation::isPlaying() const {
64 | return !!_thread;
65 | }
66 |
67 | void NFDriverFileImplementation::setPlaying(bool playing) {
68 | if (isPlaying() == playing) {
69 | return;
70 | }
71 |
72 | if (!playing) {
73 | _run = false;
74 | if (std::this_thread::get_id() != _thread->get_id()) {
75 | _thread->join();
76 | }
77 | _thread = nullptr;
78 | } else {
79 | _run = true;
80 | _thread = std::make_shared(&NFDriverFileImplementation::run, this);
81 | }
82 | }
83 |
84 | void NFDriverFileImplementation::run(NFDriverFileImplementation *driver) {
85 | FILE *fhandle = fopen(driver->_output_destination.c_str(), "wb");
86 | if (fhandle == nullptr) {
87 | driver->_error_callback(driver->_clientdata, "Failed to create file.", 0);
88 | }
89 |
90 | // Write the header.
91 | struct {
92 | unsigned char RIFF[4];
93 | unsigned int chunkSize;
94 | unsigned char WAVE[4];
95 | unsigned char FMT[4];
96 | unsigned int sixteen;
97 | unsigned short int audioFormat;
98 | unsigned short int numChannels;
99 | unsigned int samplerate;
100 | unsigned int byteRate;
101 | unsigned short int blockAlign;
102 | unsigned short int bitsPerSample;
103 | unsigned char DATA[4];
104 | unsigned int dataSize;
105 | } header;
106 | std::memcpy(header.RIFF, "RIFF", 4);
107 | std::memcpy(header.WAVE, "WAVE", 4);
108 | std::memcpy(header.FMT, "fmt ", 4);
109 | header.sixteen = 16;
110 | header.audioFormat = driver->_wav_format;
111 | header.numChannels = NF_DRIVER_CHANNELS;
112 | header.bitsPerSample = bytesPerFormat(driver->_wav_format) * 8;
113 | header.samplerate = NF_DRIVER_SAMPLERATE;
114 | header.byteRate = header.samplerate * header.numChannels * (header.bitsPerSample / 8);
115 | header.blockAlign = header.numChannels * (header.bitsPerSample / 8);
116 | std::memcpy(header.DATA, "data", 4);
117 | fwrite(&header, 1, sizeof(header), fhandle);
118 |
119 | // Rendering.
120 | const auto buffer_samples = NF_DRIVER_SAMPLE_BLOCK_SIZE * NF_DRIVER_CHANNELS;
121 | float buffer[buffer_samples];
122 | while (driver->_run) {
123 | for (int i = 0; i < buffer_samples; ++i) {
124 | buffer[i] = 0.0f;
125 | }
126 | driver->_will_render_callback(driver->_clientdata);
127 | const size_t num_frames = static_cast(
128 | driver->_render_callback(driver->_clientdata, buffer, NF_DRIVER_SAMPLE_BLOCK_SIZE));
129 | if (num_frames < 1) {
130 | driver->_stutter_callback(driver->_clientdata);
131 | } else {
132 | switch (driver->_wav_format) {
133 | case NFDriverFileWAVHeaderAudioFormatPCM: {
134 | std::vector converted_samples(num_frames * NF_DRIVER_CHANNELS);
135 | for (int i = 0; i < converted_samples.size(); ++i) {
136 | converted_samples[i] =
137 | static_cast(buffer[i] * std::numeric_limits::max());
138 | }
139 | fwrite(converted_samples.data(), sizeof(short), num_frames * NF_DRIVER_CHANNELS, fhandle);
140 | break;
141 | }
142 | case NFDriverFileWAVHeaderAudioFormatIEEEFloat:
143 | fwrite(buffer, sizeof(float), num_frames * NF_DRIVER_CHANNELS, fhandle);
144 | break;
145 | }
146 | }
147 |
148 | driver->_did_render_callback(driver->_clientdata);
149 | }
150 |
151 | // Write the size into the header and close the file.
152 | unsigned int position =
153 | static_cast((static_cast(ftell(fhandle)) - sizeof(header)));
154 | fseek(fhandle, 40, SEEK_SET);
155 | fwrite(&position, 1, 4, fhandle);
156 | position += 36;
157 | fseek(fhandle, 4, SEEK_SET);
158 | fwrite(&position, 1, 4, fhandle);
159 | fclose(fhandle);
160 | }
161 |
162 | } // namespace driver
163 | } // namespace nativeformat
164 |
--------------------------------------------------------------------------------
/ci/build_options.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | '''
3 | * Copyright (c) 2018 Spotify AB.
4 | *
5 | * Licensed to the Apache Software Foundation (ASF) under one
6 | * or more contributor license agreements. See the NOTICE file
7 | * distributed with this work for additional information
8 | * regarding copyright ownership. The ASF licenses this file
9 | * to you under the Apache License, Version 2.0 (the
10 | * "License"); you may not use this file except in compliance
11 | * with the License. You may obtain a copy of the License at
12 | *
13 | * http://www.apache.org/licenses/LICENSE-2.0
14 | *
15 | * Unless required by applicable law or agreed to in writing,
16 | * software distributed under the License is distributed on an
17 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18 | * KIND, either express or implied. See the License for the
19 | * specific language governing permissions and limitations
20 | * under the License.
21 | '''
22 |
23 | import sys
24 | import argparse
25 |
26 | # Argument parsing abstraction designed for the build context.
27 | # Generates an array of buildOptions from an input arg list.
28 | # Allows options to be grouped into workflows, and workflows
29 | # to be overridden with minor changes.
30 |
31 | # Example commands:
32 |
33 | # run the lint workflow with an override to disable dependencies install:
34 | # python build_options.py lint -installDependencies=0 -v
35 |
36 | # run the default workflow with an override to make it fly.
37 | # python build_options.py -doFlyAway=1 -v
38 |
39 |
40 | class BuildOptions:
41 |
42 | def __init__(self):
43 | self.options = {}
44 | self.workflows = {}
45 | self.verbose = True
46 |
47 | # Define a build option, with documentation.
48 | def addOption(self, option, doc):
49 | self.options[option] = doc
50 |
51 | # Define a workflow, which consists of a group of build options.
52 | # This will be an optional single positional argument.
53 | def addWorkflow(self, workflow, doc, options):
54 | for option in options:
55 | if option not in self.options:
56 | self.flushed_print(
57 | "Error: Workflow %s contains invalid option %s"
58 | % (workflow, option))
59 | exit(1)
60 | self.workflows[workflow] = {
61 | 'doc': doc,
62 | 'options': {x: '1' for x in options}
63 | }
64 |
65 | # Define the default workflow, if the cmdline input doesn't include
66 | # a position workflow arg.
67 | def setDefaultWorkflow(self, doc, options):
68 | self.addWorkflow("default", doc, options)
69 |
70 | def getOptionDoc(self, option):
71 | return self.options[option]
72 |
73 | def getWorkflowHelp(self):
74 | str = ""
75 | for workflow, data in self.workflows.items():
76 | str += "%s:\n\t%s\n" % (workflow, data['doc'])
77 | return str
78 |
79 | # Parse input arguments
80 | def parseArgs(self):
81 | parser = argparse.ArgumentParser(
82 | formatter_class=argparse.RawTextHelpFormatter)
83 |
84 | # Verbose is automatically defined
85 | parser.add_argument("-quiet", "-q",
86 | help="Mute build steps",
87 | action='store_true')
88 |
89 | # Can have any number of workflows. If 0, it runs the default workflow.
90 | # If more than 1, the built options get intersected
91 | parser.add_argument("workflows", nargs='*', default=['default'],
92 | help=self.getWorkflowHelp())
93 |
94 | # Define build options with leading -
95 | for k, v in self.options.items():
96 | parser.add_argument("-" + k, help=v)
97 | args = parser.parse_args()
98 | argHash = vars(args)
99 | result = {}
100 |
101 | if 'quiet' in argHash and argHash['quiet']:
102 | self.verbose = False
103 |
104 | for workflow in argHash['workflows']:
105 | if workflow not in self.workflows:
106 | self.flushed_print("Error: Specified invalid workflow %s" %
107 | workflow)
108 | exit(1)
109 | # Load options from selected workflows
110 | result.update(self.workflows[workflow]['options'])
111 |
112 | # Apply option overrides to workflow
113 | for option, doc in self.options.items():
114 | if option in argHash and argHash[option]:
115 | result[option] = argHash[option]
116 |
117 | return [k for k, v in result.items() if v == '1']
118 |
119 | # Print which build options are enabled.
120 | def verbosePrintBuildOptions(self, args):
121 | if self.verbose:
122 | self.flushed_print("Build Options: " + str(args))
123 |
124 | # Caller should call this when a build option is being executed
125 | # for verbose build logging.
126 | def verbosePrint(self, option):
127 | if self.verbose:
128 | self.flushed_print("===== %s =====" % self.getOptionDoc(option))
129 |
130 | # Check if this given build option is defined. If so, print the step has
131 | # begun and return true so caller can run the step.
132 | # Sanity check the input option to catch typos.
133 | def checkOption(self, args, arg, quiet=False):
134 | if arg not in self.options:
135 | self.flushed_print("Error: Checked undefined option %s" % arg)
136 | exit(1)
137 | if arg in args:
138 | if not quiet:
139 | self.verbosePrint(arg)
140 | return True
141 | return False
142 |
143 | def flushed_print(self, str):
144 | print(str)
145 | sys.stdout.flush()
146 |
147 |
148 | # Create a toy version for testing if user executes this file directly
149 | def test_version():
150 |
151 | buildOptions = BuildOptions()
152 | buildOptions.addOption("option1", "option 1 description")
153 | buildOptions.addOption("option2", "option 2 description")
154 | buildOptions.addOption("option3", "option 3 description")
155 | buildOptions.setDefaultWorkflow("Default workflow description", [
156 | 'option1'
157 | ])
158 | buildOptions.addWorkflow("workflow1", "workflow1 description", [
159 | 'option1',
160 | 'option2'
161 | ])
162 | buildOptions.addWorkflow("workflow2", "workflow2 description", [
163 | 'option2',
164 | 'option3'
165 | ])
166 |
167 | options = buildOptions.parseArgs()
168 | buildOptions.verbosePrintBuildOptions(options)
169 |
170 | if buildOptions.checkOption(options, "option1"):
171 | buildOptions.flushed_print("running option1")
172 |
173 | if buildOptions.checkOption(options, "option2"):
174 | buildOptions.flushed_print("running option2")
175 |
176 | if buildOptions.checkOption(options, "option3"):
177 | buildOptions.flushed_print("running option3")
178 |
179 |
180 | if __name__ == "__main__":
181 | test_version()
182 |
--------------------------------------------------------------------------------
/include/NFDriver/NFDriver.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2021 Spotify AB.
3 | *
4 | * Licensed to the Apache Software Foundation (ASF) under one
5 | * or more contributor license agreements. See the NOTICE file
6 | * distributed with this work for additional information
7 | * regarding copyright ownership. The ASF licenses this file
8 | * to you under the Apache License, Version 2.0 (the
9 | * "License"); you may not use this file except in compliance
10 | * with the License. You may obtain a copy of the License at
11 | *
12 | * http://www.apache.org/licenses/LICENSE-2.0
13 | *
14 | * Unless required by applicable law or agreed to in writing,
15 | * software distributed under the License is distributed on an
16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17 | * KIND, either express or implied. See the License for the
18 | * specific language governing permissions and limitations
19 | * under the License.
20 | */
21 | #pragma once
22 |
23 | #include