Compare commits

...

105 Commits

Author SHA1 Message Date
Sébastien
fdd34779e6 fix offline again-release 2022-12-02 16:26:11 -05:00
github-actions
76dd27116f Update prebuilt objects [skip actions] 2022-12-02 20:34:32 +00:00
Sebastien L
77f486e56f fix offline icons - release 2022-12-02 15:31:33 -05:00
github-actions
403623d4d6 Update prebuilt objects [skip actions] 2022-11-30 19:50:45 +00:00
Sebastien L
60b163676a Fix protocol generation - release 2022-11-30 14:46:51 -05:00
github-actions
f49c3f7206 Update prebuilt objects [skip actions] 2022-11-30 05:54:53 +00:00
philippe44
3fade26793 build protobuf 2022-11-29 16:49:35 -08:00
philippe44
856303d8f1 Add GPIO config for Infrared on SqueezeAMP 3.20 2022-11-29 13:58:09 -08:00
philippe44
b20c8306fa fix a few spotify key bugs and remove BTDM 2022-11-28 21:09:27 -08:00
Sebastien L
877f16181b Activate new workflow 2022-11-28 13:57:31 -05:00
Sebastien
2cba6972ff update build_tools [skip actions] 2022-11-28 13:45:10 -05:00
Sebastien
fbd9516667 one more update to web push - [skip actions] 2022-11-28 10:46:15 -05:00
Sebastien
646a220fd0 Merge branch 'master-v4.3' of https://github.com/sle118/squeezelite-esp32 into master-v4.3 2022-11-28 10:45:04 -05:00
Sebastien
962dbf89c8 Add more auth methods for build - [skip actions] 2022-11-28 10:44:59 -05:00
github-actions
3a658f3ba2 Update prebuilt objects [skip actions] 2022-11-28 15:22:22 +00:00
github-actions
4f5a7ade9d Update prebuilt objects [skip actions] 2022-11-28 14:57:44 +00:00
Sebastien L
f15f846030 One more fix to the build system - skip actions 2022-11-28 09:52:24 -05:00
Sebastien L
14f4caf584 Allow compiling out cspot 2022-11-28 09:22:46 -05:00
Sebastien L
46eb732d82 Merge remote-tracking branch 'origin/master-v4.3' into master-v4.3 2022-11-28 09:13:02 -05:00
Sebastien L
d092ae093c Write version.txt file before build 2022-11-28 09:12:58 -05:00
philippe44
4a51efd556 Merge pull request #206 from wizmo2/display-spi-mode-v4.3
add shaffenmeisters PR and add web config
2022-11-26 19:06:06 -08:00
Wizmo2
c1375444b4 fixed backlite 2022-11-26 21:08:39 -05:00
Wizmo2
e5eabcaf86 add shaffenmeisters PR and add web config 2022-11-25 19:40:17 -05:00
github-actions
93465db1b8 Update prebuilt objects [skip actions] 2022-11-25 19:06:15 +00:00
wizmo2
dc66d9e9dc Bluetooth Source mods (#204)
* support legacy bt pairing

* extend bt source support
2022-11-25 13:55:01 -05:00
Sebastien L
8462de1c16 Fix spotify configuration UI- release 2022-11-25 13:48:32 -05:00
Sébastien
37f48d4bc8 Align versionning in firmware - release 2022-11-24 10:07:13 -05:00
github-actions
ec019f98f3 Update prebuilt objects [skip actions] 2022-11-24 14:15:09 +00:00
Sebastien
5e5c7e0c80 Merge branch 'master-v4.3' of https://github.com/sle118/squeezelite-esp32 into master-v4.3 2022-11-24 09:07:45 -05:00
Sebastien
3144cf5f91 Change auth methods for pushing 2022-11-24 09:07:35 -05:00
github-actions
18cc0adfb4 Update prebuilt objects [skip actions] 2022-11-22 15:28:59 +00:00
github-actions
78ece491a9 Update prebuilt objects [skip actions] 2022-11-22 14:39:21 +00:00
Sébastien
9e66a822de Change call to web installer update 2022-11-22 09:35:34 -05:00
philippe44
0e12f7f887 bypass protobuf generation for now - release 2022-11-19 19:01:47 -08:00
philippe44
5df561890c mpr121 table init - release 2022-11-19 18:28:33 -08:00
philippe44
f6630fae4e release 2022-11-17 17:26:12 -08:00
philippe44
e2df4b1cc3 chmod on protoc 2022-11-17 17:20:20 -08:00
philippe44
3172576fc1 update CMake file 2022-11-17 16:36:25 -08:00
philippe44
e0dd7a596b release 2022-11-17 16:20:16 -08:00
philippe44
6e4dd65fd7 Merge branch 'master-v4.3' of https://github.com/sle118/squeezelite-esp32 into master-v4.3 2022-11-17 14:06:05 -08:00
philippe44
7e5f27af12 update cspot 2022-11-17 14:06:00 -08:00
github-actions
f805db3d27 Update prebuilt objects [skip actions] 2022-11-15 03:51:38 +00:00
philippe44
a81d0e0513 fix opus & vorbis last decode 2022-11-10 23:05:17 -08:00
Andy Boff
6c524cd094 Implement mpr121 touch sensor capability to GPIO Expanders (#192)
Co-authored-by: Andy Boff <gitdev@plek.me.uk>
2022-10-22 00:55:04 -04:00
Olecorp
e34cec1ad1 Update services.c (#189)
Reset pin config before use. Some pins (like GPIO14, JTAG TMS by default) wont work without this.
2022-10-19 22:48:20 -04:00
Sébastien
a2c16decee Adjust artifacts target folder [skip actions] 2022-10-11 11:35:15 -04:00
github-actions
d06893c43d Update prebuilt objects [skip actions] 2022-10-07 19:51:07 +00:00
Sebastien L
aecaed4a5f WIP Workflow [skip actions] 2022-10-07 15:47:49 -04:00
github-actions
113a75a61d Update prebuilt objects [skip actions] 2022-10-07 19:42:11 +00:00
Sébastien
f721d140e7 WIP Workflow [skip actions] 2022-10-07 15:39:27 -04:00
Sébastien
46848b3afe WIP Workflow [skip actions] 2022-10-07 15:37:21 -04:00
Sébastien
3d63670499 WIP Workflow [skip actions] 2022-10-07 15:31:52 -04:00
Sébastien
83114861c5 WIP Workflow [skip actions] 2022-10-07 15:30:12 -04:00
Sebastien L
5e7ab93e4a WIP Workflow [skip actions] 2022-10-07 15:29:05 -04:00
Sebastien L
2c56f2d7ae WIP Workflow [skip actions] 2022-10-07 15:27:20 -04:00
Sebastien L
c62e719c11 WIP Workflow [skip actions] 2022-10-07 15:05:21 -04:00
Sebastien L
0226355ab7 Create web_deploy.yml [skip actions] 2022-10-07 14:57:30 -04:00
Sebastien L
42bee2a7b0 WIP Workflow [skip actions] 2022-10-07 14:54:50 -04:00
Sebastien L
130f54526f WIP Workflow [skip actions] 2022-10-07 14:41:43 -04:00
Sebastien L
f14f2debc3 Merge remote-tracking branch 'origin/master-v4.3' into master-v4.3 2022-10-07 14:40:25 -04:00
github-actions
25772c9ccb WIP Workflow [skip actions] 2022-10-07 14:40:19 -04:00
github-actions
1ae1b03fc3 Update prebuilt objects [skip actions] 2022-10-07 18:31:58 +00:00
Sebastien L
08ff02dc3c Update prebuilt objects [skip actions] 2022-10-07 14:28:33 -04:00
Sebastien L
3f4df9a348 Merge remote-tracking branch 'origin/master-v4.3' into master-v4.3 2022-10-06 13:05:12 -04:00
github-actions
bb70ea1eaa Update prebuilt objects [skip actions] 2022-10-06 13:05:03 -04:00
github-actions
c0e8e36221 Update prebuilt objects [skip actions] 2022-10-06 16:54:31 +00:00
Sebastien L
4c94042c1d Update BuildTest.yml [skip actions] 2022-10-06 12:51:33 -04:00
Sebastien L
66be31a76c Merge remote-tracking branch 'origin/master-v4.3' into master-v4.3 2022-10-06 12:49:35 -04:00
Sebastien L
5a53011383 Update BuiltTest.yml [skip actions] 2022-10-06 12:49:27 -04:00
Sebastien L
9ca1b87919 Update BuiltTest.yml [skip actions] 2022-10-06 12:44:19 -04:00
Sebastien L
2698577592 Update BuildTest.yml [skip actions] 2022-10-06 11:44:18 -04:00
Sebastien L
f70f973ca9 Allow dispatch options to control build [skip actions] 2022-10-06 11:31:43 -04:00
Sebastien L
83592b7079 WIP workflow [skip actions] 2022-10-06 11:16:05 -04:00
github-actions
2967723fdf Update prebuilt objects [skip actions] 2022-10-06 14:37:41 +00:00
Sébastien
d6e75dc71e Update BuildTest.yml [skip actions] 2022-10-06 10:32:35 -04:00
github-actions
fc50d55a27 Update prebuilt objects [skip actions] 2022-10-06 14:17:54 +00:00
Sebastien L
4fff2f0dc1 Squash some commits [skip actions] 2022-10-06 09:54:07 -04:00
Sebastien L
027d81af21 Merge remote-tracking branch 'origin/master-v4.3' into master-v4.3 2022-10-06 09:53:03 -04:00
github-actions
96a2581534 Update prebuilt objects [skip actions] 2022-10-06 09:52:20 -04:00
Sébastien
461486ce21 Update BuildTest.yml
Update BuildTest.yml
Update build tools
Update BuildTest.yml
Update BuildTest.yml
Update BuildTest.yml
Update BuildTest.yml
Update BuildTest.yml
Update BuildTest.yml [skip actions]
Update BuildTest.yml [skip actions]
Update prebuilt objects [skip actions]

Update prebuilt objects [skip actions]

Update prebuilt objects [skip actions]

Update Build test [skip actions]
2022-10-06 09:52:20 -04:00
github-actions
7f0bc6c2ba Update prebuilt objects [skip actions] 2022-10-06 03:21:20 +00:00
Sébastien
551db4a7d1 Update Build test [skip actions] 2022-10-05 23:16:32 -04:00
github-actions
eee3123eba Update prebuilt objects [skip actions] 2022-10-06 03:13:55 +00:00
github-actions
d1a5e0aaa6 Update prebuilt objects [skip actions] 2022-10-06 02:46:59 +00:00
github-actions
e6d9c5f5a3 Update prebuilt objects [skip actions] 2022-10-05 19:46:26 +00:00
Sébastien
8164ccacaa Update BuildTest.yml [skip actions] 2022-10-05 15:41:09 -04:00
Sébastien
b2ceb8c0e3 Update BuildTest.yml [skip actions] 2022-10-05 15:35:01 -04:00
Sébastien
2e66a6a6cb Update BuildTest.yml 2022-10-05 15:26:00 -04:00
Sébastien
ac1817f4d3 Update BuildTest.yml 2022-10-05 15:22:40 -04:00
Sébastien
1d4bd8274b Update BuildTest.yml 2022-10-05 15:15:05 -04:00
Sébastien
58af548252 Update BuildTest.yml 2022-10-05 15:10:46 -04:00
Sébastien
c400f4467e Update BuildTest.yml 2022-10-05 14:55:09 -04:00
Sebastien L
24c69a70d2 Update build tools 2022-10-05 14:41:41 -04:00
Sébastien
0ce4e9e240 Update BuildTest.yml 2022-10-05 13:16:43 -04:00
Sébastien
b50caddb39 Update BuildTest.yml 2022-10-05 12:34:39 -04:00
Sébastien
639ed446f5 Update BuildTest.yml 2022-10-05 12:28:55 -04:00
Sebastien L
06b65f6f6c Merge remote-tracking branch 'origin/master-v4.3' into master-v4.3 2022-10-05 12:25:59 -04:00
Sebastien L
f70cd0eeb1 Push a test build script for github actions 2022-10-05 12:24:31 -04:00
github-actions
95018f39e8 Update prebuilt objects [skip actions] 2022-10-05 16:10:26 +00:00
github-actions
c8e999590d Update prebuilt objects [skip actions] 2022-10-05 15:24:44 +00:00
github-actions
b640ff1c88 Update prebuilt objects [skip actions] 2022-10-05 15:08:49 +00:00
github-actions
bfe1be3c99 Update prebuilt objects [skip actions] 2022-10-05 14:57:02 +00:00
github-actions
9416c6916a Update prebuilt objects 2022-10-05 14:04:23 +00:00
philippe44
f23116d2c6 GH desktop thought it was smart to CRLF all the pull 2022-09-26 19:58:50 -07:00
philippe44
ff1d276148 Update plugin (credits @mherger) 2022-09-25 11:32:11 -07:00
270 changed files with 8222 additions and 1251 deletions

232
.github/workflows/Platform_build.yml vendored Normal file
View File

@@ -0,0 +1,232 @@
name: Platform Build
on:
push:
branches:
- '**4.3'
workflow_dispatch:
inputs:
ui_build:
description: 'Force Rebuilding the UI. When not forced, the system will check for [ui-build] in the last commit message to trigger a ui rebuild'
required: true
type: boolean
release_build:
description: 'Force a Release build. When not forced, the system will check for release word in the last commit message to trigger a release'
required: true
type: boolean
jobs:
bootstrap:
name: Global setup
runs-on: ubuntu-latest
container:
image: sle118/squeezelite-esp32-idfv43
outputs:
build_number: ${{ steps.buildnumber.outputs.build_number }}
ui_build: ${{ steps.build_flags.outputs.ui_build }}
release_flag: ${{ steps.build_flags.outputs.release_flag }}
mock: ${{ steps.build_flags.outputs.mock }}
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 0
submodules: true
- name: Generate common build number
id: buildnumber
uses: einaregilsson/build-number@v3
with:
token: ${{secrets.github_token}}
- name: Set build flags
id: build_flags
run: |
git config --global --add safe.directory /__w/squeezelite-esp32/squeezelite-esp32
[ ${{github.event.inputs.ui_build}} ] && ui_build_option="--ui_build" || ui_build_option=""
[ ${{github.event.inputs.release_build}} ] && release_build_option="--force" || release_build_option=""
echo "ui_build_option=$ui_build_option" >> $GITHUB_ENV
echo "release_build_option=$release_build_option" >> $GITHUB_ENV
echo "Dumping environment"
env
. /opt/esp/python_env/idf4.3_py3.8_env/bin/activate
# build_flags support the following options
# --mock - to mock the compilation part - this is to be used for testing only
# --force - to force a release build even if the last commit message doesn't contain the word "release"
# --ui_build - to force a ui_build even if the last commit message doesn't contain "[ui-build]"
build_tools.py build_flags $ui_build_option $release_build_option
- name: Show Build Flags
run: |
echo "Running with the following options"
echo "Web Build Flag=${{steps.build_flags.outputs.ui_build}}"
echo "Mock flag=${{steps.build_flags.outputs.mock}}"
echo "Release Flag=${{steps.build_flags.outputs.release_flag}}"
- name: Refresh certificates
if: ${{ steps.build_flags.outputs.release_flag }}
run: |
git update-index --chmod=+x ./server_certs/getcert.sh
cd server_certs;./getcert.sh;cat github.pem;cd ..
- name: Setup Node.js dependencies
if: ${{ !env.ACT }}
uses: actions/setup-node@v3
with:
node-version: 16
cache: 'npm'
cache-dependency-path: components/wifi-manager/webapp/package.json
- name: Build Web Application
if: ${{ steps.build_flags.outputs.ui_build == 1 }}
run: |
cd components/wifi-manager/webapp/
npm install
npm run-script build
- name: Update repository with prebuilt items
if: ${{ steps.build_flags.outputs.ui_build == 1 || steps.build_flags.outputs.release_flag == 1 }}
run: |
git config user.name github-actions
git config user.email github-actions@github.com
git add server_certs
git add components/wifi-manager/webapp/*.h
git add components/wifi-manager/webapp/*.c
git add components/wifi-manager/webapp/*.cmake
git add components/wifi-manager/webapp/dist/*
git commit -m "Update prebuilt objects [skip actions]"
git push https://${{secrets.github_token}}@github.com/sle118/squeezelite-esp32.git
- name: Locally store commonly built objects
uses: actions/upload-artifact@v3
with:
name: prebuilt_objects
path: |
server_certs
components/wifi-manager/webapp/*.h
components/wifi-manager/webapp/*.c
components/wifi-manager/webapp/dist/*
components/wifi-manager/webapp/*.cmake
build:
runs-on: ubuntu-latest
container:
image: sle118/squeezelite-esp32-idfv43
needs: [bootstrap]
strategy:
matrix:
node: [I2S-4MFlash, SqueezeAmp, Muse]
depth: [16, 32]
exclude:
- node: Muse
depth: 32
- node: bootstrap
depth: 32
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 0
submodules: true
- name: Show Build Flags
run: |
echo "Running with the following options"
echo "Web Build Flag=${{needs.bootstrap.outputs.ui_build}}"
echo "Mock flag=${{needs.bootstrap.outputs.mock}}"
echo "Release Flag=${{needs.bootstrap.outputs.release_flag}}"
echo Environment File name: $GITHUB_ENV
- name: Set build parameters
run: |
. /opt/esp/python_env/idf4.3_py3.8_env/bin/activate
git config --global --add safe.directory /__w/squeezelite-esp32/squeezelite-esp32
git status
build_tools.py environment --build ${{ needs.bootstrap.outputs.build_number }} --env_file "$GITHUB_ENV" --node "${{matrix.node}}" --depth ${{matrix.depth}} --major 2 --docker sle118/squeezelite-esp32-idfv43
- uses: actions/download-artifact@master
name: Restore common objects
with:
name: prebuilt_objects
- name: Build the firmware
if: ${{ needs.bootstrap.outputs.mock == 0 }}
run: |
. ${IDF_PYTHON_ENV_PATH}/bin/activate
chmod +x ./components/spotify/cspot/bell/nanopb/generator/protoc
chmod +x ./components/spotify/cspot/bell/nanopb/generator/protoc-gen-nanopb
chmod +x ./components/spotify/cspot/bell/nanopb/generator/*.py
chmod +x ./components/spotify/cspot/bell/nanopb/generator/*.py2
chmod +x ./components/spotify/cspot/bell/nanopb/generator/proto/*.py
echo "Copying target sdkconfig"
cp build-scripts/${TARGET_BUILD_NAME}-sdkconfig.defaults sdkconfig
echo "Building project"
idf.py build -DDEPTH=${DEPTH} -DBUILD_NUMBER=${BUILD_NUMBER}-${DEPTH}
- name: Build Mock firmware
if: ${{ needs.bootstrap.outputs.mock == 1 }}
run: |
mkdir -p build
cd build
mkdir -p partition_table
mkdir -p bootloader
echo \\"mock content\\"> ./squeezelite.bin
echo \"mock content\"> ./recovery.bin
echo \"mock content\"> ./bootloader/bootloader.bin
echo \"mock content\"> ./partition_table/partition-table.bin
echo \"mock content\"> ./ota_data_initial.bin
echo \"mock content\"> ./flash_project_args
echo \"mock content\"> ./size_comp1.txt
echo \"mock content\"> ./size_comp2.txt
echo \"mock content\"> ./partitions.csv
echo { \"write_flash_args\" : [ \"--flash_mode\", \"dio\", \"--flash_size\", \"detect\", \"--flash_freq\", \"80m\" ], \"flash_settings\" : { \"flash_mode\": \"dio\", \"flash_size\": \"detect\", \"flash_freq\": \"80m\" }, \"flash_files\" : { \"0x8000\" : \"partition_table/partition-table.bin\", \"0xd000\" : \"ota_data_initial.bin\", \"0x1000\" : \"bootloader/bootloader.bin\", \"0x10000\" : \"recovery.bin\", \"0x150000\" : \"squeezelite.bin\" }, \"partition_table\" : { \"offset\" : \"0x8000\", \"file\" : \"partition_table/partition-table.bin\" }, \"otadata\" : { \"offset\" : \"0xd000\", \"file\" : \"ota_data_initial.bin\" }, \"bootloader\" : { \"offset\" : \"0x1000\", \"file\" : \"bootloader/bootloader.bin\" }, \"app\" : { \"offset\" : \"0x10000\", \"file\" : \"recovery.bin\" }, \"squeezelite\" : { \"offset\" : \"0x150000\", \"file\" : \"squeezelite.bin\" }, \"extra_esptool_args\" : { \"after\" : \"hard_reset\", \"before\" : \"default_reset\" } } > ./flasher_args.json
- name: Create Release Artifact Zip
if: ${{ needs.bootstrap.outputs.release_flag == 1 && needs.bootstrap.outputs.mock == 0 }}
run: |
if [ -z "${artifact_file_name}" ]
then
echo "No artifact file name set. Will not generate zip file."
else
echo "Generating build artifact zip file"
zip -r build_output.zip build
zip build/${artifact_file_name} partitions*.csv components/ build/*.bin build/bootloader/bootloader.bin build/partition_table/partition-table.bin build/flash_project_args build/size_*.txt
fi
- name: Upload Build Artifacts
uses: actions/upload-artifact@v3
if: ${{ needs.bootstrap.outputs.mock == 0 }}
with:
name: ${{ env.artifact_prefix }}
path: |
build/flash_project_args
build/size_comp1.txt
build/size_comp2.txt
partitions.csv
sdkconfig
server_certs/github.pem
build/*.bin
build/bootloader/bootloader.bin
build/partition_table/partition-table.bin
build_output.zip
- name: Create Release
if: ${{ needs.bootstrap.outputs.release_flag == 1 && needs.bootstrap.outputs.mock == 0 }}
id: create_release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # This token is provided by Actions, you do not need to create your own token
with:
tag_name: ${{ env.tag }}
release_name: ${{ env.name }}
body: ${{ env.description }}
draft: false
prerelease: true
- name: Upload Release Asset - Squeezelite binary file
if: ${{ needs.bootstrap.outputs.release_flag == 1 && needs.bootstrap.outputs.mock == 0 }}
id: upload-release-asset
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps
asset_path: build/squeezelite.bin
asset_name: ${{ env.artifact_bin_file_name }}
asset_content_type: application/octet-stream
- name: Upload Release Asset - Zip file
if: ${{ needs.bootstrap.outputs.release_flag == 1 && needs.bootstrap.outputs.mock == 0 }}
id: upload-release-asset-zip
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps
asset_path: build/${{ env.artifact_file_name }}
asset_name: ${{ env.artifact_file_name }}
asset_content_type: application/octet-stream
update_web_installer:
name: Update Web Installer After Release
needs: [ bootstrap, build ]
if: ${{( always() && !cancelled() ) && needs.bootstrap.outputs.release_flag == 1 && needs.bootstrap.outputs.mock == 0 }}
uses: ./.github/workflows/web_deploy.yml

View File

@@ -65,7 +65,7 @@ jobs:
BUILD_NUMBER=${{ needs.job1.outputs.build_number }}
echo "BUILD_NUMBER=${BUILD_NUMBER}" >> $GITHUB_ENV
echo "DOCKER_IMAGE_NAME=sle118/squeezelite-esp32-idfv4-master" >> $GITHUB_ENV
tag="${TARGET_BUILD_NAME}.${{matrix.depth}}.${BUILD_NUMBER}.${branch_name}"
tag="${TARGET_BUILD_NAME}.${{matrix.depth}}.${build_version_prefix}${BUILD_NUMBER}.${branch_name}"
echo "tag=${tag}" >> $GITHUB_ENV
last_commit="$(git log --pretty=format:'%s' --max-count=1)"
if [[ "$last_commit" =~ .*"Release".* ]]; then echo "release_flag=1" >> $GITHUB_ENV; else echo "release_flag=0" >> $GITHUB_ENV; fi

23
.github/workflows/web_deploy.yml vendored Normal file
View File

@@ -0,0 +1,23 @@
name: Update Web Installer
on:
workflow_call:
workflow_dispatch:
jobs:
update_web_installer:
name: Update Web Installer After Release
runs-on: ubuntu-latest
container:
image: sle118/squeezelite-esp32-idfv43
env:
WEB_INSTALLER: ${{ secrets.WEB_INSTALLER }}
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 0
submodules: true
- name: Update Web Installer Project
run: |
. /opt/esp/python_env/idf4.3_py3.8_env/bin/activate
git config --global --add safe.directory /__w/squeezelite-esp32/squeezelite-esp32
build_tools.py manifest --flash_file "/build/flash_project_args" --outdir "./bin_files" --manif_name "manifest" --max_count 3
build_tools.py pushinstaller --source "./bin_files" --manif_name "manifest" --target "web-installer" --url "https://github.com/sle118/squeezelite-esp32-installer.git" --artifacts "docs/artifacts" --web_installer_branch "main" --token "${{env.WEB_INSTALLER}}"

4
.gitignore vendored
View File

@@ -14,3 +14,7 @@ test/.vscode/tasks.json
test/sdkconfig
components/wifi-manager/UML-State-Machine-in-C
*.bak
envfile.txt
artifacts
web-installer

View File

@@ -13,7 +13,7 @@ add_definitions(-DHIERARCHICAL_STATES=1)
#add_definitions(-DNETWORK_ETHERNET_LOG_LEVEL=ESP_LOG_DEBUG)
#uncomment line below to get network status debug logs
#add_definitions(-DNETWORK_STATUS_LOG_LEVEL=ESP_LOG_DEBUG)
#add_definitions(-DNETWORK_HANDLERS_LOG_LEVEL=ESP_LOG_DEBUG)
#add_definitions(-DNETWORK_HANDLERS_LOG_LEVEL=ESP_LOG_DEBUG)
#add_definitions(-DNETWORK_WIFI_LOG_LEVEL=ESP_LOG_DEBUG)
#add_definitions(-DNETWORK_MANAGER_LOG_LEVEL=ESP_LOG_DEBUG)
#add_definitions(-DNETWORK_HTTP_SERVER_LOG_LEVEL=ESP_LOG_DEBUG)

View File

@@ -3,6 +3,32 @@ FROM ubuntu:20.04
ARG DEBIAN_FRONTEND=noninteractive
ENV GCC_TOOLS_BASE=/opt/esp/tools/xtensa-esp32-elf/esp-2021r2-8.4.0/xtensa-esp32-elf/bin/xtensa-esp32-elf-
# To build the image for a branch or a tag of IDF, pass --build-arg IDF_CLONE_BRANCH_OR_TAG=name.
# To build the image with a specific commit ID of IDF, pass --build-arg IDF_CHECKOUT_REF=commit-id.
# It is possibe to combine both, e.g.:
# IDF_CLONE_BRANCH_OR_TAG=release/vX.Y
# IDF_CHECKOUT_REF=<some commit on release/vX.Y branch>.
# The following commit contains the ldgen fix: eab738c79e063b3d6f4c345ea5e1d4f8caef725b
# to build an image using that commit: docker build . --build-arg IDF_CHECKOUT_REF=eab738c79e063b3d6f4c345ea5e1d4f8caef725b -t sle118/squeezelite-esp32-idfv43
# Docker build for release 4.3.2 as of 2022/02/28
# docker build . --build-arg IDF_CHECKOUT_REF=8bf14a9238329954c7c5062eeeda569529aedf75 -t sle118/squeezelite-esp32-idfv43
# To run the image interactive (windows):
# docker run --rm -v %cd%:/project -w /project -it sle118/squeezelite-esp32-idfv43
# To run the image interactive (linux):
# docker run --rm -v `pwd`:/project -w /project -it sle118/squeezelite-esp32-idfv43
# to build the web app inside of the interactive session
# pushd components/wifi-manager/webapp/ && npm install && npm run-script build && popd
#
# to run the docker with netwotrk port published on the host:
# docker run --rm -p 5000:5000/tcp -v %cd%:/project -w /project -it sle118/squeezelite-esp32-idfv43
ARG IDF_CLONE_URL=https://github.com/espressif/esp-idf.git
ARG IDF_CLONE_BRANCH_OR_TAG=master
ARG IDF_CHECKOUT_REF=8bf14a9238329954c7c5062eeeda569529aedf75
ENV IDF_PATH=/opt/esp/idf
ENV IDF_TOOLS_PATH=/opt/esp
# We need libpython2.7 due to GDB tools
# we also need npm 8 for the webapp to work
RUN : \
@@ -42,59 +68,49 @@ RUN : \
&& git clone https://github.com/HBehrens/puncover.git \
&& cd puncover \
&& python setup.py -q install \
&& :
# To build the image for a branch or a tag of IDF, pass --build-arg IDF_CLONE_BRANCH_OR_TAG=name.
# To build the image with a specific commit ID of IDF, pass --build-arg IDF_CHECKOUT_REF=commit-id.
# It is possibe to combine both, e.g.:
# IDF_CLONE_BRANCH_OR_TAG=release/vX.Y
# IDF_CHECKOUT_REF=<some commit on release/vX.Y branch>.
# The following commit contains the ldgen fix: eab738c79e063b3d6f4c345ea5e1d4f8caef725b
# to build an image using that commit: docker build . --build-arg IDF_CHECKOUT_REF=eab738c79e063b3d6f4c345ea5e1d4f8caef725b -t sle118/squeezelite-esp32-idfv4-master
# Docker build for release 4.3.2 as of 2022/02/28
# docker build . --build-arg IDF_CHECKOUT_REF=8bf14a9238329954c7c5062eeeda569529aedf75 -t sle118/squeezelite-esp32-idfv4-master
# To run the image interactive (windows): docker run --rm -v %cd%:/project -w /project -it sle118/squeezelite-esp32-idfv4-master
# to build the web app inside of the interactive session
# pushd components/wifi-manager/webapp/ && npm install && npm run-script build && popd
#
# to run the docker with netwotrk port published on the host:
# docker run --rm -p 5000:5000/tcp -v %cd%:/project -w /project -it sle118/squeezelite-esp32-idfv4-master
ARG IDF_CLONE_URL=https://github.com/espressif/esp-idf.git
ARG IDF_CLONE_BRANCH_OR_TAG=master
ARG IDF_CHECKOUT_REF=8bf14a9238329954c7c5062eeeda569529aedf75
ENV IDF_PATH=/opt/esp/idf
ENV IDF_TOOLS_PATH=/opt/esp
RUN echo IDF_CHECKOUT_REF=$IDF_CHECKOUT_REF IDF_CLONE_BRANCH_OR_TAG=$IDF_CLONE_BRANCH_OR_TAG && \
git clone --recursive \
&& echo IDF_CHECKOUT_REF=$IDF_CHECKOUT_REF IDF_CLONE_BRANCH_OR_TAG=$IDF_CLONE_BRANCH_OR_TAG \
&& git clone --recursive \
${IDF_CLONE_BRANCH_OR_TAG:+-b $IDF_CLONE_BRANCH_OR_TAG} \
$IDF_CLONE_URL $IDF_PATH && \
if [ -n "$IDF_CHECKOUT_REF" ]; then \
cd $IDF_PATH && \
git checkout $IDF_CHECKOUT_REF && \
git submodule update --init --recursive; \
fi
COPY docker/patches $IDF_PATH
# Install all the required tools
RUN : \
$IDF_CLONE_URL $IDF_PATH \
&& if [ -n "$IDF_CHECKOUT_REF" ]; then \
cd $IDF_PATH \
&& git checkout $IDF_CHECKOUT_REF \
&& git submodule update --init --recursive; \
fi \
&& update-ca-certificates --fresh \
&& $IDF_PATH/tools/idf_tools.py --non-interactive install required \
&& $IDF_PATH/tools/idf_tools.py --non-interactive install cmake \
&& $IDF_PATH/tools/idf_tools.py --non-interactive install-python-env \
&& :
RUN : \
echo Installing pygit2 ******************************************************** \
&& . /opt/esp/python_env/idf4.3_py3.8_env/bin/activate \
&& ln -sf /opt/esp/python_env/idf4.3_py3.8_env/bin/python /usr/local/bin/python \
&& pip install pygit2 requests \
&& pip show pygit2 \
&& python --version \
&& pip --version \
&& pip install protobuf grpcio-tools \
&& rm -rf $IDF_TOOLS_PATH/dist \
&& :
COPY docker/patches $IDF_PATH
#set idf environment variabies
ENV PATH /opt/esp/idf/components/esptool_py/esptool:/opt/esp/idf/components/espcoredump:/opt/esp/idf/components/partition_table:/opt/esp/idf/components/app_update:/opt/esp/tools/xtensa-esp32-elf/esp-2021r2-8.4.0/xtensa-esp32-elf/bin:/opt/esp/tools/xtensa-esp32s2-elf/esp-2021r2-8.4.0/xtensa-esp32s2-elf/bin:/opt/esp/tools/xtensa-esp32s3-elf/esp-2021r2-8.4.0/xtensa-esp32s3-elf/bin:/opt/esp/tools/riscv32-esp-elf/esp-2021r2-8.4.0/riscv32-esp-elf/bin:/opt/esp/tools/esp32ulp-elf/2.28.51-esp-20191205/esp32ulp-elf-binutils/bin:/opt/esp/tools/esp32s2ulp-elf/2.28.51-esp-20191205/esp32s2ulp-elf-binutils/bin:/opt/esp/tools/cmake/3.16.4/bin:/opt/esp/tools/openocd-esp32/v0.10.0-esp32-20211111/openocd-esp32/bin:/opt/esp/python_env/idf4.3_py3.8_env/bin:/opt/esp/idf/tools:$PATH
ENV GCC_TOOLS_BASE="/opt/esp/tools/xtensa-esp32-elf/esp-2021r2-8.4.0/xtensa-esp32-elf/bin/xtensa-esp32-elf-"
ENV IDF_PATH="/opt/esp/idf"
ENV IDF_PYTHON_ENV_PATH="/opt/esp/python_env/idf4.3_py3.8_env"
ENV IDF_TOOLS_EXPORT_CMD="/opt/esp/idf/export.sh"
ENV IDF_TOOLS_INSTALL_CMD="/opt/esp/idf/install.sh"
ENV IDF_TOOLS_PATH="/opt/esp"
ENV NODE_PATH="/v8/lib/node_modules"
ENV NODE_VERSION="8"
ENV OPENOCD_SCRIPTS="/opt/esp/tools/openocd-esp32/v0.10.0-esp32-20211111/openocd-esp32/share/openocd/scripts"
# Ccache is installed, enable it by default
ENV IDF_CCACHE_ENABLE=1
COPY docker/entrypoint.sh /opt/esp/entrypoint.sh
# Now install nodejs, npm and the packages we need
COPY components/wifi-manager/webapp/package.json /opt
ENV NODE_VERSION 8
@@ -117,17 +133,24 @@ SHELL ["/bin/bash", "--login", "-c"]
RUN : \
&& curl -fsSL https://deb.nodesource.com/setup_16.x | bash - \
&& apt-get install -y nodejs \
&& echo installing node modules \
&& cd /opt \
&& npm i -g npm \
&& node --version \
&& npm install -g \
&& :
&& apt-get install -y nodejs jq \
&& echo installing dev node modules globally \
&& cd /opt \
&& cat ./package.json | jq '.devDependencies | keys[] as $k | "\($k)@\(.[$k])"' | xargs -t npm install --global \
&& echo installing npm global packages \
&& npm i -g npm \
&& node --version \
&& npm install -g \
&& :
ENV NODE_PATH $NVM_DIR/v$NODE_VERSION/lib/node_modules
ENV PATH $NVM_DIR/v$NODE_VERSION/bin:$PATH
ENV PATH $IDF_PYTHON_ENV_PATH:$NVM_DIR/v$NODE_VERSION/bin:$PATH
COPY ./docker/build_tools.py /usr/sbin/build_tools.py
RUN : \
&& echo Changing permissions ******************************************************** \
&& chmod +x /opt/esp/entrypoint.sh \
&& chmod +x /usr/sbin/build_tools.py \
&& :
ENTRYPOINT [ "/opt/esp/entrypoint.sh" ]
CMD [ "/bin/bash" ]

View File

@@ -188,13 +188,14 @@ Ground -------------------------- coax signal ground
The NVS parameter "display_config" sets the parameters for an optional display. Syntax is
```
I2C,width=<pixels>,height=<pixels>[address=<i2c_address>][,reset=<gpio>][,HFlip][,VFlip][driver=SSD1306|SSD1326[:1|4]|SSD1327|SH1106]
SPI,width=<pixels>,height=<pixels>,cs=<gpio>[,back=<gpio>][,reset=<gpio>][,speed=<speed>][,HFlip][,VFlip][driver=SSD1306|SSD1322|SSD1326[:1|4]|SSD1327|SH1106|SSD1675|ST7735|ST7789|ILI9341[:16|18][,rotate]]
SPI,width=<pixels>,height=<pixels>,cs=<gpio>[,back=<gpio>][,reset=<gpio>][,speed=<speed>][,HFlip][,VFlip][driver=SSD1306|SSD1322|SSD1326[:1|4]|SSD1327|SH1106|SSD1675|ST7735|ST7789|ILI9341[:16|18][,rotate]][,mode=<mode>]
```
- back: a LED backlight used by some older devices (ST7735). It is PWM controlled for brightness
- reset: some display have a reset pin that is should normally be pulled up if unused
- VFlip and HFlip are optional can be used to change display orientation
- rotate: for non-square *drivers*, move to portrait mode. Note that *width* and *height* must be inverted then
- Default speed is 8000000 (8MHz) but SPI can work up to 26MHz or even 40MHz
- mode: Default mode = 0. Some display modules use different transaction line timings. Check the module documentation if a non-standard mode is required.
- SH1106 is 128x64 monochrome I2C/SPI [here]((https://www.waveshare.com/wiki/1.3inch_OLED_HAT))
- SSD1306 is 128x32 monochrome I2C/SPI [here](https://www.buydisplay.com/i2c-blue-0-91-inch-oled-display-module-128x32-arduino-raspberry-pi)
- SSD1322 is 256x64 grayscale 16-levels SPI in multiple sizes [here](https://www.buydisplay.com/oled-display/oled-display-module?resolution=159) - it is very nice

View File

@@ -259,7 +259,7 @@ CONFIG_CSPOT_SINK=y
# Various I/O
#
CONFIG_I2C_CONFIG=""
CONFIG_SET_GPIO=""
CONFIG_SET_GPIO="0=ir"
CONFIG_ROTARY_ENCODER=""
# end of Various I/O

View File

@@ -3,12 +3,6 @@
echo "Build process started"
pushd components/wifi-manager/webapp/
echo "Installing node.js dependencies"
npm install
echo "Building webapp"
npm run-script build
popd
echo "Setting up build name and build number"
if [ -z "${TARGET_BUILD_NAME}" ]
then

View File

@@ -11,7 +11,7 @@ bool GDS_I2CInit( int PortNumber, int SDA, int SCL, int speed );
bool GDS_I2CAttachDevice( struct GDS_Device* Device, int Width, int Height, int I2CAddress, int RSTPin, int BacklightPin );
bool GDS_SPIInit( int SPI, int DC );
bool GDS_SPIAttachDevice( struct GDS_Device* Device, int Width, int Height, int CSPin, int RSTPin, int Speed, int BacklightPin );
bool GDS_SPIAttachDevice( struct GDS_Device* Device, int Width, int Height, int CSPin, int RSTPin, int Speed, int BacklightPin, int Mode );
#ifdef __cplusplus
}

View File

@@ -34,7 +34,7 @@ bool GDS_SPIInit( int SPI, int DC ) {
return true;
}
bool GDS_SPIAttachDevice( struct GDS_Device* Device, int Width, int Height, int CSPin, int RSTPin, int BackLightPin, int Speed ) {
bool GDS_SPIAttachDevice( struct GDS_Device* Device, int Width, int Height, int CSPin, int RSTPin, int BackLightPin, int Speed, int Mode ) {
spi_device_interface_config_t SPIDeviceConfig = { };
spi_device_handle_t SPIDevice;
@@ -48,6 +48,7 @@ bool GDS_SPIAttachDevice( struct GDS_Device* Device, int Width, int Height, int
SPIDeviceConfig.clock_speed_hz = Speed > 0 ? Speed : SPI_MASTER_FREQ_8M;
SPIDeviceConfig.spics_io_num = CSPin;
SPIDeviceConfig.queue_size = 1;
SPIDeviceConfig.mode = Mode;
SPIDeviceConfig.flags = SPI_DEVICE_NO_DUMMY;
if (Device->SPIParams) Device->SPIParams(SPIDeviceConfig.clock_speed_hz, &SPIDeviceConfig.mode,
&SPIDeviceConfig.cs_ena_pretrans, &SPIDeviceConfig.cs_ena_posttrans);

View File

@@ -119,14 +119,15 @@ void display_init(char *welcome) {
ESP_LOGI(TAG, "Display is I2C on port %u", address);
} else if (strcasestr(config, "SPI") && spi_system_host != -1) {
int CS_pin = -1, speed = 0;
int CS_pin = -1, speed = 0, mode = 0;
PARSE_PARAM(config, "cs", '=', CS_pin);
PARSE_PARAM(config, "speed", '=', speed);
PARSE_PARAM(config, "mode", '=', mode);
init = true;
GDS_SPIInit( spi_system_host, spi_system_dc_gpio );
GDS_SPIAttachDevice( display, width, height, CS_pin, RST_pin, backlight_pin, speed );
GDS_SPIAttachDevice( display, width, height, CS_pin, RST_pin, backlight_pin, speed, mode );
ESP_LOGI(TAG, "Display is SPI host %u with cs:%d", spi_system_host, CS_pin);
} else {

View File

@@ -83,25 +83,26 @@ static void bt_app_task_handler(void *arg)
esp_bt_controller_mem_release(ESP_BT_MODE_BLE);
esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
if ((err = esp_bt_controller_init(&bt_cfg)) != ESP_OK) {
ESP_LOGE(TAG, "%s initialize controller failed: %s\n", __func__, esp_err_to_name(err));
goto exit;
}
if (esp_bt_controller_get_status() == ESP_BT_CONTROLLER_STATUS_IDLE ) {
if ((err = esp_bt_controller_init(&bt_cfg)) != ESP_OK) {
ESP_LOGE(TAG, "%s initialize controller failed: %s\n", __func__, esp_err_to_name(err));
goto exit;
}
if ((err = esp_bt_controller_enable(ESP_BT_MODE_CLASSIC_BT)) != ESP_OK) {
ESP_LOGE(TAG, "%s enable controller failed: %s\n", __func__, esp_err_to_name(err));
goto exit;
}
if ((err = esp_bt_controller_enable(ESP_BT_MODE_CLASSIC_BT)) != ESP_OK) {
ESP_LOGE(TAG, "%s enable controller failed: %s\n", __func__, esp_err_to_name(err));
goto exit;
}
if ((err = esp_bluedroid_init()) != ESP_OK) {
ESP_LOGE(TAG, "%s initialize bluedroid failed: %s\n", __func__, esp_err_to_name(err));
goto exit;
}
if ((err = esp_bluedroid_init()) != ESP_OK) {
ESP_LOGE(TAG, "%s initialize bluedroid failed: %s\n", __func__, esp_err_to_name(err));
goto exit;
}
if ((err = esp_bluedroid_enable()) != ESP_OK) {
ESP_LOGE(TAG, "%s enable bluedroid failed: %s\n", __func__, esp_err_to_name(err));
goto exit;
if ((err = esp_bluedroid_enable()) != ESP_OK) {
ESP_LOGE(TAG, "%s enable bluedroid failed: %s\n", __func__, esp_err_to_name(err));
goto exit;
}
}
/* Bluetooth device name, connection mode and profile set up */
@@ -114,6 +115,14 @@ static void bt_app_task_handler(void *arg)
esp_bt_gap_set_security_param(param_type, &iocap, sizeof(uint8_t));
#endif
/*
* Set default parameters for Legacy Pairing
* Use variable pin, input pin code when pairing
*/
esp_bt_pin_type_t pin_type = ESP_BT_PIN_TYPE_VARIABLE;
esp_bt_pin_code_t pin_code;
esp_bt_gap_set_pin(pin_type, 0, pin_code);
running = true;
while (running) {

View File

@@ -672,9 +672,9 @@ static void filter_inquiry_scan_result(esp_bt_gap_cb_param_t *param)
ESP_LOGV(TAG,"--Invalid class of device. Skipping.\n");
return;
}
else if (!(esp_bt_gap_get_cod_srvc(cod) & ESP_BT_COD_SRVC_RENDERING))
else if (!(esp_bt_gap_get_cod_srvc(cod) & (ESP_BT_COD_SRVC_RENDERING | ESP_BT_COD_SRVC_AUDIO)))
{
ESP_LOGV(TAG,"--Not a rendering device. Skipping.\n");
ESP_LOGV(TAG,"--Not a rendering or audio device. Skipping.\n");
return;
}

View File

@@ -634,7 +634,7 @@ cJSON * config_alloc_get_cjson(const char *key){
}
return conf_json;
}
esp_err_t config_set_cjson_str(const char *key, cJSON *value){
esp_err_t config_set_cjson_str_and_free(const char *key, cJSON *value){
char * value_str = cJSON_PrintUnformatted(value);
if(value_str==NULL){
ESP_LOGE(TAG, "Unable to print cJSON for key [%s]", key);

View File

@@ -53,7 +53,7 @@ void config_init();
void * config_alloc_get_default(nvs_type_t type, const char *key, void * default_value, size_t blob_size);
void * config_alloc_get_str(const char *key, char *lead, char *fallback);
cJSON * config_alloc_get_cjson(const char *key);
esp_err_t config_set_cjson_str(const char *key, cJSON *value);
esp_err_t config_set_cjson_str_and_free(const char *key, cJSON *value);
void config_get_uint16t_from_str(const char *key, uint16_t *value, uint16_t default_value);
void config_delete_key(const char *key);
void config_set_default(nvs_type_t type, const char *key, void * default_value, size_t blob_size);

View File

@@ -592,8 +592,9 @@ static int is_valid_gpio_number(int gpio, const char * name, FILE *f, bool manda
}
return 0;
}
#ifdef CONFIG_CSPOT_SINK
static int do_cspot_config(int argc, char **argv){
char * name = NULL;
int nerrors = arg_parse_msg(argc, argv,(struct arg_hdr **)&cspot_args);
if (nerrors != 0) {
return 1;
@@ -610,31 +611,37 @@ static int do_cspot_config(int argc, char **argv){
cJSON * cspot_config = config_alloc_get_cjson("cspot_config");
if(!cspot_config){
nerrors++;
fprintf(f,"error: Unable to get cspot config.\n");
fprintf(f,"error: Unable to get default cspot config.\n");
}
else {
cjson_update_string(&cspot_config,cspot_args.deviceName->hdr.longopts,cspot_args.deviceName->count>0?cspot_args.deviceName->sval[0]:NULL);
// cjson_update_number(&cspot_config,cspot_args.volume->hdr.longopts,cspot_args.volume->count>0?cspot_args.volume->ival[0]:0);
cjson_update_number(&cspot_config,cspot_args.bitrate->hdr.longopts,cspot_args.bitrate->count>0?cspot_args.bitrate->ival[0]:0);
if(cspot_args.deviceName->count>0){
cjson_update_string(&cspot_config,cspot_args.deviceName->hdr.longopts,cspot_args.deviceName->sval[0]);
}
if(cspot_args.bitrate->count>0){
cjson_update_number(&cspot_config,cspot_args.bitrate->hdr.longopts,cspot_args.bitrate->ival[0]);
}
if(!nerrors ){
fprintf(f,"Storing cspot parameters.\n");
nerrors+=(config_set_cjson_str("cspot_config",cspot_config) !=ESP_OK);
nerrors+=(config_set_cjson_str_and_free("cspot_config",cspot_config) !=ESP_OK);
}
if(nerrors==0){
fprintf(f,"Device name changed to %s\n",name);
if(nerrors==0 ){
if(cspot_args.deviceName->count>0){
fprintf(f,"Device name changed to %s\n",cspot_args.deviceName->sval[0]);
}
if(cspot_args.bitrate->count>0){
fprintf(f,"Bitrate changed to %u\n",cspot_args.bitrate->ival[0]);
}
}
if(!nerrors ){
fprintf(f,"Done.\n");
}
FREE_AND_NULL(name);
fflush (f);
cmd_send_messaging(argv[0],nerrors>0?MESSAGING_ERROR:MESSAGING_INFO,"%s", buf);
fclose(f);
FREE_AND_NULL(buf);
return nerrors;
}
#endif
static int do_i2s_cmd(int argc, char **argv)
{
i2s_platform_config_t i2s_dac_pin = {
@@ -742,6 +749,7 @@ cJSON * known_model_cb(){
}
return values;
}
#ifdef CONFIG_CSPOT_SINK
cJSON * cspot_cb(){
cJSON * values = cJSON_CreateObject();
if(!values){
@@ -761,13 +769,11 @@ cJSON * cspot_cb(){
if(cspot_values){
cJSON_AddNumberToObject(values,cspot_args.bitrate->hdr.longopts,cJSON_GetNumberValue(cspot_values));
}
// cspot_values = cJSON_GetObjectItem(cspot_config,cspot_args.volume->hdr.longopts);
// if(cspot_values){
// cJSON_AddNumberToObject(values,cspot_args.volume->hdr.longopts,cJSON_GetNumberValue(cspot_values));
// }
cJSON_Delete(cspot_config);
return values;
}
#endif
cJSON * i2s_cb(){
cJSON * values = cJSON_CreateObject();
@@ -1171,7 +1177,7 @@ static void register_known_templates_config(){
cmd_to_json_with_cb(&cmd,&known_model_cb);
ESP_ERROR_CHECK(esp_console_cmd_register(&cmd));
}
#ifdef CONFIG_CSPOT_SINK
static void register_cspot_config(){
cspot_args.deviceName = arg_str1(NULL,"deviceName","","Device Name");
cspot_args.bitrate = arg_int1(NULL,"bitrate","96|160|320","Streaming Bitrate (kbps)");
@@ -1187,6 +1193,7 @@ static void register_cspot_config(){
cmd_to_json_with_cb(&cmd,&cspot_cb);
ESP_ERROR_CHECK(esp_console_cmd_register(&cmd));
}
#endif
static void register_i2s_config(void){
i2s_args.model_name = arg_str1(NULL,"model_name",STR_OR_BLANK(get_dac_list()),"DAC Model Name");
i2s_args.clear = arg_lit0(NULL, "clear", "Clear configuration");
@@ -1328,8 +1335,11 @@ static void register_squeezelite_config(void){
void register_config_cmd(void){
if(!is_dac_config_locked()){
register_known_templates_config();
}
#ifdef CONFIG_CSPOT_SINK
register_cspot_config();
#endif
register_audio_config();
// register_squeezelite_config();
register_bt_source_config();

View File

@@ -101,6 +101,7 @@ static struct {
struct arg_int *reset;
struct arg_lit *clear;
struct arg_lit *invert;
struct arg_int *mode;
struct arg_end *end;
} i2cdisp_args;
@@ -377,6 +378,13 @@ static int do_i2c_set_display(int argc, char **argv)
}
/* Check "--cs" option */
nerrors +=is_output_gpio(i2cdisp_args.cs,f,&config.CS_pin, false);
/* Check "--mode" option */
if (i2cdisp_args.mode->count) {
config.mode=i2cdisp_args.mode->ival[0];
}
else {
config.mode = 0;
}
}
nerrors +=is_output_gpio(i2cdisp_args.reset,f,&config.RST_pin, false);
@@ -964,6 +972,9 @@ cJSON * i2c_set_display_cb(){
cJSON_AddBoolToObject(values,"hf",conf->hflip);
cJSON_AddBoolToObject(values,"vf",conf->vflip);
cJSON_AddBoolToObject(values,"invert",conf->invert);
if(conf->mode>=0){
cJSON_AddNumberToObject(values,"mode",conf->mode);
}
}
return values;
}
@@ -986,6 +997,7 @@ static void register_i2c_set_display(){
i2cdisp_args.rotate = arg_lit0("r", "rotate", "Rotate 180 degrees");
i2cdisp_args.invert = arg_lit0("i", "invert", "Invert colors");
i2cdisp_args.clear = arg_lit0(NULL, "clear", "clear configuration and return");
i2cdisp_args.mode = arg_int0("m", "mode", "<n>","SPI Only. Transaction Line Mode (Default 0)");
i2cdisp_args.end = arg_end(8);
const esp_console_cmd_t i2c_set_display= {
.command = CFG_TYPE_HW("display"),

View File

@@ -352,6 +352,10 @@ esp_err_t config_display_set(const display_config_t * config){
snprintf(config_buffer2,buffer_size,"%s,speed=%i",config_buffer,config->speed);
strcpy(config_buffer,config_buffer2);
}
if(config->mode >=0 && strcasecmp("SPI",config->type)==0){
snprintf(config_buffer2,buffer_size,"%s,mode=%i",config_buffer,config->mode);
strcpy(config_buffer,config_buffer2);
}
snprintf(config_buffer2,buffer_size,"%s,driver=%s%s%s%s",config_buffer,config->drivername,config->hflip?",HFlip":"",config->vflip?",VFlip":"",config->rotate?",rotate":"");
strcpy(config_buffer,config_buffer2);
log_send_messaging(MESSAGING_INFO,"Updating display configuration to %s",config_buffer);
@@ -465,6 +469,7 @@ const display_config_t * config_display_get(){
.rotate = false,
.invert = false,
.colorswap = 0,
.mode = 0,
};
char *config = config_alloc_get(NVS_TYPE_STR, "display_config");
if (!config) {
@@ -484,6 +489,8 @@ const display_config_t * config_display_get(){
PARSE_PARAM(config, "address", '=', dstruct.address);
PARSE_PARAM(config, "cs", '=', dstruct.CS_pin);
PARSE_PARAM(config, "speed", '=', dstruct.speed);
PARSE_PARAM(config, "back", '=', dstruct.back);
PARSE_PARAM(config, "mode", '=', dstruct.mode);
if (strstr(config, "I2C") ) dstruct.type=i2c_name_type;
if (strstr(config, "SPI") ) dstruct.type=spi_name_type;

View File

@@ -33,6 +33,7 @@ typedef struct {
bool rotate;
bool invert;
int colorswap;
int mode;
} display_config_t;
typedef struct eth_config_struct {

View File

@@ -415,7 +415,7 @@ bool create_rotary(void *id, int A, int B, int SW, int long_press, rotary_handle
// create companion button if rotary has a switch
if (SW != -1) button_create(id, SW, BUTTON_LOW, true, 0, rotary_button_handler, long_press, -1);
ESP_LOGI(TAG, "Creating rotary encoder A:%d B:%d, SW:%d", A, B, SW);
ESP_LOGI(TAG, "Created rotary encoder A:%d B:%d, SW:%d", A, B, SW);
return true;
}
@@ -432,5 +432,7 @@ bool create_infrared(int gpio, infrared_handler handler) {
common_task_init();
xRingbufferAddToQueueSetRead(infrared.rb, common_queue_set);
ESP_LOGI(TAG, "Created infrared receiver using GPIO %u", gpio);
return (infrared.rb != NULL);
}

View File

@@ -60,6 +60,10 @@ static const char TAG[] = "gpio expander";
static void IRAM_ATTR intr_isr_handler(void* arg);
static gpio_exp_t* find_expander(gpio_exp_t *expander, int *gpio);
static esp_err_t mpr121_init(gpio_exp_t* self);
static uint32_t mpr121_read(gpio_exp_t* self);
static void mpr121_write(gpio_exp_t* self);
static void pca9535_set_direction(gpio_exp_t* self);
static uint32_t pca9535_read(gpio_exp_t* self);
static void pca9535_write(gpio_exp_t* self);
@@ -98,6 +102,11 @@ static const struct gpio_exp_model_s {
void (*set_direction)(gpio_exp_t* self);
void (*set_pull_mode)(gpio_exp_t* self);
} registered[] = {
{ .model = "mpr121",
.trigger = GPIO_INTR_LOW_LEVEL,
.init = mpr121_init,
.read = mpr121_read,
.write = mpr121_write, },
{ .model = "pca9535",
.trigger = GPIO_INTR_LOW_LEVEL,
.set_direction = pca9535_set_direction,
@@ -498,6 +507,56 @@ static gpio_exp_t* find_expander(gpio_exp_t *expander, int *gpio) {
DRIVERS
****************************************************************************************/
/****************************************************************************************
* MPR121 family : init, direction, read and write
*/
static esp_err_t mpr121_init(gpio_exp_t* self) {
static const struct {
uint8_t addr;
uint8_t data;
} mpr121_init_table[] = {
{ 0x80, 0x63 }, /* Soft reset */
{ 0x2b, 0x01 }, { 0x2c, 0x01 }, { 0x2d, 0x10 }, { 0x2e, 0x20 }, /* MHDR, NHDR, NCLR, FDLR */
{ 0x2f, 0x01 }, { 0x30, 0x01 }, { 0x31, 0x10 }, { 0x32, 0x20 }, /* MHDF, NHDF, NCLF, FDLF */
{ 0x33, 0x01 }, { 0x34, 0x10 }, { 0x35, 0xff }, /* NHDT, NCLT, FDLT */
{ 0x5b, 0x11 }, { 0x5c, 0xff }, { 0x5d, 0x30 }, /* DTR, AFE1, AFE2 */
{ 0x7b, 0x00 }, { 0x7c, 0x00 }, { 0x7d, 0x00 }, { 0x7e, 0x00 }, { 0x7f, 0x00 },/* ACCR0, ACCR1, USL, LSL, TL */
{ 0x41, 0x28 }, { 0x42, 0x14 }, /* ELE0: Touch Threshold, Release Threshold */
{ 0x43, 0x28 }, { 0x44, 0x14 }, /* ELE1: Touch Threshold, Release Threshold */
{ 0x45, 0x28 }, { 0x46, 0x14 }, /* ELE2: Touch Threshold, Release Threshold */
{ 0x47, 0x28 }, { 0x48, 0x14 }, /* ELE3: Touch Threshold, Release Threshold */
{ 0x49, 0x28 }, { 0x4a, 0x14 }, /* ELE4: Touch Threshold, Release Threshold */
{ 0x4b, 0x28 }, { 0x4c, 0x14 }, /* ELE5: Touch Threshold, Release Threshold */
{ 0x4d, 0x28 }, { 0x4e, 0x14 }, /* ELE6: Touch Threshold, Release Threshold */
{ 0x4f, 0x28 }, { 0x50, 0x14 }, /* ELE7: Touch Threshold, Release Threshold */
{ 0x51, 0x28 }, { 0x52, 0x14 }, /* ELE8: Touch Threshold, Release Threshold */
{ 0x53, 0x28 }, { 0x54, 0x14 }, /* ELE9: Touch Threshold, Release Threshold */
{ 0x55, 0x28 }, { 0x56, 0x14 }, /* ELE10: Touch Threshold, Release Threshold */
{ 0x57, 0x28 }, { 0x58, 0x14 }, /* ELE11: Touch Threshold, Release Threshold */
{ 0x5e, 0xcc }, /* ECR - must be set last */
{0, 0}
};
esp_err_t err = 0;
for (int i = 0; mpr121_init_table[i].addr; i++) {
err |= i2c_write(self->phy.port, self->phy.addr, mpr121_init_table[i].addr, mpr121_init_table[i].data, 1);
}
return err;
}
static uint32_t mpr121_read(gpio_exp_t* self) {
// only return the lower 12 bits of the pin status registers
return i2c_read(self->phy.port, self->phy.addr, 0x00, 2) & 0x0fff;
}
static void mpr121_write(gpio_exp_t* self) {
ESP_LOGE(TAG, "MPR121 GPIO write not implemented");
}
/****************************************************************************************
* PCA9535 family : direction, read and write
*/

View File

@@ -111,6 +111,7 @@ void services_init(void) {
if (spi_config->mosi_io_num != -1 && spi_config->sclk_io_num != -1) {
spi_bus_initialize( spi_system_host, spi_config, 1 );
if (spi_system_dc_gpio != -1) {
gpio_reset_pin(spi_system_dc_gpio);
gpio_set_direction( spi_system_dc_gpio, GPIO_MODE_OUTPUT );
gpio_set_level( spi_system_dc_gpio, 0 );
} else {

View File

@@ -8,7 +8,6 @@ idf_component_register(
LDFRAGMENTS "linker.lf"
)
add_definitions(-DBELL_USE_MBEDTLS)
add_definitions(-Wno-unused-variable -Wno-unused-const-variable -Wchar-subscripts -Wunused-label -Wmaybe-uninitialized -Wmisleading-indentation)
set(BELL_DISABLE_CODECS ON)

View File

@@ -116,6 +116,7 @@ static void cspotTask(void *pvParameters) {
spircController = std::make_shared<SpircController>(mercuryManager, cspot.blob->username, audioSink);
spircController->setEventHandler([](CSpotEvent &event) {
ESP_LOGI(TAG, "Getting Spotify event %d ", (int) event.eventType);
switch (event.eventType) {
case CSpotEventType::TRACK_INFO: {
TrackInfo track = std::get<TrackInfo>(event.data);
@@ -161,6 +162,8 @@ static void cspotTask(void *pvParameters) {
}
});
// need to make sure mercuryManager is running otherwise we'll loop and destroy instances
while (!mercuryManager->isRunning) vTaskDelay(pdMS_TO_TICKS(25));
mercuryManager->reconnectedCallback = []() {
return spircController->subscribe();
};
@@ -293,18 +296,18 @@ bool NVSFile::flush() {
* Shim HTTP server for spirc
*/
static esp_err_t handlerWrapper(httpd_req_t *req) {
bell::HTTPRequest request = { };
std::unique_ptr<bell::HTTPRequest> request = std::make_unique<bell::HTTPRequest>();
char *query = NULL, *body = NULL;
bell::httpHandler *handler = (bell::httpHandler*) req->user_ctx;
size_t query_len = httpd_req_get_url_query_len(req);
request.connection = httpd_req_to_sockfd(req);
request->connection = httpd_req_to_sockfd(req);
// get body if any (add '\0' at the end if used as string)
if (req->content_len) {
body = (char*) calloc(1, req->content_len + 1);
int size = httpd_req_recv(req, body, req->content_len);
request.body = body;
request->body = body;
ESP_LOGD(TAG,"wrapper received body %d/%d", size, req->content_len);
}
@@ -324,7 +327,7 @@ static esp_err_t handlerWrapper(httpd_req_t *req) {
while (key) {
char *value = strchr(key, '=');
*value++ = '\0';
request.queryParams[key] = value;
request->queryParams[key] = value;
ESP_LOGD(TAG,"wrapper received key:%s value:%s", key, value);
key = strtok(NULL, "&");
};
@@ -337,12 +340,12 @@ static esp_err_t handlerWrapper(httpd_req_t *req) {
and then we'll return. So we can't obtain the response to be sent, as esp_http_server
normally expects, instead respond() will use raw socket and close connection
*/
(*handler)(request);
(*handler)(std::move(request));
return ESP_OK;
}
void ShimHTTPServer::registerHandler(bell::RequestType requestType, const std::string &routeUrl, bell::httpHandler handler) {
void ShimHTTPServer::registerHandler(bell::RequestType requestType, const std::string &routeUrl, bell::httpHandler handler, bool readDataToStr) {
httpd_uri_t request = {
.uri = routeUrl.c_str(),
.method = (requestType == bell::RequestType::GET ? HTTP_GET : HTTP_POST),

View File

@@ -44,7 +44,6 @@ private:
public:
ShimHTTPServer(httpd_handle_t server, int port) { serverHandle = server; serverPort = port; }
void registerHandler(bell::RequestType requestType, const std::string &, bell::httpHandler);
void registerHandler(bell::RequestType requestType, const std::string &, bell::httpHandler, bool readDataToStr = false);
void respond(const bell::HTTPResponse &);
};

View File

@@ -6,11 +6,21 @@ project(cspot)
set(CSPOT_EXTERNAL_BELL "" CACHE STRING "External bell library target name, optional")
# CMake options
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD 20)
if(MSVC)
add_compile_definitions(NOMINMAX _WINSOCK_DEPRECATED_NO_WARNINGS _CRT_SECURE_NO_WARNINGS)
add_definitions(/wd4068 /wd4244 /wd4018 /wd4101 /wd4102 /wd4142 /wd4996)
endif()
# Main library sources
file(GLOB SOURCES "src/*.cpp" "src/*.c")
if(WIN32)
list(APPEND SOURCES "mdnssvc/mdns.c" "mdnssvc/mdnsd.c")
list(APPEND EXTRA_INCLUDES "mdnssvc")
endif()
# Use externally specified bell library or the submodule
if(CSPOT_EXTERNAL_BELL)
list(APPEND EXTRA_LIBS ${CSPOT_EXTERNAL_BELL})
@@ -26,21 +36,21 @@ if(UNIX AND NOT APPLE)
endif()
# Build protobuf code
#set(NANOPB_OPTIONS "-I${CMAKE_CURRENT_SOURCE_DIR}")
#file(GLOB PROTOS protobuf/*.proto)
#nanopb_generate_cpp(PROTO_SRCS PROTO_HDRS RELPATH ${CMAKE_CURRENT_SOURCE_DIR} ${PROTOS})
#add_custom_target(generate_proto_sources DEPENDS ${PROTO_SRCS} ${PROTO_HDRS})
#set_source_files_properties(${PROTO_SRCS} ${PROTO_HDRS}
# PROPERTIES GENERATED TRUE)
file(GLOB SOURCES "src/*.cpp" "src/*.c" "protobuf/*.c")
message("BEWARE => NOT GENERATING PROTOBUF")
set(GENERATED_INCLUDES ".")
if(1)
set(NANOPB_OPTIONS "-I${CMAKE_CURRENT_SOURCE_DIR}")
file(GLOB PROTOS protobuf/*.proto)
nanopb_generate_cpp(PROTO_SRCS PROTO_HDRS RELPATH ${CMAKE_CURRENT_SOURCE_DIR} ${PROTOS})
add_custom_target(generate_proto_sources DEPENDS ${PROTO_SRCS} ${PROTO_HDRS})
set_source_files_properties(${PROTO_SRCS} ${PROTO_HDRS} PROPERTIES GENERATED TRUE)
else()
list(APPEND SOURCES "protobuf/authentication.pb.c" "protobuf/keyexchange.pb.c" "protobuf/mercury.pb.c" "protobuf/metadata.pb.c" "protobuf/spirc.pb.c")
list(APPEND EXTRA_INCLUDES ".")
message(WARNING "NOT GENERATING PROTOBUF")
endif()
add_library(cspot STATIC ${SOURCES} ${PROTO_SRCS})
# PUBLIC to propagate includes from bell to cspot dependents
target_compile_definitions(bell PUBLIC PB_ENABLE_MALLOC)
target_compile_definitions(bell PUBLIC PB_FIELD_32BIT)
target_link_libraries(cspot PUBLIC ${EXTRA_LIBS})
#target_include_directories(cspot PUBLIC "include" ${CMAKE_CURRENT_BINARY_DIR} ${NANOPB_INCLUDE_DIRS})
target_include_directories(cspot PUBLIC "include" ${GENERATED_INCLUDES} ${NANOPB_INCLUDE_DIRS})
target_include_directories(cspot PUBLIC "include" ${CMAKE_CURRENT_BINARY_DIR} ${NANOPB_INCLUDE_DIRS} ${EXTRA_INCLUDES})

Binary file not shown.

126
components/spotify/cspot/bell/.gitignore vendored Normal file
View File

@@ -0,0 +1,126 @@
# Created by https://www.toptal.com/developers/gitignore/api/c,c++,cmake,macos
# Edit at https://www.toptal.com/developers/gitignore?templates=c,c++,cmake,macos
### C ###
# Prerequisites
*.d
# Object files
*.o
*.ko
*.obj
*.elf
# Linker output
*.ilk
*.map
*.exp
# Precompiled Headers
*.gch
*.pch
# Libraries
*.lib
*.a
*.la
*.lo
# Shared objects (inc. Windows DLLs)
*.dll
*.so
*.so.*
*.dylib
# Executables
*.exe
*.out
*.app
*.i*86
*.x86_64
*.hex
# Debug files
*.dSYM/
*.su
*.idb
*.pdb
# Kernel Module Compile Results
*.mod*
*.cmd
.tmp_versions/
modules.order
Module.symvers
Mkfile.old
dkms.conf
### C++ ###
# Prerequisites
# Compiled Object files
*.slo
# Precompiled Headers
# Compiled Dynamic libraries
# Fortran module files
*.mod
*.smod
# Compiled Static libraries
*.lai
# Executables
### CMake ###
CMakeLists.txt.user
CMakeCache.txt
CMakeFiles
CMakeScripts
Testing
Makefile
cmake_install.cmake
install_manifest.txt
compile_commands.json
CTestTestfile.cmake
_deps
### CMake Patch ###
# External projects
*-prefix/
### macOS ###
# General
.DS_Store
.AppleDouble
.LSOverride
# Icon must end with two \r
Icon
# Thumbnails
._*
# Files that might appear in the root of a volume
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
.com.apple.timemachine.donotpresent
# Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk
# End of https://www.toptal.com/developers/gitignore/api/c,c++,cmake,macos
build/

View File

@@ -5,3 +5,6 @@
[submodule "cJSON"]
path = cJSON
url = https://github.com/DaveGamble/cJSON
[submodule "nanopb"]
path = nanopb
url = https://github.com/nanopb/nanopb

View File

@@ -4,79 +4,201 @@ cmake_policy(SET CMP0077 NEW)
project(bell)
# Configurable options
option(BELL_DISABLE_CODECS "Disable libhelix AAC and MP3 codecs" OFF)
option(BELL_DISABLE_SINKS "Disable built-in audio sink implementations" OFF)
option(BELL_USE_ALSA "Enable ALSA sink" OFF)
option(BELL_USE_PORTAUDIO "Enable PortAudio sink" OFF)
option(BELL_DISABLE_CODECS "Disable the entire audio codec wrapper" OFF)
option(BELL_CODEC_AAC "Support libhelix-aac codec" ON)
option(BELL_CODEC_MP3 "Support libhelix-mp3 codec" ON)
option(BELL_CODEC_VORBIS "Support tremor Vorbis codec" ON)
option(BELL_CODEC_ALAC "Support Apple ALAC codec" ON)
option(BELL_CODEC_OPUS "Support Opus codec" ON)
option(BELL_DISABLE_SINKS "Disable all built-in audio sink implementations" OFF)
# These are default OFF, as they're OS-dependent (ESP32 sinks are always enabled - no external deps)
option(BELL_SINK_ALSA "Enable ALSA audio sink" OFF)
option(BELL_SINK_PORTAUDIO "Enable PortAudio sink" OFF)
# cJSON wrapper
option(BELL_DISABLE_CJSON "Disable cJSON and JSONObject completely" OFF)
set(BELL_EXTERNAL_CJSON "" CACHE STRING "External cJSON library target name, optional")
set(BELL_EXTERNAL_TREMOR "" CACHE STRING "External tremor library target name, optional")
if(BELL_EXTERNAL_MBEDTLS)
set(MbedTLS_DIR ${BELL_EXTERNAL_MBEDTLS})
message(STATUS "Setting local mbedtls ${MbedTLS_DIR}")
endif()
# Backwards compatibility with deprecated options
if(BELL_USE_ALSA)
message(WARNING "Deprecated Bell options used, replace BELL_USE_ALSA with BELL_SINK_ALSA")
set(BELL_SINK_ALSA ${BELL_USE_ALSA})
endif()
if(BELL_USE_PORTAUDIO)
message(WARNING "Deprecated Bell options used, replace BELL_USE_PORTAUDIO with BELL_SINK_PORTAUDIO")
set(BELL_SINK_PORTAUDIO ${BELL_USE_PORTAUDIO})
endif()
message(STATUS "Bell options:")
message(STATUS " Disable all codecs: ${BELL_DISABLE_CODECS}")
if(NOT BELL_DISABLE_CODECS)
message(STATUS " - AAC audio codec: ${BELL_CODEC_AAC}")
message(STATUS " - MP3 audio codec: ${BELL_CODEC_MP3}")
message(STATUS " - Vorbis audio codec: ${BELL_CODEC_VORBIS}")
message(STATUS " - Opus audio codec: ${BELL_CODEC_OPUS}")
message(STATUS " - ALAC audio codec: ${BELL_CODEC_ALAC}")
endif()
message(STATUS " Disable built-in audio sinks: ${BELL_DISABLE_SINKS}")
if(NOT BELL_DISABLE_SINKS)
message(STATUS " - ALSA sink: ${BELL_SINK_ALSA}")
message(STATUS " - PortAudio sink: ${BELL_SINK_PORTAUDIO}")
endif()
message(STATUS " Disable cJSON and JSONObject: ${BELL_DISABLE_CJSON}")
# Include nanoPB library
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/nanopb/extra)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/nanopb/extra")
find_package(Nanopb REQUIRED)
list(APPEND EXTRA_INCLUDES ${NANOPB_INCLUDE_DIRS})
# CMake options
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
add_definitions(-DUSE_DEFAULT_STDLIB=1)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
set(AUDIO_DIR "${CMAKE_CURRENT_SOURCE_DIR}/src/audio")
add_definitions("-DUSE_DEFAULT_STDLIB=1")
# Main library sources
file(GLOB SOURCES "src/*.cpp" "src/*.c" "nanopb/*.c")
list(APPEND EXTRA_INCLUDES "include/platform")
list(APPEND EXTRA_INCLUDES "include/audio/container")
# Add platform specific sources
if(ESP_PLATFORM)
file(GLOB ESP_PLATFORM_SOURCES "src/platform/esp/*.cpp" "src/platform/esp/*.c" "src/asm/biquad_f32_ae32.S")
list(APPEND SOURCES ${ESP_PLATFORM_SOURCES})
endif()
if(UNIX)
file(GLOB UNIX_PLATFORM_SOURCES "src/platform/unix/*.cpp" "src/platform/linux/TLSSocket.cpp" "src/platform/unix/*.c")
file(GLOB UNIX_PLATFORM_SOURCES "src/platform/unix/*.cpp" "src/platform/unix/*.c")
list(APPEND SOURCES ${UNIX_PLATFORM_SOURCES})
endif()
if(APPLE)
file(GLOB APPLE_PLATFORM_SOURCES "src/platform/apple/*.cpp" "src/platform/linux/TLSSocket.cpp" "src/platform/apple/*.c")
file(GLOB APPLE_PLATFORM_SOURCES "src/platform/apple/*.cpp" "src/platform/apple/*.c")
list(APPEND SOURCES ${APPLE_PLATFORM_SOURCES})
list(APPEND EXTRA_INCLUDES "/usr/local/opt/mbedtls@3/include")
endif()
if(UNIX AND NOT APPLE)
file(GLOB LINUX_PLATFORM_SOURCES "src/platform/linux/*.cpp" "src/platform/linux/*.c")
list(APPEND SOURCES ${LINUX_PLATFORM_SOURCES})
endif()
if(WIN32)
file(GLOB WIN32_PLATFORM_SOURCES "src/platform/win32/*.cpp" "src/platform/win32/*.c")
list(APPEND SOURCES ${WIN32_PLATFORM_SOURCES})
list(APPEND EXTRA_INCLUDES "include/platform/win32")
endif()
# A hack to make Opus keep quiet
function(message)
if(NOT MESSAGE_QUIET)
_message(${ARGN})
endif()
endfunction()
if(ESP_PLATFORM)
# Use MBedTLS on ESP32
list(REMOVE_ITEM SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src/CryptoOpenSSL.cpp)
idf_build_set_property(COMPILE_DEFINITIONS "-DBELL_USE_MBEDTLS" APPEND)
list(APPEND EXTRA_LIBS idf::mbedtls idf::pthread idf::mdns)
add_definitions(-Wunused-const-variable -Wchar-subscripts -Wunused-label -Wmaybe-uninitialized -Wmisleading-indentation)
else()
# Use OpenSSL elsewhere
list(REMOVE_ITEM SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src/CryptoMbedTLS.cpp)
find_package(OpenSSL REQUIRED)
find_package(Threads REQUIRED)
set(THREADS_PREFER_PTHREAD_FLAG ON)
if(OPENSSL_FOUND)
set(OPENSSL_USE_STATIC_LIBS TRUE)
endif()
list(APPEND EXTRA_LIBS OpenSSL::Crypto OpenSSL::SSL Threads::Threads)
list(APPEND EXTRA_LIBS Threads::Threads)
find_package(MbedTLS REQUIRED)
get_target_property(MBEDTLS_INFO MbedTLS::mbedtls INTERFACE_INCLUDE_DIRECTORIES)
list(APPEND EXTRA_INCLUDES ${MBEDTLS_INFO})
# try to handle mbedtls when not system-wide installed
if(BELL_EXTERNAL_MBEDTLS)
if(MSVC)
set(MBEDTLS_RELEASE "RELEASE" CACHE STRING "local mbedtls version")
else()
set(MBEDTLS_RELEASE "NOCONFIG" CACHE STRING "local mbedtls version")
endif()
message(STATUS "using local mbedtls version ${MBEDTLS_RELEASE}")
get_target_property(MBEDTLS_INFO MbedTLS::mbedtls IMPORTED_LOCATION_${MBEDTLS_RELEASE})
list(APPEND EXTRA_LIBS ${MBEDTLS_INFO})
get_target_property(MBEDTLS_INFO MbedTLS::mbedx509 IMPORTED_LOCATION_${MBEDTLS_RELEASE})
list(APPEND EXTRA_LIBS ${MBEDTLS_INFO})
get_target_property(MBEDTLS_INFO MbedTLS::mbedcrypto IMPORTED_LOCATION_${MBEDTLS_RELEASE})
list(APPEND EXTRA_LIBS ${MBEDTLS_INFO})
else()
list(APPEND EXTRA_LIBS mbedtls mbedcrypto mbedx509)
endif()
if(MSVC)
add_compile_definitions(NOMINMAX _CRT_SECURE_NO_WARNINGS)
add_definitions(/wd4068 /wd4244 /wd4018 /wd4101 /wd4102 /wd4142)
endif()
endif()
if(BELL_DISABLE_CODECS)
list(REMOVE_ITEM SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src/DecoderGlobals.cpp)
else()
file(GLOB LIBHELIX_AAC_SOURCES "libhelix-aac/*.c")
file(GLOB LIBHELIX_MP3_SOURCES "libhelix-mp3/*.c")
list(APPEND EXTRA_INCLUDES "libhelix-aac" "libhelix-mp3")
list(APPEND SOURCES ${LIBHELIX_MP3_SOURCES} ${LIBHELIX_AAC_SOURCES})
if(NOT BELL_DISABLE_CODECS)
file(GLOB EXTRA_SOURCES "src/audio/container/*.cpp")
list(APPEND SOURCES "${EXTRA_SOURCES}")
list(APPEND SOURCES "${AUDIO_DIR}/codec/DecoderGlobals.cpp")
list(APPEND SOURCES "${AUDIO_DIR}/codec/BaseCodec.cpp")
list(APPEND SOURCES "${AUDIO_DIR}/codec/AudioCodecs.cpp")
list(APPEND EXTRA_INCLUDES "include/audio/codec")
# AAC-LC codec
if(BELL_CODEC_AAC)
file(GLOB LIBHELIX_AAC_SOURCES "libhelix-aac/*.c")
list(APPEND LIBHELIX_SOURCES ${LIBHELIX_AAC_SOURCES})
list(APPEND EXTRA_INCLUDES "libhelix-aac")
list(APPEND SOURCES "${AUDIO_DIR}/codec/AACDecoder.cpp")
list(APPEND CODEC_FLAGS "-DBELL_CODEC_AAC")
endif()
# MP3 codec
if(BELL_CODEC_MP3)
file(GLOB LIBHELIX_MP3_SOURCES "libhelix-mp3/*.c")
list(APPEND LIBHELIX_SOURCES ${LIBHELIX_MP3_SOURCES})
list(APPEND EXTRA_INCLUDES "libhelix-mp3")
list(APPEND SOURCES "${AUDIO_DIR}/codec/MP3Decoder.cpp")
list(APPEND CODEC_FLAGS "-DBELL_CODEC_MP3")
endif()
# MP3 codec
if(BELL_CODEC_ALAC)
file(GLOB ALAC_SOURCES "alac/*.c" "alac/*.cpp")
list(APPEND ALAC_SOURCES ${ALAC_SOURCES})
list(APPEND EXTRA_INCLUDES "alac")
# list(APPEND SOURCES "${AUDIO_DIR}/codec/ALACDecoder.cpp")
list(APPEND CODEC_FLAGS "-DBELL_CODEC_ALAC")
endif()
# libhelix Cygwin workaround
if(CYGWIN)
# Both Cygwin and ESP are Unix-like so this seems to work (or, at least, compile)
set_source_files_properties(src/DecoderGlobals.cpp PROPERTIES COMPILE_FLAGS -DESP_PLATFORM)
set_source_files_properties(${LIBHELIX_AAC_SOURCES} PROPERTIES COMPILE_FLAGS -DESP_PLATFORM)
set_source_files_properties(${LIBHELIX_MP3_SOURCES} PROPERTIES COMPILE_FLAGS -DESP_PLATFORM)
set_source_files_properties("${AUDIO_DIR}/codec/DecoderGlobals.cpp" ${LIBHELIX_SOURCES} PROPERTIES COMPILE_FLAGS "-DESP_PLATFORM")
endif()
list(APPEND SOURCES ${LIBHELIX_SOURCES})
list(APPEND SOURCES ${ALAC_SOURCES})
# Vorbis codec
if(BELL_CODEC_VORBIS)
file(GLOB TREMOR_SOURCES "tremor/*.c")
list(REMOVE_ITEM TREMOR_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/tremor/ivorbisfile_example.c")
list(APPEND SOURCES ${TREMOR_SOURCES})
list(APPEND EXTRA_INCLUDES "tremor")
list(APPEND SOURCES "${AUDIO_DIR}/codec/VorbisDecoder.cpp")
list(APPEND CODEC_FLAGS "-DBELL_CODEC_VORBIS")
endif()
# Opus codec
if(BELL_CODEC_OPUS)
set(OPUS_INSTALL_CMAKE_CONFIG_MODULE OFF CACHE BOOL "")
set(OPUS_INSTALL_CMAKE_CONFIG_MODULE OFF)
set(OPUS_INSTALL_PKG_CONFIG_MODULE OFF CACHE BOOL "")
set(OPUS_INSTALL_PKG_CONFIG_MODULE OFF)
set(MESSAGE_QUIET ON)
add_subdirectory("opus")
unset(MESSAGE_QUIET)
target_compile_options(opus PRIVATE "-O3")
list(APPEND EXTRA_LIBS Opus::opus)
list(APPEND SOURCES "${AUDIO_DIR}/codec/OPUSDecoder.cpp")
list(APPEND CODEC_FLAGS -DBELL_CODEC_OPUS)
endif()
# Enable global codecs
string(REPLACE ";" " " CODEC_FLAGS "${CODEC_FLAGS}")
set_source_files_properties("${AUDIO_DIR}/codec/AudioCodecs.cpp" PROPERTIES COMPILE_FLAGS "${CODEC_FLAGS}")
elseif(BELL_EXTERNAL_TREMOR)
list(APPEND EXTRA_LIBS ${BELL_EXTERNAL_TREMOR})
endif()
if(NOT BELL_DISABLE_SINKS)
@@ -85,45 +207,52 @@ if(NOT BELL_DISABLE_SINKS)
set(PLATFORM "esp")
endif()
# Add all built-in audio sinks
file(GLOB SINK_SOURCES "src/sinks/${PLATFORM}/*.cpp" "src/sinks/${PLATFORM}/*.c")
file(GLOB SINK_SOURCES "${AUDIO_DIR}/sinks/${PLATFORM}/*.cpp" "${AUDIO_DIR}/sinks/${PLATFORM}/*.c")
list(APPEND EXTRA_INCLUDES "include/audio/sinks/${PLATFORM}")
# Find ALSA if required, else remove the sink
if(BELL_USE_ALSA)
if(BELL_SINK_ALSA)
find_package(ALSA REQUIRED)
list(APPEND EXTRA_INCLUDES ${ALSA_INCLUDE_DIRS})
list(APPEND EXTRA_LIBS ${ALSA_LIBRARIES})
else()
list(REMOVE_ITEM SINK_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src/sinks/unix/ALSAAudioSink.cpp)
list(REMOVE_ITEM SINK_SOURCES "${AUDIO_DIR}/sinks/unix/ALSAAudioSink.cpp")
endif()
# Find PortAudio if required, else remove the sink
if(BELL_USE_PORTAUDIO)
find_package(portaudio REQUIRED)
list(APPEND EXTRA_INCLUDES ${PORTAUDIO_INCLUDE_DIRS})
list(APPEND EXTRA_LIBS ${PORTAUDIO_LIBRARIES})
if(BELL_SINK_PORTAUDIO)
if(WIN32)
list(APPEND EXTRA_INCLUDES "portaudio/include")
if(NOT "${CMAKE_GENERATOR}" MATCHES "(Win64|IA64)")
list(APPEND EXTRA_LIBS "${CMAKE_CURRENT_SOURCE_DIR}/portaudio/portaudio_win32.lib")
else()
list(APPEND EXTRA_LIBS "${CMAKE_CURRENT_SOURCE_DIR}/portaudio/portaudio_x64.lib")
endif()
else()
find_package(portaudio REQUIRED)
list(APPEND EXTRA_INCLUDES ${PORTAUDIO_INCLUDE_DIRS})
list(APPEND EXTRA_LIBS ${PORTAUDIO_LIBRARIES})
endif()
else()
list(REMOVE_ITEM SINK_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src/sinks/unix/PortAudioSink.cpp)
list(REMOVE_ITEM SINK_SOURCES "${AUDIO_DIR}/sinks/unix/PortAudioSink.cpp")
endif()
list(APPEND SOURCES ${SINK_SOURCES})
list(APPEND EXTRA_INCLUDES "include/sinks/${PLATFORM}")
endif()
if(BELL_EXTERNAL_CJSON)
list(APPEND EXTRA_LIBS ${BELL_EXTERNAL_CJSON})
if(BELL_DISABLE_CJSON)
list(REMOVE_ITEM SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/src/JSONObject.cpp")
else()
list(APPEND EXTRA_INCLUDES "cJSON")
list(APPEND SOURCES "cJSON/cJSON.c")
endif()
if(BELL_EXTERNAL_TREMOR)
list(APPEND EXTRA_LIBS ${BELL_EXTERNAL_TREMOR})
else()
file(GLOB TREMOR_SOURCES "tremor/*.c")
list(REMOVE_ITEM TREMOR_SOURCES "tremor/ivorbisfile_example.c")
list(APPEND EXTRA_INCLUDES "tremor")
list(APPEND SOURCES ${TREMOR_SOURCES})
if(BELL_EXTERNAL_CJSON)
list(APPEND EXTRA_LIBS ${BELL_EXTERNAL_CJSON})
else()
list(APPEND SOURCES "cJSON/cJSON.c")
list(APPEND EXTRA_INCLUDES "cJSON")
endif()
endif()
add_library(bell STATIC ${SOURCES})
# PUBLIC to propagate esp-idf includes to bell dependents
target_link_libraries(bell PUBLIC ${EXTRA_LIBS})
target_include_directories(bell PUBLIC "include" "include/platform" ${EXTRA_INCLUDES} ${CMAKE_CURRENT_BINARY_DIR})
target_include_directories(bell PUBLIC "include" ${EXTRA_INCLUDES} ${CMAKE_CURRENT_BINARY_DIR})
target_compile_definitions(bell PUBLIC PB_ENABLE_MALLOC)
if(WIN32)
target_compile_definitions(bell PUBLIC PB_NO_STATIC_ASSERT)
endif()

View File

@@ -121,6 +121,7 @@ set(SOURCES cJSON.c)
option(BUILD_SHARED_AND_STATIC_LIBS "Build both shared and static libraries" Off)
option(CJSON_OVERRIDE_BUILD_SHARED_LIBS "Override BUILD_SHARED_LIBS with CJSON_BUILD_SHARED_LIBS" OFF)
option(CJSON_BUILD_SHARED_LIBS "Overrides BUILD_SHARED_LIBS if CJSON_OVERRIDE_BUILD_SHARED_LIBS is enabled" ON)
option(ENABLE_CJSON_VERSION_SO "Enables cJSON so version" ON)
if ((CJSON_OVERRIDE_BUILD_SHARED_LIBS AND CJSON_BUILD_SHARED_LIBS) OR ((NOT CJSON_OVERRIDE_BUILD_SHARED_LIBS) AND BUILD_SHARED_LIBS))
set(CJSON_LIBRARY_TYPE SHARED)
@@ -155,17 +156,23 @@ install(TARGETS "${CJSON_LIB}"
INCLUDES DESTINATION "${CMAKE_INSTALL_FULL_INCLUDEDIR}"
)
if (BUILD_SHARED_AND_STATIC_LIBS)
install(TARGETS "${CJSON_LIB}-static" DESTINATION "${CMAKE_INSTALL_FULL_LIBDIR}")
install(TARGETS "${CJSON_LIB}-static"
EXPORT "${CJSON_LIB}"
ARCHIVE DESTINATION "${CMAKE_INSTALL_FULL_LIBDIR}"
INCLUDES DESTINATION "${CMAKE_INSTALL_FULL_INCLUDEDIR}"
)
endif()
if(ENABLE_TARGET_EXPORT)
# export library information for CMake projects
install(EXPORT "${CJSON_LIB}" DESTINATION "${CMAKE_INSTALL_FULL_LIBDIR}/cmake/cJSON")
endif()
set_target_properties("${CJSON_LIB}"
PROPERTIES
SOVERSION "${CJSON_VERSION_SO}"
VERSION "${PROJECT_VERSION}")
if(ENABLE_CJSON_VERSION_SO)
set_target_properties("${CJSON_LIB}"
PROPERTIES
SOVERSION "${CJSON_VERSION_SO}"
VERSION "${PROJECT_VERSION}")
endif()
#cJSON_Utils
option(ENABLE_CJSON_UTILS "Enable building the cJSON_Utils library." OFF)
@@ -198,7 +205,11 @@ if(ENABLE_CJSON_UTILS)
INCLUDES DESTINATION "${CMAKE_INSTALL_FULL_INCLUDEDIR}"
)
if (BUILD_SHARED_AND_STATIC_LIBS)
install(TARGETS "${CJSON_UTILS_LIB}-static" DESTINATION "${CMAKE_INSTALL_FULL_LIBDIR}")
install(TARGETS "${CJSON_UTILS_LIB}-static"
EXPORT "${CJSON_UTILS_LIB}"
ARCHIVE DESTINATION "${CMAKE_INSTALL_FULL_LIBDIR}"
INCLUDES DESTINATION "${CMAKE_INSTALL_FULL_INCLUDEDIR}"
)
endif()
install(FILES cJSON_Utils.h DESTINATION "${CMAKE_INSTALL_FULL_INCLUDEDIR}/cjson")
install (FILES "${CMAKE_CURRENT_BINARY_DIR}/libcjson_utils.pc" DESTINATION "${CMAKE_INSTALL_FULL_LIBDIR}/pkgconfig")
@@ -207,10 +218,12 @@ if(ENABLE_CJSON_UTILS)
install(EXPORT "${CJSON_UTILS_LIB}" DESTINATION "${CMAKE_INSTALL_FULL_LIBDIR}/cmake/cJSON")
endif()
set_target_properties("${CJSON_UTILS_LIB}"
PROPERTIES
SOVERSION "${CJSON_UTILS_VERSION_SO}"
VERSION "${PROJECT_VERSION}")
if(ENABLE_CJSON_VERSION_SO)
set_target_properties("${CJSON_UTILS_LIB}"
PROPERTIES
SOVERSION "${CJSON_UTILS_VERSION_SO}"
VERSION "${PROJECT_VERSION}")
endif()
endif()
# create the other package config files

View File

@@ -96,9 +96,9 @@ CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void)
return (const char*) (global_error.json + global_error.position);
}
CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON * const item)
CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON * const item)
{
if (!cJSON_IsString(item))
if (!cJSON_IsString(item))
{
return NULL;
}
@@ -106,9 +106,9 @@ CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON * const item)
return item->valuestring;
}
CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON * const item)
CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON * const item)
{
if (!cJSON_IsNumber(item))
if (!cJSON_IsNumber(item))
{
return (double) NAN;
}
@@ -511,7 +511,7 @@ static unsigned char* ensure(printbuffer * const p, size_t needed)
return NULL;
}
memcpy(newbuffer, p->buffer, p->offset + 1);
p->hooks.deallocate(p->buffer);
}
@@ -562,6 +562,10 @@ static cJSON_bool print_number(const cJSON * const item, printbuffer * const out
{
length = sprintf((char*)number_buffer, "null");
}
else if(d == (double)item->valueint)
{
length = sprintf((char*)number_buffer, "%d", item->valueint);
}
else
{
/* Try 15 decimal places of precision to avoid nonsignificant nonzero digits */
@@ -1103,7 +1107,7 @@ CJSON_PUBLIC(cJSON *) cJSON_ParseWithLengthOpts(const char *value, size_t buffer
}
buffer.content = (const unsigned char*)value;
buffer.length = buffer_length;
buffer.length = buffer_length;
buffer.offset = 0;
buffer.hooks = global_hooks;
@@ -2357,6 +2361,11 @@ static cJSON_bool replace_item_in_object(cJSON *object, const char *string, cJSO
cJSON_free(replacement->string);
}
replacement->string = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks);
if (replacement->string == NULL)
{
return false;
}
replacement->type &= ~cJSON_StringIsConst;
return cJSON_ReplaceItemViaPointer(object, get_object_item(object, string, case_sensitive), replacement);
@@ -2689,7 +2698,7 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char *const *strings, int co
if (a && a->child) {
a->child->prev = n;
}
return a;
}

View File

@@ -279,6 +279,13 @@ CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number);
/* Change the valuestring of a cJSON_String object, only takes effect when type of object is cJSON_String */
CJSON_PUBLIC(char*) cJSON_SetValuestring(cJSON *object, const char *valuestring);
/* If the object is not a boolean type this does nothing and returns cJSON_Invalid else it returns the new type*/
#define cJSON_SetBoolValue(object, boolValue) ( \
(object != NULL && ((object)->type & (cJSON_False|cJSON_True))) ? \
(object)->type=((object)->type &(~(cJSON_False|cJSON_True)))|((boolValue)?cJSON_True:cJSON_False) : \
cJSON_Invalid\
)
/* Macro for iterating over an array or object */
#define cJSON_ArrayForEach(element, array) for(element = (array != NULL) ? (array)->child : NULL; element != NULL; element = element->next)

View File

@@ -28,7 +28,6 @@
#include "unity/src/unity.h"
#include "common.h"
static void cjson_array_foreach_should_loop_over_arrays(void)
{
cJSON array[1];
@@ -77,7 +76,6 @@ static void cjson_get_object_item_should_get_object_items(void)
found = cJSON_GetObjectItem(item, NULL);
TEST_ASSERT_NULL_MESSAGE(found, "Failed to fail on NULL string.");
found = cJSON_GetObjectItem(item, "one");
TEST_ASSERT_NOT_NULL_MESSAGE(found, "Failed to find first item.");
TEST_ASSERT_EQUAL_DOUBLE(found->valuedouble, 1);
@@ -127,7 +125,8 @@ static void cjson_get_object_item_case_sensitive_should_get_object_items(void)
cJSON_Delete(item);
}
static void cjson_get_object_item_should_not_crash_with_array(void) {
static void cjson_get_object_item_should_not_crash_with_array(void)
{
cJSON *array = NULL;
cJSON *found = NULL;
array = cJSON_Parse("[1]");
@@ -138,7 +137,8 @@ static void cjson_get_object_item_should_not_crash_with_array(void) {
cJSON_Delete(array);
}
static void cjson_get_object_item_case_sensitive_should_not_crash_with_array(void) {
static void cjson_get_object_item_case_sensitive_should_not_crash_with_array(void)
{
cJSON *array = NULL;
cJSON *found = NULL;
array = cJSON_Parse("[1]");
@@ -302,7 +302,6 @@ static void cjson_replace_item_via_pointer_should_replace_items(void)
cJSON_AddItemToArray(array, middle);
cJSON_AddItemToArray(array, end);
memset(replacements, '\0', sizeof(replacements));
/* replace beginning */
@@ -329,7 +328,7 @@ static void cjson_replace_item_via_pointer_should_replace_items(void)
static void cjson_replace_item_in_object_should_preserve_name(void)
{
cJSON root[1] = {{ NULL, NULL, NULL, 0, NULL, 0, 0, NULL }};
cJSON root[1] = {{NULL, NULL, NULL, 0, NULL, 0, 0, NULL}};
cJSON *child = NULL;
cJSON *replacement = NULL;
cJSON_bool flag = false;
@@ -339,7 +338,7 @@ static void cjson_replace_item_in_object_should_preserve_name(void)
replacement = cJSON_CreateNumber(2);
TEST_ASSERT_NOT_NULL(replacement);
flag = cJSON_AddItemToObject(root, "child", child);
flag = cJSON_AddItemToObject(root, "child", child);
TEST_ASSERT_TRUE_MESSAGE(flag, "add item to object failed");
cJSON_ReplaceItemInObject(root, "child", replacement);
@@ -435,7 +434,7 @@ static void cjson_functions_should_not_crash_with_null_pointers(void)
cJSON_Delete(item);
}
static void * CJSON_CDECL failing_realloc(void *pointer, size_t size)
static void *CJSON_CDECL failing_realloc(void *pointer, size_t size)
{
(void)size;
(void)pointer;
@@ -445,7 +444,7 @@ static void * CJSON_CDECL failing_realloc(void *pointer, size_t size)
static void ensure_should_fail_on_failed_realloc(void)
{
printbuffer buffer = {NULL, 10, 0, 0, false, false, {&malloc, &free, &failing_realloc}};
buffer.buffer = (unsigned char*)malloc(100);
buffer.buffer = (unsigned char *)malloc(100);
TEST_ASSERT_NOT_NULL(buffer.buffer);
TEST_ASSERT_NULL_MESSAGE(ensure(&buffer, 200), "Ensure didn't fail with failing realloc.");
@@ -454,7 +453,7 @@ static void ensure_should_fail_on_failed_realloc(void)
static void skip_utf8_bom_should_skip_bom(void)
{
const unsigned char string[] = "\xEF\xBB\xBF{}";
parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0 } };
parse_buffer buffer = {0, 0, 0, 0, {0, 0, 0}};
buffer.content = string;
buffer.length = sizeof(string);
buffer.hooks = global_hooks;
@@ -466,7 +465,7 @@ static void skip_utf8_bom_should_skip_bom(void)
static void skip_utf8_bom_should_not_skip_bom_if_not_at_beginning(void)
{
const unsigned char string[] = " \xEF\xBB\xBF{}";
parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0 } };
parse_buffer buffer = {0, 0, 0, 0, {0, 0, 0}};
buffer.content = string;
buffer.length = sizeof(string);
buffer.hooks = global_hooks;
@@ -496,12 +495,13 @@ static void cjson_get_number_value_should_get_a_number(void)
TEST_ASSERT_EQUAL_DOUBLE(cJSON_GetNumberValue(number), number->valuedouble);
TEST_ASSERT_DOUBLE_IS_NAN(cJSON_GetNumberValue(string));
TEST_ASSERT_DOUBLE_IS_NAN(cJSON_GetNumberValue(NULL));
cJSON_Delete(number);
cJSON_Delete(string);
}
static void cjson_create_string_reference_should_create_a_string_reference(void) {
static void cjson_create_string_reference_should_create_a_string_reference(void)
{
const char *string = "I am a string!";
cJSON *string_reference = cJSON_CreateStringReference(string);
@@ -511,7 +511,8 @@ static void cjson_create_string_reference_should_create_a_string_reference(void)
cJSON_Delete(string_reference);
}
static void cjson_create_object_reference_should_create_an_object_reference(void) {
static void cjson_create_object_reference_should_create_an_object_reference(void)
{
cJSON *number_reference = NULL;
cJSON *number_object = cJSON_CreateObject();
cJSON *number = cJSON_CreateNumber(42);
@@ -529,7 +530,8 @@ static void cjson_create_object_reference_should_create_an_object_reference(void
cJSON_Delete(number_reference);
}
static void cjson_create_array_reference_should_create_an_array_reference(void) {
static void cjson_create_array_reference_should_create_an_array_reference(void)
{
cJSON *number_reference = NULL;
cJSON *number_array = cJSON_CreateArray();
cJSON *number = cJSON_CreateNumber(42);
@@ -566,7 +568,7 @@ static void cjson_add_item_to_object_should_not_use_after_free_when_string_is_al
{
cJSON *object = cJSON_CreateObject();
cJSON *number = cJSON_CreateNumber(42);
char *name = (char*)cJSON_strdup((const unsigned char*)"number", &global_hooks);
char *name = (char *)cJSON_strdup((const unsigned char *)"number", &global_hooks);
TEST_ASSERT_NOT_NULL(object);
TEST_ASSERT_NOT_NULL(number);
@@ -626,7 +628,7 @@ static void cjson_set_valuestring_to_object_should_not_leak_memory(void)
cJSON *item2 = cJSON_CreateStringReference(reference_valuestring);
char *ptr1 = NULL;
char *return_value = NULL;
cJSON_AddItemToObject(root, "one", item1);
cJSON_AddItemToObject(root, "two", item2);
@@ -650,6 +652,64 @@ static void cjson_set_valuestring_to_object_should_not_leak_memory(void)
cJSON_Delete(root);
}
static void cjson_set_bool_value_must_not_break_objects(void)
{
cJSON *bobj, *sobj, *oobj, *refobj = NULL;
TEST_ASSERT_TRUE((cJSON_SetBoolValue(refobj, 1) == cJSON_Invalid));
bobj = cJSON_CreateFalse();
TEST_ASSERT_TRUE(cJSON_IsFalse(bobj));
TEST_ASSERT_TRUE((cJSON_SetBoolValue(bobj, 1) == cJSON_True));
TEST_ASSERT_TRUE(cJSON_IsTrue(bobj));
cJSON_SetBoolValue(bobj, 1);
TEST_ASSERT_TRUE(cJSON_IsTrue(bobj));
TEST_ASSERT_TRUE((cJSON_SetBoolValue(bobj, 0) == cJSON_False));
TEST_ASSERT_TRUE(cJSON_IsFalse(bobj));
cJSON_SetBoolValue(bobj, 0);
TEST_ASSERT_TRUE(cJSON_IsFalse(bobj));
sobj = cJSON_CreateString("test");
TEST_ASSERT_TRUE(cJSON_IsString(sobj));
cJSON_SetBoolValue(sobj, 1);
TEST_ASSERT_TRUE(cJSON_IsString(sobj));
cJSON_SetBoolValue(sobj, 0);
TEST_ASSERT_TRUE(cJSON_IsString(sobj));
oobj = cJSON_CreateObject();
TEST_ASSERT_TRUE(cJSON_IsObject(oobj));
cJSON_SetBoolValue(oobj, 1);
TEST_ASSERT_TRUE(cJSON_IsObject(oobj));
cJSON_SetBoolValue(oobj, 0);
TEST_ASSERT_TRUE(cJSON_IsObject(oobj));
refobj = cJSON_CreateStringReference("conststring");
TEST_ASSERT_TRUE(cJSON_IsString(refobj));
TEST_ASSERT_TRUE(refobj->type & cJSON_IsReference);
cJSON_SetBoolValue(refobj, 1);
TEST_ASSERT_TRUE(cJSON_IsString(refobj));
TEST_ASSERT_TRUE(refobj->type & cJSON_IsReference);
cJSON_SetBoolValue(refobj, 0);
TEST_ASSERT_TRUE(cJSON_IsString(refobj));
TEST_ASSERT_TRUE(refobj->type & cJSON_IsReference);
cJSON_Delete(refobj);
refobj = cJSON_CreateObjectReference(oobj);
TEST_ASSERT_TRUE(cJSON_IsObject(refobj));
TEST_ASSERT_TRUE(refobj->type & cJSON_IsReference);
cJSON_SetBoolValue(refobj, 1);
TEST_ASSERT_TRUE(cJSON_IsObject(refobj));
TEST_ASSERT_TRUE(refobj->type & cJSON_IsReference);
cJSON_SetBoolValue(refobj, 0);
TEST_ASSERT_TRUE(cJSON_IsObject(refobj));
TEST_ASSERT_TRUE(refobj->type & cJSON_IsReference);
cJSON_Delete(refobj);
cJSON_Delete(oobj);
cJSON_Delete(bobj);
cJSON_Delete(sobj);
}
int CJSON_CDECL main(void)
{
UNITY_BEGIN();
@@ -679,6 +739,7 @@ int CJSON_CDECL main(void)
RUN_TEST(cjson_add_item_to_object_should_not_use_after_free_when_string_is_aliased);
RUN_TEST(cjson_delete_item_from_array_should_not_broken_list_structure);
RUN_TEST(cjson_set_valuestring_to_object_should_not_leak_memory);
RUN_TEST(cjson_set_bool_value_must_not_break_objects);
return UNITY_END();
}

View File

@@ -6,7 +6,14 @@
#include <map>
#include <memory>
#include <functional>
#include <iostream>
#include <vector>
#include <cstring>
#ifdef _WIN32
#include <winsock2.h>
#else
#include <sys/socket.h>
#endif
namespace bell {
@@ -20,6 +27,40 @@ class ResponseReader {
virtual void close() = 0;
};
class RequestBodyReader : public ResponseReader {
public:
std::vector<uint8_t> partialBuffer;
int fd = 0;
size_t contentLength = 0;
size_t sizeRead = 0;
RequestBodyReader(size_t contentLength, int fd, std::vector<uint8_t> &partialBuffer) {
this->contentLength = contentLength;
this->partialBuffer = partialBuffer;
this->fd = fd;
};
size_t read(char *buffer, size_t size) {
if (sizeRead < partialBuffer.size()) {
size_t toRead = std::min(size, partialBuffer.size() - sizeRead);
memcpy(buffer, &partialBuffer[sizeRead], toRead);
sizeRead += toRead;
return toRead;
} else {
size_t toRead = std::min(size, contentLength - sizeRead);
size_t read = recv(fd, buffer, toRead, 0);
sizeRead += read;
return read;
}
}
void close() {
}
size_t getTotalSize() { return contentLength; }
};
class FileResponseReader : public ResponseReader {
public:
FILE *file;
@@ -30,7 +71,7 @@ class FileResponseReader : public ResponseReader {
fileSize = ftell(file); // get current file pointer
fseek(file, 0, SEEK_SET); // seek back to beginning of file
};
~FileResponseReader() { fclose(file); };
size_t read(char *buffer, size_t size) {
return fread(buffer, 1, size, file);
@@ -48,10 +89,13 @@ enum class RequestType { GET, POST };
struct HTTPRequest {
std::map<std::string, std::string> urlParams;
std::map<std::string, std::string> queryParams;
std::unique_ptr<ResponseReader> responseReader = std::unique_ptr<RequestBodyReader>(nullptr);
std::string body;
std::string url;
int handlerId;
int connection;
int contentLength;
};
struct HTTPResponse {
@@ -64,19 +108,22 @@ struct HTTPResponse {
std::unique_ptr<ResponseReader> responseReader;
};
typedef std::function<void(HTTPRequest &)> httpHandler;
typedef std::function<void(std::unique_ptr<bell::HTTPRequest>)> httpHandler;
struct HTTPRoute {
RequestType requestType;
httpHandler handler;
bool readBodyToStr;
};
struct HTTPConnection {
int fd = 0;
std::vector<uint8_t> buffer;
std::string currentLine = "";
std::vector<uint8_t> partialBuffer = std::vector<uint8_t>();
int contentLength = 0;
bool isReadingBody = false;
std::string httpMethod;
bool toBeClosed = false;
bool headersRead = false;
bool isEventConnection = false;
bool isCaptivePortal = false;
};
@@ -96,10 +143,11 @@ public:
*
* @param requestType GET or POST
* @param endpoint registering under
* @param readResponseToStr if true, response will be read to string, otherwise it will return a reader object
* httpHandler lambda to be called when given endpoint gets executed
*/
virtual void registerHandler(RequestType requestType, const std::string & endpoint,
httpHandler) = 0;
httpHandler, bool readResponseToStr = true) = 0;
/**
* Writes given response to a fd

View File

@@ -3,6 +3,7 @@
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <string>
#include <memory>
@@ -18,7 +19,7 @@ namespace bell
virtual void info(std::string filename, int line, std::string submodule, const char *format, ...) = 0;
};
extern std::shared_ptr<bell::AbstractLogger> bellGlobalLogger;
extern bell::AbstractLogger* bellGlobalLogger;
class BellLogger : public bell::AbstractLogger
{
public:
@@ -81,23 +82,27 @@ namespace bell
void printFilename(std::string filename)
{
#ifdef _WIN32
std::string basenameStr(filename.substr(filename.rfind("\\") + 1));
#else
std::string basenameStr(filename.substr(filename.rfind("/") + 1));
#endif
unsigned long hash = 5381;
for (char const &c : basenameStr)
{
hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
}
printf("\e[0;%dm", allColors[hash % NColors]);
printf("\033[0;%dm", allColors[hash % NColors]);
printf("%s", basenameStr.c_str());
printf(colorReset);
}
private:
static constexpr const char *colorReset = "\e[0m";
static constexpr const char *colorRed = "\e[0;31m";
static constexpr const char *colorBlue = "\e[0;34m";
static constexpr const char *colorReset = "\033[0m";
static constexpr const char *colorRed = "\033[0;31m";
static constexpr const char *colorBlue = "\033[0;34m";
static constexpr const int NColors = 15;
static constexpr int allColors[NColors] = {31, 32, 33, 34, 35, 36, 37, 90, 91, 92, 93, 94, 95, 96, 97};
};

View File

@@ -7,9 +7,12 @@
#include <freertos/FreeRTOS.h>
#include <freertos/timers.h>
#include <freertos/task.h>
#elif _WIN32
#include <winsock2.h>
#else
#include <pthread.h>
#endif
#include <pthread.h>
#include <string>
namespace bell
@@ -62,14 +65,23 @@ namespace bell
esp_pthread_set_cfg(&cfg);
}
#endif
#if _WIN32
thread = CreateThread(NULL, stackSize, (LPTHREAD_START_ROUTINE) taskEntryFunc, this, 0, NULL);
return thread != NULL;
#else
return (pthread_create(&thread, NULL, taskEntryFunc, this) == 0);
#endif
}
protected:
virtual void runTask() = 0;
private:
#if _WIN32
HANDLE thread;
#else
pthread_t thread;
#endif
#ifdef ESP_PLATFORM
int priority;
StaticTask_t *xTaskBuffer;
@@ -96,7 +108,11 @@ namespace bell
{
Task* self = (Task*) This;
self->runTask();
#if _WIN32
WaitForSingleObject(self->thread, INFINITE);
#else
pthread_join(self->thread, NULL);
#endif
return NULL;
}
};

View File

@@ -18,6 +18,9 @@ void freeAndNull(void *&ptr);
#define BELL_SLEEP_MS(ms) vTaskDelay(ms / portTICK_PERIOD_MS)
#define BELL_YIELD() taskYIELD()
#elif defined(_WIN32)
#define BELL_SLEEP_MS(ms) Sleep(ms)
#define BELL_YIELD() ;
#else
#include <unistd.h>

View File

@@ -0,0 +1,127 @@
// Copyright (c) Kuba Szczodrzyński 2022-1-7.
#pragma once
#include "ByteStream.h"
#include "BellTask.h"
#include "WrappedSemaphore.h"
#include <atomic>
#include <functional>
#include <memory>
#include <mutex>
/**
* This class implements a wrapper around an arbitrary bell::ByteStream,
* providing a circular reading buffer with configurable thresholds.
*
* The BufferedStream runs a bell::Task when it's started, so the caller can
* access the buffer's data asynchronously, whenever needed. The buffer is refilled
* automatically from source stream.
*
* The class implements bell::ByteStream's methods, although for proper functioning,
* the caller code should be modified to check isReady() and isNotReady() flags.
*
* If the actual reading code can't be modified, waitForReady allows to wait for buffer readiness
* during reading. Keep in mind that using the semaphore is probably more resource effective.
*
* The source stream (passed to open() or returned by the reader) should implement the read()
* method correctly, such as that 0 is returned if, and only if the stream ends.
*/
class BufferedStream : public bell::ByteStream, bell::Task {
public:
typedef std::shared_ptr<bell::ByteStream> StreamPtr;
typedef std::function<StreamPtr(uint32_t rangeStart)> StreamReader;
public:
/**
* @param taskName name to use for the reading task
* @param bufferSize total size of the reading buffer
* @param readThreshold how much can be read before refilling the buffer
* @param readSize amount of bytes to read from the source each time
* @param readyThreshold minimum amount of available bytes to report isReady()
* @param notReadyThreshold maximum amount of available bytes to report isNotReady()
* @param waitForReady whether to wait for the buffer to be ready during reading
* @param endWithSource whether to end the streaming as soon as source returns 0 from read()
*/
BufferedStream(
const std::string &taskName,
uint32_t bufferSize,
uint32_t readThreshold,
uint32_t readSize,
uint32_t readyThreshold,
uint32_t notReadyThreshold,
bool waitForReady = false);
~BufferedStream() override;
bool open(const StreamPtr &stream);
bool open(const StreamReader &newReader, uint32_t initialOffset = 0);
void close() override;
// inherited methods
public:
/**
* Read len bytes from the buffer to dst. If waitForReady is enabled
* and readAvailable is lower than notReadyThreshold, the function
* will block until readyThreshold bytes is available.
*
* @returns number of bytes copied to dst (might be lower than len,
* if the buffer does not contain len bytes available), or 0 if the source
* stream is already closed and there is no reader attached.
*/
size_t read(uint8_t *dst, size_t len) override;
size_t skip(size_t len) override;
size_t position() override;
size_t size() override;
// stream status
public:
/**
* Total amount of bytes served to read().
*/
uint32_t readTotal;
/**
* Total amount of bytes read from source.
*/
uint32_t bufferTotal;
/**
* Amount of bytes available to read from the buffer.
*/
std::atomic<uint32_t> readAvailable;
/**
* Whether the caller should start reading the data. This indicates that a safe
* amount (determined by readyThreshold) of data is available in the buffer.
*/
bool isReady() const;
/**
* Whether the caller should stop reading the data. This indicates that the amount of data
* available for reading is decreasing to a non-safe value, as data is being read
* faster than it can be buffered.
*/
bool isNotReady() const;
/**
* Semaphore that is given when the buffer becomes ready (isReady() == true). Caller can
* wait for the semaphore instead of continuously querying isReady().
*/
WrappedSemaphore readySem;
private:
std::mutex runningMutex;
bool running = false;
bool terminate = false;
WrappedSemaphore readSem; // signal to start writing to buffer after reading from it
std::mutex readMutex; // mutex for locking read operations during writing, and vice versa
uint32_t bufferSize;
uint32_t readAt;
uint32_t readSize;
uint32_t readyThreshold;
uint32_t notReadyThreshold;
bool waitForReady;
uint8_t *buf;
uint8_t *bufEnd;
uint8_t *bufReadPtr;
uint8_t *bufWritePtr;
StreamPtr source;
StreamReader reader;
void runTask() override;
void reset();
uint32_t lengthBetween(uint8_t *me, uint8_t *other);
};

View File

@@ -1,14 +1,78 @@
#ifndef BELL_CRYPTO_H
#define BELL_CRYPTO_H
#define Crypto CryptoMbedTLS
#include <vector>
#include <string>
#include <memory>
#include <mbedtls/base64.h>
#include <mbedtls/bignum.h>
#include <mbedtls/md.h>
#include <mbedtls/aes.h>
#include <mbedtls/pkcs5.h>
#include <mbedtls/entropy.h>
#include <mbedtls/ctr_drbg.h>
#define DH_KEY_SIZE 96
static unsigned char DHPrime[] = {
/* Well-known Group 1, 768-bit prime */
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc9,
0x0f, 0xda, 0xa2, 0x21, 0x68, 0xc2, 0x34, 0xc4, 0xc6,
0x62, 0x8b, 0x80, 0xdc, 0x1c, 0xd1, 0x29, 0x02, 0x4e,
0x08, 0x8a, 0x67, 0xcc, 0x74, 0x02, 0x0b, 0xbe, 0xa6,
0x3b, 0x13, 0x9b, 0x22, 0x51, 0x4a, 0x08, 0x79, 0x8e,
0x34, 0x04, 0xdd, 0xef, 0x95, 0x19, 0xb3, 0xcd, 0x3a,
0x43, 0x1b, 0x30, 0x2b, 0x0a, 0x6d, 0xf2, 0x5f, 0x14,
0x37, 0x4f, 0xe1, 0x35, 0x6d, 0x6d, 0x51, 0xc2, 0x45,
0xe4, 0x85, 0xb5, 0x76, 0x62, 0x5e, 0x7e, 0xc6, 0xf4,
0x4c, 0x42, 0xe9, 0xa6, 0x3a, 0x36, 0x20, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff
};
static unsigned char DHGenerator[1] = {2};
class CryptoMbedTLS {
private:
mbedtls_md_context_t sha1Context;
mbedtls_aes_context aesCtx;
public:
CryptoMbedTLS();
~CryptoMbedTLS();
// Base64
std::vector<uint8_t> base64Decode(const std::string& data);
std::string base64Encode(const std::vector<uint8_t>& data);
// Sha1
void sha1Init();
void sha1Update(const std::string& s);
void sha1Update(const std::vector<uint8_t>& vec);
std::string sha1Final();
std::vector<uint8_t> sha1FinalBytes();
// HMAC SHA1
std::vector<uint8_t> sha1HMAC(const std::vector<uint8_t>& inputKey, const std::vector<uint8_t>& message);
// AES CTR
void aesCTRXcrypt(const std::vector<uint8_t>& key, std::vector<uint8_t>& iv, uint8_t* data, size_t nbytes);
// AES ECB
void aesECBdecrypt(const std::vector<uint8_t>& key, std::vector<uint8_t>& data);
// Diffie Hellman
std::vector<uint8_t> publicKey;
std::vector<uint8_t> privateKey;
void dhInit();
std::vector<uint8_t> dhCalculateShared(const std::vector<uint8_t>& remoteKey);
// PBKDF2
std::vector<uint8_t> pbkdf2HmacSha1(const std::vector<uint8_t>& password, const std::vector<uint8_t>& salt, int iterations, int digestSize);
// Random stuff
std::vector<uint8_t> generateVectorWithRandomData(size_t length);
};
#ifdef BELL_USE_MBEDTLS
#include "CryptoMbedTLS.h"
#define Crypto CryptoMbedTLS
#else
#include "CryptoOpenSSL.h"
#define Crypto CryptoOpenSSL
#endif
#endif

View File

@@ -1,78 +0,0 @@
#ifndef BELL_CRYPTOMBEDTLS_H
#define BELL_CRYPTOMBEDTLS_H
#ifdef BELL_USE_MBEDTLS
#include <vector>
#include <string>
#include <memory>
#include <mbedtls/base64.h>
#include <mbedtls/bignum.h>
#include <mbedtls/md.h>
#include <mbedtls/aes.h>
#include <mbedtls/pkcs5.h>
#include <mbedtls/entropy.h>
#include <mbedtls/ctr_drbg.h>
#define DH_KEY_SIZE 96
static unsigned char DHPrime[] = {
/* Well-known Group 1, 768-bit prime */
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc9,
0x0f, 0xda, 0xa2, 0x21, 0x68, 0xc2, 0x34, 0xc4, 0xc6,
0x62, 0x8b, 0x80, 0xdc, 0x1c, 0xd1, 0x29, 0x02, 0x4e,
0x08, 0x8a, 0x67, 0xcc, 0x74, 0x02, 0x0b, 0xbe, 0xa6,
0x3b, 0x13, 0x9b, 0x22, 0x51, 0x4a, 0x08, 0x79, 0x8e,
0x34, 0x04, 0xdd, 0xef, 0x95, 0x19, 0xb3, 0xcd, 0x3a,
0x43, 0x1b, 0x30, 0x2b, 0x0a, 0x6d, 0xf2, 0x5f, 0x14,
0x37, 0x4f, 0xe1, 0x35, 0x6d, 0x6d, 0x51, 0xc2, 0x45,
0xe4, 0x85, 0xb5, 0x76, 0x62, 0x5e, 0x7e, 0xc6, 0xf4,
0x4c, 0x42, 0xe9, 0xa6, 0x3a, 0x36, 0x20, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff
};
static unsigned char DHGenerator[1] = {2};
class CryptoMbedTLS {
private:
mbedtls_md_context_t sha1Context;
mbedtls_aes_context aesCtx;
public:
CryptoMbedTLS();
~CryptoMbedTLS();
// Base64
std::vector<uint8_t> base64Decode(const std::string& data);
std::string base64Encode(const std::vector<uint8_t>& data);
// Sha1
void sha1Init();
void sha1Update(const std::string& s);
void sha1Update(const std::vector<uint8_t>& vec);
std::string sha1Final();
std::vector<uint8_t> sha1FinalBytes();
// HMAC SHA1
std::vector<uint8_t> sha1HMAC(const std::vector<uint8_t>& inputKey, const std::vector<uint8_t>& message);
// AES CTR
void aesCTRXcrypt(const std::vector<uint8_t>& key, std::vector<uint8_t>& iv, uint8_t* data, size_t nbytes);
// AES ECB
void aesECBdecrypt(const std::vector<uint8_t>& key, std::vector<uint8_t>& data);
// Diffie Hellman
std::vector<uint8_t> publicKey;
std::vector<uint8_t> privateKey;
void dhInit();
std::vector<uint8_t> dhCalculateShared(const std::vector<uint8_t>& remoteKey);
// PBKDF2
std::vector<uint8_t> pbkdf2HmacSha1(const std::vector<uint8_t>& password, const std::vector<uint8_t>& salt, int iterations, int digestSize);
// Random stuff
std::vector<uint8_t> generateVectorWithRandomData(size_t length);
};
#endif
#endif

View File

@@ -1,84 +0,0 @@
#ifndef BELL_CRYPTOOPENSSL_H
#define BELL_CRYPTOOPENSSL_H
#include <vector>
#include <string>
#include <memory>
#include <openssl/engine.h>
#include <openssl/rand.h>
#include <openssl/err.h>
#include <openssl/dh.h>
#include <openssl/bn.h>
#include <openssl/bio.h>
#include <openssl/evp.h>
#include <openssl/sha.h>
#include <openssl/hmac.h>
#include <openssl/aes.h>
#include <openssl/modes.h>
#define DH_KEY_SIZE 96
static unsigned char DHPrime[] = {
/* Well-known Group 1, 768-bit prime */
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc9,
0x0f, 0xda, 0xa2, 0x21, 0x68, 0xc2, 0x34, 0xc4, 0xc6,
0x62, 0x8b, 0x80, 0xdc, 0x1c, 0xd1, 0x29, 0x02, 0x4e,
0x08, 0x8a, 0x67, 0xcc, 0x74, 0x02, 0x0b, 0xbe, 0xa6,
0x3b, 0x13, 0x9b, 0x22, 0x51, 0x4a, 0x08, 0x79, 0x8e,
0x34, 0x04, 0xdd, 0xef, 0x95, 0x19, 0xb3, 0xcd, 0x3a,
0x43, 0x1b, 0x30, 0x2b, 0x0a, 0x6d, 0xf2, 0x5f, 0x14,
0x37, 0x4f, 0xe1, 0x35, 0x6d, 0x6d, 0x51, 0xc2, 0x45,
0xe4, 0x85, 0xb5, 0x76, 0x62, 0x5e, 0x7e, 0xc6, 0xf4,
0x4c, 0x42, 0xe9, 0xa6, 0x3a, 0x36, 0x20, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff
};
static unsigned char DHGenerator[1] = {2};
class CryptoOpenSSL {
private:
DH* dhContext = nullptr;
SHA_CTX sha1Context;
public:
CryptoOpenSSL();
~CryptoOpenSSL();
// Base64
std::vector<uint8_t> base64Decode(const std::string& data);
std::string base64Encode(const std::vector<uint8_t>& data);
// Sha1
void sha1Init();
void sha1Update(const std::string& s);
void sha1Update(const std::vector<uint8_t>& vec);
void connectSSL(std::string url);
int readSSL(uint8_t* buf, int len);
int writeSSL(uint8_t* buf, int len);
void closeSSL();
std::string sha1Final();
std::vector<uint8_t> sha1FinalBytes();
// HMAC SHA1
std::vector<uint8_t> sha1HMAC(const std::vector<uint8_t>& inputKey, const std::vector<uint8_t>& message);
// AES CTR
void aesCTRXcrypt(const std::vector<uint8_t>& key, std::vector<uint8_t>& iv, uint8_t* buffer, size_t nbytes);
// AES ECB
void aesECBdecrypt(const std::vector<uint8_t>& key, std::vector<uint8_t>& data);
// Diffie Hellman
std::vector<uint8_t> publicKey;
std::vector<uint8_t> privateKey;
void dhInit();
std::vector<uint8_t> dhCalculateShared(const std::vector<uint8_t>& remoteKey);
// PBKDF2
std::vector<uint8_t> pbkdf2HmacSha1(const std::vector<uint8_t>& password, const std::vector<uint8_t>& salt, int iterations, int digestSize);
// Random stuff
std::vector<uint8_t> generateVectorWithRandomData(size_t length);
};
#endif

View File

@@ -4,7 +4,7 @@
#include "BellSocket.h"
#include "ByteStream.h"
#include "TCPSocket.h"
#include "platform/TLSSocket.h"
#include "TLSSocket.h"
#include <map>
#include <memory>
#include <string>

View File

@@ -11,16 +11,21 @@
#include <iostream>
#include <queue>
#include <stdio.h>
#ifdef _WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
#include "win32shim.h"
#else
#include <sys/select.h>
#include <sys/socket.h>
#include <netdb.h>
#include <unistd.h>
#endif
#include <sstream>
#include <BellLogger.h>
#include <sys/select.h>
#include <sys/types.h>
#include <unistd.h>
#include <fstream>
#include <sys/socket.h>
#include <string>
#include <netdb.h>
#include <mutex>
#include <fcntl.h>
#include "BaseHTTPServer.h"
@@ -46,7 +51,7 @@ namespace bell
std::map<int, HTTPConnection> connections;
void writeResponse(const HTTPResponse &);
void writeResponseEvents(int connFd);
void findAndHandleRoute(std::string &, std::string &, int connectionFd);
void findAndHandleRoute(HTTPConnection& connection);
std::vector<std::string> splitUrl(const std::string &url, char delimiter);
std::mutex responseMutex;
@@ -60,7 +65,7 @@ namespace bell
public:
HTTPServer(int serverPort);
void registerHandler(RequestType requestType, const std::string &, httpHandler);
void registerHandler(RequestType requestType, const std::string &, httpHandler, bool readDataToStr = false);
void respond(const HTTPResponse &);
void redirectTo(const std::string&, int connectionFd);
void publishEvent(std::string eventName, std::string eventData);

View File

@@ -6,7 +6,7 @@
#include <ByteStream.h>
#include <BellSocket.h>
#include <TCPSocket.h>
#include <platform/TLSSocket.h>
#include <TLSSocket.h>
/*
* HTTPStream

View File

@@ -9,15 +9,21 @@
#include <cstring>
#include <stdlib.h>
#include <sys/types.h>
#ifdef _WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
#include "win32shim.h"
#else
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#include <unistd.h>
#include <netinet/tcp.h>
#include <sys/ioctl.h>
#endif
#include <sstream>
#include <fstream>
#include <netinet/tcp.h>
#include <BellLogger.h>
#include <sys/ioctl.h>
namespace bell
{
@@ -77,18 +83,23 @@ namespace bell
}
size_t read(uint8_t *buf, size_t len) {
return recv(sockFd, buf, len, 0);
return recv(sockFd, (char*) buf, len, 0);
}
size_t write(uint8_t *buf, size_t len) {
return send(sockFd, buf, len, 0);
return send(sockFd, (char*) buf, len, 0);
}
size_t poll() {
int value;
ioctl(sockFd, FIONREAD, &value);
return value;
}
size_t poll() {
#ifdef _WIN32
unsigned long value;
ioctlsocket(sockFd, FIONREAD, &value);
#else
int value;
ioctl(sockFd, FIONREAD, &value);
#endif
return value;
}
void close() {
if (!isClosed) {

View File

@@ -8,50 +8,36 @@
#include <fstream>
#include <iostream>
#include <memory>
#ifdef _WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
#else
#include <netdb.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <sys/socket.h>
#include <unistd.h>
#endif
#include <sstream>
#include <stdlib.h>
#include <string>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include <vector>
#ifdef BELL_USE_MBEDTLS
#include "mbedtls/net_sockets.h"
#include "mbedtls/ssl.h"
#include "mbedtls/entropy.h"
#include "mbedtls/ctr_drbg.h"
#include "mbedtls/debug.h"
#else
#include <openssl/bio.h>
#include <openssl/err.h>
#include <openssl/ssl.h>
#endif
namespace bell {
class TLSSocket : public bell::Socket {
private:
#ifdef BELL_USE_MBEDTLS
mbedtls_net_context server_fd;
mbedtls_entropy_context entropy;
mbedtls_ctr_drbg_context ctr_drbg;
mbedtls_ssl_context ssl;
mbedtls_ssl_config conf;
#else
BIO *sbio, *out;
int len;
char tmpbuf[1024];
SSL_CTX *ctx;
SSL *ssl;
int sockFd;
int sslFd;
#endif
bool isClosed = false;
public:

View File

@@ -0,0 +1,8 @@
//
// Created by Filip Grzywok on 28/02/2022.
//
#ifndef EUPHONIUMCLI_TIMEDEFS_H
#define EUPHONIUMCLI_TIMEDEFS_H
#endif // EUPHONIUMCLI_TIMEDEFS_H

View File

@@ -0,0 +1,19 @@
// Copyright (c) Kuba Szczodrzyński 2022-1-12.
#pragma once
#include "BaseCodec.h"
#include "aacdec.h"
class AACDecoder : public BaseCodec {
private:
HAACDecoder aac;
int16_t *pcmData;
AACFrameInfo frame = {};
public:
AACDecoder();
~AACDecoder();
bool setup(uint32_t sampleRate, uint8_t channelCount, uint8_t bitDepth) override;
uint8_t *decode(uint8_t *inData, uint32_t inLen, uint32_t &outLen) override;
};

View File

@@ -0,0 +1,18 @@
// Copyright (c) Kuba Szczodrzyński 2022-1-12.
#pragma once
#include "BaseCodec.h"
#include "alac_wrapper.h"
class ALACDecoder : public BaseCodec {
private:
alac_codec_s* alacCodec;
int16_t *pcmData;
public:
ALACDecoder();
~ALACDecoder();
bool setup(uint32_t sampleRate, uint8_t channelCount, uint8_t bitDepth) override;
uint8_t *decode(uint8_t *inData, uint32_t inLen, uint32_t &outLen) override;
};

View File

@@ -0,0 +1,23 @@
// Copyright (c) Kuba Szczodrzyński 2022-1-12.
#pragma once
#include "BaseCodec.h"
#include "BaseContainer.h"
#include <memory>
enum class AudioCodec {
UNKNOWN = 0,
AAC = 1,
MP3 = 2,
VORBIS = 3,
OPUS = 4,
FLAC = 5,
};
class AudioCodecs {
public:
static std::shared_ptr<BaseCodec> getCodec(AudioCodec type);
static std::shared_ptr<BaseCodec> getCodec(BaseContainer *container);
static void addCodec(AudioCodec type, const std::shared_ptr<BaseCodec> &codec);
};

View File

@@ -0,0 +1,39 @@
// Copyright (c) Kuba Szczodrzyński 2022-1-12.
#pragma once
#include "BaseContainer.h"
class BaseCodec {
public:
/**
* Setup the codec (sample rate, channel count, etc) using the specified container.
*/
virtual bool setup(BaseContainer *container);
/**
* Setup the codec manually, using the provided values.
*/
virtual bool setup(uint32_t sampleRate, uint8_t channelCount, uint8_t bitDepth) = 0;
/**
* Decode the given sample.
*
* @param [in] inData encoded data. Should allow nullptr, in which case nullptr should be returned.
* @param [in] inLen size of inData, in bytes
* @param [out] outLen size of output PCM data, in bytes
* @return pointer to decoded raw PCM audio data, allocated inside the codec object; nullptr on failure
*/
virtual uint8_t *decode(uint8_t *inData, uint32_t inLen, uint32_t &outLen) = 0;
/**
* Read a single sample from the container, decode it, and return the result.
*
* @param [in] container media container to read the sample from (the container's codec must match this instance)
* @param [out] outLen size of output PCM data, in bytes
* @return pointer to decoded raw PCM audio data, allocated inside the codec object; nullptr on failure
*/
uint8_t *decode(BaseContainer *container, uint32_t &outLen);
/**
* Last error that occurred, this is a codec-specific value.
* This may be set by a codec upon decoding failure.
*/
int lastErrno = -1;
};

View File

@@ -43,7 +43,7 @@ namespace bell
}
};
extern std::shared_ptr<bell::DecodersInstance> decodersInstance;
extern bell::DecodersInstance* decodersInstance;
void createDecoders();
}

View File

@@ -0,0 +1,19 @@
// Copyright (c) Kuba Szczodrzyński 2022-1-14.
#pragma once
#include "BaseCodec.h"
#include "mp3dec.h"
class MP3Decoder : public BaseCodec {
private:
HMP3Decoder mp3;
int16_t *pcmData;
MP3FrameInfo frame = {};
public:
MP3Decoder();
~MP3Decoder();
bool setup(uint32_t sampleRate, uint8_t channelCount, uint8_t bitDepth) override;
uint8_t *decode(uint8_t *inData, uint32_t inLen, uint32_t &outLen) override;
};

View File

@@ -0,0 +1,19 @@
// Copyright (c) Kuba Szczodrzyński 2022-1-14.
#pragma once
#include "BaseCodec.h"
struct OpusDecoder;
class OPUSDecoder : public BaseCodec {
private:
OpusDecoder *opus;
int16_t *pcmData;
public:
OPUSDecoder();
~OPUSDecoder();
bool setup(uint32_t sampleRate, uint8_t channelCount, uint8_t bitDepth) override;
uint8_t *decode(uint8_t *inData, uint32_t inLen, uint32_t &outLen) override;
};

View File

@@ -0,0 +1,25 @@
// Copyright (c) Kuba Szczodrzyński 2022-1-14.
#pragma once
#include "BaseCodec.h"
#include "ivorbiscodec.h"
class VorbisDecoder : public BaseCodec {
private:
vorbis_info *vi = nullptr;
vorbis_comment *vc = nullptr;
vorbis_dsp_state *vd = nullptr;
ogg_packet op = {};
int16_t *pcmData;
public:
VorbisDecoder();
~VorbisDecoder();
bool setup(uint32_t sampleRate, uint8_t channelCount, uint8_t bitDepth) override;
uint8_t *decode(uint8_t *inData, uint32_t inLen, uint32_t &outLen) override;
bool setup(BaseContainer *container) override;
private:
void setPacket(uint8_t *inData, uint32_t inLen) const;
};

View File

@@ -0,0 +1,10 @@
// Copyright (c) Kuba Szczodrzyński 2022-1-15.
#pragma once
#include "BaseContainer.h"
class AudioContainers {
public:
static std::unique_ptr<BaseContainer> create(const char *mimeType);
};

View File

@@ -0,0 +1,104 @@
// Copyright (c) Kuba Szczodrzyński 2022-1-7.
#pragma once
#include "BinaryReader.h"
#include "ByteStream.h"
#include <cstdint>
#include <memory>
/**
* Either the media file or the requested position/offset is not loaded yet.
*/
#define SAMPLE_NOT_LOADED -1
/**
* The media file does not contain the requested position/offset.
*/
#define SAMPLE_NOT_FOUND -2
/**
* The file is not seekable (i.e. doesn't contain an index table).
*/
#define SAMPLE_NOT_SEEKABLE -3
enum class AudioCodec;
class BaseContainer {
public:
BaseContainer() = default;
/**
* Feed a new data source to the container.
* @param stream ByteStream reading source data
* @param position absolute position of the current ByteStream within the source media
*/
virtual void feed(const std::shared_ptr<bell::ByteStream> &stream, uint32_t position);
/**
* Try to parse the media provided by the source stream.
* @return whether parsing was successful
*/
virtual bool parse() = 0;
/**
* Get absolute offset within the source media for the given timestamp.
* When seeking to a specified time, the caller should run feed() with a stream
* reader starting at the returned offset. Depending on the container type,
* the returned offset may not point to the exact time position (i.e. chunks with
* headers), so seekTo() should be used afterwards.
*
* @param timeMs requested timestamp, in milliseconds
* @return byte offset within the source media that should be loaded
* in order to seek to the requested position; negative value on error
*/
virtual int32_t getLoadingOffset(uint32_t timeMs) = 0;
/**
* Try to seek to the specified position (in milliseconds), using the currently
* loaded source stream. This method will fail if the source stream does not yield
* data for the requested position, or block until the stream loads data for this position.
*
* @param timeMs requested timestamp, in milliseconds
*/
virtual bool seekTo(uint32_t timeMs) = 0;
/**
* Get the current playback position, in milliseconds. May return -1 if the track
* is not playing (has ended or not started yet).
*/
virtual int32_t getCurrentTimeMs() = 0;
/**
* Read an encoded audio sample from the container, starting at the current position.
*
* @param [out] len length of the data stored in the returned pointer, in bytes
* @return pointer to data allocated inside the container object; should not be freed or changed.
* On failure, nullptr is returned, and len is left unchanged.
*/
virtual uint8_t *readSample(uint32_t &len) = 0;
/**
* Get optional initialization data for the specified codec. This may be used by a codec,
* for containers that contain the setup data.
*
* @param [out] len length of the setup data
* @return ptr to [len] setup data bytes, or nullptr if not available/not supported
*/
virtual uint8_t *getSetupData(uint32_t &len, AudioCodec matchCodec) = 0;
public:
bool closed = false;
bool isSeekable = false;
// audio parameters
AudioCodec codec = (AudioCodec)0;
uint32_t sampleRate = 0;
uint8_t channelCount = 0;
uint8_t bitDepth = 0;
uint32_t durationMs = 0;
protected:
std::unique_ptr<bell::BinaryReader> reader;
std::shared_ptr<bell::ByteStream> source;
uint32_t pos = 0;
uint8_t readUint8();
uint16_t readUint16();
uint32_t readUint24();
uint32_t readUint32();
uint64_t readUint64();
uint32_t readVarint32();
uint32_t readBytes(uint8_t *dst, uint32_t num);
uint32_t skipBytes(uint32_t num);
uint32_t skipTo(uint32_t offset);
};

View File

@@ -0,0 +1,108 @@
// Copyright (c) Kuba Szczodrzyński 2022-1-8.
#pragma once
#include <cstdint>
enum class AudioSampleFormat;
enum class MP4AObjectType;
enum class MP4AProfile;
typedef struct {
/** Absolute offset of mdat header (or moof for fMP4) */
uint32_t start;
/** Absolute offset of the last mdat byte */
uint32_t end;
/** Total duration of this fragment */
uint32_t duration;
} Mpeg4Fragment;
typedef struct {
/** Number of chunks this descriptor applies to */
uint16_t count;
/** Number of samples in the described chunks */
uint32_t samples;
uint16_t sampleDescriptionId;
} Mpeg4ChunkRange;
/** Absolute offset of the chunk data */
typedef uint32_t Mpeg4ChunkOffset;
typedef struct {
/** Abs. offset of data start in the current chunk */
uint32_t start;
/** Abs. offset of data end in the current chunk */
uint32_t end;
/** Abs. offset of the next chunk data, or 0 for last chunk in a fragment */
uint32_t nextStart;
} Mpeg4Chunk;
typedef struct {
/** Number of samples this descriptor applies to */
uint32_t count;
/** Duration of the described samples */
uint32_t duration;
} Mpeg4SampleRange;
/** Size of a single sample */
typedef uint32_t Mpeg4SampleSize;
/** Flags for a sample */
typedef uint32_t SampleFlags;
/** Default values for samples in the movie/fragment */
typedef struct {
/** Absolute offset of first mdat byte */
uint32_t offset;
uint32_t sampleDescriptionId;
uint32_t duration;
uint32_t size;
SampleFlags flags;
} SampleDefaults;
/** Sample Description Table */
typedef struct {
uint16_t dataReferenceIndex;
AudioSampleFormat format;
// params for MPEG-4 Elementary Stream Descriptors
MP4AObjectType mp4aObjectType;
MP4AProfile mp4aProfile;
// atom header for unknown descriptors
uint32_t dataType;
// codec-specific data (either DecoderSpecificInfo or the entire descriptor)
uint32_t dataLength;
uint8_t *data;
} SampleDescription;
typedef struct {
// byte 1 - bits 0:7
bool durationIsEmpty : 1;
bool defaultBaseIsMoof : 1;
bool dummy1 : 6;
// byte 2 - bits 0:7
uint8_t dummy2 : 8;
// byte 3 - bits 0:7
bool baseDataOffsetPresent : 1;
bool sampleDescriptionIndexPresent : 1;
bool dummy3 : 1;
bool defaultSampleDurationPresent : 1;
bool defaultSampleSizePresent : 1;
bool defaultSampleFlagsPresent : 1;
bool dummy4 : 2;
} TfFlags;
typedef struct {
// byte 1 - bits 0:7
uint8_t dummy1 : 8;
// byte 2 - bits 0:7
bool sampleDurationPresent : 1;
bool sampleSizePresent : 1;
bool sampleFlagsPresent : 1;
bool sampleCompositionTimeOffsetsPresent : 1;
bool dummy2 : 4;
// byte 3 - bits 0:7
bool dataOffsetPresent : 1;
bool dummy3 : 1;
bool firstSampleFlagsPresent : 1;
bool dummy4 : 5;
} TrFlags;

View File

@@ -0,0 +1,114 @@
// Copyright (c) Kuba Szczodrzyński 2022-1-8.
#pragma once
#include "BaseContainer.h"
#include "Mpeg4Atoms.h"
#include <memory>
class Mpeg4Container : public BaseContainer {
public:
~Mpeg4Container();
/**
* Start parsing the MP4 file. This method expects the source to read from 0th byte.
* This method leaves pos at first mdat data byte, or mdat header for fMP4 files.
*/
bool parse() override;
int32_t getLoadingOffset(uint32_t timeMs) override;
bool seekTo(uint32_t timeMs) override;
int32_t getCurrentTimeMs() override;
uint8_t *readSample(uint32_t &len) override;
uint8_t *getSetupData(uint32_t &len, AudioCodec matchCodec) override;
void feed(const std::shared_ptr<bell::ByteStream> &stream, uint32_t position) override;
private:
/**
* Parse a single movie fragment. This method expects the source to read moof data, without the header.
* After running, [pos] is left at next mdat header. A new fragment will be created if [pos] does not exist
* in [fragments] table.
*/
bool parseMoof(uint32_t moofSize);
bool goToData();
// char mediaBrand[5];
uint32_t totalDuration;
bool totalDurationPresent = false;
int8_t audioTrackId = -1;
uint32_t timescale = 0;
uint32_t sampleSizeMax = 0;
uint8_t *sampleData = nullptr;
uint32_t sampleDataLen = 0;
bool isParsed = false;
bool isFragmented = false;
/** True if source reads **audio** mdat data bytes, false if source reads atom headers */
bool isInData = false;
private: // data for the entire movie:
/** All fragments in the MPEG file */
Mpeg4Fragment *fragments;
uint16_t fragmentsLen;
/** Default sample descriptions for each track */
SampleDefaults *sampleDefs;
uint32_t sampleDefsLen;
/** Track IDs of [sampleDef] items */
uint32_t *sampleDefTracks;
/** Sample Description Table */
SampleDescription *sampleDesc;
uint32_t sampleDescLen;
private: // data changing every fragment:
/** Chunks in the current fragment */
Mpeg4ChunkRange *chunks;
uint32_t chunksLen;
/** Absolute chunk offsets in the current fragment */
Mpeg4ChunkOffset *chunkOffsets;
uint32_t chunkOffsetsLen;
/** All sample descriptors in the current fragment */
Mpeg4SampleRange *samples;
uint32_t samplesLen;
/** All sample sizes in the current fragment */
Mpeg4SampleSize *sampleSizes;
uint32_t sampleSizesLen;
private: // current status and position within the file
/** Currently loaded fragment (ptr) */
Mpeg4Fragment *curFragment;
/** The chunk currently being processed */
Mpeg4Chunk curChunk;
/** Size of the current sample (ptr) */
Mpeg4SampleSize *curSampleSize;
private: // Mpeg4Utils.cpp
void readAtomHeader(uint32_t &size, uint32_t &type);
void freeAll();
void freeFragment();
SampleDefaults *getSampleDef(uint32_t trackId);
void setCurrentFragment();
void setCurrentSample();
static bool isInFragment(Mpeg4Fragment *f, uint32_t offset);
static AudioCodec getCodec(SampleDescription *desc);
Mpeg4Fragment *createFragment();
int64_t findSample(int64_t byTime, int32_t byPos, uint64_t startTime);
private: // Mpeg4Parser.cpp
/** Populate [chunks] using the Sample-to-chunk Table */
void readStsc();
/** Populate [chunkOffsets] using the Chunk Offset Table */
void readStco();
/** Populate [samples] using the Time-to-sample Table */
void readStts();
/** Populate [sampleSizes] using the Sample Size Table */
void readStsz();
/** Populate [sampleDesc] using the Sample Description Table */
void readStsd();
private: // Mpeg4ParserFrag.cpp
/** Populate [fragments] using the Segment Index Table */
void readSidx(uint32_t atomSize);
/** Populate [sampleDefs] using Track Extends */
void readTrex();
/** Populate [sampleDefs] using Track Fragment Header */
void readTfhd(uint32_t trafEnd, uint32_t moofOffset);
/** Populate [chunks, chunkOffsets, samples, sampleSizes] using Track Fragment Run Table */
void readTrun(uint32_t atomSize, uint32_t moofOffset);
void allocSampleData();
};

View File

@@ -0,0 +1,206 @@
// Copyright (c) Kuba Szczodrzyński 2022-1-12.
#pragma once
enum class AtomType {
/** File Type */
ATOM_FTYP = 0x66747970,
/** Movie */
ATOM_MOOV = 0x6D6F6F76,
/** Movie Header */
ATOM_MVHD = 0x6D766864,
/** Movie Extends */
ATOM_MVEX = 0x6D766578,
/** Movie Extends Header */
ATOM_MEHD = 0x6D656864,
/** Track Extends */
ATOM_TREX = 0x74726578,
/** Track */
ATOM_TRAK = 0x7472616B,
/** Track Header */
ATOM_TKHD = 0x746B6864,
/** Edit */
ATOM_EDTS = 0x65647473,
/** Edit List */
ATOM_ELST = 0x656C7374,
/** Media */
ATOM_MDIA = 0x6D646961,
/** Media Header */
ATOM_MDHD = 0x6D646864,
/** Handler Reference */
ATOM_HDLR = 0x68646C72,
/** Handler Type - Sound */
ATOM_SOUN = 0x736F756E,
/** Handler Type - Video */
ATOM_VIDE = 0x76696465,
/** Handler Type - Subtitle */
ATOM_SUBT = 0x73756274,
/** Media Information */
ATOM_MINF = 0x6D696E66,
/** Data Information */
ATOM_DINF = 0x64696E66,
/** Data Reference */
ATOM_DREF = 0x64726566,
/** Data Entry Url */
ATOM_URL = 0x75726C20,
/** Sample Table */
ATOM_STBL = 0x7374626C,
/** Sample Description */
ATOM_STSD = 0x73747364,
/** siDecompressionParam */
ATOM_WAVE = 0x77617665,
/** Format Atom */
ATOM_FRMA = 0x66726D61,
/** Audio Channel Layout Atom */
ATOM_CHAN = 0x6368616E,
/** Terminator Atom */
ATOM_TERM = 0x00000000,
/** MPEG-4 Elementary Stream Descriptor */
ATOM_ESDS = 0x65736473,
/** Time-to-sample Table */
ATOM_STTS = 0x73747473,
/** Sync Sample Table */
ATOM_STSS = 0x73747373,
/** Sample-to-chunk Table */
ATOM_STSC = 0x73747363,
/** Chunk Offset Table */
ATOM_STCO = 0x7374636F,
/** Sample Size Table */
ATOM_STSZ = 0x7374737A,
/** Sound Media Header */
ATOM_SMHD = 0x736D6864,
/** Segment Index Table */
ATOM_SIDX = 0x73696478,
/** Movie Fragment */
ATOM_MOOF = 0x6D6F6F66,
/** Movie Fragment Header */
ATOM_MFHD = 0x6D666864,
/** Track Fragment */
ATOM_TRAF = 0x74726166,
/** Track Fragment Header */
ATOM_TFHD = 0x74666864,
/** Track Fragment Run */
ATOM_TRUN = 0x7472756E,
/** Media Data */
ATOM_MDAT = 0x6D646174,
};
// These formats are the direct sub-children of the stsd atom.
// https://mp4ra.org/#/codecs (+additions)
enum class AudioSampleFormat {
UNDEFINED = 0,
A3DS = 0x61336473, // Auro-Cx 3D audio
AC3 = 0x61632d33, // AC-3 audio
AC4 = 0x61632d34, // AC-4 audio
AGSM = 0x6167736d, // GSM
ALAC = 0x616c6163, // Apple lossless audio codec
ALAW = 0x616c6177, // a-Law
CAVS = 0x63617673, // AVS2-P3 codec
DRA1 = 0x64726131, // DRA Audio
DTS_MINUS = 0x6474732d, // Dependent base layer for DTS layered audio
DTS_PLUS = 0x6474732b, // Enhancement layer for DTS layered audio
DTSC = 0x64747363, // Core Substream
DTSE = 0x64747365, // Extension Substream containing only LBR
DTSH = 0x64747368, // Core Substream + Extension Substream
DTSL = 0x6474736c, // Extension Substream containing only XLL
DTSX = 0x64747378, // DTS-UHD profile 2
DTSY = 0x64747379, // DTS-UHD profile 3 or higher
DVI = 0x64766920, // DVI (as used in RTP, 4:1 compression)
EC3 = 0x65632d33, // Enhanced AC-3 audio
ENCA = 0x656e6361, // Encrypted/Protected audio
FL32 = 0x666c3332, // 32 bit float
FL64 = 0x666c3634, // 64 bit float
FLAC = 0x664c6143, // Free Lossless Audio Codec
G719 = 0x67373139, // ITU-T Recommendation G.719 (2008)
G726 = 0x67373236, // ITU-T Recommendation G.726 (1990)
IMA4 = 0x696d6134, // IMA (International Multimedia Assocation, defunct, 4:1)
IN24 = 0x696e3234, // 24 bit integer uncompressed
IN32 = 0x696e3332, // 32 bit integer uncompressed
LPCM = 0x6c70636d, // Uncompressed audio (various integer and float formats)
M4AE = 0x6d346165, // MPEG-4 Audio Enhancement
MHA1 = 0x6d686131, // MPEG-H Audio (single stream, unencapsulated)
MHA2 = 0x6d686132, // MPEG-H Audio (multi-stream, unencapsulated)
MHM1 = 0x6d686d31, // MPEG-H Audio (single stream, MHAS encapsulated)
MHM2 = 0x6d686d32, // MPEG-H Audio (multi-stream, MHAS encapsulated)
MLPA = 0x6d6c7061, // MLP Audio
MP4A = 0x6d703461, // MPEG-4 Audio
OPUS = 0x4f707573, // Opus audio coding
QCLP = 0x51636c70, // Qualcomm PureVoice
QDM2 = 0x51444d32, // Qdesign music 2
QDMC = 0x51444d43, // Qdesign music 1
RAW = 0x72617720, // Uncompressed audio
SAMR = 0x73616d72, // Narrowband AMR voice
SAWB = 0x73617762, // Wideband AMR voice
SAWP = 0x73617770, // Extended AMR-WB (AMR-WB+)
SEVC = 0x73657663, // EVRC Voice
SEVS = 0x73657673, // Enhanced Voice Services (EVS)
SQCP = 0x73716370, // 13K Voice
SSMV = 0x73736d76, // SMV Voice
TWOS = 0x74776f73, // Uncompressed 16-bit audio
ULAW = 0x756c6177, // Samples have been compressed using uLaw 2:1.
VDVA = 0x76647661, // DV audio (variable duration per video frame)
};
// These are present in the DecoderConfigDescriptor tag in ESDS (for AudioSampleFormat::FORMAT_MP4A).
// Source: https://mp4ra.org/#/codecs
enum class MP4AObjectType {
UNDEFINED = 0,
_13K = 0xE1, // 13K Voice
AAC_LC = 0x67, // ISO/IEC 13818-7 (AAC) Low Complexity Profile
AAC_MAIN = 0x66, // ISO/IEC 13818-7 (AAC) Main Profile
AAC_SSR = 0x68, // ISO/IEC 13818-7 (AAC) Scaleable Sampling Rate Profile
AC3 = 0xA5, // AC-3
AC3_ENH = 0xA6, // Enhanced AC-3
AC4 = 0xAE, // AC-4
AURO_CX_3D = 0xAF, // Auro-Cx 3D audio
DRA = 0xA7, // DRA Audio
DTS_CORE = 0xA9, // Core Substream
DTS_CORE_EXT = 0xAA, // Core Substream + Extension Substream
DTS_LBR = 0xAC, // Extension Substream containing only LBR
DTS_UHD2 = 0xB2, // DTS-UHD profile 2
DTS_UHD3 = 0xB3, // DTS-UHD profile 3 or higher
DTS_XLL = 0xAB, // Extension Substream containing only XLL
EVRC = 0xA0, // EVRC Voice
G719 = 0xA8, // ITU G.719 Audio
MP4A = 0x40, // ISO/IEC 14496-3 (MPEG-4 Audio)
MPEG1 = 0x6B, // ISO/IEC 11172-3 (MPEG-1 Part 3)
MPEG2 = 0x69, // ISO/IEC 13818-3 (MPEG-2 Part 3)
OPUS = 0xAD, // Opus audio
SMV = 0xA1, // SMV Voice
VORBIS = 0xDD, // Vorbis
};
// These are present in the DecoderSpecificInfo tag in ESDS (for MP4AObjectType::TYPE_MP4A).
// Source: https://wiki.multimedia.cx/index.php/MPEG-4_Audio
enum class MP4AProfile {
UNDEFINED = 0,
AAC_MAIN = 1, // AAC main
AAC_LC = 2, // AAC LC
AAC_SSR = 3, // AAC SSR
AAC_LTP = 4, // AAC LTP
SBR = 5, // SBR
AAC_SCALABLE = 6, // AAC Scalable
TWINVQ = 7, // TwinVQ
CELP = 8, // CELP
HVXC = 9, // HVXC
TTSI = 12, // TTSI
MAIN_SYNTHETIC = 13, // Main synthetic
WAVETABLE_SYNTHESIS = 14, // Wavetable synthesis
GENERAL_MIDI = 15, // General MIDI
ALGORITHMIC_SYNTHESIS_AND_AUDIO_FX = 16, // Algorithmic Synthesis and Audio FX
ER_AAC_LC = 17, // ER AAC LC
ER_AAC_LTP = 19, // ER AAC LTP
ER_AAC_SCALABLE = 20, // ER AAC Scalable
ER_TWINVQ = 21, // ER TwinVQ
ER_BSAC = 22, // ER BSAC
ER_AAC_LD = 23, // ER AAC LD
ER_CELP = 24, // ER CELP
ER_HVXC = 25, // ER HVXC
ER_HILN = 26, // ER HILN
ER_PARAMETRIC = 27, // ER Parametric
SSC = 28, // SSC
LAYER_1 = 32, // Layer-1
LAYER_2 = 33, // Layer-2
LAYER_3 = 34, // Layer-3
DST = 35, // DST
};

View File

@@ -0,0 +1,81 @@
// Copyright (c) Kuba Szczodrzyński 2022-1-16.
#pragma once
#include "BaseContainer.h"
enum class ElementId;
class WebmContainer : public BaseContainer {
public:
~WebmContainer();
bool parse() override;
int32_t getLoadingOffset(uint32_t timeMs) override;
bool seekTo(uint32_t timeMs) override;
int32_t getCurrentTimeMs() override;
uint8_t *readSample(uint32_t &len) override;
uint8_t *getSetupData(uint32_t &len, AudioCodec matchCodec) override;
void feed(const std::shared_ptr<bell::ByteStream> &stream, uint32_t position) override;
private:
typedef struct {
uint32_t time;
uint32_t offset;
} CuePoint;
private:
// used while parsing
uint32_t esize;
ElementId eid;
// container parameters
char *docType = nullptr;
uint8_t audioTrackId = 255;
float timescale = 0.0f;
char *codecId = nullptr;
uint8_t *codecPrivate = nullptr;
uint32_t codecPrivateLen = 0;
// container state
CuePoint *cues = nullptr;
uint16_t cuesLen = 0;
uint32_t clusterEnd = 0;
uint32_t clusterTime = 0;
uint32_t currentTime = 0;
bool isParsed = false;
// buffer
uint8_t *sampleData = nullptr;
uint32_t sampleLen = 0;
// lacing parameters
uint32_t *laceSizes = nullptr;
uint32_t *laceCurrent = nullptr;
uint8_t laceLeft = 0;
// set to read the current buffer instead of loading new frames
uint16_t readOutFrameSize = 0;
private:
uint32_t readVarNum32(bool raw = false);
uint64_t readVarNum64();
uint32_t readUint(uint8_t len);
uint64_t readUlong(uint8_t len);
float readFloat(uint8_t len);
void readElem();
void parseSegment(uint32_t start);
void parseTrack(uint32_t end);
void parseCuePoint(uint16_t idx, uint32_t end, uint32_t segmentStart);
/**
* Continue reading elements until a block is encountered.
*
* If [untilTime] is set, the method will keep reading until [currentTime]
* is less than [untilTime]. Because of how WebM works, [pos] will be one frame later
* than the requested time, although the container will report the correct position.
*
* @return size of the frame pointed by [pos]
*/
uint32_t readCluster(uint32_t untilTime = 0);
/**
* Parse a single block within a cluster. This method will populate lacing parameters if needed.
* @param end offset of the next byte after this block
* @return size of the frame pointed by [pos]
*/
uint32_t readBlock(uint32_t end);
uint8_t *readFrame(uint32_t size, uint32_t &outLen);
};

View File

@@ -0,0 +1,713 @@
// Copyright (c) Kuba Szczodrzyński 2022-1-16.
#pragma once
enum class ElementId {
/** [sub-elements] Set the EBML characteristics of the data to follow. Each EBML document has to start with this. */
EBML = 0x1A45DFA3,
/** [u-integer] The version of EBML parser used to create the file. */
EBMLVersion = 0x4286,
/** [u-integer] The minimum EBML version a parser has to support to read this file. */
EBMLReadVersion = 0x42F7,
/** [u-integer] The maximum length of the IDs you'll find in this file (4 or less in Matroska). */
EBMLMaxIDLength = 0x42F2,
/** [u-integer] The maximum length of the sizes you'll find in this file (8 or less in Matroska). This does not
override the element size indicated at the beginning of an element. Elements that have an indicated size which is
larger than what is allowed by EBMLMaxSizeLength shall be considered invalid. */
EBMLMaxSizeLength = 0x42F3,
/** [string] A string that describes the type of document that follows this EBML header ('matroska' in our case). */
DocType = 0x4282,
/** [u-integer] The version of DocType interpreter used to create the file. */
DocTypeVersion = 0x4287,
/** [u-integer] The minimum DocType version an interpreter has to support to read this file. */
DocTypeReadVersion = 0x4285,
/** [binary] The CRC is computed on all the data from the last CRC element (or start of the upper level element), up
to the CRC element, including other previous CRC elements. All level 1 elements should include a CRC-32. */
CRC32 = 0xBF,
/** [binary] Used to void damaged data, to avoid unexpected behaviors when using damaged data. The content is
discarded. Also used to reserve space in a sub-element for later use. */
Void = 0xEC,
/** [sub-elements] Contain signature of some (coming) elements in the stream. */
SignatureSlot = 0x1B538667,
/** [u-integer] Signature algorithm used (1=RSA, 2=elliptic). */
SignatureAlgo = 0x7E8A,
/** [u-integer] Hash algorithm used (1=SHA1-160, 2=MD5). */
SignatureHash = 0x7E9A,
/** [binary] The public key to use with the algorithm (in the case of a PKI-based signature). */
SignaturePublicKey = 0x7EA5,
/** [binary] The signature of the data (until a new. */
Signature = 0x7EB5,
/** [sub-elements] Contains elements that will be used to compute the signature. */
SignatureElements = 0x7E5B,
/** [sub-elements] A list consists of a number of consecutive elements that represent one case where data is used in
signature. Ex: Cluster|Block|BlockAdditional means that the BlockAdditional of all Blocks in all Clusters is used
for encryption. */
SignatureElementList = 0x7E7B,
/** [binary] An element ID whose data will be used to compute the signature. */
SignedElement = 0x6532,
/* ebml_matroska.xml */
/** [master] The Root Element that contains all other Top-Level Elements (Elements defined only at Level 1). A
Matroska file is composed of 1 Segment. */
Segment = 0x18538067,
/** [master] Contains the Segment Position of other Top-Level Elements. */
SeekHead = 0x114D9B74,
/** [master] Contains a single seek entry to an EBML Element. */
Seek = 0x4DBB,
/** [binary] The binary ID corresponding to the Element name. */
SeekID = 0x53AB,
/** [uinteger] The Segment Position of the Element. */
SeekPosition = 0x53AC,
/** [master] Contains general information about the Segment. */
Info = 0x1549A966,
/** [binary] A randomly generated unique ID to identify the Segment amongst many others (128 bits). */
SegmentUID = 0x73A4,
/** [utf-8] A filename corresponding to this Segment. */
SegmentFilename = 0x7384,
/** [binary] A unique ID to identify the previous Segment of a Linked Segment (128 bits). */
PrevUID = 0x3CB923,
/** [utf-8] A filename corresponding to the file of the previous Linked Segment. */
PrevFilename = 0x3C83AB,
/** [binary] A unique ID to identify the next Segment of a Linked Segment (128 bits). */
NextUID = 0x3EB923,
/** [utf-8] A filename corresponding to the file of the next Linked Segment. */
NextFilename = 0x3E83BB,
/** [binary] A randomly generated unique ID that all Segments of a Linked Segment **MUST** share (128 bits). */
SegmentFamily = 0x4444,
/** [master] The mapping between this `Segment` and a segment value in the given Chapter Codec. */
ChapterTranslate = 0x6924,
/** [binary] The binary value used to represent this Segment in the chapter codec data. The format depends on the
ChapProcessCodecID used; see (#chapprocesscodecid-element). */
ChapterTranslateID = 0x69A5,
/** [uinteger] This `ChapterTranslate` applies to this chapter codec of the given chapter edition(s); see
(#chapprocesscodecid-element). */
ChapterTranslateCodec = 0x69BF,
/** [uinteger] Specify a chapter edition UID on which this `ChapterTranslate` applies. */
ChapterTranslateEditionUID = 0x69FC,
/** [uinteger] Timestamp scale in nanoseconds (1.000.000 means all timestamps in the Segment are expressed in
milliseconds). */
TimestampScale = 0x2AD7B1,
/** [float] Duration of the Segment in nanoseconds based on TimestampScale. */
Duration = 0x4489,
/** [date] The date and time that the Segment was created by the muxing application or library. */
DateUTC = 0x4461,
/** [utf-8] General name of the Segment. */
Title = 0x7BA9,
/** [utf-8] Muxing application or library (example: "libmatroska-0.4.3"). */
MuxingApp = 0x4D80,
/** [utf-8] Writing application (example: "mkvmerge-0.3.3"). */
WritingApp = 0x5741,
/** [master] The Top-Level Element containing the (monolithic) Block structure. */
Cluster = 0x1F43B675,
/** [uinteger] Absolute timestamp of the cluster (based on TimestampScale). */
Timestamp = 0xE7,
/** [master] The list of tracks that are not used in that part of the stream. It is useful when using overlay tracks
on seeking or to decide what track to use. */
SilentTracks = 0x5854,
/** [uinteger] One of the track number that are not used from now on in the stream. It could change later if not
specified as silent in a further Cluster. */
SilentTrackNumber = 0x58D7,
/** [uinteger] The Segment Position of the Cluster in the Segment (0 in live streams). It might help to
resynchronise offset on damaged streams. */
Position = 0xA7,
/** [uinteger] Size of the previous Cluster, in octets. Can be useful for backward playing. */
PrevSize = 0xAB,
/** [binary] Similar to Block, see (#block-structure), but without all the extra information, mostly used to reduced
overhead when no extra feature is needed; see (#simpleblock-structure) on SimpleBlock Structure. */
SimpleBlock = 0xA3,
/** [master] Basic container of information containing a single Block and information specific to that Block. */
BlockGroup = 0xA0,
/** [binary] Block containing the actual data to be rendered and a timestamp relative to the Cluster Timestamp; see
(#block-structure) on Block Structure. */
Block = 0xA1,
/** [binary] A Block with no data. It **MUST** be stored in the stream at the place the real Block would be in
display order. */
BlockVirtual = 0xA2,
/** [master] Contain additional blocks to complete the main one. An EBML parser that has no knowledge of the Block
structure could still see and use/skip these data. */
BlockAdditions = 0x75A1,
/** [master] Contain the BlockAdditional and some parameters. */
BlockMore = 0xA6,
/** [uinteger] An ID to identify the BlockAdditional level. If BlockAddIDType of the corresponding block is 0, this
value is also the value of BlockAddIDType for the meaning of the content of BlockAdditional. */
BlockAddID = 0xEE,
/** [binary] Interpreted by the codec as it wishes (using the BlockAddID). */
BlockAdditional = 0xA5,
/** [uinteger] The duration of the Block (based on TimestampScale). The BlockDuration Element can be useful at the
end of a Track to define the duration of the last frame (as there is no subsequent Block available), or when
there is a break in a track like for subtitle tracks. */
BlockDuration = 0x9B,
/** [uinteger] This frame is referenced and has the specified cache priority. In cache only a frame of the same or
higher priority can replace this frame. A value of 0 means the frame is not referenced. */
ReferencePriority = 0xFA,
/** [integer] A timestamp value, relative to the timestamp of the Block in this BlockGroup. This is used to
reference other frames necessary to decode this frame. The relative value **SHOULD** correspond to a valid
`Block` this `Block` depends on. Historically Matroska Writer didn't write the actual `Block(s)` this `Block`
depends on, but *some* `Block` in the past. The value "0" **MAY** also be used to signify this `Block` cannot be
decoded on its own, but without knownledge of which `Block` is necessary. In this case, other `ReferenceBlock`
**MUST NOT** be found in the same `BlockGroup`. If the `BlockGroup` doesn't have any `ReferenceBlock` element,
then the `Block` it contains can be decoded without using any other `Block` data. */
ReferenceBlock = 0xFB,
/** [integer] The Segment Position of the data that would otherwise be in position of the virtual block. */
ReferenceVirtual = 0xFD,
/** [binary] The new codec state to use. Data interpretation is private to the codec. This information **SHOULD**
always be referenced by a seek entry. */
CodecState = 0xA4,
/** [integer] Duration in nanoseconds of the silent data added to the Block (padding at the end of the Block for
positive value, at the beginning of the Block for negative value). The duration of DiscardPadding is not
calculated in the duration of the TrackEntry and **SHOULD** be discarded during playback. */
DiscardPadding = 0x75A2,
/** [master] Contains slices description. */
Slices = 0x8E,
/** [master] Contains extra time information about the data contained in the Block. Being able to interpret this
Element is not **REQUIRED** for playback. */
TimeSlice = 0xE8,
/** [uinteger] The reverse number of the frame in the lace (0 is the last frame, 1 is the next to last, etc). Being
able to interpret this Element is not **REQUIRED** for playback. */
LaceNumber = 0xCC,
/** [uinteger] The number of the frame to generate from this lace with this delay (allow you to generate many frames
from the same Block/Frame). */
FrameNumber = 0xCD,
/** [uinteger] The ID of the BlockAdditional Element (0 is the main Block). */
BlockAdditionID = 0xCB,
/** [uinteger] The (scaled) delay to apply to the Element. */
Delay = 0xCE,
/** [uinteger] The (scaled) duration to apply to the Element. */
SliceDuration = 0xCF,
/** [master] Contains information about the last reference frame. See [@?DivXTrickTrack]. */
ReferenceFrame = 0xC8,
/** [uinteger] The relative offset, in bytes, from the previous BlockGroup element for this Smooth FF/RW video track
to the containing BlockGroup element. See [@?DivXTrickTrack]. */
ReferenceOffset = 0xC9,
/** [uinteger] The timecode of the BlockGroup pointed to by ReferenceOffset. See [@?DivXTrickTrack]. */
ReferenceTimestamp = 0xCA,
/** [binary] Similar to SimpleBlock, see (#simpleblock-structure), but the data inside the Block are Transformed
(encrypt and/or signed). */
EncryptedBlock = 0xAF,
/** [master] A Top-Level Element of information with many tracks described. */
Tracks = 0x1654AE6B,
/** [master] Describes a track with all Elements. */
TrackEntry = 0xAE,
/** [uinteger] The track number as used in the Block Header (using more than 127 tracks is not encouraged, though
the design allows an unlimited number). */
TrackNumber = 0xD7,
/** [uinteger] A unique ID to identify the Track. */
TrackUID = 0x73C5,
/** [uinteger] The `TrackType` defines the type of each frame found in the Track. The value **SHOULD** be stored on
1 octet. */
TrackType = 0x83,
/** [uinteger] Set to 1 if the track is usable. It is possible to turn a not usable track into a usable track using
chapter codecs or control tracks. */
FlagEnabled = 0xB9,
/** [uinteger] Set if that track (audio, video or subs) **SHOULD** be eligible for automatic selection by the
player; see (#default-track-selection) for more details. */
FlagDefault = 0x88,
/** [uinteger] Applies only to subtitles. Set if that track **SHOULD** be eligible for automatic selection by the
player if it matches the user's language preference, even if the user's preferences would normally not enable
subtitles with the selected audio track; this can be used for tracks containing only translations of
foreign-language audio or onscreen text. See (#default-track-selection) for more details. */
FlagForced = 0x55AA,
/** [uinteger] Set to 1 if that track is suitable for users with hearing impairments, set to 0 if it is unsuitable
for users with hearing impairments. */
FlagHearingImpaired = 0x55AB,
/** [uinteger] Set to 1 if that track is suitable for users with visual impairments, set to 0 if it is unsuitable
for users with visual impairments. */
FlagVisualImpaired = 0x55AC,
/** [uinteger] Set to 1 if that track contains textual descriptions of video content, set to 0 if that track does
not contain textual descriptions of video content. */
FlagTextDescriptions = 0x55AD,
/** [uinteger] Set to 1 if that track is in the content's original language, set to 0 if it is a translation. */
FlagOriginal = 0x55AE,
/** [uinteger] Set to 1 if that track contains commentary, set to 0 if it does not contain commentary. */
FlagCommentary = 0x55AF,
/** [uinteger] Set to 1 if the track **MAY** contain blocks using lacing. When set to 0 all blocks **MUST** have
their lacing flags set to No lacing; see (#block-lacing) on Block Lacing. */
FlagLacing = 0x9C,
/** [uinteger] The minimum number of frames a player **SHOULD** be able to cache during playback. If set to 0, the
reference pseudo-cache system is not used. */
MinCache = 0x6DE7,
/** [uinteger] The maximum cache size necessary to store referenced frames in and the current frame. 0 means no
cache is needed. */
MaxCache = 0x6DF8,
/** [uinteger] Number of nanoseconds (not scaled via TimestampScale) per frame (frame in the Matroska sense -- one
Element put into a (Simple)Block). */
DefaultDuration = 0x23E383,
/** [uinteger] The period in nanoseconds (not scaled by TimestampScale) between two successive fields at the output
of the decoding process, see (#defaultdecodedfieldduration) for more information */
DefaultDecodedFieldDuration = 0x234E7A,
/** [float] DEPRECATED, DO NOT USE. The scale to apply on this track to work at normal speed in relation with other
tracks (mostly used to adjust video speed when the audio length differs). */
TrackTimestampScale = 0x23314F,
/** [integer] A value to add to the Block's Timestamp. This can be used to adjust the playback offset of a track. */
TrackOffset = 0x537F,
/** [uinteger] The maximum value of BlockAddID ((#blockaddid-element)). A value 0 means there is no BlockAdditions
((#blockadditions-element)) for this track. */
MaxBlockAdditionID = 0x55EE,
/** [master] Contains elements that extend the track format, by adding content either to each frame, with BlockAddID
((#blockaddid-element)), or to the track as a whole with BlockAddIDExtraData. */
BlockAdditionMapping = 0x41E4,
/** [uinteger] If the track format extension needs content beside frames, the value refers to the BlockAddID
((#blockaddid-element)), value being described. To keep MaxBlockAdditionID as low as possible, small values
**SHOULD** be used. */
BlockAddIDValue = 0x41F0,
/** [string] A human-friendly name describing the type of BlockAdditional data, as defined by the associated Block
Additional Mapping. */
BlockAddIDName = 0x41A4,
/** [uinteger] Stores the registered identifier of the Block Additional Mapping to define how the BlockAdditional
data should be handled. */
BlockAddIDType = 0x41E7,
/** [binary] Extra binary data that the BlockAddIDType can use to interpret the BlockAdditional data. The
interpretation of the binary data depends on the BlockAddIDType value and the corresponding Block Additional
Mapping. */
BlockAddIDExtraData = 0x41ED,
/** [utf-8] A human-readable track name. */
Name = 0x536E,
/** [string] Specifies the language of the track in the Matroska languages form; see (#language-codes) on language
codes. This Element **MUST** be ignored if the LanguageIETF Element is used in the same TrackEntry. */
Language = 0x22B59C,
/** [string] Specifies the language of the track according to [@!BCP47] and using the IANA Language Subtag Registry
[@!IANALangRegistry]. If this Element is used, then any Language Elements used in the same TrackEntry **MUST** be
ignored. */
LanguageIETF = 0x22B59D,
/** [string] An ID corresponding to the codec, see [@!MatroskaCodec] for more info. */
CodecID = 0x86,
/** [binary] Private data only known to the codec. */
CodecPrivate = 0x63A2,
/** [utf-8] A human-readable string specifying the codec. */
CodecName = 0x258688,
/** [uinteger] The UID of an attachment that is used by this codec. */
AttachmentLink = 0x7446,
/** [utf-8] A string describing the encoding setting used. */
CodecSettings = 0x3A9697,
/** [string] A URL to find information about the codec used. */
CodecInfoURL = 0x3B4040,
/** [string] A URL to download about the codec used. */
CodecDownloadURL = 0x26B240,
/** [uinteger] Set to 1 if the codec can decode potentially damaged data. */
CodecDecodeAll = 0xAA,
/** [uinteger] Specify that this track is an overlay track for the Track specified (in the u-integer). That means
when this track has a gap, see (#silenttracks-element) on SilentTracks, the overlay track **SHOULD** be used
instead. The order of multiple TrackOverlay matters, the first one is the one that **SHOULD** be used. If not
found it **SHOULD** be the second, etc. */
TrackOverlay = 0x6FAB,
/** [uinteger] CodecDelay is The codec-built-in delay in nanoseconds. This value **MUST** be subtracted from each
block timestamp in order to get the actual timestamp. The value **SHOULD** be small so the muxing of tracks with
the same actual timestamp are in the same Cluster. */
CodecDelay = 0x56AA,
/** [uinteger] After a discontinuity, SeekPreRoll is the duration in nanoseconds of the data the decoder **MUST**
decode before the decoded data is valid. */
SeekPreRoll = 0x56BB,
/** [master] The mapping between this `TrackEntry` and a track value in the given Chapter Codec. */
TrackTranslate = 0x6624,
/** [binary] The binary value used to represent this `TrackEntry` in the chapter codec data. The format depends on
the `ChapProcessCodecID` used; see (#chapprocesscodecid-element). */
TrackTranslateTrackID = 0x66A5,
/** [uinteger] This `TrackTranslate` applies to this chapter codec of the given chapter edition(s); see
(#chapprocesscodecid-element). */
TrackTranslateCodec = 0x66BF,
/** [uinteger] Specify a chapter edition UID on which this `TrackTranslate` applies. */
TrackTranslateEditionUID = 0x66FC,
/** [master] Video settings. */
Video = 0xE0,
/** [uinteger] Specify whether the video frames in this track are interlaced or not. */
FlagInterlaced = 0x9A,
/** [uinteger] Specify the field ordering of video frames in this track. */
FieldOrder = 0x9D,
/** [uinteger] Stereo-3D video mode. There are some more details in (#multi-planar-and-3d-videos). */
StereoMode = 0x53B8,
/** [uinteger] Alpha Video Mode. Presence of this Element indicates that the BlockAdditional Element could contain
Alpha data. */
AlphaMode = 0x53C0,
/** [uinteger] DEPRECATED, DO NOT USE. Bogus StereoMode value used in old versions of libmatroska. */
OldStereoMode = 0x53B9,
/** [uinteger] Width of the encoded video frames in pixels. */
PixelWidth = 0xB0,
/** [uinteger] Height of the encoded video frames in pixels. */
PixelHeight = 0xBA,
/** [uinteger] The number of video pixels to remove at the bottom of the image. */
PixelCropBottom = 0x54AA,
/** [uinteger] The number of video pixels to remove at the top of the image. */
PixelCropTop = 0x54BB,
/** [uinteger] The number of video pixels to remove on the left of the image. */
PixelCropLeft = 0x54CC,
/** [uinteger] The number of video pixels to remove on the right of the image. */
PixelCropRight = 0x54DD,
/** [uinteger] Width of the video frames to display. Applies to the video frame after cropping (PixelCrop*
Elements). */
DisplayWidth = 0x54B0,
/** [uinteger] Height of the video frames to display. Applies to the video frame after cropping (PixelCrop*
Elements). */
DisplayHeight = 0x54BA,
/** [uinteger] How DisplayWidth & DisplayHeight are interpreted. */
DisplayUnit = 0x54B2,
/** [uinteger] Specify the possible modifications to the aspect ratio. */
AspectRatioType = 0x54B3,
/** [binary] Specify the uncompressed pixel format used for the Track's data as a FourCC. This value is similar in
scope to the biCompression value of AVI's `BITMAPINFO` [@?AVIFormat]. See the YUV video formats [@?FourCC-YUV]
and RGB video formats [@?FourCC-RGB] for common values. */
UncompressedFourCC = 0x2EB524,
/** [float] Gamma Value. */
GammaValue = 0x2FB523,
/** [float] Number of frames per second. This value is Informational only. It is intended for constant frame rate
streams, and **SHOULD NOT** be used for a variable frame rate TrackEntry. */
FrameRate = 0x2383E3,
/** [master] Settings describing the colour format. */
Colour = 0x55B0,
/** [uinteger] The Matrix Coefficients of the video used to derive luma and chroma values from red, green, and blue
color primaries. For clarity, the value and meanings for MatrixCoefficients are adopted from Table 4 of ISO/IEC
23001-8:2016 or ITU-T H.273. */
MatrixCoefficients = 0x55B1,
/** [uinteger] Number of decoded bits per channel. A value of 0 indicates that the BitsPerChannel is unspecified. */
BitsPerChannel = 0x55B2,
/** [uinteger] The amount of pixels to remove in the Cr and Cb channels for every pixel not removed horizontally.
Example: For video with 4:2:0 chroma subsampling, the ChromaSubsamplingHorz **SHOULD** be set to 1. */
ChromaSubsamplingHorz = 0x55B3,
/** [uinteger] The amount of pixels to remove in the Cr and Cb channels for every pixel not removed vertically.
Example: For video with 4:2:0 chroma subsampling, the ChromaSubsamplingVert **SHOULD** be set to 1. */
ChromaSubsamplingVert = 0x55B4,
/** [uinteger] The amount of pixels to remove in the Cb channel for every pixel not removed horizontally. This is
additive with ChromaSubsamplingHorz. Example: For video with 4:2:1 chroma subsampling, the ChromaSubsamplingHorz
**SHOULD** be set to 1 and CbSubsamplingHorz **SHOULD** be set to 1. */
CbSubsamplingHorz = 0x55B5,
/** [uinteger] The amount of pixels to remove in the Cb channel for every pixel not removed vertically. This is
additive with ChromaSubsamplingVert. */
CbSubsamplingVert = 0x55B6,
/** [uinteger] How chroma is subsampled horizontally. */
ChromaSitingHorz = 0x55B7,
/** [uinteger] How chroma is subsampled vertically. */
ChromaSitingVert = 0x55B8,
/** [uinteger] Clipping of the color ranges. */
Range = 0x55B9,
/** [uinteger] The transfer characteristics of the video. For clarity, the value and meanings for
TransferCharacteristics are adopted from Table 3 of ISO/IEC 23091-4 or ITU-T H.273. */
TransferCharacteristics = 0x55BA,
/** [uinteger] The colour primaries of the video. For clarity, the value and meanings for Primaries are adopted from
Table 2 of ISO/IEC 23091-4 or ITU-T H.273. */
Primaries = 0x55BB,
/** [uinteger] Maximum brightness of a single pixel (Maximum Content Light Level) in candelas per square meter
(cd/m^2^). */
MaxCLL = 0x55BC,
/** [uinteger] Maximum brightness of a single full frame (Maximum Frame-Average Light Level) in candelas per square
meter (cd/m^2^). */
MaxFALL = 0x55BD,
/** [master] SMPTE 2086 mastering data. */
MasteringMetadata = 0x55D0,
/** [float] Red X chromaticity coordinate, as defined by CIE 1931. */
PrimaryRChromaticityX = 0x55D1,
/** [float] Red Y chromaticity coordinate, as defined by CIE 1931. */
PrimaryRChromaticityY = 0x55D2,
/** [float] Green X chromaticity coordinate, as defined by CIE 1931. */
PrimaryGChromaticityX = 0x55D3,
/** [float] Green Y chromaticity coordinate, as defined by CIE 1931. */
PrimaryGChromaticityY = 0x55D4,
/** [float] Blue X chromaticity coordinate, as defined by CIE 1931. */
PrimaryBChromaticityX = 0x55D5,
/** [float] Blue Y chromaticity coordinate, as defined by CIE 1931. */
PrimaryBChromaticityY = 0x55D6,
/** [float] White X chromaticity coordinate, as defined by CIE 1931. */
WhitePointChromaticityX = 0x55D7,
/** [float] White Y chromaticity coordinate, as defined by CIE 1931. */
WhitePointChromaticityY = 0x55D8,
/** [float] Maximum luminance. Represented in candelas per square meter (cd/m^2^). */
LuminanceMax = 0x55D9,
/** [float] Minimum luminance. Represented in candelas per square meter (cd/m^2^). */
LuminanceMin = 0x55DA,
/** [master] Describes the video projection details. Used to render spherical, VR videos or flipping videos
horizontally/vertically. */
Projection = 0x7670,
/** [uinteger] Describes the projection used for this video track. */
ProjectionType = 0x7671,
/** [binary] Private data that only applies to a specific projection. * If `ProjectionType` equals 0
(Rectangular), then this element must not be present. * If `ProjectionType` equals 1 (Equirectangular),
then this element must be present and contain the same binary data that would be stored inside an ISOBMFF
Equirectangular Projection Box ('equi'). * If `ProjectionType` equals 2 (Cubemap), then this element must be
present and contain the same binary data that would be stored inside an ISOBMFF Cubemap Projection Box
('cbmp'). * If `ProjectionType` equals 3 (Mesh), then this element must be present and contain the same binary
data that would be stored inside an ISOBMFF Mesh Projection Box ('mshp'). */
ProjectionPrivate = 0x7672,
/** [float] Specifies a yaw rotation to the projection. Value represents a clockwise rotation, in degrees, around
the up vector. This rotation must be applied before any `ProjectionPosePitch` or `ProjectionPoseRoll` rotations.
The value of this element **MUST** be in the -180 to 180 degree range, both included. Setting
`ProjectionPoseYaw` to 180 or -180 degrees, with the `ProjectionPoseRoll` and `ProjectionPosePitch` set to 0
degrees flips the image horizontally. */
ProjectionPoseYaw = 0x7673,
/** [float] Specifies a pitch rotation to the projection. Value represents a counter-clockwise rotation, in
degrees, around the right vector. This rotation must be applied after the `ProjectionPoseYaw` rotation and before
the `ProjectionPoseRoll` rotation. The value of this element **MUST** be in the -90 to 90 degree range, both
included. */
ProjectionPosePitch = 0x7674,
/** [float] Specifies a roll rotation to the projection. Value represents a counter-clockwise rotation, in degrees,
around the forward vector. This rotation must be applied after the `ProjectionPoseYaw` and `ProjectionPosePitch`
rotations. The value of this element **MUST** be in the -180 to 180 degree range, both included. Setting
`ProjectionPoseRoll` to 180 or -180 degrees, the `ProjectionPoseYaw` to 180 or -180 degrees with
`ProjectionPosePitch` set to 0 degrees flips the image vertically. Setting `ProjectionPoseRoll` to 180 or -180
degrees, with the `ProjectionPoseYaw` and `ProjectionPosePitch` set to 0 degrees flips the image horizontally and
vertically. */
ProjectionPoseRoll = 0x7675,
/** [master] Audio settings. */
Audio = 0xE1,
/** [float] Sampling frequency in Hz. */
SamplingFrequency = 0xB5,
/** [float] Real output sampling frequency in Hz (used for SBR techniques). */
OutputSamplingFrequency = 0x78B5,
/** [uinteger] Numbers of channels in the track. */
Channels = 0x9F,
/** [binary] Table of horizontal angles for each successive channel. */
ChannelPositions = 0x7D7B,
/** [uinteger] Bits per sample, mostly used for PCM. */
BitDepth = 0x6264,
/** [master] Operation that needs to be applied on tracks to create this virtual track. For more details look at
(#track-operation). */
TrackOperation = 0xE2,
/** [master] Contains the list of all video plane tracks that need to be combined to create this 3D track */
TrackCombinePlanes = 0xE3,
/** [master] Contains a video plane track that need to be combined to create this 3D track */
TrackPlane = 0xE4,
/** [uinteger] The trackUID number of the track representing the plane. */
TrackPlaneUID = 0xE5,
/** [uinteger] The kind of plane this track corresponds to. */
TrackPlaneType = 0xE6,
/** [master] Contains the list of all tracks whose Blocks need to be combined to create this virtual track */
TrackJoinBlocks = 0xE9,
/** [uinteger] The trackUID number of a track whose blocks are used to create this virtual track. */
TrackJoinUID = 0xED,
/** [uinteger] The TrackUID of the Smooth FF/RW video in the paired EBML structure corresponding to this video
track. See [@?DivXTrickTrack]. */
TrickTrackUID = 0xC0,
/** [binary] The SegmentUID of the Segment containing the track identified by TrickTrackUID. See [@?DivXTrickTrack].
*/
TrickTrackSegmentUID = 0xC1,
/** [uinteger] Set to 1 if this video track is a Smooth FF/RW track. If set to 1, MasterTrackUID and
MasterTrackSegUID should must be present and BlockGroups for this track must contain ReferenceFrame structures.
Otherwise, TrickTrackUID and TrickTrackSegUID must be present if this track has a corresponding Smooth FF/RW
track. See [@?DivXTrickTrack]. */
TrickTrackFlag = 0xC6,
/** [uinteger] The TrackUID of the video track in the paired EBML structure that corresponds to this Smooth FF/RW
track. See [@?DivXTrickTrack]. */
TrickMasterTrackUID = 0xC7,
/** [binary] The SegmentUID of the Segment containing the track identified by MasterTrackUID. See
[@?DivXTrickTrack]. */
TrickMasterTrackSegmentUID = 0xC4,
/** [master] Settings for several content encoding mechanisms like compression or encryption. */
ContentEncodings = 0x6D80,
/** [master] Settings for one content encoding like compression or encryption. */
ContentEncoding = 0x6240,
/** [uinteger] Tells when this modification was used during encoding/muxing starting with 0 and counting upwards.
The decoder/demuxer has to start with the highest order number it finds and work its way down. This value has to
be unique over all ContentEncodingOrder Elements in the TrackEntry that contains this ContentEncodingOrder
element. */
ContentEncodingOrder = 0x5031,
/** [uinteger] A bit field that describes which Elements have been modified in this way. Values (big-endian) can be
OR'ed. */
ContentEncodingScope = 0x5032,
/** [uinteger] A value describing what kind of transformation is applied. */
ContentEncodingType = 0x5033,
/** [master] Settings describing the compression used. This Element **MUST** be present if the value of
ContentEncodingType is 0 and absent otherwise. Each block **MUST** be decompressable even if no previous block is
available in order not to prevent seeking. */
ContentCompression = 0x5034,
/** [uinteger] The compression algorithm used. */
ContentCompAlgo = 0x4254,
/** [binary] Settings that might be needed by the decompressor. For Header Stripping (`ContentCompAlgo`=3), the
bytes that were removed from the beginning of each frames of the track. */
ContentCompSettings = 0x4255,
/** [master] Settings describing the encryption used. This Element **MUST** be present if the value of
`ContentEncodingType` is 1 (encryption) and **MUST** be ignored otherwise. */
ContentEncryption = 0x5035,
/** [uinteger] The encryption algorithm used. The value "0" means that the contents have not been encrypted. */
ContentEncAlgo = 0x47E1,
/** [binary] For public key algorithms this is the ID of the public key the the data was encrypted with. */
ContentEncKeyID = 0x47E2,
/** [master] Settings describing the encryption algorithm used. If `ContentEncAlgo` != 5 this **MUST** be ignored.
*/
ContentEncAESSettings = 0x47E7,
/** [uinteger] The AES cipher mode used in the encryption. */
AESSettingsCipherMode = 0x47E8,
/** [binary] A cryptographic signature of the contents. */
ContentSignature = 0x47E3,
/** [binary] This is the ID of the private key the data was signed with. */
ContentSigKeyID = 0x47E4,
/** [uinteger] The algorithm used for the signature. */
ContentSigAlgo = 0x47E5,
/** [uinteger] The hash algorithm used for the signature. */
ContentSigHashAlgo = 0x47E6,
/** [master] A Top-Level Element to speed seeking access. All entries are local to the Segment. */
Cues = 0x1C53BB6B,
/** [master] Contains all information relative to a seek point in the Segment. */
CuePoint = 0xBB,
/** [uinteger] Absolute timestamp according to the Segment time base. */
CueTime = 0xB3,
/** [master] Contain positions for different tracks corresponding to the timestamp. */
CueTrackPositions = 0xB7,
/** [uinteger] The track for which a position is given. */
CueTrack = 0xF7,
/** [uinteger] The Segment Position of the Cluster containing the associated Block. */
CueClusterPosition = 0xF1,
/** [uinteger] The relative position inside the Cluster of the referenced SimpleBlock or BlockGroup with 0 being the
first possible position for an Element inside that Cluster. */
CueRelativePosition = 0xF0,
/** [uinteger] The duration of the block according to the Segment time base. If missing the track's DefaultDuration
does not apply and no duration information is available in terms of the cues. */
CueDuration = 0xB2,
/** [uinteger] Number of the Block in the specified Cluster. */
CueBlockNumber = 0x5378,
/** [uinteger] The Segment Position of the Codec State corresponding to this Cue Element. 0 means that the data is
taken from the initial Track Entry. */
CueCodecState = 0xEA,
/** [master] The Clusters containing the referenced Blocks. */
CueReference = 0xDB,
/** [uinteger] Timestamp of the referenced Block. */
CueRefTime = 0x96,
/** [uinteger] The Segment Position of the Cluster containing the referenced Block. */
CueRefCluster = 0x97,
/** [uinteger] Number of the referenced Block of Track X in the specified Cluster. */
CueRefNumber = 0x535F,
/** [uinteger] The Segment Position of the Codec State corresponding to this referenced Element. 0 means that the
data is taken from the initial Track Entry. */
CueRefCodecState = 0xEB,
/** [master] Contain attached files. */
Attachments = 0x1941A469,
/** [master] An attached file. */
AttachedFile = 0x61A7,
/** [utf-8] A human-friendly name for the attached file. */
FileDescription = 0x467E,
/** [utf-8] Filename of the attached file. */
FileName = 0x466E,
/** [string] MIME type of the file. */
FileMimeType = 0x4660,
/** [binary] The data of the file. */
FileData = 0x465C,
/** [uinteger] Unique ID representing the file, as random as possible. */
FileUID = 0x46AE,
/** [binary] A binary value that a track/codec can refer to when the attachment is needed. */
FileReferral = 0x4675,
/** [uinteger] The timecode at which this optimized font attachment comes into context, based on the Segment
TimecodeScale. This element is reserved for future use and if written must be the segment start time. See
[@?DivXWorldFonts]. */
FileUsedStartTime = 0x4661,
/** [uinteger] The timecode at which this optimized font attachment goes out of context, based on the Segment
TimecodeScale. This element is reserved for future use and if written must be the segment end time. See
[@?DivXWorldFonts]. */
FileUsedEndTime = 0x4662,
/** [master] A system to define basic menus and partition data. For more detailed information, look at the Chapters
explanation in (#chapters). */
Chapters = 0x1043A770,
/** [master] Contains all information about a Segment edition. */
EditionEntry = 0x45B9,
/** [uinteger] A unique ID to identify the edition. It's useful for tagging an edition. */
EditionUID = 0x45BC,
/** [uinteger] Set to 1 if an edition is hidden. Hidden editions **SHOULD NOT** be available to the user interface
(but still to Control Tracks; see (#chapter-flags) on Chapter flags). */
EditionFlagHidden = 0x45BD,
/** [uinteger] Set to 1 if the edition **SHOULD** be used as the default one. */
EditionFlagDefault = 0x45DB,
/** [uinteger] Set to 1 if the chapters can be defined multiple times and the order to play them is enforced; see
(#editionflagordered). */
EditionFlagOrdered = 0x45DD,
/** [master] Contains the atom information to use as the chapter atom (apply to all tracks). */
ChapterAtom = 0xB6,
/** [uinteger] A unique ID to identify the Chapter. */
ChapterUID = 0x73C4,
/** [utf-8] A unique string ID to identify the Chapter. Use for WebVTT cue identifier storage [@!WebVTT]. */
ChapterStringUID = 0x5654,
/** [uinteger] Timestamp of the start of Chapter (not scaled). */
ChapterTimeStart = 0x91,
/** [uinteger] Timestamp of the end of Chapter (timestamp excluded, not scaled). The value **MUST** be greater than
or equal to the `ChapterTimeStart` of the same `ChapterAtom`. */
ChapterTimeEnd = 0x92,
/** [uinteger] Set to 1 if a chapter is hidden. Hidden chapters **SHOULD NOT** be available to the user interface
(but still to Control Tracks; see (#chapterflaghidden) on Chapter flags). */
ChapterFlagHidden = 0x98,
/** [uinteger] Set to 1 if the chapter is enabled. It can be enabled/disabled by a Control Track. When disabled, the
movie **SHOULD** skip all the content between the TimeStart and TimeEnd of this chapter; see (#chapter-flags) on
Chapter flags. */
ChapterFlagEnabled = 0x4598,
/** [binary] The SegmentUID of another Segment to play during this chapter. */
ChapterSegmentUID = 0x6E67,
/** [uinteger] The EditionUID to play from the Segment linked in ChapterSegmentUID. If ChapterSegmentEditionUID is
undeclared, then no Edition of the linked Segment is used; see (#medium-linking) on medium-linking Segments. */
ChapterSegmentEditionUID = 0x6EBC,
/** [uinteger] Specify the physical equivalent of this ChapterAtom like "DVD" (60) or "SIDE" (50); see
(#physical-types) for a complete list of values. */
ChapterPhysicalEquiv = 0x63C3,
/** [master] List of tracks on which the chapter applies. If this Element is not present, all tracks apply */
ChapterTrack = 0x8F,
/** [uinteger] UID of the Track to apply this chapter to. In the absence of a control track, choosing this chapter
will select the listed Tracks and deselect unlisted tracks. Absence of this Element indicates that the Chapter
**SHOULD** be applied to any currently used Tracks. */
ChapterTrackUID = 0x89,
/** [master] Contains all possible strings to use for the chapter display. */
ChapterDisplay = 0x80,
/** [utf-8] Contains the string to use as the chapter atom. */
ChapString = 0x85,
/** [string] A language corresponding to the string, in the bibliographic ISO-639-2 form [@!ISO639-2]. This Element
**MUST** be ignored if a ChapLanguageIETF Element is used within the same ChapterDisplay Element. */
ChapLanguage = 0x437C,
/** [string] Specifies a language corresponding to the ChapString in the format defined in [@!BCP47] and using the
IANA Language Subtag Registry [@!IANALangRegistry]. If a ChapLanguageIETF Element is used, then any ChapLanguage
and ChapCountry Elements used in the same ChapterDisplay **MUST** be ignored. */
ChapLanguageIETF = 0x437D,
/** [string] A country corresponding to the string, using the same 2 octets country-codes as in Internet domains
[@!IANADomains] based on [@!ISO3166-1] alpha-2 codes. This Element **MUST** be ignored if a ChapLanguageIETF
Element is used within the same ChapterDisplay Element. */
ChapCountry = 0x437E,
/** [master] Contains all the commands associated to the Atom. */
ChapProcess = 0x6944,
/** [uinteger] Contains the type of the codec used for the processing. A value of 0 means native Matroska processing
(to be defined), a value of 1 means the DVD command set is used; see (#menu-features) on DVD menus. More codec
IDs can be added later. */
ChapProcessCodecID = 0x6955,
/** [binary] Some optional data attached to the ChapProcessCodecID information. For ChapProcessCodecID = 1, it
is the "DVD level" equivalent; see (#menu-features) on DVD menus. */
ChapProcessPrivate = 0x450D,
/** [master] Contains all the commands associated to the Atom. */
ChapProcessCommand = 0x6911,
/** [uinteger] Defines when the process command **SHOULD** be handled */
ChapProcessTime = 0x6922,
/** [binary] Contains the command information. The data **SHOULD** be interpreted depending on the
ChapProcessCodecID value. For ChapProcessCodecID = 1, the data correspond to the binary DVD cell pre/post
commands; see (#menu-features) on DVD menus. */
ChapProcessData = 0x6933,
/** [master] Element containing metadata describing Tracks, Editions, Chapters, Attachments, or the Segment as a
whole. A list of valid tags can be found in [@!MatroskaTags]. */
Tags = 0x1254C367,
/** [master] A single metadata descriptor. */
Tag = 0x7373,
/** [master] Specifies which other elements the metadata represented by the Tag applies to. If empty or not present,
then the Tag describes everything in the Segment. */
Targets = 0x63C0,
/** [uinteger] A number to indicate the logical level of the target. */
TargetTypeValue = 0x68CA,
/** [string] An informational string that can be used to display the logical level of the target like "ALBUM",
"TRACK", "MOVIE", "CHAPTER", etc ; see Section 6.4 of [@!MatroskaTags]. */
TargetType = 0x63CA,
/** [uinteger] A unique ID to identify the Track(s) the tags belong to. */
TagTrackUID = 0x63C5,
/** [uinteger] A unique ID to identify the EditionEntry(s) the tags belong to. */
TagEditionUID = 0x63C9,
/** [uinteger] A unique ID to identify the Chapter(s) the tags belong to. */
TagChapterUID = 0x63C4,
/** [uinteger] A unique ID to identify the Attachment(s) the tags belong to. */
TagAttachmentUID = 0x63C6,
/** [master] Contains general information about the target. */
SimpleTag = 0x67C8,
/** [utf-8] The name of the Tag that is going to be stored. */
TagName = 0x45A3,
/** [string] Specifies the language of the tag specified, in the Matroska languages form; see (#language-codes) on
language codes. This Element **MUST** be ignored if the TagLanguageIETF Element is used within the same SimpleTag
Element. */
TagLanguage = 0x447A,
/** [string] Specifies the language used in the TagString according to [@!BCP47] and using the IANA Language Subtag
Registry [@!IANALangRegistry]. If this Element is used, then any TagLanguage Elements used in the same SimpleTag
**MUST** be ignored. */
TagLanguageIETF = 0x447B,
/** [uinteger] A boolean value to indicate if this is the default/original language to use for the given tag. */
TagDefault = 0x4484,
/** [uinteger] A variant of the TagDefault element with a bogus Element ID; see (#tagdefault-element). */
TagDefaultBogus = 0x44B4,
/** [utf-8] The value of the Tag. */
TagString = 0x4487,
/** [binary] The values of the Tag, if it is binary. Note that this cannot be used in the same SimpleTag as
TagString. */
TagBinary = 0x4485,
};

View File

@@ -0,0 +1,27 @@
#ifndef ES8311AUDIOSINK_H
#define ES8311AUDIOSINK_H
#include "driver/i2s.h"
#include <vector>
#include <iostream>
#include "BufferedAudioSink.h"
#include <stdio.h>
#include <string.h>
#include "driver/gpio.h"
#include "driver/i2c.h"
#include <sys/unistd.h>
#include <sys/stat.h>
#include "esp_err.h"
#include "esp_log.h"
class ES8311AudioSink : public BufferedAudioSink
{
public:
ES8311AudioSink();
~ES8311AudioSink();
void writeReg(uint8_t reg_add, uint8_t data);
void volumeChanged(uint16_t volume);
private:
};
#endif

View File

@@ -0,0 +1,121 @@
/*
* ES8311.h -- ES8311 ALSA SoC Audio Codec
*
* Authors:
*
* Based on ES8374.h by David Yang
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef _ES8311_H
#define _ES8311_H
#include "driver/i2c.h"
#include "esxxx_common.h"
/*
* ES8311_REGISTER NAME_REG_REGISTER ADDRESS
*/
#define ES8311_RESET_REG00 0x00 /*reset digital,csm,clock manager etc.*/
/*
* Clock Scheme Register definition
*/
#define ES8311_CLK_MANAGER_REG01 0x01 /* select clk src for mclk, enable clock for codec */
#define ES8311_CLK_MANAGER_REG02 0x02 /* clk divider and clk multiplier */
#define ES8311_CLK_MANAGER_REG03 0x03 /* adc fsmode and osr */
#define ES8311_CLK_MANAGER_REG04 0x04 /* dac osr */
#define ES8311_CLK_MANAGER_REG05 0x05 /* clk divier for adc and dac */
#define ES8311_CLK_MANAGER_REG06 0x06 /* bclk inverter and divider */
#define ES8311_CLK_MANAGER_REG07 0x07 /* tri-state, lrck divider */
#define ES8311_CLK_MANAGER_REG08 0x08 /* lrck divider */
#define ES8311_SDPIN_REG09 0x09 /* dac serial digital port */
#define ES8311_SDPOUT_REG0A 0x0A /* adc serial digital port */
#define ES8311_SYSTEM_REG0B 0x0B /* system */
#define ES8311_SYSTEM_REG0C 0x0C /* system */
#define ES8311_SYSTEM_REG0D 0x0D /* system, power up/down */
#define ES8311_SYSTEM_REG0E 0x0E /* system, power up/down */
#define ES8311_SYSTEM_REG0F 0x0F /* system, low power */
#define ES8311_SYSTEM_REG10 0x10 /* system */
#define ES8311_SYSTEM_REG11 0x11 /* system */
#define ES8311_SYSTEM_REG12 0x12 /* system, Enable DAC */
#define ES8311_SYSTEM_REG13 0x13 /* system */
#define ES8311_SYSTEM_REG14 0x14 /* system, select DMIC, select analog pga gain */
#define ES8311_ADC_REG15 0x15 /* ADC, adc ramp rate, dmic sense */
#define ES8311_ADC_REG16 0x16 /* ADC */
#define ES8311_ADC_REG17 0x17 /* ADC, volume */
#define ES8311_ADC_REG18 0x18 /* ADC, alc enable and winsize */
#define ES8311_ADC_REG19 0x19 /* ADC, alc maxlevel */
#define ES8311_ADC_REG1A 0x1A /* ADC, alc automute */
#define ES8311_ADC_REG1B 0x1B /* ADC, alc automute, adc hpf s1 */
#define ES8311_ADC_REG1C 0x1C /* ADC, equalizer, hpf s2 */
#define ES8311_DAC_REG31 0x31 /* DAC, mute */
#define ES8311_DAC_REG32 0x32 /* DAC, volume */
#define ES8311_DAC_REG33 0x33 /* DAC, offset */
#define ES8311_DAC_REG34 0x34 /* DAC, drc enable, drc winsize */
#define ES8311_DAC_REG35 0x35 /* DAC, drc maxlevel, minilevel */
#define ES8311_DAC_REG37 0x37 /* DAC, ramprate */
#define ES8311_GPIO_REG44 0x44 /* GPIO, dac2adc for test */
#define ES8311_GP_REG45 0x45 /* GP CONTROL */
#define ES8311_CHD1_REGFD 0xFD /* CHIP ID1 */
#define ES8311_CHD2_REGFE 0xFE /* CHIP ID2 */
#define ES8311_CHVER_REGFF 0xFF /* VERSION */
#define ES8311_CHD1_REGFD 0xFD /* CHIP ID1 */
#define ES8311_MAX_REGISTER 0xFF
typedef struct {
ESCodecMode esMode;
i2c_port_t i2c_port_num;
i2c_config_t i2c_cfg;
DacOutput dacOutput;
AdcInput adcInput;
} Es8311Config;
#define AUDIO_CODEC_ES8311_DEFAULT(){ \
.esMode = ES_MODE_SLAVE, \
.i2c_port_num = I2C_NUM_0, \
.i2c_cfg = { \
.mode = I2C_MODE_MASTER, \
.sda_io_num = IIC_DATA, \
.scl_io_num = IIC_CLK, \
.sda_pullup_en = GPIO_PULLUP_ENABLE,\
.scl_pullup_en = GPIO_PULLUP_ENABLE,\
.master.clk_speed = 100000\
}, \
.adcInput = ADC_INPUT_LINPUT1_RINPUT1,\
.dacOutput = DAC_OUTPUT_LOUT1 | DAC_OUTPUT_LOUT2 | DAC_OUTPUT_ROUT1 | DAC_OUTPUT_ROUT2,\
};
int Es8311Init(Es8311Config *cfg);
void Es8311Uninit();
esp_err_t Es8311GetRef(bool flag);
esp_err_t Es7243Init(void);
int Es7243ReadReg(uint8_t regAdd);
int Es8311ConfigFmt(ESCodecModule mode, ESCodecI2SFmt fmt);
int Es8311I2sConfigClock(ESCodecI2sClock cfg);
int Es8311SetBitsPerSample(ESCodecModule mode, BitsLength bitPerSample);
int Es8311Start(ESCodecModule mode);
int Es8311Stop(ESCodecModule mode);
int Es8311SetVoiceVolume(int volume);
int Es8311GetVoiceVolume(int *volume);
int Es8311SetVoiceMute(int enable);
int Es8311GetVoiceMute(int *mute);
int Es8311SetMicGain(MicGain gain);
int Es8311ConfigAdcInput(AdcInput input);
int Es8311ConfigDacOutput(DacOutput output);
int ES8311WriteReg(uint8_t regAdd, uint8_t data);
void Es8311ReadAll();
int Es8311ReadReg(uint8_t regAdd);
#endif

View File

@@ -0,0 +1,166 @@
#ifndef __ESCODEC_COMMON_H__
#define __ESCODEC_COMMON_H__
typedef enum BitsLength {
BIT_LENGTH_MIN = -1,
BIT_LENGTH_16BITS = 0x03,
BIT_LENGTH_18BITS = 0x02,
BIT_LENGTH_20BITS = 0x01,
BIT_LENGTH_24BITS = 0x00,
BIT_LENGTH_32BITS = 0x04,
BIT_LENGTH_MAX,
} BitsLength;
typedef enum {
SAMPLE_RATE_MIN = -1,
SAMPLE_RATE_16K,
SAMPLE_RATE_32K,
SAMPLE_RATE_44_1K,
SAMPLE_RATE_MAX,
} SampleRate;
typedef enum {
MclkDiv_MIN = -1,
MclkDiv_1 = 1,
MclkDiv_2 = 2,
MclkDiv_3 = 3,
MclkDiv_4 = 4,
MclkDiv_6 = 5,
MclkDiv_8 = 6,
MclkDiv_9 = 7,
MclkDiv_11 = 8,
MclkDiv_12 = 9,
MclkDiv_16 = 10,
MclkDiv_18 = 11,
MclkDiv_22 = 12,
MclkDiv_24 = 13,
MclkDiv_33 = 14,
MclkDiv_36 = 15,
MclkDiv_44 = 16,
MclkDiv_48 = 17,
MclkDiv_66 = 18,
MclkDiv_72 = 19,
MclkDiv_5 = 20,
MclkDiv_10 = 21,
MclkDiv_15 = 22,
MclkDiv_17 = 23,
MclkDiv_20 = 24,
MclkDiv_25 = 25,
MclkDiv_30 = 26,
MclkDiv_32 = 27,
MclkDiv_34 = 28,
MclkDiv_7 = 29,
MclkDiv_13 = 30,
MclkDiv_14 = 31,
MclkDiv_MAX,
} SclkDiv;
typedef enum {
LclkDiv_MIN = -1,
LclkDiv_128 = 0,
LclkDiv_192 = 1,
LclkDiv_256 = 2,
LclkDiv_384 = 3,
LclkDiv_512 = 4,
LclkDiv_576 = 5,
LclkDiv_768 = 6,
LclkDiv_1024 = 7,
LclkDiv_1152 = 8,
LclkDiv_1408 = 9,
LclkDiv_1536 = 10,
LclkDiv_2112 = 11,
LclkDiv_2304 = 12,
LclkDiv_125 = 16,
LclkDiv_136 = 17,
LclkDiv_250 = 18,
LclkDiv_272 = 19,
LclkDiv_375 = 20,
LclkDiv_500 = 21,
LclkDiv_544 = 22,
LclkDiv_750 = 23,
LclkDiv_1000 = 24,
LclkDiv_1088 = 25,
LclkDiv_1496 = 26,
LclkDiv_1500 = 27,
LclkDiv_MAX,
} LclkDiv;
typedef enum {
ADC_INPUT_MIN = -1,
ADC_INPUT_LINPUT1_RINPUT1 = 0x00,
ADC_INPUT_MIC1 = 0x05,
ADC_INPUT_MIC2 = 0x06,
ADC_INPUT_LINPUT2_RINPUT2 = 0x50,
ADC_INPUT_DIFFERENCE = 0xf0,
ADC_INPUT_MAX,
} AdcInput;
typedef enum {
DAC_OUTPUT_MIN = -1,
DAC_OUTPUT_LOUT1 = 0x04,
DAC_OUTPUT_LOUT2 = 0x08,
DAC_OUTPUT_SPK = 0x09,
DAC_OUTPUT_ROUT1 = 0x10,
DAC_OUTPUT_ROUT2 = 0x20,
DAC_OUTPUT_ALL = 0x3c,
DAC_OUTPUT_MAX,
} DacOutput;
typedef enum {
D2SE_PGA_GAIN_MIN = -1,
D2SE_PGA_GAIN_DIS = 0,
D2SE_PGA_GAIN_EN = 1,
D2SE_PGA_GAIN_MAX = 2,
} D2SEPGA;
typedef enum {
MIC_GAIN_MIN = -1,
MIC_GAIN_0DB = 0,
MIC_GAIN_3DB = 3,
MIC_GAIN_6DB = 6,
MIC_GAIN_9DB = 9,
MIC_GAIN_12DB = 12,
MIC_GAIN_15DB = 15,
MIC_GAIN_18DB = 18,
MIC_GAIN_21DB = 21,
MIC_GAIN_24DB = 24,
#if defined CONFIG_CODEC_CHIP_IS_ES8311
MIC_GAIN_30DB = 30,
MIC_GAIN_36DB = 36,
MIC_GAIN_42DB = 42,
#endif
MIC_GAIN_MAX,
} MicGain;
typedef enum {
ES_MODULE_MIN = -1,
ES_MODULE_ADC = 0x01,
ES_MODULE_DAC = 0x02,
ES_MODULE_ADC_DAC = 0x03,
ES_MODULE_LINE = 0x04,
ES_MODULE_MAX
} ESCodecModule;
typedef enum {
ES_MODE_MIN = -1,
ES_MODE_SLAVE = 0x00,
ES_MODE_MASTER = 0x01,
ES_MODE_MAX,
} ESCodecMode;
typedef enum {
ES_ = -1,
ES_I2S_NORMAL = 0,
ES_I2S_LEFT = 1,
ES_I2S_RIGHT = 2,
ES_I2S_DSP = 3,
ES_I2S_MAX
} ESCodecI2SFmt;
typedef struct {
SclkDiv sclkDiv;
LclkDiv lclkDiv;
} ESCodecI2sClock;
#endif //__ESCODEC_COMMON_H__

View File

@@ -5,7 +5,7 @@
#include "AudioSink.h"
#include <alsa/asoundlib.h>
#include <stdio.h>
#include <Task.h>
#include <BellTask.h>
#include <unistd.h>
#include <memory>
#include <mutex>

View File

@@ -0,0 +1,18 @@
#ifndef BELLL_MDNS_SERVICE_H
#define BELLL_MDNS_SERVICE_H
#include <string>
#include <map>
class MDNSService {
public:
static void registerService(
const std::string &serviceName,
const std::string &serviceType,
const std::string &serviceProto,
const std::string &serviceHost,
int servicePort,
const std::map<std::string, std::string> txtData
);
};
#endif

View File

@@ -6,6 +6,8 @@
#include "freertos/semphr.h"
#elif __APPLE__
#include <dispatch/dispatch.h>
#elif _WIN32
#include <winsock2.h>
#else
#include <time.h>
#include <semaphore.h>
@@ -18,6 +20,8 @@ private:
xSemaphoreHandle semaphoreHandle;
#elif __APPLE__
dispatch_semaphore_t semaphoreHandle;
#elif _WIN32
HANDLE semaphoreHandle;
#else
sem_t semaphoreHandle;
#endif

View File

@@ -0,0 +1,15 @@
#pragma once
#include <winsock2.h>
#define SHUT_RDWR SD_BOTH
#define ssize_t SSIZE_T
#define strcasecmp stricmp
#define strncasecmp _strnicmp
#define bzero(p,n) memset(p,0,n)
#define usleep(x) Sleep((x)/1000)
inline void close(int sock) { closesocket(sock); }
inline size_t read(int sock, char* buf, size_t n) { return recv(sock, buf, n, 0); }
inline int write(int sock, const char* buf, size_t n) { return send(sock, buf, n, 0); }

View File

@@ -0,0 +1,39 @@
name: CIFuzz
on:
push:
branches:
- master
paths:
- '**.c'
- '**.h'
pull_request:
branches:
- master
paths:
- '**.c'
- '**.h'
jobs:
Fuzzing:
runs-on: ubuntu-latest
steps:
- name: Build Fuzzers
id: build
uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master
with:
oss-fuzz-project-name: 'nanopb'
dry-run: false
sanitizer: undefined
- name: Run Fuzzers
uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master
with:
oss-fuzz-project-name: 'nanopb'
fuzz-seconds: 600
dry-run: false
sanitizer: undefined
- name: Upload Crash
uses: actions/upload-artifact@v1
if: failure() && steps.build.outcome == 'success'
with:
name: artifacts
path: ./out/artifacts

View File

@@ -0,0 +1,63 @@
name: platformio
on:
push:
pull_request:
jobs:
platformio:
name: Build and run PlatformIO example
runs-on: ubuntu-latest
steps:
- name: ⤵️ Check out code from GitHub
uses: actions/checkout@v2
with:
path: nanopb
- name: Installing dependencies for local act
if: ${{ env.ACT }}
run: |
sudo apt update
- name: Installing common dependencies
run: |
sudo apt install -y python3-pip
- name: Install and setup PlatformIO
run: |
pip3 install -U platformio
export PATH=~/.local/bin:$PATH
- name: Build PlatformIO package
run: |
cd nanopb
pio package pack
- name: Example - Extract PlatformIO package to example dir
run: |
cp -R nanopb/examples/platformio example
mkdir -p example/lib/nanopb
tar -xzf nanopb/Nanopb-*.tar.gz -C example/lib/nanopb
- name: Example - Build
run: |
cd example
pio run
- name: Example - Run test without options
run: example/.pio/build/pio_without_options/program
- name: Example - Run test with options
run: example/.pio/build/pio_with_options/program
- name: Build with default platformio.ini
run: |
mkdir -p test_default_pio_conf
cd test_default_pio_conf
pio project init
ln -s ../nanopb lib/nanopb
echo "[env:native]" >> platformio.ini
echo "platform = native" >> platformio.ini
echo "lib_deps = Nanopb" >> platformio.ini
echo "int main(int argc, char *argv[]){}" > src/main.cpp
pio run

View File

@@ -0,0 +1,15 @@
name: spm
on:
push:
pull_request:
jobs:
swift-build-run:
runs-on: macOS-latest
steps:
- uses: actions/checkout@v2
- name: Build
run: swift build
- name: Run
run: swift test

View File

@@ -98,3 +98,19 @@ leabut <leabut@users.noreply.github.com>
Angel ILIEV <a.v.iliev13@gmail.com>
Jakub Tymejczyk <jakub@tymejczyk.pl>
Matthew Simmons <simmonmt@acm.org>
Anthony Pesch <inolen@gmail.com>
Avik De <avikde@gmail.com>
ConradWood <github@conradwood.net>
David Sabatie <david.sabatie@notrenet.com>
Sebastian Stockhammer <sebastian.stockhammer@rosenberger.de>
Gil Shapira <gil.shapira@intusurg.com>
Ian Frosst <ianjfrosst@gmail.com>
Ingo Kresse <ingo.kresse@kuka.com>
Ivan Zrno <ivan.zrno2@gmail.com>
Jonathan Seilkopf <j.seilkopf@isatech.de>
Karl Ljungkvist <k.ljungkvist@gmail.com>
Mathis Logemann <mathisloge@gmail.com>
Oleg Dolgy <60554929+odolgy@users.noreply.github.com>
Pavel Sokolov <pavel@sokolov.me>
Slavey Karadzhov <slav@attachix.com>
Tobias Nießen <tniessen@tnie.de>

View File

@@ -1,3 +1,43 @@
nanopb-0.4.6 (2022-05-30)
Fix passing of error message from substream callback (#703)
Fix comments going to wrong member variables (#701)
Fix regression in 0.4.3 where generator did not find all dependencies (#720)
Fix FindNanopb.cmake not finding options file (#659)
Fix double-definition errors with size_union (#692)
Fix generator error with same inner message name (#746)
Fix infinite recursion in generator/protoc script (#762)
Fix unicode comment handling for Python 2 (#740)
Fix compiler warnings with PB_BUFFER_ONLY (#717)
Fix options dependency in nanopb.mk (#666)
Fix handling of filenames with dot in them in FindNanopb.cmake (#756)
Add fallback_type option (#772, #773)
Use C11 static assert mechanism by default (#761, #766)
Use 'static_assert' keyword for iar (#679)
Explicitly check for pItem == NULL to satisfy Xcode analyzer (#667, #674)
Support --proto-path as alias to -I (#749)
Refactor name mangling to separate class, improve error messages (#735)
Move PB_WT_PACKED definition to the header to fix compiler warnings (#671)
FindNanopb.cmake: use --nanopb_opt for option passing by default (#752)
FindNanopb.cmake: Add option NANOPB_GENERATE_CPP_STANDALONE (#741)
FindNanopb.cmake: Add PROTOC_OPTIONS variable (#768, #771)
CMakeLists: add build interface for using as a submodule (#669)
CMakeLists: fix error with nanopb_BUILD_GENERATOR=OFF (#764)
CMakeLists: make more uniform (#676)
CMakeLists: Fix uninitialized PYTHON_INSTDIR (#652)
Clean up CMake examples (#741)
Rebuild nanopb_pb2.py and print version numbers on import failure (#733, #742)
Use memcpy instead of iterating on buf_read/write (#751)
Add generator support for PlatformIO (#718)
Add clean target to generator/proto/Makefile (#681)
Windows .bats: use standard python invocation instead of py.exe launcher (#657)
Fix problems running tests with newer SCons version
Improve handling of varint overflows
Improve optimization for little-endian platforms
NOTE: During development, prereleases were published on PlatformIO registry
as versions 0.4.6 - 0.4.6.3. The version 0.4.6.4 on PlatformIO corresponds
to the real final 0.4.6 release.
nanopb-0.4.5 (2021-03-22)
Fix invalid free() with oneof (#647, GHSA-7mv5-5mxh-qg88)
Fix unordered field numbers inside oneof causing fields to be ignored (#617)
@@ -149,6 +189,13 @@ nanopb-0.4.0 (2019-12-20)
CMake: Split nanopb_out command (#454)
CMake: install created shared library(dll) in windows to the binary folder (#447)
nanopb-0.3.9.9 (2022-04-23)
Fix Xcode analyzer warnings (#667, #674)
Fix clang sanitizer warnings
Note: there are no known functional differences between 0.3.9.8 and 0.3.9.9.
The changes are merely to fix warnings introduced by new compiler versions.
nanopb-0.3.9.8 (2021-03-22)
Fix invalid free() with oneof (#647, GHSA-7mv5-5mxh-qg88)
Don't generate lines with trailing spaces (#622)

View File

@@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 2.8.12)
project(nanopb C)
set(nanopb_VERSION_STRING nanopb-0.4.6-dev)
set(nanopb_VERSION_STRING nanopb-0.4.7-dev)
set(nanopb_SOVERSION 0)
string(REPLACE "nanopb-" "" nanopb_VERSION ${nanopb_VERSION_STRING})
@@ -65,10 +65,10 @@ if(nanopb_BUILD_GENERATOR)
DESTINATION ${PYTHON_INSTDIR}/proto/
)
endforeach()
endif()
install(FILES generator/proto/_utils.py
DESTINATION ${PYTHON_INSTDIR}/proto/)
install( FILES generator/proto/_utils.py
DESTINATION ${PYTHON_INSTDIR}/proto/ )
endif()
if(WIN32)
install(
@@ -123,7 +123,7 @@ if(nanopb_BUILD_RUNTIME)
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
target_include_directories(protobuf-nanopb-static INTERFACE
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
)
endif()

View File

@@ -9,9 +9,6 @@ nanopb_generate_cpp(PROTO_SRCS PROTO_HDRS RELPATH proto
proto/simple.proto proto/sub/unlucky.proto)
include_directories(${CMAKE_CURRENT_BINARY_DIR})
#add_custom_target(generate_proto_sources DEPENDS ${PROTO_SRCS} ${PROTO_HDRS})
set_source_files_properties(${PROTO_SRCS} ${PROTO_HDRS}
PROPERTIES GENERATED TRUE)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Werror -g -O0")

View File

@@ -7,9 +7,6 @@ include_directories(${NANOPB_INCLUDE_DIRS})
nanopb_generate_cpp(PROTO_SRCS PROTO_HDRS simple.proto)
include_directories(${CMAKE_CURRENT_BINARY_DIR})
#add_custom_target(generate_proto_sources DEPENDS ${PROTO_SRCS} ${PROTO_HDRS})
set_source_files_properties(${PROTO_SRCS} ${PROTO_HDRS}
PROPERTIES GENERATED TRUE)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Werror -g -O0")

0
components/spotify/cspot/bell/nanopb/generator/protoc Normal file → Executable file
View File

View File

@@ -10,5 +10,4 @@
# --plugin= on the command line.
MYPATH=$(dirname "$0")
echo "Executing $MYPATH/nanopb_generator.py "
exec "$MYPATH/nanopb_generator.py" --protoc-plugin

View File

@@ -52,6 +52,11 @@
* Normally it is automatically detected based on __BYTE_ORDER__ macro. */
/* #define PB_LITTLE_ENDIAN_8BIT 1 */
/* Configure static assert mechanism. Instead of changing these, set your
* compiler to C11 standard mode if possible. */
/* #define PB_C99_STATIC_ASSERT 1 */
/* #define PB_NO_STATIC_ASSERT 1 */
/******************************************************************
* You usually don't need to change anything below this line. *
* Feel free to look around and use the defined macros, though. *
@@ -60,7 +65,7 @@
/* Version of the nanopb library. Just in case you want to check it in
* your own program. */
#define NANOPB_VERSION "nanopb-0.4.6-dev"
#define NANOPB_VERSION "nanopb-0.4.7-dev"
/* Include all the system headers needed by nanopb. You will need the
* definitions of the following:
@@ -165,14 +170,17 @@ extern "C" {
# if defined(__ICCARM__)
/* IAR has static_assert keyword but no _Static_assert */
# define PB_STATIC_ASSERT(COND,MSG) static_assert(COND,#MSG);
# elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
/* C11 standard _Static_assert mechanism */
# define PB_STATIC_ASSERT(COND,MSG) _Static_assert(COND,#MSG);
# else
# elif defined(PB_C99_STATIC_ASSERT)
/* Classic negative-size-array static assert mechanism */
# define PB_STATIC_ASSERT(COND,MSG) typedef char PB_STATIC_ASSERT_MSG(MSG, __LINE__, __COUNTER__)[(COND)?1:-1];
# define PB_STATIC_ASSERT_MSG(MSG, LINE, COUNTER) PB_STATIC_ASSERT_MSG_(MSG, LINE, COUNTER)
# define PB_STATIC_ASSERT_MSG_(MSG, LINE, COUNTER) pb_static_assertion_##MSG##_##LINE##_##COUNTER
# elif defined(__cplusplus)
/* C++11 standard static_assert mechanism */
# define PB_STATIC_ASSERT(COND,MSG) static_assert(COND,#MSG);
# else
/* C11 standard _Static_assert mechanism */
# define PB_STATIC_ASSERT(COND,MSG) _Static_assert(COND,#MSG);
# endif
# endif
#else
@@ -180,6 +188,14 @@ extern "C" {
# define PB_STATIC_ASSERT(COND,MSG)
#endif
/* Test that PB_STATIC_ASSERT works
* If you get errors here, you may need to do one of these:
* - Enable C11 standard support in your compiler
* - Define PB_C99_STATIC_ASSERT to enable C99 standard support
* - Define PB_NO_STATIC_ASSERT to disable static asserts altogether
*/
PB_STATIC_ASSERT(1, STATIC_ASSERT_IS_NOT_WORKING)
/* Number of required fields to keep track of. */
#ifndef PB_MAX_REQUIRED_FIELDS
#define PB_MAX_REQUIRED_FIELDS 64
@@ -886,10 +902,13 @@ struct pb_extension_s {
#define PB_INLINE_CONSTEXPR PB_CONSTEXPR
#endif // __cplusplus >= 201703L
extern "C++"
{
namespace nanopb {
// Each type will be partially specialized by the generator.
template <typename GenMessageT> struct MessageDescriptor;
} // namespace nanopb
}
#endif /* __cplusplus */
#endif

View File

@@ -67,14 +67,12 @@ typedef struct {
static bool checkreturn buf_read(pb_istream_t *stream, pb_byte_t *buf, size_t count)
{
size_t i;
const pb_byte_t *source = (const pb_byte_t*)stream->state;
stream->state = (pb_byte_t*)stream->state + count;
if (buf != NULL)
{
for (i = 0; i < count; i++)
buf[i] = source[i];
memcpy(buf, source, count * sizeof(pb_byte_t));
}
return true;
@@ -211,18 +209,20 @@ static bool checkreturn pb_decode_varint32_eof(pb_istream_t *stream, uint32_t *d
PB_RETURN_ERROR(stream, "varint overflow");
}
}
else if (bitpos == 28)
{
if ((byte & 0x70) != 0 && (byte & 0x78) != 0x78)
{
PB_RETURN_ERROR(stream, "varint overflow");
}
result |= (uint32_t)(byte & 0x0F) << bitpos;
}
else
{
result |= (uint32_t)(byte & 0x7F) << bitpos;
}
bitpos = (uint_fast8_t)(bitpos + 7);
} while (byte & 0x80);
if (bitpos == 35 && (byte & 0x70) != 0)
{
/* The last byte was at bitpos=28, so only bottom 4 bits fit. */
PB_RETURN_ERROR(stream, "varint overflow");
}
}
*dest = result;
@@ -243,12 +243,12 @@ bool checkreturn pb_decode_varint(pb_istream_t *stream, uint64_t *dest)
do
{
if (bitpos >= 64)
PB_RETURN_ERROR(stream, "varint overflow");
if (!pb_readbyte(stream, &byte))
return false;
if (bitpos >= 63 && (byte & 0xFE) != 0)
PB_RETURN_ERROR(stream, "varint overflow");
result |= (uint64_t)(byte & 0x7F) << bitpos;
bitpos = (uint_fast8_t)(bitpos + 7);
} while (byte & 0x80);
@@ -761,7 +761,10 @@ static bool checkreturn decode_callback_field(pb_istream_t *stream, pb_wire_type
{
prev_bytes_left = substream.bytes_left;
if (!field->descriptor->field_callback(&substream, NULL, field))
PB_RETURN_ERROR(stream, "callback failed");
{
PB_SET_ERROR(stream, substream.errmsg ? substream.errmsg : "callback failed");
return false;
}
} while (substream.bytes_left > 0 && substream.bytes_left < prev_bytes_left);
if (!pb_close_string_substream(stream, &substream))

View File

@@ -51,12 +51,10 @@ static bool checkreturn pb_enc_fixed_length_bytes(pb_ostream_t *stream, const pb
static bool checkreturn buf_write(pb_ostream_t *stream, const pb_byte_t *buf, size_t count)
{
size_t i;
pb_byte_t *dest = (pb_byte_t*)stream->state;
stream->state = dest + count;
for (i = 0; i < count; i++)
dest[i] = buf[i];
memcpy(dest, buf, count * sizeof(pb_byte_t));
return true;
}
@@ -626,8 +624,9 @@ bool checkreturn pb_encode_varint(pb_ostream_t *stream, pb_uint64_t value)
bool checkreturn pb_encode_svarint(pb_ostream_t *stream, pb_int64_t value)
{
pb_uint64_t zigzagged;
pb_uint64_t mask = ((pb_uint64_t)-1) >> 1; /* Satisfy clang -fsanitize=integer */
if (value < 0)
zigzagged = ~((pb_uint64_t)value << 1);
zigzagged = ~(((pb_uint64_t)value & mask) << 1);
else
zigzagged = (pb_uint64_t)value << 1;

View File

@@ -146,7 +146,7 @@ int main(int argc, char *argv[])
filename = argv[2];
}
elf_firmware_t firmware;
elf_firmware_t firmware = {};
elf_read_firmware(filename, &firmware);
avr_init(g_avr);
avr_load_firmware(g_avr, &firmware);

Binary file not shown.

View File

@@ -1,88 +0,0 @@
#include "BaseHTTPServer.h"
#include <sstream>
unsigned char bell::BaseHTTPServer::h2int(char c)
{
if (c >= '0' && c <= '9')
{
return ((unsigned char)c - '0');
}
if (c >= 'a' && c <= 'f')
{
return ((unsigned char)c - 'a' + 10);
}
if (c >= 'A' && c <= 'F')
{
return ((unsigned char)c - 'A' + 10);
}
return (0);
}
std::string bell::BaseHTTPServer::urlDecode(std::string str)
{
std::string encodedString = "";
char c;
char code0;
char code1;
for (int i = 0; i < str.length(); i++)
{
c = str[i];
if (c == '+')
{
encodedString += ' ';
}
else if (c == '%')
{
i++;
code0 = str[i];
i++;
code1 = str[i];
c = (h2int(code0) << 4) | h2int(code1);
encodedString += c;
}
else
{
encodedString += c;
}
}
return encodedString;
}
std::vector<std::string> bell::BaseHTTPServer::splitUrl(const std::string &url, char delimiter)
{
std::stringstream ssb(url);
std::string segment;
std::vector<std::string> seglist;
while (std::getline(ssb, segment, delimiter))
{
seglist.push_back(segment);
}
return seglist;
}
std::map<std::string, std::string> bell::BaseHTTPServer::parseQueryString(const std::string &queryString)
{
std::map<std::string, std::string> query;
auto prefixedString = "&" + queryString;
while (prefixedString.find("&") != std::string::npos)
{
auto keyStart = prefixedString.find("&");
auto keyEnd = prefixedString.find("=");
// Find second occurence of "&" in prefixedString
auto valueEnd = prefixedString.find("&", keyStart + 1);
if (valueEnd == std::string::npos)
{
valueEnd = prefixedString.size();
}
auto key = prefixedString.substr(keyStart + 1, keyEnd - 1);
auto value = prefixedString.substr(keyEnd + 1, valueEnd - keyEnd - 1);
query[key] = urlDecode(value);
prefixedString = prefixedString.substr(valueEnd);
}
return query;
}

View File

@@ -1,9 +1,9 @@
#include "BellLogger.h"
std::shared_ptr<bell::AbstractLogger> bell::bellGlobalLogger;
bell::AbstractLogger* bell::bellGlobalLogger;
void bell::setDefaultLogger() {
bell::bellGlobalLogger = std::make_shared<bell::BellLogger>();
bell::bellGlobalLogger = new bell::BellLogger();
}
void bell::enableSubmoduleLogging() {

Some files were not shown because too many files have changed in this diff Show More