Compare commits
85 Commits
support-2.
...
master
Author | SHA1 | Date |
---|---|---|
Nanang Izzuddin | 1dab9b63ac | |
Nanang Izzuddin | 30829f03a7 | |
sauwming | 24ac5875ff | |
Nanang Izzuddin | ca2dacf024 | |
sauwming | f406002f68 | |
Nanang Izzuddin | f38d781a82 | |
sauwming | 4f3df90a3e | |
sauwming | 472bda5087 | |
sauwming | 0d2ebdc7e3 | |
sauwming | c5bc3d1ef5 | |
sauwming | 72d885d5d7 | |
Amilcar Ubiera | 12d0468cb6 | |
Amilcar Ubiera | 6d114d71d5 | |
sauwming | e7e7f28f16 | |
sauwming | 86b7dd48b5 | |
sauwming | 51e52062e1 | |
Nanang Izzuddin | 478aeb95e9 | |
sauwming | c0de1a4224 | |
Santiago De la Cruz | 427a2b3ab8 | |
Amilcar Ubiera | ca4b078cc1 | |
Goodicus | a7c4d83807 | |
naf | cfde494dc3 | |
Nanang Izzuddin | a974061441 | |
Andreas Wehrmann | ed40439b0d | |
Fil | 70332e3510 | |
sauwming | c36802585d | |
Nanang Izzuddin | 7d2248f38a | |
sauwming | 9e6a63e42f | |
sauwming | 5ef8463d56 | |
sauwming | 2d6a9d4442 | |
Goodicus | b0be1706ea | |
Akos Denke | 7178ab01a8 | |
Jannis Muething | fc3b03c937 | |
Nanang Izzuddin | beb06a57ca | |
sauwming | f33d5fc555 | |
sauwming | a32d7c2907 | |
sauwming | 776c70ef01 | |
sauwming | 0de8fef515 | |
sauwming | e12a8d17a0 | |
Goodicus | d692a9940f | |
sauwming | b3ea8a29ac | |
Nanang Izzuddin | e2b7d73ef5 | |
dependabot[bot] | ce8d20cadf | |
Nanang Izzuddin | 569aac1b1c | |
sauwming | 712b06407f | |
sauwming | d762276861 | |
Amilcar Ubiera | 53d96cd5b8 | |
sauwming | 98d51a0e58 | |
Riza Sulistyo | b6cc71ad19 | |
sauwming | f2055ef7a3 | |
sauwming | 19c018affd | |
Brad Smith | 26bdf998f0 | |
sauwming | ca0c4403ec | |
sauwming | 3ed76a11c0 | |
sauwming | 86e22f4329 | |
sauwming | c6fd43208d | |
Riza Sulistyo | 4dfbdf7b1f | |
Florian Xaver | 71e7087836 | |
Nanang Izzuddin | a31d048ecb | |
Nanang Izzuddin | 8e9857a81e | |
Riza Sulistyo | b981b45183 | |
sauwming | 42a3e78d75 | |
sauwming | 033e4d7ae3 | |
sauwming | 5601a20c1e | |
sauwming | ca2e450edf | |
Gregor Jasny | 48f3723d71 | |
sauwming | 043926a584 | |
sauwming | 378e97ca10 | |
Brad Smith | 4140143493 | |
Olle Axelsson | 5229ce2473 | |
Santiago De la Cruz | 648aa3c3f0 | |
Riza Sulistyo | 78b73c977d | |
Nanang Izzuddin | 04f81212a3 | |
Florian Xaver | f9ed97b87d | |
Ihor Olkhovskyi | 9287ac21e6 | |
Nanang Izzuddin | e235868cef | |
silentindark | 6157218806 | |
silentindark | c224f26420 | |
jimying | 5188d056a7 | |
sauwming | ca5255795a | |
Brad Smith | da91020a44 | |
Gregor Jasny | cf4f2d84dc | |
sauwming | 58a101c945 | |
sauwming | 528f90adfb | |
Riza Sulistyo | b3e5f76788 |
|
@ -23,21 +23,21 @@ jobs:
|
|||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: install dependencies
|
||||
run: brew install openssl@1.1 opencore-amr swig sipp
|
||||
run: brew install openssl opencore-amr swig sipp
|
||||
- name: config site
|
||||
run: cd pjlib/include/pj && cp config_site_test.h config_site.h
|
||||
- name: configure
|
||||
run: CFLAGS="-g -I/usr/local/include -I/usr/local/opt/openssl@1.1/include -fPIC" LDFLAGS="-L/usr/local/lib -L/usr/local/opt/openssl@1.1/lib" CXXFLAGS="-g -fPIC" ./configure
|
||||
run: CFLAGS="-g $(pkg-config --cflags openssl) $(pkg-config --cflags opencore-amrnb) -fPIC" LDFLAGS="$(pkg-config --libs-only-L openssl) $(pkg-config --libs-only-L openssl)/lib $(pkg-config --libs-only-L opencore-amrnb)" CXXFLAGS="-g -fPIC" ./configure
|
||||
- name: make
|
||||
run: make
|
||||
- name: set up Python
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.10'
|
||||
- name: swig bindings
|
||||
run: cd pjsip-apps/src/swig && make
|
||||
- name: disable firewall
|
||||
run: sudo /usr/libexec/ApplicationFirewall/socketfilterfw --setglobalstate off
|
||||
- name: set up Python 3.10 for pjsua test
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.10'
|
||||
- name: unit tests
|
||||
run: make pjlib-test-ci pjmedia-test pjlib-util-test pjsua-test
|
||||
|
||||
|
@ -47,11 +47,11 @@ jobs:
|
|||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: install dependencies
|
||||
run: brew install openssl@1.1 opencore-amr
|
||||
run: brew install openssl opencore-amr
|
||||
- name: config site
|
||||
run: cd pjlib/include/pj && cp config_site_test.h config_site.h
|
||||
- name: configure
|
||||
run: CFLAGS="-g -I/usr/local/include -I/usr/local/opt/openssl@1.1/include" LDFLAGS="-L/usr/local/lib -L/usr/local/opt/openssl@1.1/lib" ./configure
|
||||
run: CFLAGS="-g $(pkg-config --cflags openssl) $(pkg-config --cflags opencore-amrnb)" LDFLAGS="$(pkg-config --libs-only-L openssl) $(pkg-config --libs-only-L openssl)/lib $(pkg-config --libs-only-L opencore-amrnb)" ./configure
|
||||
- name: make
|
||||
run: make
|
||||
- name: disable firewall
|
||||
|
@ -65,11 +65,11 @@ jobs:
|
|||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: install dependencies
|
||||
run: brew install openssl@1.1 opencore-amr
|
||||
run: brew install openssl opencore-amr
|
||||
- name: config site
|
||||
run: cd pjlib/include/pj && cp config_site_test.h config_site.h
|
||||
- name: configure
|
||||
run: CFLAGS="-g -I/usr/local/include -I/usr/local/opt/openssl@1.1/include" LDFLAGS="-L/usr/local/lib -L/usr/local/opt/openssl@1.1/lib" ./configure
|
||||
run: CFLAGS="-g $(pkg-config --cflags openssl) $(pkg-config --cflags opencore-amrnb)" LDFLAGS="$(pkg-config --libs-only-L openssl) $(pkg-config --libs-only-L openssl)/lib $(pkg-config --libs-only-L opencore-amrnb)" ./configure
|
||||
- name: make
|
||||
run: make
|
||||
- name: disable firewall
|
||||
|
@ -86,11 +86,15 @@ jobs:
|
|||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: install dependencies
|
||||
run: brew install openssl@1.1 swig
|
||||
run: brew install openssl swig
|
||||
- name: configure
|
||||
run: CFLAGS="-I/usr/local/include -I/usr/local/opt/openssl@1.1/include -fPIC" LDFLAGS="-L/usr/local/lib -L/usr/local/opt/openssl@1.1/lib" CXXFLAGS="-fPIC" ./configure
|
||||
run: CFLAGS="$(pkg-config --cflags openssl) -fPIC" LDFLAGS="$(pkg-config --libs-only-L openssl) $(pkg-config --libs-only-L openssl)/lib" CXXFLAGS="-fPIC" ./configure
|
||||
- name: make
|
||||
run: make
|
||||
- name: set up Python
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.10'
|
||||
- name: swig bindings
|
||||
run: cd pjsip-apps/src/swig && make
|
||||
|
||||
|
@ -105,6 +109,10 @@ jobs:
|
|||
run: CFLAGS="-fPIC" CXXFLAGS="-fPIC" ./configure --with-gnutls=/usr/local/
|
||||
- name: make
|
||||
run: make
|
||||
- name: set up Python
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.10'
|
||||
- name: swig bindings
|
||||
run: cd pjsip-apps/src/swig && make
|
||||
|
||||
|
@ -115,21 +123,21 @@ jobs:
|
|||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: install dependencies
|
||||
run: brew install openssl@1.1 openh264 libvpx opencore-amr swig sipp
|
||||
run: brew install openssl openh264 libvpx opencore-amr swig sipp
|
||||
- name: config site
|
||||
run: cd pjlib/include/pj && cp config_site_test.h config_site.h && echo "#define PJMEDIA_HAS_VIDEO 1" >> config_site.h
|
||||
- name: configure
|
||||
run: CFLAGS="-g -I/usr/local/include -I/usr/local/opt/openssl@1.1/include -DHAS_VID_CODEC_TEST=0 -fPIC" LDFLAGS="-L/usr/local/lib -L/usr/local/opt/openssl@1.1/lib" CXXFLAGS="-g -fPIC" ./configure
|
||||
run: CFLAGS="-g $(pkg-config --cflags openssl) $(pkg-config --cflags opencore-amrnb) -DHAS_VID_CODEC_TEST=0 -fPIC" LDFLAGS="$(pkg-config --libs-only-L openssl) $(pkg-config --libs-only-L openssl)/lib $(pkg-config --libs-only-L opencore-amrnb)" CXXFLAGS="-g -fPIC" ./configure
|
||||
- name: make
|
||||
run: make
|
||||
- name: set up Python
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.10'
|
||||
- name: swig bindings
|
||||
run: cd pjsip-apps/src/swig && make
|
||||
- name: disable firewall
|
||||
run: sudo /usr/libexec/ApplicationFirewall/socketfilterfw --setglobalstate off
|
||||
- name: set up Python 3.10 for pjsua test
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: '3.10'
|
||||
- name: unit tests
|
||||
run: make pjlib-test-ci pjmedia-test pjlib-util-test pjsua-test
|
||||
|
||||
|
@ -139,11 +147,11 @@ jobs:
|
|||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: install dependencies
|
||||
run: brew install openssl@1.1 openh264 libvpx opencore-amr
|
||||
run: brew install openssl openh264 libvpx opencore-amr
|
||||
- name: config site
|
||||
run: cd pjlib/include/pj && cp config_site_test.h config_site.h && echo "#define PJMEDIA_HAS_VIDEO 1" >> config_site.h
|
||||
- name: configure
|
||||
run: CFLAGS="-g -I/usr/local/include -I/usr/local/opt/openssl@1.1/include" LDFLAGS="-L/usr/local/lib -L/usr/local/opt/openssl@1.1/lib" ./configure
|
||||
run: CFLAGS="-g $(pkg-config --cflags openssl) $(pkg-config --cflags opencore-amrnb)" LDFLAGS="$(pkg-config --libs-only-L openssl) $(pkg-config --libs-only-L openssl)/lib $(pkg-config --libs-only-L opencore-amrnb)" ./configure
|
||||
- name: make
|
||||
run: make
|
||||
- name: disable firewall
|
||||
|
@ -157,11 +165,11 @@ jobs:
|
|||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: install dependencies
|
||||
run: brew install openssl@1.1 openh264 libvpx opencore-amr
|
||||
run: brew install openssl openh264 libvpx opencore-amr
|
||||
- name: config site
|
||||
run: cd pjlib/include/pj && cp config_site_test.h config_site.h && echo "#define PJMEDIA_HAS_VIDEO 1" >> config_site.h
|
||||
- name: configure
|
||||
run: CFLAGS="-g -I/usr/local/include -I/usr/local/opt/openssl@1.1/include" LDFLAGS="-L/usr/local/lib -L/usr/local/opt/openssl@1.1/lib" ./configure
|
||||
run: CFLAGS="-g $(pkg-config --cflags openssl) $(pkg-config --cflags opencore-amrnb)" LDFLAGS="$(pkg-config --libs-only-L openssl) $(pkg-config --libs-only-L openssl)/lib $(pkg-config --libs-only-L opencore-amrnb)" ./configure
|
||||
- name: make
|
||||
run: make
|
||||
- name: disable firewall
|
||||
|
@ -175,19 +183,23 @@ jobs:
|
|||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: install dependencies
|
||||
run: brew install openssl@1.1 x264 libvpx nasm swig
|
||||
run: brew install openssl x264 libvpx nasm swig
|
||||
- name: get ffmpeg
|
||||
run: git clone --single-branch --branch release/4.2 https://github.com/FFmpeg/FFmpeg.git
|
||||
run: git clone --single-branch --branch release/7.0 https://github.com/FFmpeg/FFmpeg.git
|
||||
- name: configure ffmpeg
|
||||
run: cd FFmpeg && ./configure --enable-shared --disable-static --enable-gpl --enable-libx264
|
||||
run: cd FFmpeg && LDFLAGS="-Wl,-ld_classic" ./configure --enable-shared --disable-static --enable-gpl --enable-libx264
|
||||
- name: build ffmpeg
|
||||
run: cd FFmpeg && make -j10 && sudo make install
|
||||
- name: config site
|
||||
run: echo -e "#define PJMEDIA_HAS_VIDEO 1\n" > pjlib/include/pj/config_site.h
|
||||
- name: configure
|
||||
run: CFLAGS="-I/usr/local/include -I/usr/local/opt/openssl@1.1/include -fPIC" LDFLAGS="-L/usr/local/lib -L/usr/local/opt/openssl@1.1/lib" CXXFLAGS="-fPIC" ./configure
|
||||
run: CFLAGS="$(pkg-config --cflags openssl) -fPIC" LDFLAGS="$(pkg-config --libs-only-L openssl) $(pkg-config --libs-only-L openssl)/lib" CXXFLAGS="-fPIC" ./configure
|
||||
- name: make
|
||||
run: make
|
||||
- name: set up Python
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.10'
|
||||
- name: swig bindings
|
||||
run: cd pjsip-apps/src/swig && make
|
||||
|
||||
|
@ -197,12 +209,16 @@ jobs:
|
|||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: install dependencies
|
||||
run: brew install openssl@1.1 libvpx swig
|
||||
run: brew install openssl libvpx swig
|
||||
- name: config site
|
||||
run: echo -e "#define PJMEDIA_HAS_VIDEO 1\n#define PJMEDIA_HAS_VID_TOOLBOX_CODEC 1\n" > pjlib/include/pj/config_site.h
|
||||
- name: configure
|
||||
run: CFLAGS="-I/usr/local/include -I/usr/local/opt/openssl@1.1/include -fPIC" LDFLAGS="-L/usr/local/lib -L/usr/local/opt/openssl@1.1/lib" CXXFLAGS="-fPIC" ./configure
|
||||
run: CFLAGS="$(pkg-config --cflags openssl) -fPIC" LDFLAGS="$(pkg-config --libs-only-L openssl) $(pkg-config --libs-only-L openssl)/lib" CXXFLAGS="-fPIC" ./configure
|
||||
- name: make
|
||||
run: make
|
||||
- name: set up Python
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.10'
|
||||
- name: swig bindings
|
||||
run: cd pjsip-apps/src/swig && make
|
||||
|
|
|
@ -178,25 +178,10 @@ jobs:
|
|||
msbuild pjproject-vs14.sln /p:PlatformToolset=v143 /p:Configuration=Release /p:Platform=win32 /p:UseEnv=true
|
||||
shell: cmd
|
||||
|
||||
windows-with-video-libvpx-unit-test-1:
|
||||
windows-with-video-libvpx-schannel-unit-test-1:
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- uses: actions/checkout@master
|
||||
- name: get openssl
|
||||
run: Invoke-WebRequest -Uri "https://github.com/pjsip/third_party_libs/raw/main/openssl-1.1.1s-win.zip" -OutFile ".\openssl.zip"
|
||||
shell: powershell
|
||||
- name: expand openssl
|
||||
run: |
|
||||
Expand-Archive -LiteralPath .\openssl.zip -DestinationPath .; pwd
|
||||
cd openssl_build
|
||||
Add-Content ..\openssl_dir.txt $pwd.Path
|
||||
shell: powershell
|
||||
- name: check openssl folder
|
||||
run: |
|
||||
set /P OPENSSL_DIR=<openssl_dir.txt
|
||||
dir "%OPENSSL_DIR%\include"
|
||||
dir "%OPENSSL_DIR%\lib"
|
||||
shell: cmd
|
||||
- name: get vpx
|
||||
run: Invoke-WebRequest -Uri "https://github.com/pjsip/third_party_libs/raw/main/vpx-1.12-win.zip" -Outfile "vpx.zip"
|
||||
shell: powershell
|
||||
|
@ -231,6 +216,8 @@ jobs:
|
|||
run: |
|
||||
cd pjlib/include/pj; cp config_site_test.h config_site.h
|
||||
Add-Content config_site.h "#define PJ_HAS_SSL_SOCK 1"
|
||||
Add-Content config_site.h "#define PJ_SSL_SOCK_IMP PJ_SSL_SOCK_IMP_SCHANNEL"
|
||||
Add-Content config_site.h "#undef PJMEDIA_SRTP_HAS_DTLS"
|
||||
Add-Content config_site.h "#define PJMEDIA_HAS_VIDEO 1"
|
||||
Add-Content config_site.h "#define PJMEDIA_VIDEO_DEV_HAS_DSHOW 1"
|
||||
Add-Content config_site.h "#define PJMEDIA_HAS_LIBYUV 1"
|
||||
|
@ -258,7 +245,7 @@ jobs:
|
|||
set /P SDL_DIR=<sdl_dir.txt
|
||||
cd tests/pjsua/tools
|
||||
set INCLUDE=%INCLUDE%;%OPENSSL_DIR%\include;%VPX_DIR%\include;%SDL_DIR%\include
|
||||
set LIB=%LIB%;%OPENSSL_DIR%\lib;%VPX_DIR%\lib;%SDL_DIR%\lib\x86
|
||||
set LIB=%LIB%;%VPX_DIR%\lib;%SDL_DIR%\lib\x86
|
||||
call "%PROGRAMFILES%\Microsoft Visual Studio\2022\Enterprise\Common7\Tools\VsDevCmd.bat"
|
||||
msbuild cmp_wav.vcxproj /p:PlatformToolset=v143 /p:Configuration=Release /p:Platform=win32 /p:UseEnv=true
|
||||
shell: cmd
|
||||
|
@ -268,9 +255,8 @@ jobs:
|
|||
python-version: '3.10'
|
||||
- name: unit tests
|
||||
run: |
|
||||
$env:OPENSSL_DIR = Get-Content .\openssl_dir.txt
|
||||
$env:SDL_DIR = Get-Content .\sdl_dir.txt
|
||||
$env:PATH+=";$env:OPENSSL_DIR\bin;$env:SDL_DIR\lib\x86;"
|
||||
$env:PATH+=";$env:SDL_DIR\lib\x86;"
|
||||
cd tests/pjsua; python runall.py
|
||||
cd ../../pjlib/bin; ./pjlib-test-i386-Win32-vc14-Release.exe --ci-mode
|
||||
cd ../../pjlib-util/bin; ./pjlib-util-test-i386-Win32-vc14-Release.exe
|
||||
|
|
82
SECURITY.md
82
SECURITY.md
|
@ -17,50 +17,50 @@ Encrypt sensitive information using our PGP public key below.
|
|||
```
|
||||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
Comment: User-ID: Teluu <security@pjsip.org>
|
||||
Comment: Created: 7/29/2021 8:24 AM
|
||||
Comment: Expires: 7/29/2023 12:00 PM
|
||||
Comment: Created: 1/24/2024 10:05 AM
|
||||
Comment: Expires: 12/31/2029 12:00 PM
|
||||
Comment: Type: 3,072-bit RSA (secret key available)
|
||||
Comment: Usage: Signing, Encryption, Certifying User-IDs
|
||||
Comment: Fingerprint: C2A9D29D94D131466D8832AE15BA5B3B5DAE8B36
|
||||
Comment: Fingerprint: BCCC7ADEFFABAAB10FA4CDC027E875D43D995460
|
||||
|
||||
|
||||
mQGNBGECAzwBDADjloGXRtTaSoTj+Nz4uy5Ei8e9CpIe0kEXLUykdr0bxWh7EiUX
|
||||
EqkZnFXbt3bWcFTVp7CQMn1as8/AUSteRbKuweLVyx/fFFtxrOQIBNqrwJhwwbmx
|
||||
SKLc4Pe/RqT8HmJb+MRnU3rkuzJ4ak0Nh5fLUFL/gBmped8MqBmF8OobJt0U/z/d
|
||||
opqVGfnHPablA3nJUcbMW97GJ8FH4cX5ZT+46cbpoJo/L7WbMUpbZcnz+iPiQFFO
|
||||
/oO7AbVihdvFNd0SoXi7aE8i8BFIhOYa9nLJId/PMRqG9aFTRP8dOwbOL+EekQ7d
|
||||
5x81bQLgjpXogORDxiUns0cFgPBDz5P1Y1qXlQ+HYa8m/vIKnEZMo1mnNhBR40cM
|
||||
XyrapeA9WcXiYNo4FBEt6rHoCKpGbMG5Rfpk5u5KljDGxg3tdbuXNfbJPFAOp3IB
|
||||
hQ72zhT4rWV31J8IEmoBOT8smf04cEr+jfrjs/ejYJh//Ez7AzMhyoDm1m1ELWwW
|
||||
Mzvm5QPtm1pwHakAEQEAAbQaVGVsdXUgPHNlY3VyaXR5QHBqc2lwLm9yZz6JAdQE
|
||||
EwEIAD4WIQTCqdKdlNExRm2IMq4Vuls7Xa6LNgUCYQIDPAIbAwUJA8KZlAULCQgH
|
||||
AgYVCgkICwIEFgIDAQIeAQIXgAAKCRAVuls7Xa6LNhEGC/4p9GiArgRF0DgVa40O
|
||||
JeH8mObjpweBvQc1zpHX2cA9DhkEs/vP0lg29v1248HnnZFz0HBnXKGQVq599jZX
|
||||
blm1IphNJSWfkutfjIIH80fqDCuqHOHLhrf0qzDxIAWaSSr0Bh/rGHlsPo2+s35f
|
||||
3EMwpkDzETnoLeJMShxAwJOocZBqIieWK2/MZKdLnwn2Evb40BJ63UftFOCf7LuQ
|
||||
tbZQ/w2op3Capt+6BL5aNAwnhz5uTgzUE2dLA31YCpWPDJbE1vMy05suzbEqGLu1
|
||||
aAFAKocdw1gbFrvEj2nDhH3dD10kQeMtXNPXqtQfRcmQCi8HCetfmFjfB8n5J6YW
|
||||
G6dtmiC9RfDgUlrhfTcHRL7ioD2g8jZt2LE2yXulS+8AD10/WQTWkEHYmly0bHAE
|
||||
sbAtwNA1asVsuVNUreTirZA0KgTJRySe/WbCyaCXStlTHy2X2aKR0jaNhm56Snpz
|
||||
K+aRPTsc6ZFOQOzBMys7hBCAQlCQ0CQyzucMfV3Egl83Qxm5AY0EYQIDPAEMALRb
|
||||
OcHPuJ77J+jZGtNAp27/QDXsA1AwvyxDVP+BhZUS3gKXqoyXS3THNEQoqL8GhvZz
|
||||
j/sDQo7Hs6p3oEj+HXF2LzlOjiaqObZsYaEBrMo/OS6p/8YvVOa39eTtuvgNVeDB
|
||||
EitlH8/pjk5bsZ0KFWqijcqsu0i4ye758UyERZ1ruXHNMB4auow4ZAwqn0vNN0CH
|
||||
f1hP/2qMLw5krCgHx1QowMk7S83ljFF5J36ojOuVQjzrCd96eWMHCdUpXbBJv7dd
|
||||
firVH9JIOAMDRAEoeX/EjWqeHlPVoOElGUWqAVKveQ0GNdN10hT+1gg0lxqR8f5G
|
||||
QDz7u6pDHJHhDQeMH6HYpRLXiXN23AEYnwpzFyw7p22WihV/6rKzGAP7JECZGDsD
|
||||
w5x2/YWRcg04MWcnY25f79JM/QWfRGfX6cxdKPxDDgZKUREzESy8/VeefF+xLklg
|
||||
O8t9xASz7dU4iSzwdyT5AJX7hIjyJxij8EroQ+4rn4m/zwVE9I9vUNn139kIaQAR
|
||||
AQABiQG8BBgBCAAmFiEEwqnSnZTRMUZtiDKuFbpbO12uizYFAmECAzwCGwwFCQPC
|
||||
mZQACgkQFbpbO12uizZQHwwAkActQzy2bb6naSAAVgxvobrNuXzO+HygJLgBa37l
|
||||
NdFxbBnN0YjYYrjA5PJJZYTcEaedz8Uec2onqTDpsaMDRwouCRayo19WizmSQd34
|
||||
DdygKA2CecQdXxKUf/2vxE//Jxq1/Sq0+facynhTygG24aSI44F/iw2h+9Z9JPcM
|
||||
BwtNLdGcuWEU2slHcN24sBveBHbTyCe4h52OMr/HBPldAREa2zojF4J8fxTPD6ES
|
||||
wx8mWc79sr50EPejw2r3ipKjrbxiB1yDtiry/eZatidb0slGWLzBhawOkZAUrVJh
|
||||
DODKf+upkfP8V/MayqRdNNH8FDxYUgxYwnX9+VbtJr7BrvnoyGgOwIuxN5TV+EQt
|
||||
+Bf7Kzzsqz2/bzsPtnd/F3faAAoOEzby//fdLWUpKcubf7kVq0EQ9bMKwC56rLpd
|
||||
BnLaAfcL/676JS3bjJMc3ij3T2doC3IFwj84kNoBk+ArgBFlKjcB84Uket+rj23e
|
||||
SjwjgsVZsFg9w1+m0F72hyAQ
|
||||
=rD28
|
||||
mQGNBGWwfm8BDACpBBGoBkkxgkm6hao9Fk63iEt3mJ6Ycg2BabeA7ZeHAA1IMkMG
|
||||
6247Y08Mk5DkqS+SeDu//44I6MQ/3tEDHqr59/F1qqhsu4zvPDOSgcfCET9kL7u0
|
||||
XhCrJC0DbEpTNmY9prnvNnzJOTzvbDQVysUII6b4UwhWC+Y+qhl6csVhoHUphwMs
|
||||
XZDtMR3EPpNbIrkXgUWRhEkcR2iuuLxnmdGTH8gDrtiq+IBcANkzojIEEQPulv6r
|
||||
IrrGbVx8hFRgbk5mJwIy6xRfr+5ah5gUeNM8fV/BwCUOP++qtY3c491I499XXdWa
|
||||
OpSRTSYgqY0kI0rl8B75FLG0qjnB1ySbmek++bWzK6sCJWmJxJJGjzVr3sccHOQZ
|
||||
hDUoK82OFkvde0em8HU1WnshRbSJhchrL6bO4uDMrGCYdO9uE2XHb/UiKFE9mCrw
|
||||
JKZlDg6PPUf8Gkqf594S3raekrvwWEmq/JWsk3WtNancMUQRd1pQR6ouXU0mHIih
|
||||
+1qf6hvXITxzDccAEQEAAbQaVGVsdXUgPHNlY3VyaXR5QHBqc2lwLm9yZz6JAdcE
|
||||
EwEIAEEWIQS8zHre/6uqsQ+kzcAn6HXUPZlUYAUCZbB+bwIbAwUJCypO4QULCQgH
|
||||
AgIiAgYVCgkICwIEFgIDAQIeBwIXgAAKCRAn6HXUPZlUYJmfDACLT86rTd+JMpUY
|
||||
iqYbELpOBfMkY0ebXVWQE/1FjmE5itS6XgHb3BWwXq99wtn9yKgwqbG8F2A/PVZd
|
||||
4Ga/EI0jyfJN85tjbk+bEqAkKIhzVljuLl6qkDqOOr6EzGAVAHLIJ1NgPLOOZKF8
|
||||
WM4t3WBTKRTJmGL9uNE/yblbRqrtsLAbtLcyZk0f8E8UYCIrWHKV7teop0VeBUw3
|
||||
+a0ISa9NHCLH35FYGROPL3s1CieWrYOSS/B8ncChqB8sfCE3UkcTTWvPSvCpYEIY
|
||||
mZjQa975HFcvYaD+sYJ+ZwJJGg5fm1jLaGFrL5zTvPpx53Y3u/SBXTeGEmal/tvp
|
||||
s5hz/3ZZeSmTLLcWjG1xcxVGnQF7EK4h1EmvcTz7mZrTY+ZHohnv7a50G3C5eo2s
|
||||
tNkf0E0ajfmgLXClxWMue+TzhwnnMQN7jdbTRU8SLgooG4LJeww7TiLI2eiyZC7L
|
||||
wOhNsbOyofnIfT0q/xWHKGJFe7Sffk6+cT/Jw0EWrt+34ATEUmC5AY0EZbB+bwEM
|
||||
AKan7Fo7Y2PDLh+hMb4KrPfQyypBIv8+//Ln4oEZLcYFcNzdWWVc4z54YfqkSu8j
|
||||
vGhjYKk5JK1l9RBHPoFGPV4pmG2hf/wSeNoYcs7Tz4wQapCYLNL6ouA9hJIezG5S
|
||||
BYs74njIrFtycJXlXhOlqzsJQ7dcMWlYjeXyiOFVYWyzcfwZWGJQ7i6YotmRxx6j
|
||||
IfJ3abRJtgTeUXqUNUagetpOjno+R8uYhm6r1sgajyi/WE8QMixVNoWgUo94jhk4
|
||||
ZAcAAw/gBN+pGQawf9TOC4llle8g0YENf39m/GtQ6PD6ks1pSnjXNLhiIHkrv5eD
|
||||
+I8td0RSbsHqgWjO1F4/h1eH4yQXbV5QTIcVgE5yLqIQaoScEFsOokLFm8NDWrVA
|
||||
eI0TBbOm1qtHaPpJROrEQkTyJBBFCFKRuC5u7LCirlN+O21lZDgKg/bPNe6tV4zr
|
||||
30FEsVy0njusY5ZSapbLemAOQldIwphgp8WBMFxq1tb86n6dOLYYte1A8DF3ryHM
|
||||
iQARAQABiQG8BBgBCAAmFiEEvMx63v+rqrEPpM3AJ+h11D2ZVGAFAmWwfm8CGwwF
|
||||
CQsqTuEACgkQJ+h11D2ZVGAcLAv+JB0iNqrtVG/cqBz44VC2+zJ6rAuGYuiR1sNL
|
||||
Ejvk9D483ZUKUpsZOjpVkgEJ88Fw73RoAiuEvF78mN6CloIIxQtJCFRs66PECjJP
|
||||
m9pjzx5wer2TqC+7l6fNp8pXFuLoeirvYTPisdUM+cqJ9N37BekqqiE0LSdGWcmK
|
||||
GqlO3DjPgyWfjE5rSGy9Bu4l9HKmv8AUtFiw3g65cwDC/23LFYK+HJB8gelLytkp
|
||||
kLSC6HbNg6lpnFoqhIJYBr3TK8IKXhD62dO4B3IyWnqMnKFJ2fv1ILj42LlzWgZo
|
||||
ULnZUI/EUpV3+5ELVmNKJiWGB1OgVsaJalN5TMqnr2iXPg1qnJzvzvvuwwDfA6g0
|
||||
EeR5H7yOK5WvQvGDJrUaESXRMZgubJmv42EmfT048Ajq1/SaWTdQqRK9CoFIJTOY
|
||||
lQAakbU2ukwSJRdwd+PDRFWB8c4geIAtiYJw+LseTKtjo4++hADQBoRkqgnKB1o7
|
||||
oUbFbwQAAHfNE3xFJespnLA/KbbO
|
||||
=Oiwu
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
||||
```
|
||||
|
|
61
aconfigure
61
aconfigure
|
@ -712,6 +712,7 @@ ac_pjmedia_video_has_qt
|
|||
ac_darwin_cflags
|
||||
ac_pjmedia_video_has_ios_opengl
|
||||
ac_pjmedia_video_has_vtoolbox
|
||||
ac_pjmedia_video_has_metal
|
||||
ac_pjmedia_video_has_darwin
|
||||
ac_dshow_ldflags
|
||||
ac_dshow_cflags
|
||||
|
@ -4848,7 +4849,7 @@ fi
|
|||
|
||||
if test "$AR_FLAGS" = ""; then AR_FLAGS="rv"; fi
|
||||
|
||||
if test "$LD" = ""; then LD="$CC"; fi
|
||||
if test "$LD" = ""; then LD="$CXX"; fi
|
||||
|
||||
if test "$LDOUT" = ""; then LDOUT="-o "; fi
|
||||
|
||||
|
@ -6517,19 +6518,26 @@ rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
|
|||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking ioqueue backend" >&5
|
||||
printf %s "checking ioqueue backend... " >&6; }
|
||||
|
||||
ac_os_objs=ioqueue_select.o
|
||||
ac_linux_poll=select
|
||||
|
||||
case $target in
|
||||
*darwin* | *bsd*)
|
||||
# Check whether --enable-kqueue was given.
|
||||
if test ${enable_kqueue+y}
|
||||
then :
|
||||
enableval=$enable_kqueue;
|
||||
ac_os_objs=ioqueue_kqueue.o
|
||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: kqueue()" >&5
|
||||
if test "$enable_kqueue" = "yes"; then
|
||||
ac_os_objs=ioqueue_kqueue.o
|
||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: kqueue()" >&5
|
||||
printf "%s\n" "kqueue()" >&6; }
|
||||
else
|
||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: select()" >&5
|
||||
printf "%s\n" "select()" >&6; }
|
||||
fi
|
||||
|
||||
else $as_nop
|
||||
|
||||
ac_os_objs=ioqueue_select.o
|
||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: select()" >&5
|
||||
printf "%s\n" "select()" >&6; }
|
||||
|
||||
|
@ -6541,19 +6549,22 @@ fi
|
|||
if test ${enable_epoll+y}
|
||||
then :
|
||||
enableval=$enable_epoll;
|
||||
ac_os_objs=ioqueue_epoll.o
|
||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: /dev/epoll" >&5
|
||||
if test "$enable_epoll" = "yes"; then
|
||||
ac_os_objs=ioqueue_epoll.o
|
||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: /dev/epoll" >&5
|
||||
printf "%s\n" "/dev/epoll" >&6; }
|
||||
printf "%s\n" "#define PJ_HAS_LINUX_EPOLL 1" >>confdefs.h
|
||||
printf "%s\n" "#define PJ_HAS_LINUX_EPOLL 1" >>confdefs.h
|
||||
|
||||
ac_linux_poll=epoll
|
||||
ac_linux_poll=epoll
|
||||
else
|
||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: select()" >&5
|
||||
printf "%s\n" "select()" >&6; }
|
||||
fi
|
||||
|
||||
else $as_nop
|
||||
|
||||
ac_os_objs=ioqueue_select.o
|
||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: select()" >&5
|
||||
printf "%s\n" "select()" >&6; }
|
||||
ac_linux_poll=select
|
||||
|
||||
fi
|
||||
|
||||
|
@ -7469,6 +7480,7 @@ printf "%s\n" "Checking if OpenGL ES 2 is available... no" >&6; }
|
|||
|
||||
|
||||
|
||||
|
||||
SAVED_LIBS="$LIBS"
|
||||
LIBS="-framework AVFoundation -framework CoreGraphics -framework QuartzCore -framework CoreVideo -framework CoreMedia"
|
||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||
|
@ -7508,6 +7520,26 @@ then :
|
|||
else $as_nop
|
||||
ac_pjmedia_video_has_vtoolbox=no
|
||||
fi
|
||||
rm -f core conftest.err conftest.$ac_objext conftest.beam \
|
||||
conftest$ac_exeext conftest.$ac_ext
|
||||
LIBS="-framework Metal"
|
||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||
/* end confdefs.h. */
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
_ACEOF
|
||||
if ac_fn_c_try_link "$LINENO"
|
||||
then :
|
||||
ac_pjmedia_video_has_metal=yes
|
||||
else $as_nop
|
||||
ac_pjmedia_video_has_metal=no
|
||||
fi
|
||||
rm -f core conftest.err conftest.$ac_objext conftest.beam \
|
||||
conftest$ac_exeext conftest.$ac_ext
|
||||
LIBS="-framework OpenGLES"
|
||||
|
@ -7539,6 +7571,15 @@ printf "%s\n" "Checking if AVFoundation framework is available... yes" >&6; }
|
|||
else
|
||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: Checking if AVFoundation framework is available... no" >&5
|
||||
printf "%s\n" "Checking if AVFoundation framework is available... no" >&6; }
|
||||
fi
|
||||
if test "$ac_pjmedia_video_has_metal" = "yes"; then
|
||||
ac_darwin_cflags+=" -DPJMEDIA_VIDEO_DEV_HAS_METAL=1"
|
||||
LIBS="$LIBS -framework Metal -framework MetalKit"
|
||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: Checking if Metal framework is available... yes" >&5
|
||||
printf "%s\n" "Checking if Metal framework is available... yes" >&6; }
|
||||
else
|
||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: Checking if Metal framework is available... no" >&5
|
||||
printf "%s\n" "Checking if Metal framework is available... no" >&6; }
|
||||
fi
|
||||
if test "$ac_pjmedia_video_has_vtoolbox" = "yes"; then
|
||||
#ac_darwin_cflags+=" -DPJMEDIA_HAS_VID_TOOLBOX_CODEC=1"
|
||||
|
|
|
@ -46,7 +46,7 @@ AC_CHECK_TOOLS([AR], [ar gar], :)
|
|||
|
||||
if test "$AR_FLAGS" = ""; then AR_FLAGS="rv"; fi
|
||||
AC_SUBST(AR_FLAGS)
|
||||
if test "$LD" = ""; then LD="$CC"; fi
|
||||
if test "$LD" = ""; then LD="$CXX"; fi
|
||||
AC_SUBST(LD)
|
||||
if test "$LDOUT" = ""; then LDOUT="-o "; fi
|
||||
AC_SUBST(LDOUT)
|
||||
|
@ -467,17 +467,23 @@ AC_SUBST(ac_os_objs)
|
|||
AC_SUBST(ac_linux_poll)
|
||||
AC_MSG_CHECKING([ioqueue backend])
|
||||
|
||||
ac_os_objs=ioqueue_select.o
|
||||
ac_linux_poll=select
|
||||
|
||||
case $target in
|
||||
*darwin* | *bsd*)
|
||||
AC_ARG_ENABLE(kqueue,
|
||||
AS_HELP_STRING([--enable-kqueue],
|
||||
[Use kqueue ioqueue on macos/BSD (experimental)]),
|
||||
[
|
||||
ac_os_objs=ioqueue_kqueue.o
|
||||
AC_MSG_RESULT([kqueue()])
|
||||
if test "$enable_kqueue" = "yes"; then
|
||||
ac_os_objs=ioqueue_kqueue.o
|
||||
AC_MSG_RESULT([kqueue()])
|
||||
else
|
||||
AC_MSG_RESULT([select()])
|
||||
fi
|
||||
],
|
||||
[
|
||||
ac_os_objs=ioqueue_select.o
|
||||
AC_MSG_RESULT([select()])
|
||||
])
|
||||
;;
|
||||
|
@ -486,15 +492,17 @@ case $target in
|
|||
AS_HELP_STRING([--enable-epoll],
|
||||
[Use /dev/epoll ioqueue on Linux (experimental)]),
|
||||
[
|
||||
ac_os_objs=ioqueue_epoll.o
|
||||
AC_MSG_RESULT([/dev/epoll])
|
||||
AC_DEFINE(PJ_HAS_LINUX_EPOLL,1)
|
||||
ac_linux_poll=epoll
|
||||
if test "$enable_epoll" = "yes"; then
|
||||
ac_os_objs=ioqueue_epoll.o
|
||||
AC_MSG_RESULT([/dev/epoll])
|
||||
AC_DEFINE(PJ_HAS_LINUX_EPOLL,1)
|
||||
ac_linux_poll=epoll
|
||||
else
|
||||
AC_MSG_RESULT([select()])
|
||||
fi
|
||||
],
|
||||
[
|
||||
ac_os_objs=ioqueue_select.o
|
||||
AC_MSG_RESULT([select()])
|
||||
ac_linux_poll=select
|
||||
])
|
||||
;;
|
||||
esac
|
||||
|
@ -1047,6 +1055,7 @@ else
|
|||
*darwin*)
|
||||
ac_pjmedia_video=darwin_os
|
||||
AC_SUBST(ac_pjmedia_video_has_darwin)
|
||||
AC_SUBST(ac_pjmedia_video_has_metal)
|
||||
AC_SUBST(ac_pjmedia_video_has_vtoolbox)
|
||||
AC_SUBST(ac_pjmedia_video_has_ios_opengl)
|
||||
AC_SUBST(ac_darwin_cflags)
|
||||
|
@ -1059,6 +1068,10 @@ else
|
|||
AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [])],
|
||||
[ac_pjmedia_video_has_vtoolbox=yes],
|
||||
[ac_pjmedia_video_has_vtoolbox=no])
|
||||
LIBS="-framework Metal"
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [])],
|
||||
[ac_pjmedia_video_has_metal=yes],
|
||||
[ac_pjmedia_video_has_metal=no])
|
||||
LIBS="-framework OpenGLES"
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [])],
|
||||
[ac_pjmedia_video_has_ios_opengl=yes],
|
||||
|
@ -1071,6 +1084,13 @@ else
|
|||
else
|
||||
AC_MSG_RESULT([Checking if AVFoundation framework is available... no])
|
||||
fi
|
||||
if test "$ac_pjmedia_video_has_metal" = "yes"; then
|
||||
ac_darwin_cflags+=" -DPJMEDIA_VIDEO_DEV_HAS_METAL=1"
|
||||
LIBS="$LIBS -framework Metal -framework MetalKit"
|
||||
AC_MSG_RESULT([Checking if Metal framework is available... yes])
|
||||
else
|
||||
AC_MSG_RESULT([Checking if Metal framework is available... no])
|
||||
fi
|
||||
if test "$ac_pjmedia_video_has_vtoolbox" = "yes"; then
|
||||
#ac_darwin_cflags+=" -DPJMEDIA_HAS_VID_TOOLBOX_CODEC=1"
|
||||
LIBS="$LIBS -framework VideoToolbox"
|
||||
|
|
|
@ -204,6 +204,7 @@ AC_PJMEDIA_VIDEO_HAS_QT = @ac_pjmedia_video_has_qt@
|
|||
|
||||
# Darwin (Mac and iOS)
|
||||
AC_PJMEDIA_VIDEO_HAS_DARWIN = @ac_pjmedia_video_has_darwin@
|
||||
AC_PJMEDIA_VIDEO_HAS_METAL = @ac_pjmedia_video_has_metal@
|
||||
AC_PJMEDIA_VIDEO_HAS_VTOOLBOX = @ac_pjmedia_video_has_vtoolbox@
|
||||
AC_PJMEDIA_VIDEO_HAS_IOS_OPENGL = @ac_pjmedia_video_has_ios_opengl@
|
||||
DARWIN_CFLAGS = @ac_darwin_cflags@
|
||||
|
|
|
@ -20,8 +20,8 @@ if test "$*" = "--help" -o "$*" = "-h"; then
|
|||
echo " ARCH Optional flags to specify target architecture, e.g."
|
||||
echo " ARCH=\"-arch armv7\". Default is arm64."
|
||||
echo " MIN_IOS Optional flags to specify minimum supported iOS"
|
||||
echo " versions, e.g. MIN_IOS=\"-miphoneos-version-min=10.0\". "
|
||||
echo " Default is 7.0."
|
||||
echo " versions, e.g. MIN_IOS=\"-miphoneos-version-min=11.0\". "
|
||||
echo " Default is 11.0."
|
||||
echo ""
|
||||
exit 0
|
||||
fi
|
||||
|
@ -123,7 +123,7 @@ if test "${ARCH_VAL}" = "arm64e"; then
|
|||
fi
|
||||
|
||||
if test "${MIN_IOS}" = ""; then
|
||||
MIN_IOS_VER="7.0"
|
||||
MIN_IOS_VER="11.0"
|
||||
echo "$F: MIN_IOS is not specified, choosing ${MIN_IOS_VER}"
|
||||
MIN_IOS="-miphoneos-version-min=${MIN_IOS_VER}"
|
||||
fi
|
||||
|
|
|
@ -64,6 +64,21 @@ PJ_BEGIN_DECL
|
|||
PJ_DECL(pj_status_t) pj_base64_encode(const pj_uint8_t *input, int in_len,
|
||||
char *output, int *out_len);
|
||||
|
||||
/**
|
||||
* Encode a buffer into base64 (URL and Filename Safe) encoding.
|
||||
*
|
||||
* @param input The input buffer.
|
||||
* @param in_len Size of the input buffer.
|
||||
* @param output Output buffer. Caller must allocate this buffer with
|
||||
* the appropriate size.
|
||||
* @param out_len On entry, it specifies the length of the output buffer.
|
||||
* Upon return, this will be filled with the actual
|
||||
* length of the output buffer.
|
||||
*
|
||||
* @return PJ_SUCCESS on success.
|
||||
*/
|
||||
PJ_DECL(pj_status_t) pj_base64url_encode(const pj_uint8_t *input, int in_len,
|
||||
char *output, int *out_len);
|
||||
|
||||
/**
|
||||
* Decode base64 string.
|
||||
|
@ -78,6 +93,18 @@ PJ_DECL(pj_status_t) pj_base64_encode(const pj_uint8_t *input, int in_len,
|
|||
PJ_DECL(pj_status_t) pj_base64_decode(const pj_str_t *input,
|
||||
pj_uint8_t *out, int *out_len);
|
||||
|
||||
/**
|
||||
* Decode base64 (URL and Filename Safe) string.
|
||||
*
|
||||
* @param input Input string.
|
||||
* @param out Buffer to store the output. Caller must allocate
|
||||
* this buffer with the appropriate size.
|
||||
* @param out_len On entry, it specifies the length of the output buffer.
|
||||
* Upon return, this will be filled with the actual
|
||||
* length of the output.
|
||||
*/
|
||||
PJ_DECL(pj_status_t) pj_base64url_decode(const pj_str_t *input,
|
||||
pj_uint8_t *out, int *out_len);
|
||||
|
||||
|
||||
/**
|
||||
|
|
|
@ -163,7 +163,7 @@ static void on_data_read(pj_http_req *hreq, void *data, pj_size_t size)
|
|||
PJ_UNUSED_ARG(hreq);
|
||||
PJ_UNUSED_ARG(data);
|
||||
|
||||
PJ_LOG(5, (THIS_FILE, "\nData received: %ld bytes", size));
|
||||
PJ_LOG(5, (THIS_FILE, "\nData received: %lu bytes", (unsigned long)size));
|
||||
if (size > 0) {
|
||||
#ifdef VERBOSE
|
||||
printf("%.*s\n", (int)size, (char *)data);
|
||||
|
@ -190,8 +190,8 @@ static void on_send_data(pj_http_req *hreq,
|
|||
*data = sdata;
|
||||
*size = sendsz;
|
||||
|
||||
PJ_LOG(5, (THIS_FILE, "\nSending data progress: %ld out of %ld bytes",
|
||||
send_size, total_size));
|
||||
PJ_LOG(5, (THIS_FILE, "\nSending data progress: %lu out of %lu bytes",
|
||||
(unsigned long)send_size, (unsigned long)total_size));
|
||||
}
|
||||
|
||||
|
||||
|
@ -210,7 +210,8 @@ static void on_complete(pj_http_req *hreq, pj_status_t status,
|
|||
PJ_LOG(3, (THIS_FILE, "Error %d", status));
|
||||
return;
|
||||
}
|
||||
PJ_LOG(5, (THIS_FILE, "\nData completed: %ld bytes", resp->size));
|
||||
PJ_LOG(5, (THIS_FILE, "\nData completed: %lu bytes",
|
||||
(unsigned long)resp->size));
|
||||
if (resp->size > 0 && resp->data) {
|
||||
#ifdef VERBOSE
|
||||
printf("%.*s\n", (int)resp->size, (char *)resp->data);
|
||||
|
|
|
@ -33,7 +33,18 @@ static const char base64_char[] = {
|
|||
'8', '9', '+', '/'
|
||||
};
|
||||
|
||||
static int base256_char(char c)
|
||||
/* Base 64 Encoding with URL and Filename Safe Alphabet (RFC 4648 section 5) */
|
||||
static const char base64url_char[] = {
|
||||
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
|
||||
'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
|
||||
'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
|
||||
'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
|
||||
'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
|
||||
'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7',
|
||||
'8', '9', '-', '_'
|
||||
};
|
||||
|
||||
static int base256_char(char c, pj_bool_t url)
|
||||
{
|
||||
if (c >= 'A' && c <= 'Z')
|
||||
return (c - 'A');
|
||||
|
@ -41,9 +52,9 @@ static int base256_char(char c)
|
|||
return (c - 'a' + 26);
|
||||
else if (c >= '0' && c <= '9')
|
||||
return (c - '0' + 52);
|
||||
else if (c == '+')
|
||||
else if ((!url && c == '+') || (url && c == '-'))
|
||||
return (62);
|
||||
else if (c == '/')
|
||||
else if ((!url && c == '/') || (url && c == '_'))
|
||||
return (63);
|
||||
else {
|
||||
/* It *may* happen on bad input, so this is not a good idea.
|
||||
|
@ -55,17 +66,18 @@ static int base256_char(char c)
|
|||
|
||||
|
||||
static void base256to64(pj_uint8_t c1, pj_uint8_t c2, pj_uint8_t c3,
|
||||
int padding, char *output)
|
||||
int padding, char *output, pj_bool_t url)
|
||||
{
|
||||
*output++ = base64_char[c1>>2];
|
||||
*output++ = base64_char[((c1 & 0x3)<< 4) | ((c2 & 0xF0) >> 4)];
|
||||
const char *b64 = url ? base64url_char : base64_char;
|
||||
*output++ = b64[c1>>2];
|
||||
*output++ = b64[((c1 & 0x3)<< 4) | ((c2 & 0xF0) >> 4)];
|
||||
switch (padding) {
|
||||
case 0:
|
||||
*output++ = base64_char[((c2 & 0xF) << 2) | ((c3 & 0xC0) >>6)];
|
||||
*output = base64_char[c3 & 0x3F];
|
||||
*output++ = b64[((c2 & 0xF) << 2) | ((c3 & 0xC0) >>6)];
|
||||
*output = b64[c3 & 0x3F];
|
||||
break;
|
||||
case 1:
|
||||
*output++ = base64_char[((c2 & 0xF) << 2) | ((c3 & 0xC0) >>6)];
|
||||
*output++ = b64[((c2 & 0xF) << 2) | ((c3 & 0xC0) >>6)];
|
||||
*output = PADDING;
|
||||
break;
|
||||
case 2:
|
||||
|
@ -76,9 +88,9 @@ static void base256to64(pj_uint8_t c1, pj_uint8_t c2, pj_uint8_t c3,
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
PJ_DEF(pj_status_t) pj_base64_encode(const pj_uint8_t *input, int in_len,
|
||||
char *output, int *out_len)
|
||||
static pj_status_t b64_encode(const pj_uint8_t *input, int in_len,
|
||||
char *output, int *out_len,
|
||||
pj_bool_t url)
|
||||
{
|
||||
const pj_uint8_t *pi = input;
|
||||
pj_uint8_t c1, c2, c3;
|
||||
|
@ -94,7 +106,7 @@ PJ_DEF(pj_status_t) pj_base64_encode(const pj_uint8_t *input, int in_len,
|
|||
++i;
|
||||
|
||||
if (i == in_len) {
|
||||
base256to64(c1, 0, 0, 2, po);
|
||||
base256to64(c1, 0, 0, 2, po, url);
|
||||
po += 4;
|
||||
break;
|
||||
} else {
|
||||
|
@ -102,13 +114,13 @@ PJ_DEF(pj_status_t) pj_base64_encode(const pj_uint8_t *input, int in_len,
|
|||
++i;
|
||||
|
||||
if (i == in_len) {
|
||||
base256to64(c1, c2, 0, 1, po);
|
||||
base256to64(c1, c2, 0, 1, po, url);
|
||||
po += 4;
|
||||
break;
|
||||
} else {
|
||||
c3 = *pi++;
|
||||
++i;
|
||||
base256to64(c1, c2, c3, 0, po);
|
||||
base256to64(c1, c2, c3, 0, po, url);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -119,9 +131,9 @@ PJ_DEF(pj_status_t) pj_base64_encode(const pj_uint8_t *input, int in_len,
|
|||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
PJ_DEF(pj_status_t) pj_base64_decode(const pj_str_t *input,
|
||||
pj_uint8_t *out, int *out_len)
|
||||
static pj_status_t b64_decode(const pj_str_t *input,
|
||||
pj_uint8_t *out, int *out_len,
|
||||
pj_bool_t url)
|
||||
{
|
||||
const char *buf;
|
||||
int len;
|
||||
|
@ -142,7 +154,7 @@ PJ_DEF(pj_status_t) pj_base64_decode(const pj_str_t *input,
|
|||
/* Fill up c, silently ignoring invalid characters */
|
||||
for (k=0; k<4 && i<len; ++k) {
|
||||
do {
|
||||
c[k] = base256_char(buf[i++]);
|
||||
c[k] = base256_char(buf[i++], url);
|
||||
} while (c[k]==INV && i<len);
|
||||
}
|
||||
|
||||
|
@ -168,4 +180,26 @@ PJ_DEF(pj_status_t) pj_base64_decode(const pj_str_t *input,
|
|||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
PJ_DEF(pj_status_t) pj_base64_encode(const pj_uint8_t *input, int in_len,
|
||||
char *output, int *out_len)
|
||||
{
|
||||
return b64_encode(input, in_len, output, out_len, PJ_FALSE);
|
||||
}
|
||||
|
||||
PJ_DEF(pj_status_t) pj_base64url_encode(const pj_uint8_t *input, int in_len,
|
||||
char *output, int *out_len)
|
||||
{
|
||||
return b64_encode(input, in_len, output, out_len, PJ_TRUE);
|
||||
}
|
||||
|
||||
PJ_DEF(pj_status_t) pj_base64_decode(const pj_str_t *input,
|
||||
pj_uint8_t *out, int *out_len)
|
||||
{
|
||||
return b64_decode(input, out, out_len, PJ_FALSE);
|
||||
}
|
||||
|
||||
PJ_DEF(pj_status_t) pj_base64url_decode(const pj_str_t *input,
|
||||
pj_uint8_t *out, int *out_len)
|
||||
{
|
||||
return b64_decode(input, out, out_len, PJ_TRUE);
|
||||
}
|
||||
|
|
|
@ -1840,15 +1840,15 @@ PJ_DEF(pj_status_t) pj_dns_resolver_add_entry( pj_dns_resolver *resolver,
|
|||
pj_bzero(&key, sizeof(struct res_key));
|
||||
if (pkt->hdr.anscount) {
|
||||
/* Make sure name is not too long. */
|
||||
PJ_ASSERT_RETURN(pkt->ans[0].name.slen < PJ_MAX_HOSTNAME,
|
||||
PJ_ENAMETOOLONG);
|
||||
PJ_ASSERT_ON_FAIL(pkt->ans[0].name.slen < PJ_MAX_HOSTNAME,
|
||||
{ pj_grp_lock_release(resolver->grp_lock); return PJ_ENAMETOOLONG; });
|
||||
|
||||
init_res_key(&key, pkt->ans[0].type, &pkt->ans[0].name);
|
||||
|
||||
} else {
|
||||
/* Make sure name is not too long. */
|
||||
PJ_ASSERT_RETURN(pkt->q[0].name.slen < PJ_MAX_HOSTNAME,
|
||||
PJ_ENAMETOOLONG);
|
||||
PJ_ASSERT_ON_FAIL(pkt->q[0].name.slen < PJ_MAX_HOSTNAME,
|
||||
{ pj_grp_lock_release(resolver->grp_lock); return PJ_ENAMETOOLONG; });
|
||||
|
||||
init_res_key(&key, pkt->q[0].type, &pkt->q[0].name);
|
||||
}
|
||||
|
@ -1942,12 +1942,12 @@ PJ_DEF(void) pj_dns_resolver_dump(pj_dns_resolver *resolver,
|
|||
}
|
||||
}
|
||||
PJ_LOG(3,(resolver->name.ptr, " Nb. of pending query free nodes: %lu",
|
||||
pj_list_size(&resolver->query_free_nodes)));
|
||||
(unsigned long)pj_list_size(&resolver->query_free_nodes)));
|
||||
PJ_LOG(3,(resolver->name.ptr, " Nb. of timer entries: %lu",
|
||||
pj_timer_heap_count(resolver->timer)));
|
||||
(unsigned long)pj_timer_heap_count(resolver->timer)));
|
||||
PJ_LOG(3,(resolver->name.ptr, " Pool capacity: %lu, used size: %lu",
|
||||
pj_pool_get_capacity(resolver->pool),
|
||||
pj_pool_get_used_size(resolver->pool)));
|
||||
(unsigned long)pj_pool_get_capacity(resolver->pool),
|
||||
(unsigned long)pj_pool_get_used_size(resolver->pool)));
|
||||
|
||||
pj_grp_lock_release(resolver->grp_lock);
|
||||
#endif
|
||||
|
|
|
@ -142,14 +142,17 @@ PJ_DEF(void) pj_scan_skip_whitespace( pj_scanner *scanner )
|
|||
{
|
||||
register char *s = scanner->curptr;
|
||||
|
||||
while (PJ_SCAN_IS_SPACE(*s)) {
|
||||
while (PJ_SCAN_CHECK_EOF(s) && PJ_SCAN_IS_SPACE(*s)) {
|
||||
++s;
|
||||
}
|
||||
|
||||
if (PJ_SCAN_IS_NEWLINE(*s) && (scanner->skip_ws & PJ_SCAN_AUTOSKIP_NEWLINE)) {
|
||||
for (;;) {
|
||||
if (PJ_SCAN_CHECK_EOF(s) && PJ_SCAN_IS_NEWLINE(*s) &&
|
||||
(scanner->skip_ws & PJ_SCAN_AUTOSKIP_NEWLINE))
|
||||
{
|
||||
for (; PJ_SCAN_CHECK_EOF(s); ) {
|
||||
if (*s == '\r') {
|
||||
++s;
|
||||
if (!PJ_SCAN_CHECK_EOF(s)) break;
|
||||
if (*s == '\n') ++s;
|
||||
++scanner->line;
|
||||
scanner->curptr = scanner->start_line = s;
|
||||
|
@ -160,30 +163,33 @@ PJ_DEF(void) pj_scan_skip_whitespace( pj_scanner *scanner )
|
|||
} else if (PJ_SCAN_IS_SPACE(*s)) {
|
||||
do {
|
||||
++s;
|
||||
} while (PJ_SCAN_IS_SPACE(*s));
|
||||
} while (PJ_SCAN_CHECK_EOF(s) && PJ_SCAN_IS_SPACE(*s));
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (PJ_SCAN_IS_NEWLINE(*s) && (scanner->skip_ws & PJ_SCAN_AUTOSKIP_WS_HEADER)==PJ_SCAN_AUTOSKIP_WS_HEADER) {
|
||||
if (PJ_SCAN_CHECK_EOF(s) && PJ_SCAN_IS_NEWLINE(*s) &&
|
||||
(scanner->skip_ws & PJ_SCAN_AUTOSKIP_WS_HEADER)==
|
||||
PJ_SCAN_AUTOSKIP_WS_HEADER)
|
||||
{
|
||||
/* Check for header continuation. */
|
||||
scanner->curptr = s;
|
||||
|
||||
if (*s == '\r') {
|
||||
++s;
|
||||
}
|
||||
if (*s == '\n') {
|
||||
if (PJ_SCAN_CHECK_EOF(s) && *s == '\n') {
|
||||
++s;
|
||||
}
|
||||
scanner->start_line = s;
|
||||
|
||||
if (PJ_SCAN_IS_SPACE(*s)) {
|
||||
if (PJ_SCAN_CHECK_EOF(s) && PJ_SCAN_IS_SPACE(*s)) {
|
||||
register char *t = s;
|
||||
do {
|
||||
++t;
|
||||
} while (PJ_SCAN_IS_SPACE(*t));
|
||||
} while (PJ_SCAN_CHECK_EOF(t) && PJ_SCAN_IS_SPACE(*t));
|
||||
|
||||
++scanner->line;
|
||||
scanner->curptr = t;
|
||||
|
@ -220,8 +226,7 @@ PJ_DEF(int) pj_scan_peek( pj_scanner *scanner,
|
|||
return -1;
|
||||
}
|
||||
|
||||
/* Don't need to check EOF with PJ_SCAN_CHECK_EOF(s) */
|
||||
while (pj_cis_match(spec, *s))
|
||||
while (PJ_SCAN_CHECK_EOF(s) && pj_cis_match(spec, *s))
|
||||
++s;
|
||||
|
||||
pj_strset3(out, scanner->curptr, s);
|
||||
|
@ -277,17 +282,15 @@ PJ_DEF(void) pj_scan_get( pj_scanner *scanner,
|
|||
|
||||
do {
|
||||
++s;
|
||||
} while (pj_cis_match(spec, *s));
|
||||
/* No need to check EOF here (PJ_SCAN_CHECK_EOF(s)) because
|
||||
* buffer is NULL terminated and pj_cis_match(spec,0) should be
|
||||
* false.
|
||||
*/
|
||||
} while (PJ_SCAN_CHECK_EOF(s) && pj_cis_match(spec, *s));
|
||||
|
||||
pj_strset3(out, scanner->curptr, s);
|
||||
|
||||
scanner->curptr = s;
|
||||
|
||||
if (PJ_SCAN_IS_PROBABLY_SPACE(*s) && scanner->skip_ws) {
|
||||
if (!pj_scan_is_eof(scanner) &&
|
||||
PJ_SCAN_IS_PROBABLY_SPACE(*s) && scanner->skip_ws)
|
||||
{
|
||||
pj_scan_skip_whitespace(scanner);
|
||||
}
|
||||
}
|
||||
|
@ -330,18 +333,20 @@ PJ_DEF(void) pj_scan_get_unescape( pj_scanner *scanner,
|
|||
char *start = s;
|
||||
do {
|
||||
++s;
|
||||
} while (pj_cis_match(spec, *s));
|
||||
} while (PJ_SCAN_CHECK_EOF(s) && pj_cis_match(spec, *s));
|
||||
|
||||
if (dst != start) pj_memmove(dst, start, s-start);
|
||||
dst += (s-start);
|
||||
}
|
||||
|
||||
} while (*s == '%');
|
||||
} while (PJ_SCAN_CHECK_EOF(s) && (*s == '%'));
|
||||
|
||||
scanner->curptr = s;
|
||||
out->slen = (dst - out->ptr);
|
||||
|
||||
if (PJ_SCAN_IS_PROBABLY_SPACE(*s) && scanner->skip_ws) {
|
||||
if (!pj_scan_is_eof(scanner) &&
|
||||
PJ_SCAN_IS_PROBABLY_SPACE(*s) && scanner->skip_ws)
|
||||
{
|
||||
pj_scan_skip_whitespace(scanner);
|
||||
}
|
||||
}
|
||||
|
@ -422,7 +427,9 @@ PJ_DEF(void) pj_scan_get_quotes(pj_scanner *scanner,
|
|||
|
||||
scanner->curptr = s;
|
||||
|
||||
if (PJ_SCAN_IS_PROBABLY_SPACE(*s) && scanner->skip_ws) {
|
||||
if (!pj_scan_is_eof(scanner) &&
|
||||
PJ_SCAN_IS_PROBABLY_SPACE(*s) && scanner->skip_ws)
|
||||
{
|
||||
pj_scan_skip_whitespace(scanner);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -76,7 +76,8 @@ PJ_DEF(pj_status_t) pjstun_parse_msg( void *buf, pj_size_t buf_len,
|
|||
msg_len = pj_ntohs(msg->hdr->length);
|
||||
if (msg_len != buf_len - sizeof(pjstun_msg_hdr)) {
|
||||
PJ_LOG(4,(THIS_FILE, "Error: invalid msg_len %d (expecting %lu)",
|
||||
msg_len, buf_len - sizeof(pjstun_msg_hdr)));
|
||||
msg_len, (unsigned long)
|
||||
(buf_len - sizeof(pjstun_msg_hdr))));
|
||||
return PJLIB_UTIL_ESTUNINMSGLEN;
|
||||
}
|
||||
|
||||
|
|
|
@ -345,8 +345,9 @@ PJ_DEF(pj_status_t) pjstun_get_mapped_addr2(pj_pool_factory *pf,
|
|||
}
|
||||
}
|
||||
|
||||
TRACE_((THIS_FILE, " Pool usage=%d of %d", pj_pool_get_used_size(pool),
|
||||
pj_pool_get_capacity(pool)));
|
||||
TRACE_((THIS_FILE, " Pool usage=%lu of %lu",
|
||||
(unsigned long)pj_pool_get_used_size(pool),
|
||||
(unsigned long)pj_pool_get_capacity(pool)));
|
||||
|
||||
pj_pool_release(pool);
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug-Dynamic|ARM">
|
||||
|
@ -998,6 +998,7 @@
|
|||
</ClCompile>
|
||||
<ClCompile Include="..\src\pj\ssl_sock_ossl.c" />
|
||||
<ClCompile Include="..\src\pj\ssl_sock_gtls.c" />
|
||||
<ClCompile Include="..\src\pj\ssl_sock_schannel.c" />
|
||||
<ClCompile Include="..\src\pj\string.c" />
|
||||
<ClCompile Include="..\src\pj\symbols.c">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug-Dynamic|Win32'">true</ExcludedFromBuild>
|
||||
|
|
|
@ -1077,6 +1077,9 @@
|
|||
/** Using Apple's Network framework */
|
||||
#define PJ_SSL_SOCK_IMP_APPLE 4
|
||||
|
||||
/** Using Windows's Schannel */
|
||||
#define PJ_SSL_SOCK_IMP_SCHANNEL 5
|
||||
|
||||
/**
|
||||
* Select which SSL socket implementation to use. Currently pjlib supports
|
||||
* PJ_SSL_SOCK_IMP_OPENSSL, which uses OpenSSL, and PJ_SSL_SOCK_IMP_GNUTLS,
|
||||
|
@ -1502,7 +1505,7 @@ PJ_BEGIN_DECL
|
|||
* Extra suffix for the version (e.g. "-trunk"), or empty for
|
||||
* web release version.
|
||||
*/
|
||||
#define PJ_VERSION_NUM_EXTRA ""
|
||||
#define PJ_VERSION_NUM_EXTRA "-dev"
|
||||
|
||||
/**
|
||||
* PJLIB version number consists of three bytes with the following format:
|
||||
|
|
|
@ -170,6 +170,27 @@ PJ_IDECL(void) pj_list_insert_nodes_after(pj_list_type *lst,
|
|||
pj_list_type *nodes);
|
||||
|
||||
|
||||
/**
|
||||
* Insert a list to another list before the specified element position.
|
||||
*
|
||||
* @param pos The element to which the node will be inserted before.
|
||||
* @param lst The list to be inserted.
|
||||
*/
|
||||
PJ_IDECL(void) pj_list_insert_list_before(pj_list_type *pos,
|
||||
pj_list_type *lst);
|
||||
|
||||
|
||||
/**
|
||||
* Insert a list to another list after the specified element position.
|
||||
*
|
||||
* @param pos The element in the list which will precede the inserted
|
||||
* list.
|
||||
* @param lst The list to be inserted.
|
||||
*/
|
||||
PJ_IDECL(void) pj_list_insert_list_after(pj_list_type *pos,
|
||||
pj_list_type *lst);
|
||||
|
||||
|
||||
/**
|
||||
* Remove elements from the source list, and insert them to the destination
|
||||
* list. The elements of the source list will occupy the
|
||||
|
|
|
@ -54,6 +54,23 @@ PJ_IDEF(void) pj_list_insert_nodes_before(pj_list_type *pos, pj_list_type *lst)
|
|||
pj_list_insert_nodes_after(((pj_list*)pos)->prev, lst);
|
||||
}
|
||||
|
||||
PJ_IDEF(void) pj_list_insert_list_after(pj_list_type *pos, pj_list_type *lst)
|
||||
{
|
||||
if (!pj_list_empty(lst)) {
|
||||
pj_list *lst_last = (pj_list *) ((pj_list*)lst)->prev;
|
||||
pj_list *pos_next = (pj_list *) ((pj_list*)pos)->next;
|
||||
|
||||
pj_link_node(pos, (pj_list *) ((pj_list*)lst)->next);
|
||||
pj_link_node(lst_last, pos_next);
|
||||
pj_list_init(lst);
|
||||
}
|
||||
}
|
||||
|
||||
PJ_IDEF(void) pj_list_insert_list_before(pj_list_type *pos, pj_list_type *lst)
|
||||
{
|
||||
pj_list_insert_list_after(((pj_list*)pos)->prev, lst);
|
||||
}
|
||||
|
||||
PJ_IDEF(void) pj_list_merge_last(pj_list_type *lst1, pj_list_type *lst2)
|
||||
{
|
||||
if (!pj_list_empty(lst2)) {
|
||||
|
|
|
@ -849,12 +849,16 @@ struct pj_caching_pool
|
|||
|
||||
/**
|
||||
* Total size of memory currently used by application.
|
||||
*
|
||||
* This field is deprecated.
|
||||
*/
|
||||
pj_size_t used_size;
|
||||
|
||||
/**
|
||||
* The maximum size of memory used by application throughout the life
|
||||
* of the caching pool.
|
||||
*
|
||||
* This field is deprecated.
|
||||
*/
|
||||
pj_size_t peak_used_size;
|
||||
|
||||
|
|
|
@ -117,6 +117,11 @@ typedef enum pj_ssl_cert_verify_flag_t
|
|||
*/
|
||||
PJ_SSL_CERT_ECHAIN_TOO_LONG = (1 << 8),
|
||||
|
||||
/**
|
||||
* The certificate signature is created using a weak hashing algorithm.
|
||||
*/
|
||||
PJ_SSL_CERT_EWEAK_SIGNATURE = (1 << 9),
|
||||
|
||||
/**
|
||||
* The server identity does not match to any identities specified in
|
||||
* the certificate, e.g: subjectAltName extension, subject common name.
|
||||
|
@ -145,6 +150,59 @@ typedef enum pj_ssl_cert_name_type
|
|||
PJ_SSL_CERT_NAME_IP
|
||||
} pj_ssl_cert_name_type;
|
||||
|
||||
/**
|
||||
* Field type for looking up SSL certificate in the certificate stores.
|
||||
*/
|
||||
typedef enum pj_ssl_cert_lookup_type
|
||||
{
|
||||
/**
|
||||
* No certificate to be looked up.
|
||||
*/
|
||||
PJ_SSL_CERT_LOOKUP_NONE,
|
||||
|
||||
/**
|
||||
* Lookup by subject, this will lookup any first certificate whose
|
||||
* subject containing the specified keyword. Note that subject may not
|
||||
* be unique in the store, so the lookup may end up selecting a wrong
|
||||
* certificate.
|
||||
*/
|
||||
PJ_SSL_CERT_LOOKUP_SUBJECT,
|
||||
|
||||
/**
|
||||
* Lookup by fingerprint/thumbprint (SHA1 hash), this will lookup
|
||||
* any first certificate whose fingerprint matching the specified
|
||||
* keyword. The keyword is an array of hash octets.
|
||||
*/
|
||||
PJ_SSL_CERT_LOOKUP_FINGERPRINT,
|
||||
|
||||
/**
|
||||
* Lookup by friendly name, this will lookup any first certificate
|
||||
* whose friendly name containing the specified keyword. Note that
|
||||
* friendly name may not be unique in the store, so the lookup may end up
|
||||
* selecting a wrong certificate.
|
||||
*/
|
||||
PJ_SSL_CERT_LOOKUP_FRIENDLY_NAME
|
||||
|
||||
} pj_ssl_cert_lookup_type;
|
||||
|
||||
/**
|
||||
* Describe structure of certificate lookup criteria.
|
||||
*/
|
||||
typedef struct pj_ssl_cert_lookup_criteria
|
||||
{
|
||||
/**
|
||||
* Certificate field type to look.
|
||||
*/
|
||||
pj_ssl_cert_lookup_type type;
|
||||
|
||||
/*
|
||||
* Keyword to match on the field specified in \a type.
|
||||
*/
|
||||
pj_str_t keyword;
|
||||
|
||||
} pj_ssl_cert_lookup_criteria;
|
||||
|
||||
|
||||
/**
|
||||
* Describe structure of certificate info.
|
||||
*/
|
||||
|
@ -273,6 +331,30 @@ PJ_DECL(pj_status_t) pj_ssl_cert_load_from_buffer(pj_pool_t *pool,
|
|||
const pj_str_t *privkey_pass,
|
||||
pj_ssl_cert_t **p_cert);
|
||||
|
||||
/**
|
||||
* Create credential from OS certificate store, this function will lookup
|
||||
* certificate using the specified criterias.
|
||||
*
|
||||
* Currently this is used by Windows Schannel backend only, it will lookup
|
||||
* in the Current User store first, if no certificate with the specified
|
||||
* criteria is not found, it will lookup in the Local Machine store.
|
||||
*
|
||||
* Note that for manual verification (e.g: when pj_ssl_sock_param.verify_peer
|
||||
* is disabled), the backend will provide pre-verification result against
|
||||
* trusted CA certificates in Current User store only (will not check CA
|
||||
* certificates in the Local Machine store).
|
||||
*
|
||||
* @param pool The pool.
|
||||
* @param criteria The lookup criteria.
|
||||
* @param p_cert Pointer to credential instance to be created.
|
||||
*
|
||||
* @return PJ_SUCCESS when successful.
|
||||
*/
|
||||
PJ_DECL(pj_status_t) pj_ssl_cert_load_from_store(
|
||||
pj_pool_t *pool,
|
||||
const pj_ssl_cert_lookup_criteria *criteria,
|
||||
pj_ssl_cert_t **p_cert);
|
||||
|
||||
/**
|
||||
* Dump SSL certificate info.
|
||||
*
|
||||
|
|
|
@ -143,6 +143,9 @@ static void activesock_destroy_iphone_os_stream(pj_activesock_t *asock)
|
|||
|
||||
static void activesock_create_iphone_os_stream(pj_activesock_t *asock)
|
||||
{
|
||||
#if (defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && \
|
||||
__IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_9_0)
|
||||
|
||||
if (ios_bg_support && asock->bg_setting && asock->stream_oriented) {
|
||||
activesock_destroy_iphone_os_stream(asock);
|
||||
|
||||
|
@ -164,6 +167,8 @@ static void activesock_create_iphone_os_stream(pj_activesock_t *asock)
|
|||
activesock_destroy_iphone_os_stream(asock);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
@ -508,7 +513,8 @@ static void ioqueue_on_read_complete(pj_ioqueue_key_t *key,
|
|||
ret = (*asock->cb.on_data_read)(asock, r->pkt, r->size,
|
||||
PJ_SUCCESS, &remainder);
|
||||
PJ_ASSERT_ON_FAIL(
|
||||
!asock->stream_oriented || remainder <= r->size, {
|
||||
!ret || !asock->stream_oriented || remainder <= r->size,
|
||||
{
|
||||
PJ_LOG(2, ("",
|
||||
"App bug! Invalid remainder length from "
|
||||
"activesock on_data_read()."));
|
||||
|
@ -584,7 +590,8 @@ static void ioqueue_on_read_complete(pj_ioqueue_key_t *key,
|
|||
ret = (*asock->cb.on_data_read)(asock, r->pkt, r->size,
|
||||
status, &remainder);
|
||||
PJ_ASSERT_ON_FAIL(
|
||||
!asock->stream_oriented || remainder <= r->size, {
|
||||
!ret || !asock->stream_oriented || remainder <= r->size,
|
||||
{
|
||||
PJ_LOG(2, ("",
|
||||
"App bug! Invalid remainder length from "
|
||||
"activesock on_data_read()."));
|
||||
|
|
|
@ -187,9 +187,9 @@ static pj_hash_entry **find_entry( pj_pool_t *pool, pj_hash_table_t *ht,
|
|||
|
||||
entry = PJ_POOL_ALLOC_T(pool, pj_hash_entry);
|
||||
PJ_LOG(6, ("hashtbl",
|
||||
"%p: New p_entry %p created, pool used=%u, cap=%u",
|
||||
ht, entry, pj_pool_get_used_size(pool),
|
||||
pj_pool_get_capacity(pool)));
|
||||
"%p: New p_entry %p created, pool used=%lu, cap=%lu",
|
||||
ht, entry, (unsigned long)pj_pool_get_used_size(pool),
|
||||
(unsigned long)pj_pool_get_capacity(pool)));
|
||||
}
|
||||
entry->next = NULL;
|
||||
entry->hash = hash;
|
||||
|
|
|
@ -1056,7 +1056,7 @@ retry_on_restart:
|
|||
/*
|
||||
* Check that address storage can hold the address parameter.
|
||||
*/
|
||||
PJ_ASSERT_RETURN(addrlen <= (int)sizeof(pj_sockaddr_in), PJ_EBUG);
|
||||
PJ_ASSERT_RETURN(addrlen <= (int)sizeof(pj_sockaddr), PJ_EBUG);
|
||||
|
||||
/*
|
||||
* Schedule asynchronous send.
|
||||
|
|
|
@ -63,7 +63,7 @@ struct write_operation
|
|||
pj_size_t size;
|
||||
pj_ssize_t written;
|
||||
unsigned flags;
|
||||
pj_sockaddr_in rmt_addr;
|
||||
pj_sockaddr rmt_addr;
|
||||
int rmt_addrlen;
|
||||
};
|
||||
|
||||
|
|
|
@ -495,6 +495,7 @@ PJ_DEF(pj_status_t) pj_ioqueue_destroy( pj_ioqueue_t *ioqueue )
|
|||
}
|
||||
#endif
|
||||
|
||||
pj_lock_release(ioqueue->lock);
|
||||
if (ioqueue->auto_delete_lock)
|
||||
pj_lock_destroy(ioqueue->lock);
|
||||
|
||||
|
|
|
@ -91,6 +91,7 @@ PJ_DEF(int) pj_run_app(pj_main_func_ptr main_func, int argc, char *argv[],
|
|||
param.main_func = main_func;
|
||||
if (pthread_create(&thread, NULL, &main_thread, ¶m) == 0) {
|
||||
CFRunLoopRun();
|
||||
pthread_join(thread, NULL);
|
||||
}
|
||||
|
||||
PJ_UNUSED_ARG(pool);
|
||||
|
|
|
@ -52,8 +52,9 @@ static pj_pool_block *pj_pool_create_block( pj_pool_t *pool, pj_size_t size)
|
|||
PJ_CHECK_STACK();
|
||||
pj_assert(size >= sizeof(pj_pool_block));
|
||||
|
||||
LOG((pool->obj_name, "create_block(sz=%u), cur.cap=%u, cur.used=%u",
|
||||
size, pool->capacity, pj_pool_get_used_size(pool)));
|
||||
LOG((pool->obj_name, "create_block(sz=%lu), cur.cap=%lu, cur.used=%lu",
|
||||
(unsigned long)size, (unsigned long)pool->capacity,
|
||||
(unsigned long)pj_pool_get_used_size(pool)));
|
||||
|
||||
/* Request memory from allocator. */
|
||||
block = (pj_pool_block*)
|
||||
|
@ -116,9 +117,10 @@ PJ_DEF(void*) pj_pool_allocate_find(pj_pool_t *pool, pj_size_t size)
|
|||
|
||||
/* If pool is configured NOT to expand, return error. */
|
||||
if (pool->increment_size == 0) {
|
||||
LOG((pool->obj_name, "Can't expand pool to allocate %u bytes "
|
||||
"(used=%u, cap=%u)",
|
||||
size, pj_pool_get_used_size(pool), pool->capacity));
|
||||
LOG((pool->obj_name, "Can't expand pool to allocate %lu bytes "
|
||||
"(used=%lu, cap=%lu)",
|
||||
(unsigned long)size, (unsigned long)pj_pool_get_used_size(pool),
|
||||
(unsigned long)pool->capacity));
|
||||
(*pool->callback)(pool, size);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -142,8 +144,10 @@ PJ_DEF(void*) pj_pool_allocate_find(pj_pool_t *pool, pj_size_t size)
|
|||
}
|
||||
|
||||
LOG((pool->obj_name,
|
||||
"%u bytes requested, resizing pool by %u bytes (used=%u, cap=%u)",
|
||||
size, block_size, pj_pool_get_used_size(pool), pool->capacity));
|
||||
"%lu bytes requested, resizing pool by %lu bytes (used=%lu, cap=%lu)",
|
||||
(unsigned long)size, (unsigned long)block_size,
|
||||
(unsigned long)pj_pool_get_used_size(pool),
|
||||
(unsigned long)pool->capacity));
|
||||
|
||||
block = pj_pool_create_block(pool, block_size);
|
||||
if (!block)
|
||||
|
@ -233,7 +237,8 @@ PJ_DEF(pj_pool_t*) pj_pool_create_int( pj_pool_factory *f, const char *name,
|
|||
/* Pool initial capacity and used size */
|
||||
pool->capacity = initial_size;
|
||||
|
||||
LOG((pool->obj_name, "pool created, size=%u", pool->capacity));
|
||||
LOG((pool->obj_name, "pool created, size=%lu",
|
||||
(unsigned long)pool->capacity));
|
||||
return pool;
|
||||
}
|
||||
|
||||
|
@ -278,9 +283,10 @@ static void reset_pool(pj_pool_t *pool)
|
|||
*/
|
||||
PJ_DEF(void) pj_pool_reset(pj_pool_t *pool)
|
||||
{
|
||||
LOG((pool->obj_name, "reset(): cap=%d, used=%d(%d%%)",
|
||||
pool->capacity, pj_pool_get_used_size(pool),
|
||||
pj_pool_get_used_size(pool)*100/pool->capacity));
|
||||
LOG((pool->obj_name, "reset(): cap=%lu, used=%lu(%lu%%)",
|
||||
(unsigned long)pool->capacity,
|
||||
(unsigned long)pj_pool_get_used_size(pool),
|
||||
(unsigned long)(pj_pool_get_used_size(pool)*100/pool->capacity)));
|
||||
|
||||
reset_pool(pool);
|
||||
}
|
||||
|
@ -292,9 +298,10 @@ PJ_DEF(void) pj_pool_destroy_int(pj_pool_t *pool)
|
|||
{
|
||||
pj_size_t initial_size;
|
||||
|
||||
LOG((pool->obj_name, "destroy(): cap=%d, used=%d(%d%%), block0=%p-%p",
|
||||
pool->capacity, pj_pool_get_used_size(pool),
|
||||
pj_pool_get_used_size(pool)*100/pool->capacity,
|
||||
LOG((pool->obj_name, "destroy(): cap=%lu, used=%lu(%lu%%), block0=%p-%p",
|
||||
(unsigned long)pool->capacity,
|
||||
(unsigned long)pj_pool_get_used_size(pool),
|
||||
(unsigned long)(pj_pool_get_used_size(pool)*100/pool->capacity),
|
||||
((pj_pool_block*)pool->block_list.next)->buf,
|
||||
((pj_pool_block*)pool->block_list.next)->end));
|
||||
|
||||
|
|
|
@ -75,8 +75,12 @@ PJ_DEF(void) pj_caching_pool_init( pj_caching_pool *cp,
|
|||
cp->factory.create_pool = &cpool_create_pool;
|
||||
cp->factory.release_pool = &cpool_release_pool;
|
||||
cp->factory.dump_status = &cpool_dump_status;
|
||||
cp->factory.on_block_alloc = &cpool_on_block_alloc;
|
||||
cp->factory.on_block_free = &cpool_on_block_free;
|
||||
|
||||
/* Deprecated, these callbacks are only used for updating cp.used_size &
|
||||
* cp.peak_used_size which are no longer used.
|
||||
*/
|
||||
//cp->factory.on_block_alloc = &cpool_on_block_alloc;
|
||||
//cp->factory.on_block_free = &cpool_on_block_free;
|
||||
|
||||
pool = pj_pool_create_on_buf("cachingpool", cp->pool_buf, sizeof(cp->pool_buf));
|
||||
status = pj_lock_create_simple_mutex(pool, "cachingpool", &cp->lock);
|
||||
|
@ -188,7 +192,8 @@ static pj_pool_t* cpool_create_pool(pj_pool_factory *pf,
|
|||
cp->capacity = 0;
|
||||
}
|
||||
|
||||
PJ_LOG(6, (pool->obj_name, "pool reused, size=%u", pool->capacity));
|
||||
PJ_LOG(6, (pool->obj_name, "pool reused, size=%lu",
|
||||
(unsigned long)pool->capacity));
|
||||
}
|
||||
|
||||
/* Put in used list. */
|
||||
|
@ -219,6 +224,7 @@ static void cpool_release_pool( pj_pool_factory *pf, pj_pool_t *pool)
|
|||
#if PJ_SAFE_POOL
|
||||
/* Make sure pool is still in our used list */
|
||||
if (pj_list_find_node(&cp->used_list, pool) != pool) {
|
||||
pj_lock_release(cp->lock);
|
||||
pj_assert(!"Attempt to destroy pool that has been destroyed before");
|
||||
return;
|
||||
}
|
||||
|
@ -245,9 +251,11 @@ static void cpool_release_pool( pj_pool_factory *pf, pj_pool_t *pool)
|
|||
}
|
||||
|
||||
/* Reset pool. */
|
||||
PJ_LOG(6, (pool->obj_name, "recycle(): cap=%d, used=%d(%d%%)",
|
||||
pool_capacity, pj_pool_get_used_size(pool),
|
||||
pj_pool_get_used_size(pool)*100/pool_capacity));
|
||||
PJ_LOG(6, (pool->obj_name, "recycle(): cap=%lu, used=%lu(%lu%%)",
|
||||
(unsigned long)pool_capacity,
|
||||
(unsigned long)pj_pool_get_used_size(pool),
|
||||
(unsigned long)(pj_pool_get_used_size(pool)*100/
|
||||
pool_capacity)));
|
||||
pj_pool_reset(pool);
|
||||
|
||||
pool_capacity = pj_pool_get_capacity(pool);
|
||||
|
@ -279,8 +287,9 @@ static void cpool_dump_status(pj_pool_factory *factory, pj_bool_t detail )
|
|||
pj_lock_acquire(cp->lock);
|
||||
|
||||
PJ_LOG(3,("cachpool", " Dumping caching pool:"));
|
||||
PJ_LOG(3,("cachpool", " Capacity=%lu, max_capacity=%lu, used_cnt=%lu", \
|
||||
cp->capacity, cp->max_capacity, cp->used_count));
|
||||
PJ_LOG(3,("cachpool", " Capacity=%lu, max_capacity=%lu, used_cnt=%lu",
|
||||
(unsigned long)cp->capacity, (unsigned long)cp->max_capacity,
|
||||
(unsigned long)cp->used_count));
|
||||
if (detail) {
|
||||
pj_pool_t *pool = (pj_pool_t*) cp->used_list.next;
|
||||
pj_size_t total_used = 0, total_capacity = 0;
|
||||
|
@ -294,7 +303,7 @@ static void cpool_dump_status(pj_pool_factory *factory, pj_bool_t detail )
|
|||
#if 0
|
||||
PJ_LOG(6, ("cachpool", " %16s block %u, size %ld",
|
||||
pj_pool_getobjname(pool), nblocks,
|
||||
block->end - block->buf + 1));
|
||||
(long)(block->end - block->buf + 1)));
|
||||
#endif
|
||||
nblocks++;
|
||||
block = block->next;
|
||||
|
@ -303,9 +312,10 @@ static void cpool_dump_status(pj_pool_factory *factory, pj_bool_t detail )
|
|||
PJ_LOG(3,("cachpool", " %16s: %8lu of %8lu (%lu%%) used, "
|
||||
"nblocks: %d",
|
||||
pj_pool_getobjname(pool),
|
||||
pj_pool_get_used_size(pool),
|
||||
pool_capacity,
|
||||
pj_pool_get_used_size(pool)*100/pool_capacity,
|
||||
(unsigned long)pj_pool_get_used_size(pool),
|
||||
(unsigned long)pool_capacity,
|
||||
(unsigned long)(pj_pool_get_used_size(pool)*
|
||||
100/pool_capacity),
|
||||
nblocks));
|
||||
|
||||
#if PJ_POOL_MAX_SEARCH_BLOCK_COUNT == 0
|
||||
|
@ -323,8 +333,10 @@ static void cpool_dump_status(pj_pool_factory *factory, pj_bool_t detail )
|
|||
}
|
||||
if (total_capacity) {
|
||||
PJ_LOG(3,("cachpool", " Total %9lu of %9lu (%lu %%) used!",
|
||||
total_used, total_capacity,
|
||||
total_used * 100 / total_capacity));
|
||||
(unsigned long)total_used,
|
||||
(unsigned long)total_capacity,
|
||||
(unsigned long)(total_used * 100 /
|
||||
total_capacity)));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -173,6 +173,10 @@ PJ_DEF(pj_status_t) pj_ssl_cert_get_verify_status_strings(
|
|||
case PJ_SSL_CERT_ECHAIN_TOO_LONG:
|
||||
p = "The certificate chain length is too long";
|
||||
break;
|
||||
case PJ_SSL_CERT_EWEAK_SIGNATURE:
|
||||
p = "The certificate signature is created using a weak hashing "
|
||||
"algorithm";
|
||||
break;
|
||||
case PJ_SSL_CERT_EIDENTITY_NOT_MATCH:
|
||||
p = "The server identity does not match to any identities "
|
||||
"specified in the certificate";
|
||||
|
|
|
@ -52,9 +52,22 @@ static pj_bool_t asock_on_data_sent (pj_activesock_t *asock,
|
|||
*******************************************************************
|
||||
*/
|
||||
|
||||
static pj_size_t next_pow2(pj_size_t n)
|
||||
{
|
||||
/* Next 32-bit power of two */
|
||||
pj_size_t power = 1;
|
||||
while (power < n && power < 0x8000000) {
|
||||
power <<= 1;
|
||||
}
|
||||
return power;
|
||||
}
|
||||
|
||||
static pj_status_t circ_init(pj_pool_factory *factory,
|
||||
circ_buf_t *cb, pj_size_t cap)
|
||||
{
|
||||
/* Round-up cap */
|
||||
cap = next_pow2(cap);
|
||||
|
||||
cb->cap = cap;
|
||||
cb->readp = 0;
|
||||
cb->writep = 0;
|
||||
|
@ -68,17 +81,24 @@ static pj_status_t circ_init(pj_pool_factory *factory,
|
|||
/* Allocate circular buffer */
|
||||
cb->buf = pj_pool_alloc(cb->pool, cap);
|
||||
if (!cb->buf) {
|
||||
pj_pool_release(cb->pool);
|
||||
pj_pool_secure_release(&cb->pool);
|
||||
return PJ_ENOMEM;
|
||||
}
|
||||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
static void circ_reset(circ_buf_t* cb)
|
||||
{
|
||||
cb->readp = 0;
|
||||
cb->writep = 0;
|
||||
cb->size = 0;
|
||||
}
|
||||
|
||||
static void circ_deinit(circ_buf_t *cb)
|
||||
{
|
||||
if (cb->pool) {
|
||||
pj_pool_release(cb->pool);
|
||||
pj_pool_secure_release(&cb->pool);
|
||||
cb->pool = NULL;
|
||||
}
|
||||
}
|
||||
|
@ -104,6 +124,8 @@ static void circ_read(circ_buf_t *cb, pj_uint8_t *dst, pj_size_t len)
|
|||
pj_size_t tbc = PJ_MIN(size_after, len);
|
||||
pj_size_t rem = len - tbc;
|
||||
|
||||
pj_assert(cb->size >= len);
|
||||
|
||||
pj_memcpy(dst, cb->buf + cb->readp, tbc);
|
||||
pj_memcpy(dst + tbc, cb->buf, rem);
|
||||
|
||||
|
@ -113,6 +135,21 @@ static void circ_read(circ_buf_t *cb, pj_uint8_t *dst, pj_size_t len)
|
|||
cb->size -= len;
|
||||
}
|
||||
|
||||
/* Cancel previous read, partially or fully.
|
||||
* Should be called in the same mutex block as circ_read().
|
||||
*/
|
||||
static void circ_read_cancel(circ_buf_t* cb, pj_size_t len)
|
||||
{
|
||||
pj_assert(cb->cap - cb->size >= len);
|
||||
|
||||
if (cb->readp < len)
|
||||
cb->readp = cb->cap - (len - cb->readp);
|
||||
else
|
||||
cb->readp -= len;
|
||||
|
||||
cb->size += len;
|
||||
}
|
||||
|
||||
static pj_status_t circ_write(circ_buf_t *cb,
|
||||
const pj_uint8_t *src, pj_size_t len)
|
||||
{
|
||||
|
@ -121,14 +158,8 @@ static pj_status_t circ_write(circ_buf_t *cb,
|
|||
/* Minimum required capacity */
|
||||
pj_size_t min_cap = len + cb->size;
|
||||
|
||||
/* Next 32-bit power of two */
|
||||
min_cap--;
|
||||
min_cap |= min_cap >> 1;
|
||||
min_cap |= min_cap >> 2;
|
||||
min_cap |= min_cap >> 4;
|
||||
min_cap |= min_cap >> 8;
|
||||
min_cap |= min_cap >> 16;
|
||||
min_cap++;
|
||||
/* Round-up minimum capacity */
|
||||
min_cap = next_pow2(min_cap);
|
||||
|
||||
/* Create a new pool to hold a bigger buffer, using the same factory */
|
||||
pj_pool_t *pool = pj_pool_create(cb->pool->factory, "tls-circ%p",
|
||||
|
@ -153,7 +184,7 @@ static pj_status_t circ_write(circ_buf_t *cb,
|
|||
cb->size = old_size;
|
||||
|
||||
/* Release the previous pool */
|
||||
pj_pool_release(cb->pool);
|
||||
pj_pool_secure_release(&cb->pool);
|
||||
|
||||
/* Update circular buffer members */
|
||||
cb->pool = pool;
|
||||
|
@ -1737,7 +1768,7 @@ static pj_status_t ssl_send (pj_ssl_sock_t *ssock,
|
|||
unsigned flags)
|
||||
{
|
||||
pj_status_t status;
|
||||
int nwritten;
|
||||
int nwritten = 0;
|
||||
|
||||
/* Write the plain data to SSL, after SSL encrypts it, the buffer will
|
||||
* contain the secured data to be sent via socket. Note that re-
|
||||
|
@ -2241,8 +2272,9 @@ static void wipe_buf(pj_str_t *buf)
|
|||
}
|
||||
|
||||
PJ_DEF(void) pj_ssl_cert_wipe_keys(pj_ssl_cert_t *cert)
|
||||
{
|
||||
{
|
||||
if (cert) {
|
||||
#if (PJ_SSL_SOCK_IMP != PJ_SSL_SOCK_IMP_SCHANNEL)
|
||||
wipe_buf(&cert->CA_file);
|
||||
wipe_buf(&cert->CA_path);
|
||||
wipe_buf(&cert->cert_file);
|
||||
|
@ -2251,6 +2283,10 @@ PJ_DEF(void) pj_ssl_cert_wipe_keys(pj_ssl_cert_t *cert)
|
|||
wipe_buf(&cert->CA_buf);
|
||||
wipe_buf(&cert->cert_buf);
|
||||
wipe_buf(&cert->privkey_buf);
|
||||
#else
|
||||
cert->criteria.type = PJ_SSL_CERT_LOOKUP_NONE;
|
||||
wipe_buf(&cert->criteria.keyword);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2274,6 +2310,7 @@ PJ_DEF(pj_status_t) pj_ssl_cert_load_from_files2(pj_pool_t *pool,
|
|||
const pj_str_t *privkey_pass,
|
||||
pj_ssl_cert_t **p_cert)
|
||||
{
|
||||
#if (PJ_SSL_SOCK_IMP != PJ_SSL_SOCK_IMP_SCHANNEL)
|
||||
pj_ssl_cert_t *cert;
|
||||
|
||||
PJ_ASSERT_RETURN(pool && (CA_file || CA_path) && cert_file &&
|
||||
|
@ -2294,6 +2331,16 @@ PJ_DEF(pj_status_t) pj_ssl_cert_load_from_files2(pj_pool_t *pool,
|
|||
*p_cert = cert;
|
||||
|
||||
return PJ_SUCCESS;
|
||||
#else
|
||||
PJ_UNUSED_ARG(pool);
|
||||
PJ_UNUSED_ARG(CA_file);
|
||||
PJ_UNUSED_ARG(CA_path);
|
||||
PJ_UNUSED_ARG(cert_file);
|
||||
PJ_UNUSED_ARG(privkey_file);
|
||||
PJ_UNUSED_ARG(privkey_pass);
|
||||
PJ_UNUSED_ARG(p_cert);
|
||||
return PJ_ENOTSUP;
|
||||
#endif
|
||||
}
|
||||
|
||||
PJ_DEF(pj_status_t) pj_ssl_cert_load_from_buffer(pj_pool_t *pool,
|
||||
|
@ -2303,6 +2350,7 @@ PJ_DEF(pj_status_t) pj_ssl_cert_load_from_buffer(pj_pool_t *pool,
|
|||
const pj_str_t *privkey_pass,
|
||||
pj_ssl_cert_t **p_cert)
|
||||
{
|
||||
#if (PJ_SSL_SOCK_IMP != PJ_SSL_SOCK_IMP_SCHANNEL)
|
||||
pj_ssl_cert_t *cert;
|
||||
|
||||
PJ_ASSERT_RETURN(pool && CA_buf && cert_buf && privkey_buf, PJ_EINVAL);
|
||||
|
@ -2316,8 +2364,44 @@ PJ_DEF(pj_status_t) pj_ssl_cert_load_from_buffer(pj_pool_t *pool,
|
|||
*p_cert = cert;
|
||||
|
||||
return PJ_SUCCESS;
|
||||
#else
|
||||
PJ_UNUSED_ARG(pool);
|
||||
PJ_UNUSED_ARG(CA_buf);
|
||||
PJ_UNUSED_ARG(cert_buf);
|
||||
PJ_UNUSED_ARG(privkey_buf);
|
||||
PJ_UNUSED_ARG(privkey_pass);
|
||||
PJ_UNUSED_ARG(p_cert);
|
||||
return PJ_ENOTSUP;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
PJ_DEF(pj_status_t) pj_ssl_cert_load_from_store(
|
||||
pj_pool_t *pool,
|
||||
const pj_ssl_cert_lookup_criteria *criteria,
|
||||
pj_ssl_cert_t **p_cert)
|
||||
{
|
||||
#if (PJ_SSL_SOCK_IMP == PJ_SSL_SOCK_IMP_SCHANNEL)
|
||||
pj_ssl_cert_t *cert;
|
||||
|
||||
PJ_ASSERT_RETURN(pool && criteria && p_cert, PJ_EINVAL);
|
||||
|
||||
cert = PJ_POOL_ZALLOC_T(pool, pj_ssl_cert_t);
|
||||
pj_memcpy(&cert->criteria, criteria, sizeof(*criteria));
|
||||
pj_strdup_with_null(pool, &cert->criteria.keyword, &criteria->keyword);
|
||||
|
||||
*p_cert = cert;
|
||||
|
||||
return PJ_SUCCESS;
|
||||
#else
|
||||
PJ_UNUSED_ARG(pool);
|
||||
PJ_UNUSED_ARG(criteria);
|
||||
PJ_UNUSED_ARG(p_cert);
|
||||
return PJ_ENOTSUP;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/* Set SSL socket credentials. */
|
||||
PJ_DEF(pj_status_t) pj_ssl_sock_set_certificate(
|
||||
pj_ssl_sock_t *ssock,
|
||||
|
@ -2330,6 +2414,8 @@ PJ_DEF(pj_status_t) pj_ssl_sock_set_certificate(
|
|||
|
||||
cert_ = PJ_POOL_ZALLOC_T(pool, pj_ssl_cert_t);
|
||||
pj_memcpy(cert_, cert, sizeof(pj_ssl_cert_t));
|
||||
|
||||
#if (PJ_SSL_SOCK_IMP != PJ_SSL_SOCK_IMP_SCHANNEL)
|
||||
pj_strdup_with_null(pool, &cert_->CA_file, &cert->CA_file);
|
||||
pj_strdup_with_null(pool, &cert_->CA_path, &cert->CA_path);
|
||||
pj_strdup_with_null(pool, &cert_->cert_file, &cert->cert_file);
|
||||
|
@ -2339,6 +2425,10 @@ PJ_DEF(pj_status_t) pj_ssl_sock_set_certificate(
|
|||
pj_strdup(pool, &cert_->CA_buf, &cert->CA_buf);
|
||||
pj_strdup(pool, &cert_->cert_buf, &cert->cert_buf);
|
||||
pj_strdup(pool, &cert_->privkey_buf, &cert->privkey_buf);
|
||||
#else
|
||||
pj_strdup_with_null(pool, &cert_->criteria.keyword,
|
||||
&cert->criteria.keyword);
|
||||
#endif
|
||||
|
||||
ssock->cert = cert_;
|
||||
|
||||
|
|
|
@ -152,6 +152,7 @@ struct pj_ssl_sock_t
|
|||
*/
|
||||
struct pj_ssl_cert_t
|
||||
{
|
||||
#if (PJ_SSL_SOCK_IMP != PJ_SSL_SOCK_IMP_SCHANNEL)
|
||||
pj_str_t CA_file;
|
||||
pj_str_t CA_path;
|
||||
pj_str_t cert_file;
|
||||
|
@ -162,6 +163,9 @@ struct pj_ssl_cert_t
|
|||
pj_ssl_cert_buffer CA_buf;
|
||||
pj_ssl_cert_buffer cert_buf;
|
||||
pj_ssl_cert_buffer privkey_buf;
|
||||
#else
|
||||
pj_ssl_cert_lookup_criteria criteria;
|
||||
#endif
|
||||
};
|
||||
|
||||
/* ssl available ciphers */
|
||||
|
@ -205,9 +209,11 @@ static pj_status_t flush_delayed_send(pj_ssl_sock_t *ssock);
|
|||
static pj_status_t circ_init(pj_pool_factory *factory,
|
||||
circ_buf_t *cb, pj_size_t cap);
|
||||
static void circ_deinit(circ_buf_t *cb);
|
||||
static void circ_reset(circ_buf_t* cb);
|
||||
static pj_bool_t circ_empty(const circ_buf_t *cb);
|
||||
static pj_size_t circ_size(const circ_buf_t *cb);
|
||||
static void circ_read(circ_buf_t *cb, pj_uint8_t *dst, pj_size_t len);
|
||||
static void circ_read_cancel(circ_buf_t* cb, pj_size_t len);
|
||||
static pj_status_t circ_write(circ_buf_t *cb,
|
||||
const pj_uint8_t *src, pj_size_t len);
|
||||
|
||||
|
|
|
@ -159,10 +159,12 @@ static void update_certs_info(pj_ssl_sock_t* ssock,
|
|||
pj_ssl_cert_info *remote_cert_info,
|
||||
pj_bool_t is_verify);
|
||||
|
||||
#if !USING_LIBRESSL && OPENSSL_VERSION_NUMBER >= 0x10100000L
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
|
||||
# define OPENSSL_NO_SSL2 /* seems to be removed in 1.1.0 */
|
||||
# ifndef M_ASN1_STRING_data
|
||||
# define M_ASN1_STRING_data(x) ASN1_STRING_get0_data(x)
|
||||
# define M_ASN1_STRING_length(x) ASN1_STRING_length(x)
|
||||
# endif
|
||||
# if defined(OPENSSL_API_COMPAT) && OPENSSL_API_COMPAT >= 0x10100000L || \
|
||||
defined(OPENSSL_NO_DEPRECATED)
|
||||
|
||||
|
@ -179,7 +181,7 @@ static void update_certs_info(pj_ssl_sock_t* ssock,
|
|||
# endif
|
||||
|
||||
# endif
|
||||
#elif !USING_LIBRESSL
|
||||
#else
|
||||
# define SSL_CIPHER_get_id(c) (c)->id
|
||||
# define SSL_set_session(ssl, s) (ssl)->session = (s)
|
||||
# define X509_STORE_CTX_get0_cert(ctx) ((ctx)->cert)
|
||||
|
@ -481,11 +483,12 @@ static pj_str_t ssl_strerror(pj_status_t status,
|
|||
*/
|
||||
static const struct ssl_ciphers_t ADDITIONAL_CIPHERS[] = {
|
||||
{0xFF000000, "DEFAULT"},
|
||||
{0xFF000001, "@SECLEVEL=1"},
|
||||
{0xFF000002, "@SECLEVEL=2"},
|
||||
{0xFF000003, "@SECLEVEL=3"},
|
||||
{0xFF000004, "@SECLEVEL=4"},
|
||||
{0xFF000005, "@SECLEVEL=5"}
|
||||
{0xFF000001, "@SECLEVEL=0"},
|
||||
{0xFF000002, "@SECLEVEL=1"},
|
||||
{0xFF000003, "@SECLEVEL=2"},
|
||||
{0xFF000004, "@SECLEVEL=3"},
|
||||
{0xFF000005, "@SECLEVEL=4"},
|
||||
{0xFF000006, "@SECLEVEL=5"}
|
||||
};
|
||||
static const unsigned int ADDITIONAL_CIPHER_COUNT =
|
||||
sizeof (ADDITIONAL_CIPHERS) / sizeof (ADDITIONAL_CIPHERS[0]);
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -381,8 +381,9 @@ static pj_status_t grow_heap(pj_timer_heap_t *ht)
|
|||
pj_timer_entry_dup *new_dup;
|
||||
#endif
|
||||
|
||||
PJ_LOG(6,(THIS_FILE, "Growing heap size from %d to %d",
|
||||
ht->max_size, new_size));
|
||||
PJ_LOG(6,(THIS_FILE, "Growing heap size from %lu to %lu",
|
||||
(unsigned long)ht->max_size,
|
||||
(unsigned long)new_size));
|
||||
|
||||
// First grow the heap itself.
|
||||
new_heap = (pj_timer_entry_dup**)
|
||||
|
@ -533,11 +534,14 @@ static int cancel( pj_timer_heap_t *ht,
|
|||
|
||||
PJ_CHECK_STACK();
|
||||
|
||||
// Check to see if the timer_id is out of range
|
||||
// Check to see if the timer_id is out of range.
|
||||
// Moved to cancel_timer() as it needs to validate _timer_id earlier
|
||||
/*
|
||||
if (entry->_timer_id < 1 || (pj_size_t)entry->_timer_id >= ht->max_size) {
|
||||
entry->_timer_id = -1;
|
||||
return 0;
|
||||
}
|
||||
*/
|
||||
|
||||
timer_node_slot = ht->timer_ids[entry->_timer_id];
|
||||
|
||||
|
@ -810,6 +814,13 @@ static int cancel_timer(pj_timer_heap_t *ht,
|
|||
PJ_ASSERT_RETURN(ht && entry, PJ_EINVAL);
|
||||
|
||||
lock_timer_heap(ht);
|
||||
|
||||
// Check to see if the timer_id is out of range
|
||||
if (entry->_timer_id < 1 || (pj_size_t)entry->_timer_id >= ht->max_size) {
|
||||
unlock_timer_heap(ht);
|
||||
return 0;
|
||||
}
|
||||
|
||||
timer_copy = GET_TIMER(ht, entry);
|
||||
grp_lock = timer_copy->_grp_lock;
|
||||
|
||||
|
|
|
@ -121,8 +121,8 @@ static void on_read_complete(pj_ioqueue_key_t *key,
|
|||
PJ_LOG(3,(THIS_FILE,
|
||||
".....additional info: type=%s, total read=%lu, "
|
||||
"total sent=%lu",
|
||||
item->type_name, item->bytes_recv,
|
||||
item->bytes_sent));
|
||||
item->type_name, (unsigned long)item->bytes_recv,
|
||||
(unsigned long)item->bytes_sent));
|
||||
}
|
||||
} else {
|
||||
last_error_counter++;
|
||||
|
@ -480,8 +480,10 @@ static int perform_test(const pj_ioqueue_cfg *cfg,
|
|||
if (display_report) {
|
||||
PJ_LOG(3,(THIS_FILE, " %s %d threads, %d pairs", type_name,
|
||||
thread_cnt, sockpair_cnt));
|
||||
PJ_LOG(3,(THIS_FILE, " Elapsed : %lu msec", total_elapsed_usec/1000));
|
||||
PJ_LOG(3,(THIS_FILE, " Bandwidth: %lu KB/s", *p_bandwidth));
|
||||
PJ_LOG(3,(THIS_FILE, " Elapsed : %lu msec",
|
||||
(unsigned long)(total_elapsed_usec/1000)));
|
||||
PJ_LOG(3,(THIS_FILE, " Bandwidth: %lu KB/s",
|
||||
(unsigned long)*p_bandwidth));
|
||||
PJ_LOG(3,(THIS_FILE, " Threads statistics:"));
|
||||
PJ_LOG(3,(THIS_FILE, " ============================="));
|
||||
PJ_LOG(3,(THIS_FILE, " Thread Loops Events Errors"));
|
||||
|
@ -506,7 +508,7 @@ static int perform_test(const pj_ioqueue_cfg *cfg,
|
|||
} else {
|
||||
PJ_LOG(3,(THIS_FILE, " %.4s %2d %2d %8lu KB/s",
|
||||
type_name, thread_cnt, sockpair_cnt,
|
||||
*p_bandwidth));
|
||||
(unsigned long)*p_bandwidth));
|
||||
}
|
||||
|
||||
/* Done. */
|
||||
|
@ -578,7 +580,7 @@ static int ioqueue_perf_test_imp(const pj_ioqueue_cfg *cfg)
|
|||
test_param[best_index].type_name,
|
||||
test_param[best_index].thread_cnt,
|
||||
test_param[best_index].sockpair_cnt,
|
||||
best_bandwidth));
|
||||
(unsigned long)best_bandwidth));
|
||||
PJ_LOG(3,(THIS_FILE, " (Note: packet size=%d, total errors=%u)",
|
||||
BUF_SIZE, last_error_counter));
|
||||
return 0;
|
||||
|
|
|
@ -69,7 +69,7 @@ static int capacity_test(void)
|
|||
|
||||
if (pj_pool_alloc(pool, freesize) == NULL) {
|
||||
PJ_LOG(3,("test", "...error: wrong freesize %lu reported",
|
||||
freesize));
|
||||
(unsigned long)freesize));
|
||||
pj_pool_release(pool);
|
||||
return -210;
|
||||
}
|
||||
|
@ -175,7 +175,8 @@ static int drain_test(pj_size_t size, pj_size_t increment)
|
|||
void *p;
|
||||
int status = 0;
|
||||
|
||||
PJ_LOG(3,("test", "...drain_test(%lu,%lu)", size, increment));
|
||||
PJ_LOG(3,("test", "...drain_test(%lu,%lu)", (unsigned long)size,
|
||||
(unsigned long)increment));
|
||||
|
||||
if (!pool)
|
||||
return -10;
|
||||
|
@ -208,7 +209,7 @@ static int drain_test(pj_size_t size, pj_size_t increment)
|
|||
/* Check that capacity is zero. */
|
||||
if (GET_FREE(pool) != 0) {
|
||||
PJ_LOG(3,("test", "....error: returned free=%lu (expecting 0)",
|
||||
GET_FREE(pool)));
|
||||
(unsigned long)(GET_FREE(pool))));
|
||||
status=-30; goto on_error;
|
||||
}
|
||||
|
||||
|
|
|
@ -541,14 +541,15 @@ static int send_recv_test(int sock_type,
|
|||
rc = -155; goto on_error;
|
||||
}
|
||||
if (received <= 0) {
|
||||
PJ_LOG(3,("", "...error: socket has closed! (received=%ld)",
|
||||
received));
|
||||
PJ_LOG(3,("", "...error: socket has closed! (received=%lu)",
|
||||
(unsigned long)received));
|
||||
rc = -156; goto on_error;
|
||||
}
|
||||
if (received != DATA_LEN-total_received) {
|
||||
if (sock_type != pj_SOCK_STREAM()) {
|
||||
PJ_LOG(3,("", "...error: expecting %lu bytes, got %lu bytes",
|
||||
DATA_LEN-total_received, received));
|
||||
(unsigned long)(DATA_LEN-total_received),
|
||||
(unsigned long)received));
|
||||
rc = -157; goto on_error;
|
||||
}
|
||||
}
|
||||
|
@ -599,14 +600,15 @@ static int send_recv_test(int sock_type,
|
|||
rc = -170; goto on_error;
|
||||
}
|
||||
if (received <= 0) {
|
||||
PJ_LOG(3,("", "...error: socket has closed! (received=%ld)",
|
||||
received));
|
||||
PJ_LOG(3,("", "...error: socket has closed! (received=%lu)",
|
||||
(unsigned long)received));
|
||||
rc = -173; goto on_error;
|
||||
}
|
||||
if (received != BIG_DATA_LEN-total_received) {
|
||||
if (sock_type != pj_SOCK_STREAM()) {
|
||||
PJ_LOG(3,("", "...error: expecting %lu bytes, got %lu bytes",
|
||||
BIG_DATA_LEN-total_received, received));
|
||||
(unsigned long)BIG_DATA_LEN-total_received,
|
||||
(unsigned long)received));
|
||||
rc = -176; goto on_error;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -350,7 +350,8 @@ static pj_bool_t ssl_on_data_read(pj_ssl_sock_t *ssock,
|
|||
}
|
||||
|
||||
pj_sockaddr_print((pj_sockaddr_t*)&info.local_addr, buf, sizeof(buf), 1);
|
||||
PJ_LOG(3, ("", "...%s successfully recv %lu bytes echo", buf, st->recv));
|
||||
PJ_LOG(3, ("", "...%s successfully recv %lu bytes echo", buf,
|
||||
(unsigned long)st->recv));
|
||||
st->done = PJ_TRUE;
|
||||
}
|
||||
}
|
||||
|
@ -501,7 +502,8 @@ static int https_client_test(unsigned ms_timeout)
|
|||
}
|
||||
|
||||
PJ_LOG(3, ("", "...Done!"));
|
||||
PJ_LOG(3, ("", ".....Sent/recv: %lu/%lu bytes", state.sent, state.recv));
|
||||
PJ_LOG(3, ("", ".....Sent/recv: %lu/%lu bytes", (unsigned long)state.sent,
|
||||
(unsigned long)state.recv));
|
||||
|
||||
on_return:
|
||||
if (ssock && !state.err && !state.done)
|
||||
|
@ -538,6 +540,39 @@ static pj_status_t load_cert_to_buf(pj_pool_t *pool, const pj_str_t *file_name,
|
|||
}
|
||||
#endif
|
||||
|
||||
static pj_status_t load_cert_from_store(pj_pool_t *pool,
|
||||
pj_ssl_cert_t **p_cert)
|
||||
{
|
||||
#if 0
|
||||
/* To test loading certificate from the store, follow these steps:
|
||||
* 1. Install the certificate & the private-key pair to the store,
|
||||
* and optionally set the friendly-name for it.
|
||||
* 2. Update the lookup criteria below (field & keyword).
|
||||
*/
|
||||
pj_ssl_cert_lookup_criteria crit = {0};
|
||||
|
||||
/* Lookup by subject */
|
||||
crit.type = PJ_SSL_CERT_LOOKUP_SUBJECT;
|
||||
pj_cstr(&crit.keyword, "test.pjsip.org");
|
||||
|
||||
/* Lookup by friendly-name */
|
||||
//crit.type = PJ_SSL_CERT_LOOKUP_FRIENDLY_NAME;
|
||||
//pj_cstr(&crit.keyword, "schannel-test");
|
||||
|
||||
/* Lookup by fingerprint */
|
||||
//crit.type = PJ_SSL_CERT_LOOKUP_FINGERPRINT;
|
||||
//pj_cstr(&crit.keyword, "\x08\x3a\x6c\xdc\xd0\x19\x59\xec\x28\xc3"
|
||||
// "\x81\xb8\xc0\x21\x09\xe9\xd5\xf6\x57\x7d");
|
||||
|
||||
return pj_ssl_cert_load_from_store(pool, &crit, p_cert);
|
||||
#else
|
||||
/* Set no certificate, Schannel will use self-signed cert */
|
||||
PJ_UNUSED_ARG(pool);
|
||||
PJ_UNUSED_ARG(p_cert);
|
||||
return PJ_ENOTFOUND;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int echo_test(pj_ssl_sock_proto srv_proto, pj_ssl_sock_proto cli_proto,
|
||||
pj_ssl_cipher srv_cipher, pj_ssl_cipher cli_cipher,
|
||||
pj_bool_t req_client_cert, pj_bool_t client_provide_cert)
|
||||
|
@ -600,6 +635,19 @@ static int echo_test(pj_ssl_sock_proto srv_proto, pj_ssl_sock_proto cli_proto,
|
|||
}
|
||||
|
||||
/* Set server cert */
|
||||
#if (PJ_SSL_SOCK_IMP == PJ_SSL_SOCK_IMP_SCHANNEL)
|
||||
/* Schannel backend currently can only load certificates from
|
||||
* OS cert store. If the certificate loading fails, we'll skip setting
|
||||
* certificate, so the SSL socket will create & use a self-signed cert.
|
||||
*/
|
||||
status = load_cert_from_store(pool, &cert);
|
||||
if (status == PJ_SUCCESS) {
|
||||
status = pj_ssl_sock_set_certificate(ssock_serv, pool, cert);
|
||||
if (status != PJ_SUCCESS) {
|
||||
goto on_return;
|
||||
}
|
||||
}
|
||||
#else
|
||||
{
|
||||
pj_str_t ca_file = pj_str(CERT_CA_FILE);
|
||||
pj_str_t cert_file = pj_str(CERT_FILE);
|
||||
|
@ -641,6 +689,7 @@ static int echo_test(pj_ssl_sock_proto srv_proto, pj_ssl_sock_proto cli_proto,
|
|||
goto on_return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
status = pj_ssl_sock_start_accept(ssock_serv, pool, &addr, pj_sockaddr_get_len(&addr));
|
||||
if (status != PJ_SUCCESS) {
|
||||
|
@ -684,9 +733,22 @@ static int echo_test(pj_ssl_sock_proto srv_proto, pj_ssl_sock_proto cli_proto,
|
|||
goto on_return;
|
||||
}
|
||||
|
||||
/* Set cert for client */
|
||||
{
|
||||
/* Set cert for client.
|
||||
* Reusing certificate for server above, but if client_provide_cert
|
||||
* is not set, override the certificate with CA certificate.
|
||||
*/
|
||||
#if (PJ_SSL_SOCK_IMP == PJ_SSL_SOCK_IMP_SCHANNEL)
|
||||
if (client_provide_cert) {
|
||||
status = load_cert_from_store(pool, &cert);
|
||||
if (status == PJ_SUCCESS)
|
||||
status = pj_ssl_sock_set_certificate(ssock_cli, pool, cert);
|
||||
|
||||
if (status != PJ_SUCCESS) {
|
||||
goto on_return;
|
||||
}
|
||||
}
|
||||
#else
|
||||
{
|
||||
if (!client_provide_cert) {
|
||||
pj_str_t ca_file = pj_str(CERT_CA_FILE);
|
||||
pj_str_t null_str = pj_str("");
|
||||
|
@ -718,6 +780,7 @@ static int echo_test(pj_ssl_sock_proto srv_proto, pj_ssl_sock_proto cli_proto,
|
|||
goto on_return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
status = pj_ssl_sock_start_connect(ssock_cli, pool, &addr, &listen_addr, pj_sockaddr_get_len(&addr));
|
||||
if (status == PJ_SUCCESS) {
|
||||
|
@ -755,7 +818,8 @@ static int echo_test(pj_ssl_sock_proto srv_proto, pj_ssl_sock_proto cli_proto,
|
|||
}
|
||||
|
||||
PJ_LOG(3, ("", "...Done!"));
|
||||
PJ_LOG(3, ("", ".....Sent/recv: %lu/%lu bytes", state_cli.sent, state_cli.recv));
|
||||
PJ_LOG(3, ("", ".....Sent/recv: %lu/%lu bytes", (unsigned long)state_cli.sent,
|
||||
(unsigned long)state_cli.recv));
|
||||
|
||||
on_return:
|
||||
#if (PJ_SSL_SOCK_IMP == PJ_SSL_SOCK_IMP_DARWIN) || \
|
||||
|
@ -923,7 +987,41 @@ static int client_non_ssl(unsigned ms_timeout)
|
|||
goto on_return;
|
||||
}
|
||||
|
||||
pj_ssl_sock_param_default(¶m);
|
||||
param.cb.on_accept_complete2 = &ssl_on_accept_complete;
|
||||
param.cb.on_data_read = &ssl_on_data_read;
|
||||
param.cb.on_data_sent = &ssl_on_data_sent;
|
||||
param.ioqueue = ioqueue;
|
||||
param.timer_heap = timer;
|
||||
param.timeout.sec = 0;
|
||||
param.timeout.msec = ms_timeout;
|
||||
pj_time_val_normalize(¶m.timeout);
|
||||
|
||||
/* SERVER */
|
||||
param.user_data = &state_serv;
|
||||
state_serv.pool = pool;
|
||||
state_serv.is_server = PJ_TRUE;
|
||||
state_serv.is_verbose = PJ_TRUE;
|
||||
|
||||
status = pj_ssl_sock_create(pool, ¶m, &ssock_serv);
|
||||
if (status != PJ_SUCCESS) {
|
||||
goto on_return;
|
||||
}
|
||||
|
||||
/* Set cert */
|
||||
#if (PJ_SSL_SOCK_IMP == PJ_SSL_SOCK_IMP_SCHANNEL)
|
||||
/* Schannel backend currently can only load certificates from
|
||||
* OS cert store. If the certificate loading fails, we'll skip setting
|
||||
* certificate, so the SSL socket will create & use a self-signed cert.
|
||||
*/
|
||||
status = load_cert_from_store(pool, &cert);
|
||||
if (status == PJ_SUCCESS) {
|
||||
status = pj_ssl_sock_set_certificate(ssock_serv, pool, cert);
|
||||
if (status != PJ_SUCCESS) {
|
||||
goto on_return;
|
||||
}
|
||||
}
|
||||
#else
|
||||
{
|
||||
pj_str_t ca_file = pj_str(CERT_CA_FILE);
|
||||
pj_str_t cert_file = pj_str(CERT_FILE);
|
||||
|
@ -961,31 +1059,11 @@ static int client_non_ssl(unsigned ms_timeout)
|
|||
}
|
||||
}
|
||||
|
||||
pj_ssl_sock_param_default(¶m);
|
||||
param.cb.on_accept_complete2 = &ssl_on_accept_complete;
|
||||
param.cb.on_data_read = &ssl_on_data_read;
|
||||
param.cb.on_data_sent = &ssl_on_data_sent;
|
||||
param.ioqueue = ioqueue;
|
||||
param.timer_heap = timer;
|
||||
param.timeout.sec = 0;
|
||||
param.timeout.msec = ms_timeout;
|
||||
pj_time_val_normalize(¶m.timeout);
|
||||
|
||||
/* SERVER */
|
||||
param.user_data = &state_serv;
|
||||
state_serv.pool = pool;
|
||||
state_serv.is_server = PJ_TRUE;
|
||||
state_serv.is_verbose = PJ_TRUE;
|
||||
|
||||
status = pj_ssl_sock_create(pool, ¶m, &ssock_serv);
|
||||
if (status != PJ_SUCCESS) {
|
||||
goto on_return;
|
||||
}
|
||||
|
||||
status = pj_ssl_sock_set_certificate(ssock_serv, pool, cert);
|
||||
if (status != PJ_SUCCESS) {
|
||||
goto on_return;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Init bind address */
|
||||
{
|
||||
|
@ -1258,7 +1336,49 @@ static int perf_test(unsigned clients, unsigned ms_handshake_timeout)
|
|||
goto on_return;
|
||||
}
|
||||
|
||||
pj_ssl_sock_param_default(¶m);
|
||||
param.cb.on_accept_complete2 = &ssl_on_accept_complete;
|
||||
param.cb.on_connect_complete = &ssl_on_connect_complete;
|
||||
param.cb.on_data_read = &ssl_on_data_read;
|
||||
param.cb.on_data_sent = &ssl_on_data_sent;
|
||||
param.ioqueue = ioqueue;
|
||||
param.timer_heap = timer;
|
||||
param.timeout.sec = 0;
|
||||
param.timeout.msec = ms_handshake_timeout;
|
||||
pj_time_val_normalize(¶m.timeout);
|
||||
|
||||
/* Init default bind address */
|
||||
{
|
||||
pj_str_t tmp_st;
|
||||
pj_sockaddr_init(PJ_AF_INET, &addr, pj_strset2(&tmp_st, "127.0.0.1"), 0);
|
||||
}
|
||||
|
||||
/* SERVER */
|
||||
param.user_data = &state_serv;
|
||||
|
||||
state_serv.pool = pool;
|
||||
state_serv.echo = PJ_TRUE;
|
||||
state_serv.is_server = PJ_TRUE;
|
||||
|
||||
status = pj_ssl_sock_create(pool, ¶m, &ssock_serv);
|
||||
if (status != PJ_SUCCESS) {
|
||||
goto on_return;
|
||||
}
|
||||
|
||||
/* Set cert */
|
||||
#if (PJ_SSL_SOCK_IMP == PJ_SSL_SOCK_IMP_SCHANNEL)
|
||||
/* Schannel backend currently can only load certificates from
|
||||
* OS cert store. If the certificate loading fails, we'll skip setting
|
||||
* certificate, so the SSL socket will create & use a self-signed cert.
|
||||
*/
|
||||
status = load_cert_from_store(pool, &cert);
|
||||
if (status == PJ_SUCCESS) {
|
||||
status = pj_ssl_sock_set_certificate(ssock_serv, pool, cert);
|
||||
if (status != PJ_SUCCESS) {
|
||||
goto on_return;
|
||||
}
|
||||
}
|
||||
#else
|
||||
{
|
||||
pj_str_t ca_file = pj_str(CERT_CA_FILE);
|
||||
pj_str_t cert_file = pj_str(CERT_FILE);
|
||||
|
@ -1296,39 +1416,11 @@ static int perf_test(unsigned clients, unsigned ms_handshake_timeout)
|
|||
}
|
||||
}
|
||||
|
||||
pj_ssl_sock_param_default(¶m);
|
||||
param.cb.on_accept_complete2 = &ssl_on_accept_complete;
|
||||
param.cb.on_connect_complete = &ssl_on_connect_complete;
|
||||
param.cb.on_data_read = &ssl_on_data_read;
|
||||
param.cb.on_data_sent = &ssl_on_data_sent;
|
||||
param.ioqueue = ioqueue;
|
||||
param.timer_heap = timer;
|
||||
param.timeout.sec = 0;
|
||||
param.timeout.msec = ms_handshake_timeout;
|
||||
pj_time_val_normalize(¶m.timeout);
|
||||
|
||||
/* Init default bind address */
|
||||
{
|
||||
pj_str_t tmp_st;
|
||||
pj_sockaddr_init(PJ_AF_INET, &addr, pj_strset2(&tmp_st, "127.0.0.1"), 0);
|
||||
}
|
||||
|
||||
/* SERVER */
|
||||
param.user_data = &state_serv;
|
||||
|
||||
state_serv.pool = pool;
|
||||
state_serv.echo = PJ_TRUE;
|
||||
state_serv.is_server = PJ_TRUE;
|
||||
|
||||
status = pj_ssl_sock_create(pool, ¶m, &ssock_serv);
|
||||
if (status != PJ_SUCCESS) {
|
||||
goto on_return;
|
||||
}
|
||||
|
||||
status = pj_ssl_sock_set_certificate(ssock_serv, pool, cert);
|
||||
if (status != PJ_SUCCESS) {
|
||||
goto on_return;
|
||||
}
|
||||
#endif
|
||||
|
||||
status = pj_ssl_sock_start_accept(ssock_serv, pool, &addr, pj_sockaddr_get_len(&addr));
|
||||
if (status != PJ_SUCCESS) {
|
||||
|
@ -1464,7 +1556,8 @@ static int perf_test(unsigned clients, unsigned ms_handshake_timeout)
|
|||
}
|
||||
|
||||
PJ_LOG(3, ("", ".....Clients: %d (%d errors)", clients, cli_err));
|
||||
PJ_LOG(3, ("", ".....Total sent/recv: %lu/%lu bytes", tot_sent, tot_recv));
|
||||
PJ_LOG(3, ("", ".....Total sent/recv: %lu/%lu bytes",
|
||||
(unsigned long)tot_sent, (unsigned long)tot_recv));
|
||||
|
||||
on_return:
|
||||
if (ssock_serv)
|
||||
|
@ -1531,6 +1624,15 @@ int ssl_sock_test(void)
|
|||
* which require SSL server, for now.
|
||||
*/
|
||||
|
||||
/* Schannel backend notes:
|
||||
* - currently it does not support ciphers settings, so we exclude tests
|
||||
* whose ciphers setting is specified.
|
||||
* - TLS protocol older than 1.0 is not supported, TLS 1.0 & 1.1 will be
|
||||
* disabled soon, TLS 1.3 is supported since Windows 11, so for now
|
||||
* we only include tests with TLS 1.2.
|
||||
*/
|
||||
|
||||
#if (PJ_SSL_SOCK_IMP != PJ_SSL_SOCK_IMP_SCHANNEL)
|
||||
PJ_LOG(3,("", "..echo test w/ TLSv1 and PJ_TLS_RSA_WITH_AES_256_CBC_SHA cipher"));
|
||||
ret = echo_test(PJ_SSL_SOCK_PROTO_TLS1, PJ_SSL_SOCK_PROTO_TLS1,
|
||||
PJ_TLS_RSA_WITH_AES_256_CBC_SHA, PJ_TLS_RSA_WITH_AES_256_CBC_SHA,
|
||||
|
@ -1544,6 +1646,7 @@ int ssl_sock_test(void)
|
|||
PJ_FALSE, PJ_FALSE);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
#endif
|
||||
|
||||
PJ_LOG(3,("", "..echo test w/ compatible proto: server TLSv1.2 vs client TLSv1.2"));
|
||||
ret = echo_test(PJ_SSL_SOCK_PROTO_TLS1_2, PJ_SSL_SOCK_PROTO_TLS1_2,
|
||||
|
@ -1552,6 +1655,7 @@ int ssl_sock_test(void)
|
|||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
#if (PJ_SSL_SOCK_IMP != PJ_SSL_SOCK_IMP_SCHANNEL)
|
||||
PJ_LOG(3,("", "..echo test w/ compatible proto: server TLSv1.2+1.3 vs client TLSv1.3"));
|
||||
ret = echo_test(PJ_SSL_SOCK_PROTO_TLS1_2 | PJ_SSL_SOCK_PROTO_TLS1_3, PJ_SSL_SOCK_PROTO_TLS1_3,
|
||||
-1, -1,
|
||||
|
@ -1565,9 +1669,10 @@ int ssl_sock_test(void)
|
|||
PJ_FALSE, PJ_FALSE);
|
||||
if (ret == 0)
|
||||
return PJ_EBUG;
|
||||
#endif
|
||||
|
||||
/* We can't set min/max proto for TLS protocol higher than 1.0. */
|
||||
#if (PJ_SSL_SOCK_IMP != PJ_SSL_SOCK_IMP_DARWIN)
|
||||
#if (PJ_SSL_SOCK_IMP != PJ_SSL_SOCK_IMP_DARWIN && PJ_SSL_SOCK_IMP != PJ_SSL_SOCK_IMP_SCHANNEL)
|
||||
PJ_LOG(3,("", "..echo test w/ incompatible proto: server TLSv1.2 vs client TLSv1.3"));
|
||||
ret = echo_test(PJ_SSL_SOCK_PROTO_TLS1_2, PJ_SSL_SOCK_PROTO_TLS1_3,
|
||||
-1, -1,
|
||||
|
@ -1580,7 +1685,7 @@ int ssl_sock_test(void)
|
|||
* deprecated and we only have sec_protocol_options_append_tls_ciphersuite(),
|
||||
* but there's no API to remove certain or all ciphers.
|
||||
*/
|
||||
#if (PJ_SSL_SOCK_IMP != PJ_SSL_SOCK_IMP_APPLE)
|
||||
#if (PJ_SSL_SOCK_IMP != PJ_SSL_SOCK_IMP_APPLE && PJ_SSL_SOCK_IMP != PJ_SSL_SOCK_IMP_SCHANNEL)
|
||||
PJ_LOG(3,("", "..echo test w/ incompatible ciphers"));
|
||||
ret = echo_test(PJ_SSL_SOCK_PROTO_DEFAULT, PJ_SSL_SOCK_PROTO_DEFAULT,
|
||||
PJ_TLS_RSA_WITH_DES_CBC_SHA, PJ_TLS_RSA_WITH_AES_256_CBC_SHA,
|
||||
|
@ -1589,6 +1694,7 @@ int ssl_sock_test(void)
|
|||
return PJ_EBUG;
|
||||
#endif
|
||||
|
||||
#if (PJ_SSL_SOCK_IMP != PJ_SSL_SOCK_IMP_SCHANNEL)
|
||||
PJ_LOG(3,("", "..echo test w/ client cert required but not provided"));
|
||||
ret = echo_test(PJ_SSL_SOCK_PROTO_DEFAULT, PJ_SSL_SOCK_PROTO_DEFAULT,
|
||||
PJ_TLS_RSA_WITH_AES_256_CBC_SHA, PJ_TLS_RSA_WITH_AES_256_CBC_SHA,
|
||||
|
@ -1602,6 +1708,7 @@ int ssl_sock_test(void)
|
|||
PJ_TRUE, PJ_TRUE);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
#endif
|
||||
|
||||
#if WITH_BENCHMARK
|
||||
PJ_LOG(3,("", "..performance test"));
|
||||
|
|
|
@ -68,7 +68,7 @@ static int test_timer_heap(void)
|
|||
pool = pj_pool_create( mem, NULL, size, 4000, NULL);
|
||||
if (!pool) {
|
||||
PJ_LOG(3,("test", "...error: unable to create pool of %lu bytes",
|
||||
size));
|
||||
(unsigned long)size));
|
||||
return -10;
|
||||
}
|
||||
|
||||
|
@ -161,8 +161,8 @@ static int test_timer_heap(void)
|
|||
} while (PJ_TIME_VAL_LTE(now, expire)&&pj_timer_heap_count(timer) > 0);
|
||||
|
||||
if (pj_timer_heap_count(timer)) {
|
||||
PJ_LOG(3, (THIS_FILE, "ERROR: %ld timers left",
|
||||
pj_timer_heap_count(timer)));
|
||||
PJ_LOG(3, (THIS_FILE, "ERROR: %lu timers left",
|
||||
(unsigned long)pj_timer_heap_count(timer)));
|
||||
++err;
|
||||
}
|
||||
t_sched.u32.lo /= count;
|
||||
|
@ -715,8 +715,8 @@ on_return:
|
|||
if (timer)
|
||||
pj_timer_heap_destroy(timer);
|
||||
|
||||
PJ_LOG(3,("test", "Total memory of timer heap: %ld",
|
||||
pj_timer_heap_mem_size(ST_ENTRY_COUNT)));
|
||||
PJ_LOG(3,("test", "Total memory of timer heap: %lu",
|
||||
(unsigned long)pj_timer_heap_mem_size(ST_ENTRY_COUNT)));
|
||||
|
||||
if (tparam.idx)
|
||||
pj_atomic_destroy(tparam.idx);
|
||||
|
|
|
@ -300,6 +300,13 @@ ifeq ($(AC_PJMEDIA_VIDEO_HAS_DARWIN),yes)
|
|||
export PJMEDIA_VIDEODEV_OBJS += darwin_dev.o
|
||||
endif
|
||||
|
||||
#
|
||||
# Metal video device
|
||||
#
|
||||
ifeq ($(AC_PJMEDIA_VIDEO_HAS_METAL),yes)
|
||||
export PJMEDIA_VIDEODEV_OBJS += metal_dev.o
|
||||
endif
|
||||
|
||||
#
|
||||
# VideoToolbox codec
|
||||
#
|
||||
|
|
|
@ -58,6 +58,11 @@ typedef enum pjmedia_vid_dev_hwnd_type
|
|||
*/
|
||||
PJMEDIA_VID_DEV_HWND_TYPE_WINDOWS,
|
||||
|
||||
/**
|
||||
* Native view on Cocoa Mac.
|
||||
*/
|
||||
PJMEDIA_VID_DEV_HWND_TYPE_COCOA,
|
||||
|
||||
/**
|
||||
* Native view on iOS.
|
||||
*/
|
||||
|
|
|
@ -150,9 +150,9 @@ static int AndroidRecorderCallback(void *userData)
|
|||
{
|
||||
struct android_aud_stream *stream = (struct android_aud_stream *)userData;
|
||||
jmethodID read_method=0, record_method=0, stop_method=0;
|
||||
int size = stream->rec_buf_size;
|
||||
jbyteArray inputBuffer;
|
||||
jbyte *buf;
|
||||
int size = stream->rec_buf_size / 2;
|
||||
jshortArray inputBuffer;
|
||||
jshort *buf;
|
||||
JNIEnv *jni_env = 0;
|
||||
pj_bool_t attached = attach_jvm(&jni_env);
|
||||
|
||||
|
@ -166,7 +166,7 @@ static int AndroidRecorderCallback(void *userData)
|
|||
|
||||
/* Get methods ids */
|
||||
read_method = (*jni_env)->GetMethodID(jni_env, stream->record_class,
|
||||
"read", "([BII)I");
|
||||
"read", "([SII)I");
|
||||
record_method = (*jni_env)->GetMethodID(jni_env, stream->record_class,
|
||||
"startRecording", "()V");
|
||||
stop_method = (*jni_env)->GetMethodID(jni_env, stream->record_class,
|
||||
|
@ -177,7 +177,7 @@ static int AndroidRecorderCallback(void *userData)
|
|||
}
|
||||
|
||||
/* Create a buffer for frames read */
|
||||
inputBuffer = (*jni_env)->NewByteArray(jni_env, size);
|
||||
inputBuffer = (*jni_env)->NewShortArray(jni_env, size);
|
||||
if (inputBuffer == 0) {
|
||||
PJ_LOG(3, (THIS_FILE, "Unable to allocate input buffer"));
|
||||
goto on_return;
|
||||
|
@ -190,7 +190,7 @@ static int AndroidRecorderCallback(void *userData)
|
|||
while (!stream->quit_flag) {
|
||||
pjmedia_frame frame;
|
||||
pj_status_t status;
|
||||
int bytesRead;
|
||||
int shortRead;
|
||||
|
||||
if (!stream->running) {
|
||||
(*jni_env)->CallVoidMethod(jni_env, stream->record, stop_method);
|
||||
|
@ -200,25 +200,25 @@ static int AndroidRecorderCallback(void *userData)
|
|||
(*jni_env)->CallVoidMethod(jni_env, stream->record, record_method);
|
||||
}
|
||||
|
||||
bytesRead = (*jni_env)->CallIntMethod(jni_env, stream->record,
|
||||
shortRead = (*jni_env)->CallIntMethod(jni_env, stream->record,
|
||||
read_method, inputBuffer,
|
||||
0, size);
|
||||
if (bytesRead <= 0 || bytesRead != size) {
|
||||
if (shortRead <= 0 || shortRead != size) {
|
||||
PJ_LOG (4, (THIS_FILE, "Record thread : error %d reading data",
|
||||
bytesRead));
|
||||
shortRead));
|
||||
continue;
|
||||
}
|
||||
|
||||
buf = (*jni_env)->GetByteArrayElements(jni_env, inputBuffer, 0);
|
||||
buf = (*jni_env)->GetShortArrayElements(jni_env, inputBuffer, 0);
|
||||
frame.type = PJMEDIA_FRAME_TYPE_AUDIO;
|
||||
frame.size = size;
|
||||
frame.size = stream->rec_buf_size;
|
||||
frame.bit_info = 0;
|
||||
frame.buf = (void *)buf;
|
||||
frame.timestamp.u64 = stream->rec_timestamp.u64;
|
||||
|
||||
status = (*stream->rec_cb)(stream->user_data, &frame);
|
||||
(*jni_env)->ReleaseByteArrayElements(jni_env, inputBuffer, buf,
|
||||
JNI_ABORT);
|
||||
(*jni_env)->ReleaseShortArrayElements(jni_env, inputBuffer, buf,
|
||||
JNI_ABORT);
|
||||
if (status != PJ_SUCCESS || stream->quit_flag)
|
||||
break;
|
||||
|
||||
|
@ -241,9 +241,9 @@ static int AndroidTrackCallback(void *userData)
|
|||
{
|
||||
struct android_aud_stream *stream = (struct android_aud_stream*) userData;
|
||||
jmethodID write_method=0, play_method=0, stop_method=0, flush_method=0;
|
||||
int size = stream->play_buf_size;
|
||||
jbyteArray outputBuffer;
|
||||
jbyte *buf;
|
||||
int size = stream->play_buf_size / 2;
|
||||
jshortArray outputBuffer;
|
||||
jshort *buf;
|
||||
JNIEnv *jni_env = 0;
|
||||
pj_bool_t attached = attach_jvm(&jni_env);
|
||||
|
||||
|
@ -255,7 +255,7 @@ static int AndroidTrackCallback(void *userData)
|
|||
|
||||
/* Get methods ids */
|
||||
write_method = (*jni_env)->GetMethodID(jni_env, stream->track_class,
|
||||
"write", "([BII)I");
|
||||
"write", "([SII)I");
|
||||
play_method = (*jni_env)->GetMethodID(jni_env, stream->track_class,
|
||||
"play", "()V");
|
||||
stop_method = (*jni_env)->GetMethodID(jni_env, stream->track_class,
|
||||
|
@ -269,12 +269,12 @@ static int AndroidTrackCallback(void *userData)
|
|||
goto on_return;
|
||||
}
|
||||
|
||||
outputBuffer = (*jni_env)->NewByteArray(jni_env, size);
|
||||
outputBuffer = (*jni_env)->NewShortArray(jni_env, size);
|
||||
if (outputBuffer == 0) {
|
||||
PJ_LOG(3, (THIS_FILE, "Unable to allocate output buffer"));
|
||||
goto on_return;
|
||||
}
|
||||
buf = (*jni_env)->GetByteArrayElements(jni_env, outputBuffer, 0);
|
||||
buf = (*jni_env)->GetShortArrayElements(jni_env, outputBuffer, 0);
|
||||
|
||||
/* Start playing */
|
||||
pj_thread_set_prio(NULL, THREAD_PRIORITY_URGENT_AUDIO);
|
||||
|
@ -283,7 +283,7 @@ static int AndroidTrackCallback(void *userData)
|
|||
while (!stream->quit_flag) {
|
||||
pjmedia_frame frame;
|
||||
pj_status_t status;
|
||||
int bytesWritten;
|
||||
int shortWritten;
|
||||
|
||||
if (!stream->running) {
|
||||
(*jni_env)->CallVoidMethod(jni_env, stream->track, stop_method);
|
||||
|
@ -295,7 +295,7 @@ static int AndroidTrackCallback(void *userData)
|
|||
}
|
||||
|
||||
frame.type = PJMEDIA_FRAME_TYPE_AUDIO;
|
||||
frame.size = size;
|
||||
frame.size = stream->play_buf_size;
|
||||
frame.buf = (void *)buf;
|
||||
frame.timestamp.u64 = stream->play_timestamp.u64;
|
||||
frame.bit_info = 0;
|
||||
|
@ -307,16 +307,16 @@ static int AndroidTrackCallback(void *userData)
|
|||
if (frame.type != PJMEDIA_FRAME_TYPE_AUDIO)
|
||||
pj_bzero(frame.buf, frame.size);
|
||||
|
||||
(*jni_env)->ReleaseByteArrayElements(jni_env, outputBuffer, buf,
|
||||
(*jni_env)->ReleaseShortArrayElements(jni_env, outputBuffer, buf,
|
||||
JNI_COMMIT);
|
||||
|
||||
/* Write to the device output. */
|
||||
bytesWritten = (*jni_env)->CallIntMethod(jni_env, stream->track,
|
||||
shortWritten = (*jni_env)->CallIntMethod(jni_env, stream->track,
|
||||
write_method, outputBuffer,
|
||||
0, size);
|
||||
if (bytesWritten <= 0 || bytesWritten != size) {
|
||||
if (shortWritten <= 0 || shortWritten != size) {
|
||||
PJ_LOG(4, (THIS_FILE, "Player thread: Error %d writing data",
|
||||
bytesWritten));
|
||||
shortWritten));
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -324,7 +324,7 @@ static int AndroidTrackCallback(void *userData)
|
|||
stream->param.channel_count;
|
||||
};
|
||||
|
||||
(*jni_env)->ReleaseByteArrayElements(jni_env, outputBuffer, buf, 0);
|
||||
(*jni_env)->ReleaseShortArrayElements(jni_env, outputBuffer, buf, 0);
|
||||
(*jni_env)->DeleteLocalRef(jni_env, outputBuffer);
|
||||
|
||||
on_return:
|
||||
|
@ -476,7 +476,8 @@ static pj_status_t android_create_stream(pjmedia_aud_dev_factory *f,
|
|||
|
||||
PJ_ASSERT_RETURN(param->channel_count >= 1 && param->channel_count <= 2,
|
||||
PJ_EINVAL);
|
||||
PJ_ASSERT_RETURN(param->bits_per_sample==8 || param->bits_per_sample==16,
|
||||
PJ_ASSERT_RETURN(/* param->bits_per_sample==8 || */
|
||||
param->bits_per_sample==16,
|
||||
PJ_EINVAL);
|
||||
PJ_ASSERT_RETURN(play_cb && rec_cb && p_aud_strm, PJ_EINVAL);
|
||||
|
||||
|
@ -500,8 +501,11 @@ static pj_status_t android_create_stream(pjmedia_aud_dev_factory *f,
|
|||
12 /*CHANNEL_IN_STEREO*/;
|
||||
channelOutCfg = (param->channel_count == 1)? 4 /*CHANNEL_OUT_MONO*/:
|
||||
12 /*CHANNEL_OUT_STEREO*/;
|
||||
sampleFormat = (param->bits_per_sample == 8)? 3 /*ENCODING_PCM_8BIT*/:
|
||||
2 /*ENCODING_PCM_16BIT*/;
|
||||
|
||||
// The 8bit/byte read/write methods no longer support 16bit
|
||||
//sampleFormat = (param->bits_per_sample == 8)? 3 /*ENCODING_PCM_8BIT*/:
|
||||
// 2 /*ENCODING_PCM_16BIT*/;
|
||||
sampleFormat = 2 /*ENCODING_PCM_16BIT*/;
|
||||
|
||||
attached = attach_jvm(&jni_env);
|
||||
|
||||
|
|
|
@ -29,6 +29,12 @@
|
|||
#define COREAUDIO_MAC 1
|
||||
#endif
|
||||
|
||||
#if (TARGET_OS_OSX && defined(__MAC_12_0))
|
||||
#define AUDIO_OBJECT_ELEMENT_MAIN kAudioObjectPropertyElementMain;
|
||||
#else
|
||||
#define AUDIO_OBJECT_ELEMENT_MAIN kAudioObjectPropertyElementMaster;
|
||||
#endif
|
||||
|
||||
#include <AudioUnit/AudioUnit.h>
|
||||
#include <AudioToolbox/AudioConverter.h>
|
||||
#if COREAUDIO_MAC
|
||||
|
@ -447,7 +453,7 @@ static pj_status_t ca_factory_refresh(pjmedia_aud_dev_factory *f)
|
|||
/* Find out how many audio devices there are */
|
||||
addr.mSelector = kAudioHardwarePropertyDevices;
|
||||
addr.mScope = kAudioObjectPropertyScopeGlobal;
|
||||
addr.mElement = kAudioObjectPropertyElementMaster;
|
||||
addr.mElement = AUDIO_OBJECT_ELEMENT_MAIN;
|
||||
ostatus = AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &addr,
|
||||
0, NULL, &dev_size);
|
||||
if (ostatus != noErr) {
|
||||
|
@ -492,7 +498,7 @@ static pj_status_t ca_factory_refresh(pjmedia_aud_dev_factory *f)
|
|||
/* Find default audio input device */
|
||||
addr.mSelector = kAudioHardwarePropertyDefaultInputDevice;
|
||||
addr.mScope = kAudioObjectPropertyScopeGlobal;
|
||||
addr.mElement = kAudioObjectPropertyElementMaster;
|
||||
addr.mElement = AUDIO_OBJECT_ELEMENT_MAIN;
|
||||
size = sizeof(dev_id);
|
||||
|
||||
ostatus = AudioObjectGetPropertyData(kAudioObjectSystemObject,
|
||||
|
@ -544,7 +550,7 @@ static pj_status_t ca_factory_refresh(pjmedia_aud_dev_factory *f)
|
|||
/* Get device name */
|
||||
addr.mSelector = kAudioDevicePropertyDeviceName;
|
||||
addr.mScope = kAudioObjectPropertyScopeGlobal;
|
||||
addr.mElement = kAudioObjectPropertyElementMaster;
|
||||
addr.mElement = AUDIO_OBJECT_ELEMENT_MAIN;
|
||||
size = sizeof(cdi->info.name);
|
||||
AudioObjectGetPropertyData(cdi->dev_id, &addr,
|
||||
0, NULL,
|
||||
|
|
|
@ -1141,7 +1141,8 @@ static pj_status_t and_media_codec_encode(pjmedia_codec *codec,
|
|||
} else {
|
||||
PJ_LOG(4,(THIS_FILE, "Encoder getInputBuffer "
|
||||
"size: %lu, expecting %d.",
|
||||
output_size, input_size));
|
||||
(unsigned long)output_size,
|
||||
input_size));
|
||||
}
|
||||
goto on_return;
|
||||
}
|
||||
|
@ -1262,7 +1263,8 @@ static pj_status_t and_media_codec_decode(pjmedia_codec *codec,
|
|||
&input_size);
|
||||
if (input_buf == 0) {
|
||||
PJ_LOG(4,(THIS_FILE, "Decoder getInputBuffer failed "
|
||||
"return input_buf=%d, size=%lu", *input_buf, input_size));
|
||||
"return input_buf=%d, size=%lu", *input_buf,
|
||||
(unsigned long)input_size));
|
||||
goto on_return;
|
||||
}
|
||||
|
||||
|
|
|
@ -1033,7 +1033,8 @@ static pj_status_t and_media_codec_encode_begin(pjmedia_vid_codec *codec,
|
|||
} else {
|
||||
PJ_LOG(4,(THIS_FILE, "Encoder getInputBuffer "
|
||||
"size: %lu, expecting %lu.",
|
||||
output_size, input->size));
|
||||
(unsigned long)output_size,
|
||||
(unsigned long)input->size));
|
||||
}
|
||||
goto on_return;
|
||||
}
|
||||
|
|
|
@ -1182,7 +1182,7 @@ static pj_status_t oh264_codec_decode(pjmedia_vid_codec *codec,
|
|||
|
||||
PJ_LOG(5,(THIS_FILE, "Decode couldn't produce picture, "
|
||||
"input nframes=%lu, concatenated size=%d bytes, ret=%d",
|
||||
count, whole_len, ret));
|
||||
(unsigned long)count, whole_len, ret));
|
||||
}
|
||||
|
||||
return status;
|
||||
|
|
|
@ -931,7 +931,7 @@ static pj_status_t codec_parse( pjmedia_codec *codec,
|
|||
sizeof(tmp_buf));
|
||||
if (size < 0) {
|
||||
PJ_LOG(5, (THIS_FILE, "Parse failed! (pkt_size=%lu, err=%d)",
|
||||
pkt_size, size));
|
||||
(unsigned long)pkt_size, size));
|
||||
pj_mutex_unlock (opus_data->mutex);
|
||||
return PJMEDIA_CODEC_EFAILED;
|
||||
}
|
||||
|
|
|
@ -22,7 +22,6 @@
|
|||
#include <pjmedia/errno.h>
|
||||
#include <pjmedia/endpoint.h>
|
||||
#include <pjmedia/port.h>
|
||||
#include <speex/speex.h>
|
||||
#include <pj/assert.h>
|
||||
#include <pj/log.h>
|
||||
#include <pj/pool.h>
|
||||
|
@ -34,6 +33,7 @@
|
|||
*/
|
||||
#if defined(PJMEDIA_HAS_SPEEX_CODEC) && PJMEDIA_HAS_SPEEX_CODEC!=0
|
||||
|
||||
#include <speex/speex.h>
|
||||
|
||||
#define THIS_FILE "speex_codec.c"
|
||||
|
||||
|
|
|
@ -554,17 +554,20 @@ static OSStatus create_encoder(vtool_codec_data *vtool_data)
|
|||
|
||||
ret = VTSessionCopySupportedPropertyDictionary(vtool_data->enc,
|
||||
&supported_prop);
|
||||
if (ret == noErr &&
|
||||
CFDictionaryContainsKey(supported_prop,
|
||||
if (ret == noErr) {
|
||||
if (CFDictionaryContainsKey(supported_prop,
|
||||
kVTCompressionPropertyKey_MaxH264SliceBytes))
|
||||
{
|
||||
/* kVTCompressionPropertyKey_MaxH264SliceBytes is not yet supported
|
||||
* by Apple. We leave it here for possible future enhancements.
|
||||
SET_PROPERTY(vtool_data->enc,
|
||||
kVTCompressionPropertyKey_MaxH264SliceBytes,
|
||||
// param->enc_mtu - NAL_HEADER_ADD_0X30BYTES
|
||||
(__bridge CFTypeRef)@(param->enc_mtu - 50));
|
||||
*/
|
||||
{
|
||||
/* kVTCompressionPropertyKey_MaxH264SliceBytes is not yet supported
|
||||
* by Apple. We leave it here for possible future enhancements.
|
||||
SET_PROPERTY(vtool_data->enc,
|
||||
kVTCompressionPropertyKey_MaxH264SliceBytes,
|
||||
// param->enc_mtu - NAL_HEADER_ADD_0X30BYTES
|
||||
(__bridge CFTypeRef)@(param->enc_mtu - 50));
|
||||
*/
|
||||
}
|
||||
|
||||
CFRelease(supported_prop);
|
||||
}
|
||||
|
||||
VTCompressionSessionPrepareToEncodeFrames(vtool_data->enc);
|
||||
|
@ -1404,8 +1407,8 @@ on_return:
|
|||
PJMEDIA_EVENT_PUBLISH_DEFAULT);
|
||||
|
||||
PJ_LOG(5,(THIS_FILE, "Decode couldn't produce picture, "
|
||||
"input nframes=%ld, concatenated size=%d bytes",
|
||||
count, whole_len));
|
||||
"input nframes=%lu, concatenated size=%d bytes",
|
||||
(unsigned long)count, whole_len));
|
||||
|
||||
output->type = PJMEDIA_FRAME_TYPE_NONE;
|
||||
output->size = 0;
|
||||
|
|
|
@ -830,7 +830,7 @@ on_return:
|
|||
|
||||
PJ_LOG(4,(THIS_FILE, "Decode couldn't produce picture, "
|
||||
"input nframes=%lu, concatenated size=%d bytes",
|
||||
count, whole_len));
|
||||
(unsigned long)count, whole_len));
|
||||
|
||||
output->type = PJMEDIA_FRAME_TYPE_NONE;
|
||||
output->size = 0;
|
||||
|
|
|
@ -313,23 +313,34 @@ static pj_status_t darwin_factory_refresh(pjmedia_vid_dev_factory *f)
|
|||
if (NSClassFromString(@"AVCaptureSession")) {
|
||||
NSArray *dev_list = NULL;
|
||||
|
||||
#if (TARGET_OS_IPHONE && defined(__IPHONE_10_0)) || \
|
||||
(TARGET_OS_OSX && defined(__MAC_10_15))
|
||||
if (__builtin_available(macOS 10.15, iOS 10.0, *)) {
|
||||
if (@available(macOS 10.15, iOS 10.0, *)) {
|
||||
/* Starting in iOS 10 and macOS 10.15, [AVCaptureDevice devices]
|
||||
* is deprecated and replaced by AVCaptureDeviceDiscoverySession.
|
||||
*/
|
||||
AVCaptureDeviceDiscoverySession *dds;
|
||||
NSArray<AVCaptureDeviceType> *dev_types =
|
||||
@[AVCaptureDeviceTypeBuiltInWideAngleCamera
|
||||
#if TARGET_OS_OSX && defined(__MAC_10_15)
|
||||
, AVCaptureDeviceTypeExternalUnknown
|
||||
#endif
|
||||
NSMutableArray<AVCaptureDeviceType> *dev_types =
|
||||
[NSMutableArray arrayWithCapacity:5];
|
||||
|
||||
[dev_types addObject:AVCaptureDeviceTypeBuiltInWideAngleCamera];
|
||||
#if TARGET_OS_IPHONE && defined(__IPHONE_10_0)
|
||||
, AVCaptureDeviceTypeBuiltInDuoCamera
|
||||
, AVCaptureDeviceTypeBuiltInTelephotoCamera
|
||||
// Deprecated in iOS 10.2
|
||||
// AVCaptureDeviceTypeBuiltInDuoCamera
|
||||
[dev_types addObject:AVCaptureDeviceTypeBuiltInTelephotoCamera];
|
||||
#endif
|
||||
|
||||
#if (TARGET_OS_IPHONE && defined(__IPHONE_17_0)) || \
|
||||
(TARGET_OS_OSX && defined(__MAC_14_0))
|
||||
if (@available(macOS 14.0, iOS 17.0, *)) {
|
||||
[dev_types addObject:AVCaptureDeviceTypeExternal];
|
||||
} else {
|
||||
# if (TARGET_OS_OSX && __MAC_OS_X_VERSION_MIN_REQUIRED < 140000)
|
||||
[dev_types addObject:AVCaptureDeviceTypeExternalUnknown];
|
||||
# endif
|
||||
}
|
||||
|
||||
#elif TARGET_OS_OSX
|
||||
[dev_types addObject:AVCaptureDeviceTypeExternalUnknown];
|
||||
#endif
|
||||
];
|
||||
|
||||
dds = [AVCaptureDeviceDiscoverySession
|
||||
discoverySessionWithDeviceTypes:dev_types
|
||||
|
@ -338,13 +349,11 @@ static pj_status_t darwin_factory_refresh(pjmedia_vid_dev_factory *f)
|
|||
|
||||
dev_list = [dds devices];
|
||||
} else {
|
||||
#if __MAC_OS_X_VERSION_MIN_REQUIRED < __MAC_10_15
|
||||
#if (TARGET_OS_OSX && __MAC_OS_X_VERSION_MIN_REQUIRED < __MAC_10_15) || \
|
||||
(TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_10_0)
|
||||
dev_list = [AVCaptureDevice devices];
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
dev_list = [AVCaptureDevice devices];
|
||||
#endif
|
||||
|
||||
for (AVCaptureDevice *device in dev_list) {
|
||||
if (![device hasMediaType:AVMediaTypeVideo] ||
|
||||
|
@ -1040,6 +1049,32 @@ static pj_status_t darwin_stream_get_cap(pjmedia_vid_dev_stream *s,
|
|||
return PJMEDIA_EVID_INVCAP;
|
||||
}
|
||||
|
||||
static pj_bool_t set_orientation(struct darwin_stream *strm)
|
||||
{
|
||||
#if (TARGET_OS_OSX && __MAC_OS_X_VERSION_MIN_REQUIRED < 140000) || \
|
||||
(TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MIN_REQUIRED < 170000)
|
||||
|
||||
const AVCaptureVideoOrientation cap_ori[4] =
|
||||
{
|
||||
AVCaptureVideoOrientationLandscapeLeft, /* NATURAL */
|
||||
AVCaptureVideoOrientationPortrait, /* 90DEG */
|
||||
AVCaptureVideoOrientationLandscapeRight, /* 180DEG */
|
||||
AVCaptureVideoOrientationPortraitUpsideDown, /* 270DEG */
|
||||
};
|
||||
AVCaptureConnection *vidcon;
|
||||
|
||||
vidcon = [strm->video_output
|
||||
connectionWithMediaType:AVMediaTypeVideo];
|
||||
if ([vidcon isVideoOrientationSupported]) {
|
||||
vidcon.videoOrientation = cap_ori[strm->param.orient-1];
|
||||
return PJ_TRUE;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
return PJ_FALSE;
|
||||
}
|
||||
|
||||
/* API: set capability */
|
||||
static pj_status_t darwin_stream_set_cap(pjmedia_vid_dev_stream *s,
|
||||
pjmedia_vid_dev_cap cap,
|
||||
|
@ -1242,6 +1277,7 @@ static pj_status_t darwin_stream_set_cap(pjmedia_vid_dev_stream *s,
|
|||
case PJMEDIA_VID_DEV_CAP_ORIENTATION:
|
||||
{
|
||||
pjmedia_orient orient = *(pjmedia_orient *)pval;
|
||||
pj_bool_t support_ori = PJ_FALSE;
|
||||
|
||||
pj_assert(orient >= PJMEDIA_ORIENT_UNKNOWN &&
|
||||
orient <= PJMEDIA_ORIENT_ROTATE_270DEG);
|
||||
|
@ -1263,30 +1299,35 @@ static pj_status_t darwin_stream_set_cap(pjmedia_vid_dev_stream *s,
|
|||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
const AVCaptureVideoOrientation cap_ori[4] =
|
||||
{
|
||||
AVCaptureVideoOrientationLandscapeLeft, /* NATURAL */
|
||||
AVCaptureVideoOrientationPortrait, /* 90DEG */
|
||||
AVCaptureVideoOrientationLandscapeRight, /* 180DEG */
|
||||
AVCaptureVideoOrientationPortraitUpsideDown, /* 270DEG */
|
||||
};
|
||||
AVCaptureConnection *vidcon;
|
||||
pj_bool_t support_ori = PJ_TRUE;
|
||||
|
||||
|
||||
pj_assert(strm->param.dir == PJMEDIA_DIR_CAPTURE);
|
||||
|
||||
|
||||
if (!strm->video_output)
|
||||
return PJMEDIA_EVID_NOTREADY;
|
||||
|
||||
vidcon = [strm->video_output
|
||||
connectionWithMediaType:AVMediaTypeVideo];
|
||||
if ([vidcon isVideoOrientationSupported]) {
|
||||
vidcon.videoOrientation = cap_ori[strm->param.orient-1];
|
||||
#if (TARGET_OS_IPHONE && defined(__IPHONE_17_0)) || \
|
||||
(TARGET_OS_OSX && defined(__MAC_14_0))
|
||||
if (@available(macOS 14.0, iOS 17.0, *)) {
|
||||
|
||||
const CGFloat cap_ori[4] = { 0, 90, 180, 270};
|
||||
AVCaptureConnection *vidcon;
|
||||
|
||||
vidcon = [strm->video_output
|
||||
connectionWithMediaType:AVMediaTypeVideo];
|
||||
if ([vidcon isVideoRotationAngleSupported:
|
||||
cap_ori[strm->param.orient-1]])
|
||||
{
|
||||
vidcon.videoRotationAngle = cap_ori[strm->param.orient-1];
|
||||
support_ori = PJ_TRUE;
|
||||
}
|
||||
|
||||
} else {
|
||||
support_ori = PJ_FALSE;
|
||||
support_ori = set_orientation(strm);
|
||||
}
|
||||
|
||||
#else
|
||||
support_ori = set_orientation(strm);
|
||||
#endif
|
||||
|
||||
if (!strm->conv.conv) {
|
||||
pj_status_t status;
|
||||
pjmedia_rect_size orig_size;
|
||||
|
|
|
@ -0,0 +1,971 @@
|
|||
/*
|
||||
* Copyright (C) 2024 Teluu Inc. (http://www.teluu.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#include "util.h"
|
||||
#include <pjmedia-videodev/videodev_imp.h>
|
||||
#include <pj/assert.h>
|
||||
#include <pj/log.h>
|
||||
#include <pj/os.h>
|
||||
|
||||
#if defined(PJMEDIA_HAS_VIDEO) && PJMEDIA_HAS_VIDEO != 0 && \
|
||||
defined(PJMEDIA_VIDEO_DEV_HAS_METAL) && PJMEDIA_VIDEO_DEV_HAS_METAL != 0
|
||||
|
||||
#import "MetalKit/MetalKit.h"
|
||||
#include "TargetConditionals.h"
|
||||
|
||||
#define THIS_FILE "metal_dev.m"
|
||||
#define DEFAULT_CLOCK_RATE 90000
|
||||
#define DEFAULT_WIDTH 640
|
||||
#define DEFAULT_HEIGHT 480
|
||||
#define DEFAULT_FPS 15
|
||||
|
||||
#if TARGET_OS_IPHONE
|
||||
# define NSView UIView
|
||||
# define NSWindow UIWindow
|
||||
#endif
|
||||
|
||||
typedef struct metal_fmt_info
|
||||
{
|
||||
pjmedia_format_id pjmedia_format;
|
||||
MTLPixelFormat metal_format;
|
||||
} metal_fmt_info;
|
||||
|
||||
static metal_fmt_info metal_fmts[] =
|
||||
{
|
||||
{ PJMEDIA_FORMAT_BGRA, MTLPixelFormatBGRA8Unorm },
|
||||
{ PJMEDIA_FORMAT_RGBA, MTLPixelFormatRGBA8Unorm },
|
||||
};
|
||||
|
||||
struct metal_dev_info
|
||||
{
|
||||
pjmedia_vid_dev_info info;
|
||||
};
|
||||
|
||||
/* metal factory */
|
||||
struct metal_factory
|
||||
{
|
||||
pjmedia_vid_dev_factory base;
|
||||
pj_pool_t *pool;
|
||||
pj_pool_factory *pf;
|
||||
|
||||
unsigned dev_count;
|
||||
struct metal_dev_info dev_info[1];
|
||||
};
|
||||
|
||||
@interface MetalRenderer : NSObject<MTKViewDelegate>
|
||||
@end
|
||||
|
||||
/* Video stream. */
|
||||
struct metal_stream
|
||||
{
|
||||
pjmedia_vid_dev_stream base; /**< Base stream */
|
||||
pjmedia_vid_dev_param param; /**< Settings */
|
||||
pj_pool_t *pool; /**< Memory pool */
|
||||
struct metal_factory *factory; /**< Factory */
|
||||
|
||||
pjmedia_vid_dev_cb vid_cb; /**< Stream callback */
|
||||
void *user_data; /**< Application data */
|
||||
|
||||
pjmedia_rect_size size;
|
||||
unsigned bytes_per_row;
|
||||
unsigned frame_size; /**< Frame size (bytes)*/
|
||||
pj_bool_t is_planar;
|
||||
|
||||
pjmedia_vid_dev_conv conv;
|
||||
pjmedia_rect_size vid_size;
|
||||
|
||||
MetalRenderer *renderer;
|
||||
MTKView *view;
|
||||
MTLPixelFormat format;
|
||||
|
||||
NSWindow *window;
|
||||
|
||||
pj_bool_t is_running;
|
||||
pj_bool_t is_rendering;
|
||||
void *render_buf;
|
||||
pj_size_t render_buf_size;
|
||||
|
||||
pj_timestamp frame_ts;
|
||||
unsigned ts_inc;
|
||||
};
|
||||
|
||||
|
||||
/* Prototypes */
|
||||
static pj_status_t metal_factory_init(pjmedia_vid_dev_factory *f);
|
||||
static pj_status_t metal_factory_destroy(pjmedia_vid_dev_factory *f);
|
||||
static pj_status_t metal_factory_refresh(pjmedia_vid_dev_factory *f);
|
||||
static unsigned metal_factory_get_dev_count(pjmedia_vid_dev_factory *f);
|
||||
static pj_status_t metal_factory_get_dev_info(pjmedia_vid_dev_factory *f,
|
||||
unsigned index,
|
||||
pjmedia_vid_dev_info *info);
|
||||
static pj_status_t metal_factory_default_param(pj_pool_t *pool,
|
||||
pjmedia_vid_dev_factory *f,
|
||||
unsigned index,
|
||||
pjmedia_vid_dev_param *param);
|
||||
static pj_status_t metal_factory_create_stream(
|
||||
pjmedia_vid_dev_factory *f,
|
||||
pjmedia_vid_dev_param *param,
|
||||
const pjmedia_vid_dev_cb *cb,
|
||||
void *user_data,
|
||||
pjmedia_vid_dev_stream **p_vid_strm);
|
||||
|
||||
static pj_status_t metal_stream_get_param(pjmedia_vid_dev_stream *strm,
|
||||
pjmedia_vid_dev_param *param);
|
||||
static pj_status_t metal_stream_get_cap(pjmedia_vid_dev_stream *strm,
|
||||
pjmedia_vid_dev_cap cap,
|
||||
void *value);
|
||||
static pj_status_t metal_stream_set_cap(pjmedia_vid_dev_stream *strm,
|
||||
pjmedia_vid_dev_cap cap,
|
||||
const void *value);
|
||||
static pj_status_t metal_stream_start(pjmedia_vid_dev_stream *strm);
|
||||
static pj_status_t metal_stream_put_frame(pjmedia_vid_dev_stream *strm,
|
||||
const pjmedia_frame *frame);
|
||||
static pj_status_t metal_stream_stop(pjmedia_vid_dev_stream *strm);
|
||||
static pj_status_t metal_stream_destroy(pjmedia_vid_dev_stream *strm);
|
||||
|
||||
/* Operations */
|
||||
static pjmedia_vid_dev_factory_op factory_op =
|
||||
{
|
||||
&metal_factory_init,
|
||||
&metal_factory_destroy,
|
||||
&metal_factory_get_dev_count,
|
||||
&metal_factory_get_dev_info,
|
||||
&metal_factory_default_param,
|
||||
&metal_factory_create_stream,
|
||||
&metal_factory_refresh
|
||||
};
|
||||
|
||||
static pjmedia_vid_dev_stream_op stream_op =
|
||||
{
|
||||
&metal_stream_get_param,
|
||||
&metal_stream_get_cap,
|
||||
&metal_stream_set_cap,
|
||||
&metal_stream_start,
|
||||
NULL,
|
||||
&metal_stream_put_frame,
|
||||
&metal_stream_stop,
|
||||
&metal_stream_destroy
|
||||
};
|
||||
|
||||
static void dispatch_sync_on_main_queue(void (^block)(void))
|
||||
{
|
||||
if ([NSThread isMainThread]) {
|
||||
block();
|
||||
} else {
|
||||
dispatch_sync(dispatch_get_main_queue(), block);
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Factory operations
|
||||
*/
|
||||
/*
|
||||
* Init metal_ video driver.
|
||||
*/
|
||||
pjmedia_vid_dev_factory* pjmedia_metal_factory(pj_pool_factory *pf)
|
||||
{
|
||||
struct metal_factory *f;
|
||||
pj_pool_t *pool;
|
||||
|
||||
pool = pj_pool_create(pf, "metal video", 8000, 4000, NULL);
|
||||
f = PJ_POOL_ZALLOC_T(pool, struct metal_factory);
|
||||
f->pf = pf;
|
||||
f->pool = pool;
|
||||
f->base.op = &factory_op;
|
||||
|
||||
return &f->base;
|
||||
}
|
||||
|
||||
|
||||
/* API: init factory */
|
||||
static pj_status_t metal_factory_init(pjmedia_vid_dev_factory *f)
|
||||
{
|
||||
return metal_factory_refresh(f);
|
||||
}
|
||||
|
||||
/* API: destroy factory */
|
||||
static pj_status_t metal_factory_destroy(pjmedia_vid_dev_factory *f)
|
||||
{
|
||||
struct metal_factory *qf = (struct metal_factory*)f;
|
||||
pj_pool_t *pool = qf->pool;
|
||||
|
||||
qf->pool = NULL;
|
||||
pj_pool_release(pool);
|
||||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
/* API: refresh the list of devices */
|
||||
static pj_status_t metal_factory_refresh(pjmedia_vid_dev_factory *f)
|
||||
{
|
||||
struct metal_factory *qf = (struct metal_factory*)f;
|
||||
|
||||
if (@available(macOS 10.14, iOS 12.0, *)) {
|
||||
struct metal_dev_info *qdi;
|
||||
unsigned l;
|
||||
id<MTLDevice> device;
|
||||
|
||||
device = MTLCreateSystemDefaultDevice();
|
||||
if (!device) {
|
||||
PJ_LOG(3, (THIS_FILE, "No Metal device found"));
|
||||
return PJ_SUCCESS;
|
||||
} else {
|
||||
[device release];
|
||||
}
|
||||
|
||||
/* Init output device */
|
||||
qdi = &qf->dev_info[qf->dev_count++];
|
||||
pj_bzero(qdi, sizeof(*qdi));
|
||||
pj_ansi_strxcpy(qdi->info.name, "Metal", sizeof(qdi->info.name));
|
||||
pj_ansi_strxcpy(qdi->info.driver, "Apple", sizeof(qdi->info.driver));
|
||||
qdi->info.dir = PJMEDIA_DIR_RENDER;
|
||||
qdi->info.has_callback = PJ_FALSE;
|
||||
|
||||
/* Set supported formats */
|
||||
qdi->info.caps |= PJMEDIA_VID_DEV_CAP_FORMAT |
|
||||
PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW |
|
||||
PJMEDIA_VID_DEV_CAP_OUTPUT_RESIZE |
|
||||
PJMEDIA_VID_DEV_CAP_OUTPUT_POSITION |
|
||||
PJMEDIA_VID_DEV_CAP_OUTPUT_HIDE |
|
||||
PJMEDIA_VID_DEV_CAP_ORIENTATION;
|
||||
|
||||
for (l = 0; l < PJ_ARRAY_SIZE(metal_fmts); l++) {
|
||||
pjmedia_format *fmt = &qdi->info.fmt[qdi->info.fmt_cnt++];
|
||||
pjmedia_format_init_video(fmt, metal_fmts[l].pjmedia_format,
|
||||
DEFAULT_WIDTH, DEFAULT_HEIGHT,
|
||||
DEFAULT_FPS, 1);
|
||||
}
|
||||
}
|
||||
|
||||
PJ_LOG(4, (THIS_FILE, "Metal video initialized with %d devices",
|
||||
qf->dev_count));
|
||||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
/* API: get number of devices */
|
||||
static unsigned metal_factory_get_dev_count(pjmedia_vid_dev_factory *f)
|
||||
{
|
||||
struct metal_factory *qf = (struct metal_factory*)f;
|
||||
return qf->dev_count;
|
||||
}
|
||||
|
||||
/* API: get device info */
|
||||
static pj_status_t metal_factory_get_dev_info(pjmedia_vid_dev_factory *f,
|
||||
unsigned index,
|
||||
pjmedia_vid_dev_info *info)
|
||||
{
|
||||
struct metal_factory *qf = (struct metal_factory*)f;
|
||||
|
||||
PJ_ASSERT_RETURN(index < qf->dev_count, PJMEDIA_EVID_INVDEV);
|
||||
|
||||
pj_memcpy(info, &qf->dev_info[index].info, sizeof(*info));
|
||||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
/* API: create default device parameter */
|
||||
static pj_status_t metal_factory_default_param(pj_pool_t *pool,
|
||||
pjmedia_vid_dev_factory *f,
|
||||
unsigned index,
|
||||
pjmedia_vid_dev_param *param)
|
||||
{
|
||||
struct metal_factory *qf = (struct metal_factory*)f;
|
||||
struct metal_dev_info *di;
|
||||
|
||||
PJ_ASSERT_RETURN(index < qf->dev_count, PJMEDIA_EVID_INVDEV);
|
||||
PJ_UNUSED_ARG(pool);
|
||||
|
||||
di = &qf->dev_info[index];
|
||||
|
||||
pj_bzero(param, sizeof(*param));
|
||||
if (di->info.dir & PJMEDIA_DIR_RENDER) {
|
||||
param->dir = PJMEDIA_DIR_RENDER;
|
||||
param->rend_id = index;
|
||||
param->cap_id = PJMEDIA_VID_INVALID_DEV;
|
||||
} else {
|
||||
return PJMEDIA_EVID_INVDEV;
|
||||
}
|
||||
|
||||
param->flags = PJMEDIA_VID_DEV_CAP_FORMAT;
|
||||
param->clock_rate = DEFAULT_CLOCK_RATE;
|
||||
pj_memcpy(¶m->fmt, &di->info.fmt[0], sizeof(param->fmt));
|
||||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
@implementation MetalRenderer
|
||||
{
|
||||
MTKView *_view;
|
||||
id<MTLDevice> device;
|
||||
id<MTLCommandQueue> commandQueue;
|
||||
id<MTLRenderPipelineState> pipelineState;
|
||||
id<MTLBuffer> vertexBuffer;
|
||||
id<MTLBuffer> textureCoordBuffer;
|
||||
|
||||
@public
|
||||
struct metal_stream *stream;
|
||||
}
|
||||
|
||||
#define _STRINGIFY( _x ) # _x
|
||||
|
||||
- (nonnull instancetype)initWithMetalKitView:(nonnull MTKView *)mtkView
|
||||
{
|
||||
self = [super init];
|
||||
if (self) {
|
||||
NSString *code;
|
||||
NSError *error = nil;
|
||||
id<MTLLibrary> shaderLibrary;
|
||||
id <MTLFunction> fragmentProgram;
|
||||
id <MTLFunction> vertexProgram;
|
||||
MTLRenderPipelineDescriptor *pQuadPipelineStateDescriptor;
|
||||
|
||||
/* Create a buffer for a full-screen quad */
|
||||
static const float vertexData[] = {
|
||||
-1.0, -1.0, 0.0, 1.0,
|
||||
1.0, -1.0, 0.0, 1.0,
|
||||
-1.0, 1.0, 0.0, 1.0,
|
||||
1.0, 1.0, 0.0, 1.0,
|
||||
};
|
||||
|
||||
/* Create texture coordinates for a full-screen quad */
|
||||
static const float textureCoordinates[] = {
|
||||
0.0, 1.0,
|
||||
1.0, 1.0,
|
||||
0.0, 0.0,
|
||||
1.0, 0.0,
|
||||
};
|
||||
|
||||
_view = mtkView;
|
||||
device = mtkView.device;
|
||||
/* Create the command queue */
|
||||
commandQueue = [device newCommandQueue];
|
||||
|
||||
/* Metal shader code */
|
||||
code = [NSString stringWithFormat:@"#include <metal_stdlib>\n%s",
|
||||
_STRINGIFY(
|
||||
using namespace metal;
|
||||
|
||||
struct VertexInOut
|
||||
{
|
||||
float4 m_Position [[position]];
|
||||
float2 m_TexCoord [[user(texturecoord)]];
|
||||
};
|
||||
|
||||
vertex VertexInOut
|
||||
texturedVertex(constant float4 *pPosition [[ buffer(0) ]],
|
||||
constant packed_float2 *pTexCoords [[ buffer(1) ]],
|
||||
constant float4x4 *pMVP [[ buffer(2) ]],
|
||||
uint vid [[ vertex_id ]])
|
||||
{
|
||||
VertexInOut outVertices;
|
||||
|
||||
outVertices.m_Position = pPosition[vid];
|
||||
outVertices.m_TexCoord = pTexCoords[vid];
|
||||
|
||||
return outVertices;
|
||||
}
|
||||
|
||||
fragment half4
|
||||
texturedFrag(VertexInOut inFrag [[ stage_in ]],
|
||||
texture2d<half> tex2D [[ texture(0) ]])
|
||||
{
|
||||
constexpr sampler quad_sampler;
|
||||
half4 color = tex2D.sample(quad_sampler, inFrag.m_TexCoord);
|
||||
|
||||
return color;
|
||||
}
|
||||
)];
|
||||
|
||||
/* Create a Metal library instance by compiling the code */
|
||||
shaderLibrary = [device newLibraryWithSource:code options:nil
|
||||
error:&error];
|
||||
if (error) {
|
||||
NSLog(@"Unable to create Metal library err: %@", error);
|
||||
return self;
|
||||
}
|
||||
|
||||
fragmentProgram = [shaderLibrary newFunctionWithName:@"texturedFrag"];
|
||||
vertexProgram = [shaderLibrary newFunctionWithName:@"texturedVertex"];
|
||||
if (!fragmentProgram || !vertexProgram) {
|
||||
NSLog(@"Unable to load Metal functions");
|
||||
return self;
|
||||
}
|
||||
|
||||
/* Create a pipeline state */
|
||||
pQuadPipelineStateDescriptor = [MTLRenderPipelineDescriptor new];
|
||||
pQuadPipelineStateDescriptor.colorAttachments[0].pixelFormat =
|
||||
stream->format;
|
||||
pQuadPipelineStateDescriptor.vertexFunction = vertexProgram;
|
||||
pQuadPipelineStateDescriptor.fragmentFunction = fragmentProgram;
|
||||
|
||||
pipelineState = [device
|
||||
newRenderPipelineStateWithDescriptor:pQuadPipelineStateDescriptor
|
||||
error:&error];
|
||||
if (error) {
|
||||
NSLog(@"newRenderPipelineStateWithDescriptor err: %@", error);
|
||||
return self;
|
||||
}
|
||||
|
||||
vertexBuffer = [device newBufferWithBytes:vertexData
|
||||
length:sizeof(vertexData)
|
||||
options:MTLResourceStorageModeShared];
|
||||
|
||||
textureCoordBuffer = [device newBufferWithBytes:textureCoordinates
|
||||
length:sizeof(textureCoordinates)
|
||||
options:MTLResourceStorageModeShared];
|
||||
|
||||
[pQuadPipelineStateDescriptor release];
|
||||
[fragmentProgram release];
|
||||
[vertexProgram release];
|
||||
[shaderLibrary release];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
if (vertexBuffer) {
|
||||
[vertexBuffer release];
|
||||
vertexBuffer = nil;
|
||||
}
|
||||
if (textureCoordBuffer) {
|
||||
[textureCoordBuffer release];
|
||||
textureCoordBuffer = nil;
|
||||
}
|
||||
if (device) {
|
||||
[device release];
|
||||
device = nil;
|
||||
}
|
||||
if (commandQueue) {
|
||||
[commandQueue release];
|
||||
commandQueue = nil;
|
||||
}
|
||||
if (pipelineState) {
|
||||
[pipelineState release];
|
||||
pipelineState = nil;
|
||||
}
|
||||
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (void)update_image
|
||||
{
|
||||
MTLRenderPassDescriptor *renderPassDescriptor;
|
||||
id<MTLCommandBuffer> commandBuffer;
|
||||
id<MTLRenderCommandEncoder> renderEncoder;
|
||||
id<MTLDrawable> drawable;
|
||||
id<MTLTexture> texture;
|
||||
MTLTextureDescriptor *textureDescriptor;
|
||||
MTLRegion region;
|
||||
unsigned width = stream->size.w, height = stream->size.h;
|
||||
|
||||
/* Place the buffer into a texture */
|
||||
textureDescriptor = [MTLTextureDescriptor
|
||||
texture2DDescriptorWithPixelFormat:stream->format
|
||||
width:width height:height mipmapped:NO];
|
||||
|
||||
texture = [device newTextureWithDescriptor:textureDescriptor];
|
||||
region = MTLRegionMake2D(0, 0, width, height);
|
||||
[texture replaceRegion:region mipmapLevel:0 withBytes:stream->render_buf
|
||||
bytesPerRow:stream->bytes_per_row];
|
||||
|
||||
/* The render pass descriptor references the texture into which Metal
|
||||
* should draw.
|
||||
*/
|
||||
renderPassDescriptor = _view.currentRenderPassDescriptor;
|
||||
if (renderPassDescriptor == nil)
|
||||
return;
|
||||
|
||||
commandBuffer = [commandQueue commandBuffer];
|
||||
|
||||
renderEncoder = [commandBuffer renderCommandEncoderWithDescriptor:
|
||||
renderPassDescriptor];
|
||||
[renderEncoder setRenderPipelineState:pipelineState];
|
||||
[renderEncoder setVertexBuffer:vertexBuffer offset:0 atIndex:0];
|
||||
[renderEncoder setVertexBuffer:textureCoordBuffer offset:0 atIndex:1];
|
||||
|
||||
[renderEncoder setFragmentTexture:texture atIndex:0];
|
||||
[renderEncoder drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:0
|
||||
vertexCount:4];
|
||||
|
||||
[renderEncoder endEncoding];
|
||||
|
||||
/* Get the drawable that will be presented at the end of the frame */
|
||||
drawable = _view.currentDrawable;
|
||||
|
||||
/* Request that the drawable texture be presented by the windowing system
|
||||
* once drawing is done.
|
||||
*/
|
||||
[commandBuffer presentDrawable:drawable];
|
||||
[commandBuffer commit];
|
||||
|
||||
[texture release];
|
||||
|
||||
stream->is_rendering = PJ_FALSE;
|
||||
}
|
||||
|
||||
|
||||
/* Called whenever the view needs to render a frame. */
|
||||
- (void)drawInMTKView:(nonnull MTKView *)view
|
||||
{
|
||||
}
|
||||
|
||||
/* Called whenever view changes orientation or is resized */
|
||||
- (void)mtkView:(nonnull MTKView *)view drawableSizeWillChange:(CGSize)size
|
||||
{
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
static pj_status_t metal_init_view(struct metal_stream *strm)
|
||||
{
|
||||
pjmedia_vid_dev_param *param = &strm->param;
|
||||
CGRect view_rect = CGRectMake(0, 0, param->fmt.det.vid.size.w,
|
||||
param->fmt.det.vid.size.h);
|
||||
|
||||
if (param->flags & PJMEDIA_VID_DEV_CAP_OUTPUT_RESIZE) {
|
||||
view_rect.size.width = param->disp_size.w;
|
||||
view_rect.size.height = param->disp_size.h;
|
||||
}
|
||||
|
||||
if (param->flags & PJMEDIA_VID_DEV_CAP_OUTPUT_POSITION) {
|
||||
view_rect.origin.x = param->window_pos.x;
|
||||
view_rect.origin.y = param->window_pos.y;
|
||||
}
|
||||
|
||||
strm->view = [[MTKView alloc] initWithFrame:view_rect];
|
||||
if (!strm->view)
|
||||
return PJMEDIA_EVID_SYSERR;
|
||||
|
||||
strm->view.enableSetNeedsDisplay = NO;
|
||||
strm->view.paused = NO;
|
||||
strm->view.device = MTLCreateSystemDefaultDevice();
|
||||
strm->view.clearColor = MTLClearColorMake(0.0, 0.0, 0.0, 1.0);
|
||||
strm->param.window.info.window = strm->view;
|
||||
|
||||
strm->renderer = [MetalRenderer alloc];
|
||||
if (!strm->renderer)
|
||||
return PJ_ENOMEM;
|
||||
|
||||
strm->renderer->stream = strm;
|
||||
strm->view.delegate = strm->renderer;
|
||||
[strm->renderer initWithMetalKitView:strm->view];
|
||||
|
||||
if (param->flags & PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW) {
|
||||
PJ_ASSERT_RETURN(param->window.info.ios.window, PJ_EINVAL);
|
||||
metal_stream_set_cap(&strm->base, PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW,
|
||||
param->window.info.ios.window);
|
||||
} else {
|
||||
#if !TARGET_OS_IPHONE
|
||||
/* Create the main window */
|
||||
strm->window = [[NSWindow alloc] initWithContentRect:view_rect
|
||||
styleMask:(NSWindowStyleMaskTitled |
|
||||
NSWindowStyleMaskClosable |
|
||||
NSWindowStyleMaskResizable)
|
||||
backing:NSBackingStoreBuffered
|
||||
defer:NO];
|
||||
if (!strm->window)
|
||||
return PJMEDIA_EVID_SYSERR;
|
||||
|
||||
/* Make the window visible */
|
||||
[strm->window.contentView addSubview:strm->view];
|
||||
[strm->window makeKeyAndOrderFront:strm->window];
|
||||
strm->param.window.info.window = strm->window;
|
||||
#endif
|
||||
}
|
||||
if (param->flags & PJMEDIA_VID_DEV_CAP_OUTPUT_HIDE) {
|
||||
metal_stream_set_cap(&strm->base, PJMEDIA_VID_DEV_CAP_OUTPUT_HIDE,
|
||||
¶m->window_hide);
|
||||
}
|
||||
if (param->flags & PJMEDIA_VID_DEV_CAP_ORIENTATION) {
|
||||
metal_stream_set_cap(&strm->base, PJMEDIA_VID_DEV_CAP_ORIENTATION,
|
||||
¶m->orient);
|
||||
}
|
||||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
static metal_fmt_info* get_metal_format_info(pjmedia_format_id id)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < PJ_ARRAY_SIZE(metal_fmts); i++) {
|
||||
if (metal_fmts[i].pjmedia_format == id)
|
||||
return &metal_fmts[i];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* API: create stream */
|
||||
static pj_status_t metal_factory_create_stream(
|
||||
pjmedia_vid_dev_factory *f,
|
||||
pjmedia_vid_dev_param *param,
|
||||
const pjmedia_vid_dev_cb *cb,
|
||||
void *user_data,
|
||||
pjmedia_vid_dev_stream **p_vid_strm)
|
||||
{
|
||||
struct metal_factory *qf = (struct metal_factory*)f;
|
||||
pj_pool_t *pool;
|
||||
struct metal_stream *strm;
|
||||
pjmedia_video_format_detail *vfd;
|
||||
const pjmedia_video_format_info *vfi;
|
||||
metal_fmt_info *mfi;
|
||||
pj_status_t status = PJ_SUCCESS;
|
||||
|
||||
PJ_ASSERT_RETURN(f && param && p_vid_strm, PJ_EINVAL);
|
||||
PJ_ASSERT_RETURN(param->fmt.type == PJMEDIA_TYPE_VIDEO &&
|
||||
param->fmt.detail_type == PJMEDIA_FORMAT_DETAIL_VIDEO &&
|
||||
param->dir == PJMEDIA_DIR_RENDER,
|
||||
PJ_EINVAL);
|
||||
|
||||
if (!(mfi = get_metal_format_info(param->fmt.id)))
|
||||
return PJMEDIA_EVID_BADFORMAT;
|
||||
|
||||
vfi = pjmedia_get_video_format_info(NULL, param->fmt.id);
|
||||
if (!vfi)
|
||||
return PJMEDIA_EVID_BADFORMAT;
|
||||
|
||||
/* Create and Initialize stream descriptor */
|
||||
pool = pj_pool_create(qf->pf, "metal-dev", 4000, 4000, NULL);
|
||||
PJ_ASSERT_RETURN(pool != NULL, PJ_ENOMEM);
|
||||
|
||||
strm = PJ_POOL_ZALLOC_T(pool, struct metal_stream);
|
||||
pj_memcpy(&strm->param, param, sizeof(*param));
|
||||
strm->pool = pool;
|
||||
pj_memcpy(&strm->vid_cb, cb, sizeof(*cb));
|
||||
strm->user_data = user_data;
|
||||
strm->factory = qf;
|
||||
|
||||
vfd = pjmedia_format_get_video_format_detail(&strm->param.fmt, PJ_TRUE);
|
||||
pj_memcpy(&strm->size, &vfd->size, sizeof(vfd->size));
|
||||
strm->bytes_per_row = strm->size.w * vfi->bpp / 8;
|
||||
strm->frame_size = strm->bytes_per_row * strm->size.h;
|
||||
strm->ts_inc = PJMEDIA_SPF2(param->clock_rate, &vfd->fps, 1);
|
||||
strm->is_planar = vfi->plane_cnt > 1;
|
||||
strm->format = mfi->metal_format;
|
||||
|
||||
if (param->dir & PJMEDIA_DIR_RENDER) {
|
||||
/* Create renderer stream here */
|
||||
|
||||
dispatch_sync_on_main_queue(^{
|
||||
metal_init_view(strm);
|
||||
});
|
||||
|
||||
strm->render_buf = pj_pool_alloc(pool, strm->frame_size);
|
||||
strm->render_buf_size = strm->frame_size;
|
||||
|
||||
PJ_LOG(4, (THIS_FILE, "Metal renderer initialized"));
|
||||
}
|
||||
|
||||
/* Done */
|
||||
strm->base.op = &stream_op;
|
||||
*p_vid_strm = &strm->base;
|
||||
|
||||
return PJ_SUCCESS;
|
||||
|
||||
on_error:
|
||||
metal_stream_destroy((pjmedia_vid_dev_stream *)strm);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* API: Get stream info. */
|
||||
static pj_status_t metal_stream_get_param(pjmedia_vid_dev_stream *s,
|
||||
pjmedia_vid_dev_param *pi)
|
||||
{
|
||||
struct metal_stream *strm = (struct metal_stream*)s;
|
||||
|
||||
PJ_ASSERT_RETURN(strm && pi, PJ_EINVAL);
|
||||
|
||||
pj_memcpy(pi, &strm->param, sizeof(*pi));
|
||||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
/* API: get capability */
|
||||
static pj_status_t metal_stream_get_cap(pjmedia_vid_dev_stream *s,
|
||||
pjmedia_vid_dev_cap cap,
|
||||
void *pval)
|
||||
{
|
||||
struct metal_stream *strm = (struct metal_stream*)s;
|
||||
|
||||
PJ_ASSERT_RETURN(s && pval, PJ_EINVAL);
|
||||
PJ_UNUSED_ARG(strm);
|
||||
|
||||
switch (cap) {
|
||||
case PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW:
|
||||
{
|
||||
pjmedia_vid_dev_hwnd *hwnd = (pjmedia_vid_dev_hwnd *) pval;
|
||||
hwnd->type = TARGET_OS_IPHONE? PJMEDIA_VID_DEV_HWND_TYPE_IOS:
|
||||
PJMEDIA_VID_DEV_HWND_TYPE_COCOA;
|
||||
hwnd->info.window = (void *)strm->view;
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return PJMEDIA_EVID_INVCAP;
|
||||
}
|
||||
|
||||
/* API: set capability */
|
||||
static pj_status_t metal_stream_set_cap(pjmedia_vid_dev_stream *s,
|
||||
pjmedia_vid_dev_cap cap,
|
||||
const void *pval)
|
||||
{
|
||||
struct metal_stream *strm = (struct metal_stream*)s;
|
||||
|
||||
PJ_ASSERT_RETURN(s && pval, PJ_EINVAL);
|
||||
|
||||
switch (cap) {
|
||||
case PJMEDIA_VID_DEV_CAP_FORMAT:
|
||||
{
|
||||
const pjmedia_video_format_info *vfi;
|
||||
pjmedia_video_format_detail *vfd;
|
||||
pjmedia_format *fmt = (pjmedia_format *)pval;
|
||||
metal_fmt_info *ifi;
|
||||
|
||||
if (!(ifi = get_metal_format_info(fmt->id)))
|
||||
return PJMEDIA_EVID_BADFORMAT;
|
||||
|
||||
vfi = pjmedia_get_video_format_info(
|
||||
pjmedia_video_format_mgr_instance(),
|
||||
fmt->id);
|
||||
if (!vfi)
|
||||
return PJMEDIA_EVID_BADFORMAT;
|
||||
|
||||
pjmedia_format_copy(&strm->param.fmt, fmt);
|
||||
|
||||
vfd = pjmedia_format_get_video_format_detail(fmt, PJ_TRUE);
|
||||
pj_memcpy(&strm->size, &vfd->size, sizeof(vfd->size));
|
||||
strm->bytes_per_row = strm->size.w * vfi->bpp / 8;
|
||||
strm->frame_size = strm->bytes_per_row * strm->size.h;
|
||||
if (strm->render_buf_size < strm->frame_size) {
|
||||
/* Realloc only when needed */
|
||||
strm->render_buf = pj_pool_alloc(strm->pool, strm->frame_size);
|
||||
strm->render_buf_size = strm->frame_size;
|
||||
}
|
||||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
case PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW:
|
||||
{
|
||||
strm->param.window.info.window = (void *)pval;
|
||||
dispatch_sync_on_main_queue(^{
|
||||
[(NSView *)pval addSubview:strm->view];
|
||||
});
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
case PJMEDIA_VID_DEV_CAP_OUTPUT_RESIZE:
|
||||
{
|
||||
pj_memcpy(&strm->param.disp_size, pval,
|
||||
sizeof(strm->param.disp_size));
|
||||
dispatch_sync_on_main_queue(^{
|
||||
CGRect r = (strm->window)? strm->window.frame:
|
||||
strm->view.bounds;
|
||||
r.size = CGSizeMake(strm->param.disp_size.w,
|
||||
strm->param.disp_size.h);
|
||||
if (!strm->window)
|
||||
strm->view.bounds = r;
|
||||
#if !TARGET_OS_IPHONE
|
||||
else
|
||||
[strm->window setFrame:r display:YES];
|
||||
#endif
|
||||
});
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
case PJMEDIA_VID_DEV_CAP_OUTPUT_POSITION:
|
||||
{
|
||||
pj_memcpy(&strm->param.window_pos, pval,
|
||||
sizeof(strm->param.window_pos));
|
||||
dispatch_sync_on_main_queue(^{
|
||||
#if TARGET_OS_IPHONE
|
||||
strm->view.center =
|
||||
CGPointMake(strm->param.window_pos.x +
|
||||
strm->param.disp_size.w/2.0,
|
||||
strm->param.window_pos.y +
|
||||
strm->param.disp_size.h/2.0);
|
||||
#else
|
||||
if (strm->window) {
|
||||
[strm->window setFrameOrigin:
|
||||
NSMakePoint(strm->param.window_pos.x,
|
||||
strm->param.window_pos.y)];
|
||||
} else {
|
||||
[strm->view setFrameOrigin:
|
||||
NSMakePoint(strm->param.window_pos.x,
|
||||
strm->param.window_pos.y)];
|
||||
}
|
||||
#endif
|
||||
});
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
case PJMEDIA_VID_DEV_CAP_OUTPUT_HIDE:
|
||||
{
|
||||
dispatch_sync_on_main_queue(^{
|
||||
pj_bool_t hide = *((pj_bool_t *)pval);
|
||||
if (strm->window) {
|
||||
#if !TARGET_OS_IPHONE
|
||||
if (hide)
|
||||
[strm->window orderOut: nil];
|
||||
else
|
||||
[strm->window orderFront: nil];
|
||||
#endif
|
||||
} else {
|
||||
strm->view.hidden = (BOOL)hide;
|
||||
}
|
||||
});
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
case PJMEDIA_VID_DEV_CAP_ORIENTATION:
|
||||
{
|
||||
pjmedia_orient orient = *(pjmedia_orient *)pval;
|
||||
|
||||
pj_assert(orient >= PJMEDIA_ORIENT_UNKNOWN &&
|
||||
orient <= PJMEDIA_ORIENT_ROTATE_270DEG);
|
||||
|
||||
if (orient == PJMEDIA_ORIENT_UNKNOWN)
|
||||
return PJ_EINVAL;
|
||||
|
||||
pj_memcpy(&strm->param.orient, pval,
|
||||
sizeof(strm->param.orient));
|
||||
|
||||
dispatch_sync_on_main_queue(^{
|
||||
CGFloat angle = -M_PI_2 * ((int)strm->param.orient-1);
|
||||
#if TARGET_OS_IPHONE
|
||||
strm->view.transform =
|
||||
CGAffineTransformMakeRotation(angle);
|
||||
#else
|
||||
strm->view.layer.affineTransform =
|
||||
CGAffineTransformMakeRotation(angle);
|
||||
#endif
|
||||
});
|
||||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return PJMEDIA_EVID_INVCAP;
|
||||
}
|
||||
|
||||
/* API: Start stream. */
|
||||
static pj_status_t metal_stream_start(pjmedia_vid_dev_stream *strm)
|
||||
{
|
||||
struct metal_stream *stream = (struct metal_stream*)strm;
|
||||
|
||||
PJ_LOG(4, (THIS_FILE, "Starting Metal video stream"));
|
||||
stream->is_running = PJ_TRUE;
|
||||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/* API: Put frame from stream */
|
||||
static pj_status_t metal_stream_put_frame(pjmedia_vid_dev_stream *strm,
|
||||
const pjmedia_frame *frame)
|
||||
{
|
||||
struct metal_stream *stream = (struct metal_stream*)strm;
|
||||
|
||||
/* Video conference just trying to send heart beat for updating timestamp
|
||||
* or keep-alive, this port doesn't need any, just ignore.
|
||||
*/
|
||||
if (frame->size==0 || frame->buf==NULL)
|
||||
return PJ_SUCCESS;
|
||||
|
||||
if (!stream->is_running)
|
||||
return PJ_EINVALIDOP;
|
||||
|
||||
/* Prevent more than one async rendering task. */
|
||||
if (stream->is_rendering)
|
||||
return PJ_EIGNORED;
|
||||
|
||||
if (stream->frame_size >= frame->size)
|
||||
pj_memcpy(stream->render_buf, frame->buf, frame->size);
|
||||
else
|
||||
pj_memcpy(stream->render_buf, frame->buf, stream->frame_size);
|
||||
|
||||
/* Perform video display in the main thread */
|
||||
stream->is_rendering = PJ_TRUE;
|
||||
[stream->renderer performSelectorOnMainThread:@selector(update_image)
|
||||
withObject:nil waitUntilDone:NO];
|
||||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
/* API: Stop stream. */
|
||||
static pj_status_t metal_stream_stop(pjmedia_vid_dev_stream *strm)
|
||||
{
|
||||
struct metal_stream *stream = (struct metal_stream*)strm;
|
||||
unsigned i;
|
||||
|
||||
PJ_LOG(4, (THIS_FILE, "Stopping Metal video stream"));
|
||||
|
||||
stream->is_running = PJ_FALSE;
|
||||
|
||||
/* Wait until the rendering finishes */
|
||||
for (i = 0; i < 15; i++) pj_thread_sleep(10);
|
||||
while (stream->is_rendering);
|
||||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/* API: Destroy stream. */
|
||||
static pj_status_t metal_stream_destroy(pjmedia_vid_dev_stream *strm)
|
||||
{
|
||||
struct metal_stream *stream = (struct metal_stream*)strm;
|
||||
|
||||
PJ_ASSERT_RETURN(stream != NULL, PJ_EINVAL);
|
||||
|
||||
metal_stream_stop(strm);
|
||||
|
||||
if (stream->renderer) {
|
||||
[stream->renderer release];
|
||||
stream->renderer = nil;
|
||||
}
|
||||
|
||||
if (stream->view) {
|
||||
[stream->view
|
||||
performSelectorOnMainThread:@selector(removeFromSuperview)
|
||||
withObject:nil waitUntilDone:YES];
|
||||
[stream->view release];
|
||||
stream->view = nil;
|
||||
}
|
||||
|
||||
if (stream->window) {
|
||||
[stream->window performSelectorOnMainThread:@selector(close)
|
||||
withObject:nil waitUntilDone:YES];
|
||||
stream->window = nil;
|
||||
}
|
||||
|
||||
pjmedia_vid_dev_conv_destroy_converter(&stream->conv);
|
||||
|
||||
pj_pool_release(stream->pool);
|
||||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
#endif /* PJMEDIA_VIDEO_DEV_HAS_METAL */
|
|
@ -34,6 +34,10 @@ pjmedia_vid_dev_factory* pjmedia_dshow_factory(pj_pool_factory *pf);
|
|||
pjmedia_vid_dev_factory* pjmedia_cbar_factory(pj_pool_factory *pf);
|
||||
#endif
|
||||
|
||||
#if PJMEDIA_VIDEO_DEV_HAS_METAL
|
||||
pjmedia_vid_dev_factory* pjmedia_metal_factory(pj_pool_factory *pf);
|
||||
#endif
|
||||
|
||||
#if PJMEDIA_VIDEO_DEV_HAS_SDL
|
||||
pjmedia_vid_dev_factory* pjmedia_sdl_factory(pj_pool_factory *pf);
|
||||
#endif
|
||||
|
@ -97,6 +101,9 @@ PJ_DEF(pj_status_t) pjmedia_vid_dev_subsys_init(pj_pool_factory *pf)
|
|||
#if PJMEDIA_VIDEO_DEV_HAS_QT
|
||||
vid_subsys->drv[vid_subsys->drv_cnt++].create = &pjmedia_qt_factory;
|
||||
#endif
|
||||
#if PJMEDIA_VIDEO_DEV_HAS_METAL
|
||||
vid_subsys->drv[vid_subsys->drv_cnt++].create = &pjmedia_metal_factory;
|
||||
#endif
|
||||
#if PJMEDIA_VIDEO_DEV_HAS_OPENGL
|
||||
vid_subsys->drv[vid_subsys->drv_cnt++].create = &pjmedia_opengl_factory;
|
||||
#endif
|
||||
|
|
|
@ -79,7 +79,8 @@ pjmedia_clock_src_get_time_msec( const pjmedia_clock_src *clocksrc )
|
|||
{
|
||||
pj_timestamp ts;
|
||||
|
||||
pjmedia_clock_src_get_current_timestamp(clocksrc, &ts);
|
||||
if (pjmedia_clock_src_get_current_timestamp(clocksrc, &ts) != PJ_SUCCESS)
|
||||
return 0;
|
||||
|
||||
#if PJ_HAS_INT64
|
||||
if (ts.u64 > PJ_UINT64(0x3FFFFFFFFFFFFF))
|
||||
|
|
|
@ -1049,6 +1049,7 @@ PJ_DEF(pj_status_t) pjmedia_conf_disconnect_port( pjmedia_conf *conf,
|
|||
unsigned sink_slot )
|
||||
{
|
||||
struct conf_port *src_port, *dst_port;
|
||||
pj_bool_t no_conn = PJ_FALSE;
|
||||
unsigned i;
|
||||
|
||||
/* Check arguments */
|
||||
|
@ -1098,9 +1099,12 @@ PJ_DEF(pj_status_t) pjmedia_conf_disconnect_port( pjmedia_conf *conf,
|
|||
pjmedia_delay_buf_reset(src_port->delay_buf);
|
||||
}
|
||||
|
||||
/* Evaluate connect_cnt with mutex, but pause sound dev outside mutex */
|
||||
no_conn = (conf->connect_cnt == 0);
|
||||
|
||||
pj_mutex_unlock(conf->mutex);
|
||||
|
||||
if (conf->connect_cnt == 0) {
|
||||
if (no_conn) {
|
||||
pause_sound(conf);
|
||||
}
|
||||
|
||||
|
|
|
@ -24,14 +24,12 @@
|
|||
#include <pj/log.h>
|
||||
#include <pj/pool.h>
|
||||
|
||||
#define THIS_FILE "resample.c"
|
||||
|
||||
#if PJMEDIA_RESAMPLE_IMP==PJMEDIA_RESAMPLE_LIBRESAMPLE
|
||||
|
||||
#include <third_party/resample/include/resamplesubs.h>
|
||||
|
||||
#define THIS_FILE "resample.c"
|
||||
|
||||
|
||||
|
||||
struct pjmedia_resample
|
||||
{
|
||||
|
@ -158,7 +156,7 @@ PJ_DEF(void) pjmedia_resample_run( pjmedia_resample *resample,
|
|||
* So here comes the trick.
|
||||
*
|
||||
* First of all, because of the history and lookahead requirement,
|
||||
* resample->buffer need to accomodate framesize+2*xoff samples in its
|
||||
* resample->buffer need to accommodate framesize+2*xoff samples in its
|
||||
* buffer. This is done when the buffer is created.
|
||||
*
|
||||
* On the first run, the input frame (supplied by application) is
|
||||
|
@ -176,8 +174,8 @@ PJ_DEF(void) pjmedia_resample_run( pjmedia_resample *resample,
|
|||
* | 0000 | 0000 | frame0... |
|
||||
* +------+------+--------------+
|
||||
* ^ ^ ^ ^
|
||||
* 0 xoff 2*xoff size+2*xoff
|
||||
*
|
||||
* 0 xoff 2*xoff size+2*xoff
|
||||
*
|
||||
* (Note again: resample algorithm is called at resample->buffer+xoff)
|
||||
*
|
||||
* At the end of the run, 2*xoff samples from the end of
|
||||
|
@ -204,7 +202,7 @@ PJ_DEF(void) pjmedia_resample_run( pjmedia_resample *resample,
|
|||
* | frm0 | frm0 | frame1... |
|
||||
* +------+------+--------------+
|
||||
* ^ ^ ^ ^
|
||||
* 0 xoff 2*xoff size+2*xoff
|
||||
* 0 xoff 2*xoff size+2*xoff
|
||||
*
|
||||
* As you can see from above diagram, the resampling algorithm is
|
||||
* actually called from the last xoff part of previous frame (frm0).
|
||||
|
@ -320,6 +318,8 @@ PJ_DEF(pj_status_t) pjmedia_resample_create( pj_pool_t *pool,
|
|||
PJ_UNUSED_ARG(samples_per_frame);
|
||||
PJ_UNUSED_ARG(p_resample);
|
||||
|
||||
PJ_LOG(3, (THIS_FILE, "No resampler created (sample rate conversion is "
|
||||
"disabled or no resample implementation selected)"));
|
||||
return PJ_EINVALIDOP;
|
||||
}
|
||||
|
||||
|
|
|
@ -597,8 +597,8 @@ PJ_DEF(pj_status_t) pjmedia_sdp_rtpmap_to_attr(pj_pool_t *pool,
|
|||
PJ_ASSERT_RETURN(pool && rtpmap && p_attr, PJ_EINVAL);
|
||||
|
||||
/* Check that mandatory attributes are specified. */
|
||||
PJ_ASSERT_RETURN(rtpmap->enc_name.slen && rtpmap->clock_rate,
|
||||
PJMEDIA_SDP_EINRTPMAP);
|
||||
PJ_ASSERT_RETURN(rtpmap->pt.slen && rtpmap->enc_name.slen &&
|
||||
rtpmap->clock_rate, PJMEDIA_SDP_EINRTPMAP);
|
||||
|
||||
|
||||
attr = PJ_POOL_ALLOC_T(pool, pjmedia_sdp_attr);
|
||||
|
@ -617,7 +617,7 @@ PJ_DEF(pj_status_t) pjmedia_sdp_rtpmap_to_attr(pj_pool_t *pool,
|
|||
rtpmap->clock_rate,
|
||||
(rtpmap->param.slen ? "/" : ""),
|
||||
(int)rtpmap->param.slen,
|
||||
rtpmap->param.ptr);
|
||||
rtpmap->param.slen ? rtpmap->param.ptr : "");
|
||||
|
||||
if (len < 1 || len >= (int)sizeof(tempbuf))
|
||||
return PJMEDIA_SDP_ERTPMAPTOOLONG;
|
||||
|
@ -895,9 +895,11 @@ static int print_session(const pjmedia_sdp_session *ses,
|
|||
int printed;
|
||||
|
||||
/* Check length for v= and o= lines. */
|
||||
if (len < 5+
|
||||
2+ses->origin.user.slen+18+
|
||||
ses->origin.net_type.slen+ses->origin.addr.slen + 2)
|
||||
if (len < 5 + 2 + ses->origin.user.slen +
|
||||
20 + 20 + 3 + /* max digits of origin.id and version +
|
||||
* whitespaces */
|
||||
ses->origin.net_type.slen + ses->origin.addr_type.slen +
|
||||
ses->origin.addr.slen + 2 + 2)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
@ -959,7 +961,7 @@ static int print_session(const pjmedia_sdp_session *ses,
|
|||
}
|
||||
|
||||
/* Time */
|
||||
if ((end-p) < 24) {
|
||||
if ((end-p) < 2+20+1+20+2) {
|
||||
return -1;
|
||||
}
|
||||
*p++ = 't';
|
||||
|
@ -1770,7 +1772,7 @@ PJ_DEF(pj_uint32_t) pjmedia_sdp_transport_get_proto(const pj_str_t *tp)
|
|||
PJ_ASSERT_RETURN(tp, PJMEDIA_TP_PROTO_NONE);
|
||||
|
||||
idx = pj_strtok2(tp, "/", &token, 0);
|
||||
if (idx != tp->slen)
|
||||
if ((idx != tp->slen) && (tp->slen != token.slen))
|
||||
pj_strset(&rest, tp->ptr + token.slen + 1, tp->slen - token.slen - 1);
|
||||
|
||||
if (pj_stricmp2(&token, "RTP") == 0) {
|
||||
|
|
|
@ -1087,10 +1087,11 @@ static pj_status_t send_rtcp(pjmedia_stream *stream,
|
|||
pj_status_t status;
|
||||
|
||||
/* We need to prevent data race since there is only a single instance
|
||||
* of rtcp packet buffer. Let's just use the JB mutex for this instead
|
||||
* of creating a separate lock.
|
||||
* of rtcp packet buffer. And to avoid deadlock with media transport,
|
||||
* we use the transport's group lock.
|
||||
*/
|
||||
pj_mutex_lock(stream->jb_mutex);
|
||||
if (stream->transport->grp_lock)
|
||||
pj_grp_lock_acquire(stream->transport->grp_lock);
|
||||
|
||||
/* Build RTCP RR/SR packet */
|
||||
pjmedia_rtcp_build_rtcp(&stream->rtcp, &sr_rr_pkt, &len);
|
||||
|
@ -1211,7 +1212,8 @@ static pj_status_t send_rtcp(pjmedia_stream *stream,
|
|||
}
|
||||
}
|
||||
|
||||
pj_mutex_unlock(stream->jb_mutex);
|
||||
if (stream->transport->grp_lock)
|
||||
pj_grp_lock_release(stream->transport->grp_lock);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
@ -3068,7 +3070,7 @@ PJ_DEF(pj_status_t) pjmedia_stream_destroy( pjmedia_stream *stream )
|
|||
PJ_ASSERT_RETURN(stream != NULL, PJ_EINVAL);
|
||||
|
||||
/* Send RTCP BYE (also SDES & XR) */
|
||||
if (stream->transport && stream->jb_mutex && !stream->rtcp_sdes_bye_disabled) {
|
||||
if (stream->transport && !stream->rtcp_sdes_bye_disabled) {
|
||||
#if defined(PJMEDIA_HAS_RTCP_XR) && (PJMEDIA_HAS_RTCP_XR != 0)
|
||||
send_rtcp(stream, PJ_TRUE, PJ_TRUE, stream->rtcp.xr_enabled, PJ_FALSE);
|
||||
#else
|
||||
|
|
|
@ -187,6 +187,7 @@ pjmedia_transport_loop_create2(pjmedia_endpt *endpt,
|
|||
if (status != PJ_SUCCESS)
|
||||
return status;
|
||||
|
||||
tp->base.grp_lock = grp_lock;
|
||||
pj_grp_lock_add_ref(grp_lock);
|
||||
pj_grp_lock_add_handler(grp_lock, pool, tp, &tp_loop_on_destroy);
|
||||
|
||||
|
|
|
@ -464,7 +464,7 @@ static pj_status_t ssl_generate_cert(X509 **p_cert, EVP_PKEY **p_priv_key)
|
|||
if (!X509_set_pubkey(cert, priv_key)) goto on_error;
|
||||
|
||||
/* Sign with the private key */
|
||||
if (!X509_sign(cert, priv_key, EVP_sha1())) goto on_error;
|
||||
if (!X509_sign(cert, priv_key, EVP_sha256())) goto on_error;
|
||||
|
||||
/* Free big number */
|
||||
BN_free(bne);
|
||||
|
@ -745,7 +745,7 @@ static pj_status_t send_raw(dtls_srtp *ds, unsigned idx, const void *buf,
|
|||
{
|
||||
#if DTLS_DEBUG
|
||||
PJ_LOG(2,(ds->base.name, "DTLS-SRTP %s sending %lu bytes",
|
||||
CHANNEL_TO_STRING(idx), len));
|
||||
CHANNEL_TO_STRING(idx), (unsigned long)len));
|
||||
#endif
|
||||
|
||||
return (idx == RTP_CHANNEL?
|
||||
|
@ -829,8 +829,6 @@ static pj_status_t ssl_flush_wbio(dtls_srtp *ds, unsigned idx)
|
|||
PJ_LOG(2,(ds->base.name, "DTLS-SRTP negotiation for %s completed!",
|
||||
CHANNEL_TO_STRING(idx)));
|
||||
|
||||
DTLS_UNLOCK(ds);
|
||||
|
||||
/* Stop the retransmission clock. Note that the clock may not be stopped
|
||||
* if this function is called from clock thread context. We'll try again
|
||||
* later in socket context.
|
||||
|
@ -838,6 +836,8 @@ static pj_status_t ssl_flush_wbio(dtls_srtp *ds, unsigned idx)
|
|||
if (ds->clock[idx])
|
||||
pjmedia_clock_stop(ds->clock[idx]);
|
||||
|
||||
DTLS_UNLOCK(ds);
|
||||
|
||||
/* Get SRTP key material */
|
||||
status = ssl_get_srtp_material(ds, idx);
|
||||
if (status != PJ_SUCCESS) {
|
||||
|
@ -1280,7 +1280,7 @@ static pj_status_t dtls_on_recv(pjmedia_transport *tp, unsigned idx,
|
|||
|
||||
#if DTLS_DEBUG
|
||||
PJ_LOG(2,(ds->base.name, "DTLS-SRTP %s receiving %lu bytes",
|
||||
CHANNEL_TO_STRING(idx), size));
|
||||
CHANNEL_TO_STRING(idx), (unsigned long)size));
|
||||
#endif
|
||||
|
||||
/* This is DTLS packet, let's process it. Note that if DTLS nego has
|
||||
|
@ -1890,8 +1890,10 @@ static pj_status_t dtls_media_stop(pjmedia_transport *tp)
|
|||
PJ_LOG(2,(ds->base.name, "dtls_media_stop()"));
|
||||
#endif
|
||||
|
||||
DTLS_LOCK(ds);
|
||||
dtls_media_stop_channel(ds, RTP_CHANNEL);
|
||||
dtls_media_stop_channel(ds, RTCP_CHANNEL);
|
||||
DTLS_UNLOCK(ds);
|
||||
|
||||
ds->setup = DTLS_SETUP_UNKNOWN;
|
||||
ds->use_ice = PJ_FALSE;
|
||||
|
|
|
@ -34,6 +34,9 @@
|
|||
# endif
|
||||
#endif
|
||||
|
||||
#if (PJ_SSL_SOCK_IMP == PJ_SSL_SOCK_IMP_APPLE)
|
||||
#include <Security/SecRandom.h>
|
||||
#endif
|
||||
|
||||
#include <pj/rand.h>
|
||||
|
||||
|
@ -134,6 +137,16 @@ static pj_status_t generate_crypto_attr_value(pj_pool_t *pool,
|
|||
"(native err=%d)", err));
|
||||
return PJMEDIA_ERRNO_FROM_LIBSRTP(1);
|
||||
}
|
||||
#elif defined(PJ_HAS_SSL_SOCK) && (PJ_HAS_SSL_SOCK != 0) && \
|
||||
(PJ_SSL_SOCK_IMP == PJ_SSL_SOCK_IMP_APPLE)
|
||||
int err = SecRandomCopyBytes(kSecRandomDefault,
|
||||
crypto_suites[cs_idx].cipher_key_len,
|
||||
&key);
|
||||
if (err != errSecSuccess) {
|
||||
PJ_LOG(4,(THIS_FILE, "Failed generating random key "
|
||||
"(native err=%d)", err));
|
||||
return PJMEDIA_ERRNO_FROM_LIBSRTP(1);
|
||||
}
|
||||
#else
|
||||
PJ_LOG(3,(THIS_FILE, "Warning: simple random generator is used "
|
||||
"for generating SRTP key"));
|
||||
|
|
|
@ -1398,7 +1398,8 @@ static pj_status_t vid_pasv_port_put_frame(struct pjmedia_port *this_port,
|
|||
if (frame->size != vp->src_size) {
|
||||
if (frame->size > 0) {
|
||||
PJ_LOG(4,(THIS_FILE, "Unexpected frame size %lu, expected %lu",
|
||||
frame->size, vp->src_size));
|
||||
(unsigned long)frame->size,
|
||||
(unsigned long)vp->src_size));
|
||||
}
|
||||
|
||||
pj_memcpy(&frame_, frame, sizeof(pjmedia_frame));
|
||||
|
|
|
@ -584,7 +584,12 @@ static pj_status_t send_rtcp(pjmedia_vid_stream *stream,
|
|||
int len, max_len;
|
||||
pj_status_t status;
|
||||
|
||||
pj_grp_lock_acquire( stream->grp_lock );
|
||||
|
||||
/* To avoid deadlock with media transport, we use the transport's
|
||||
* group lock.
|
||||
*/
|
||||
if (stream->transport->grp_lock)
|
||||
pj_grp_lock_acquire( stream->transport->grp_lock );
|
||||
|
||||
/* Build RTCP RR/SR packet */
|
||||
pjmedia_rtcp_build_rtcp(&stream->rtcp, &sr_rr_pkt, &len);
|
||||
|
@ -667,7 +672,8 @@ static pj_status_t send_rtcp(pjmedia_vid_stream *stream,
|
|||
}
|
||||
}
|
||||
|
||||
pj_grp_lock_release( stream->grp_lock );
|
||||
if (stream->transport->grp_lock)
|
||||
pj_grp_lock_release( stream->transport->grp_lock );
|
||||
|
||||
return status;
|
||||
}
|
||||
|
@ -2191,7 +2197,7 @@ PJ_DEF(pj_status_t) pjmedia_vid_stream_destroy( pjmedia_vid_stream *stream )
|
|||
pjmedia_event_unsubscribe(NULL, &stream_event_cb, stream, &stream->rtcp);
|
||||
|
||||
/* Send RTCP BYE (also SDES) */
|
||||
if (stream->transport && stream->grp_lock && !stream->rtcp_sdes_bye_disabled) {
|
||||
if (stream->transport && !stream->rtcp_sdes_bye_disabled) {
|
||||
send_rtcp(stream, PJ_TRUE, PJ_TRUE, PJ_FALSE, PJ_FALSE);
|
||||
}
|
||||
|
||||
|
|
|
@ -220,7 +220,7 @@ PJ_DEF(pj_status_t) pjmedia_wav_writer_port_create( pj_pool_t *pool,
|
|||
(int)fport->base.info.name.slen,
|
||||
fport->base.info.name.ptr,
|
||||
PJMEDIA_PIA_SRATE(&fport->base.info),
|
||||
fport->bufsize / 1000));
|
||||
(unsigned long)(fport->bufsize / 1000)));
|
||||
|
||||
|
||||
return PJ_SUCCESS;
|
||||
|
|
|
@ -178,7 +178,8 @@ static int codec_test_encode(pjmedia_codec_mgr *mgr,
|
|||
break;
|
||||
}
|
||||
|
||||
PJ_LOG(1,(THIS_FILE," failed: mismatch at pos %ld", pos+i));
|
||||
PJ_LOG(1,(THIS_FILE," failed: mismatch at pos %lu",
|
||||
(unsigned long)(pos+i)));
|
||||
rc = -200;
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -240,7 +240,7 @@ static int loopback_test(void)
|
|||
if ((cdi.dir & PJMEDIA_DIR_CAPTURE) == 0)
|
||||
continue;
|
||||
|
||||
for (j=i+1; j<count; ++j) {
|
||||
for (j=0; j<count; ++j) {
|
||||
pjmedia_vid_dev_info rdi;
|
||||
unsigned k;
|
||||
|
||||
|
|
|
@ -223,6 +223,14 @@ typedef struct pj_turn_sock_tls_cfg
|
|||
*/
|
||||
pj_str_t password;
|
||||
|
||||
/**
|
||||
* Lookup certificate from OS certificate store with specified criteria.
|
||||
*
|
||||
* Currently only used by TLS backend Windows Schannel, please check
|
||||
* pj_ssl_cert_load_from_store() for more info.
|
||||
*/
|
||||
pj_ssl_cert_lookup_criteria cert_lookup;
|
||||
|
||||
/**
|
||||
* The ssl socket parameter.
|
||||
* These fields are used by TURN TLS:
|
||||
|
@ -355,8 +363,8 @@ typedef struct pj_turn_sock_cfg
|
|||
unsigned so_sndbuf_size;
|
||||
|
||||
/**
|
||||
* This specifies TLS settings for TLS transport. It is only be used
|
||||
* when this TLS is used to connect to the TURN server.
|
||||
* This specifies TLS settings for TLS transport. It's only applicable when
|
||||
* TLS is used to connect to the TURN server.
|
||||
*/
|
||||
pj_turn_sock_tls_cfg tls_cfg;
|
||||
|
||||
|
|
|
@ -1047,8 +1047,8 @@ static pj_bool_t alloc_on_data_recvfrom(pj_activesock_t *asock,
|
|||
}
|
||||
}
|
||||
if (i==alloc->perm_cnt) {
|
||||
PJ_LOG(5,("", "Client %s received %ld bytes unauthorized data from peer %s",
|
||||
client_info, size, peer_info));
|
||||
PJ_LOG(5,("", "Client %s received %lu bytes unauthorized data from peer %s",
|
||||
client_info, (unsigned long)size, peer_info));
|
||||
if (alloc->perm_cnt == 0)
|
||||
PJ_LOG(5,("", "Client %s has no permission", client_info));
|
||||
return PJ_TRUE;
|
||||
|
@ -1073,8 +1073,8 @@ static pj_bool_t alloc_on_data_recvfrom(pj_activesock_t *asock,
|
|||
|
||||
/* Send */
|
||||
sent = size;
|
||||
PJ_LOG(5,("", "Forwarding %ld bytes data from peer %s to client %s",
|
||||
sent, peer_info, client_info));
|
||||
PJ_LOG(5,("", "Forwarding %lu bytes data from peer %s to client %s",
|
||||
(unsigned long)sent, peer_info, client_info));
|
||||
|
||||
pj_activesock_sendto(alloc->test_srv->turn_sock, &alloc->send_key, buffer,
|
||||
&sent, 0, &alloc->client_addr,
|
||||
|
|
|
@ -1677,8 +1677,8 @@ static pj_bool_t on_check_complete(pj_ice_sess *ice,
|
|||
}
|
||||
}
|
||||
|
||||
LOG5((ice->obj_name, "Check %ld is successful%s",
|
||||
GET_CHECK_ID(&ice->clist, check),
|
||||
LOG5((ice->obj_name, "Check %d is successful%s",
|
||||
(int)GET_CHECK_ID(&ice->clist, check),
|
||||
(check->nominated ? " and nominated" : "")));
|
||||
|
||||
/* On the first valid pair, we call the callback, if present */
|
||||
|
|
|
@ -2547,8 +2547,8 @@ PJ_DEF(pj_status_t) pj_stun_msg_decode(pj_pool_t *pool,
|
|||
if (pdu_len > 0) {
|
||||
/* Stray trailing bytes */
|
||||
PJ_LOG(4,(THIS_FILE,
|
||||
"Error decoding STUN message: unparsed trailing %ld bytes",
|
||||
pdu_len));
|
||||
"Error decoding STUN message: unparsed trailing %lu bytes",
|
||||
(unsigned long)pdu_len));
|
||||
return PJNATH_EINSTUNMSGLEN;
|
||||
}
|
||||
|
||||
|
|
|
@ -664,7 +664,9 @@ PJ_DEF(pj_status_t) pj_turn_session_set_server( pj_turn_session *sess,
|
|||
unsigned i, cnt;
|
||||
|
||||
/* Default port must be specified */
|
||||
PJ_ASSERT_RETURN(default_port>0 && default_port<65536, PJ_EINVAL);
|
||||
PJ_ASSERT_ON_FAIL(default_port>0 && default_port<65536,
|
||||
{status=PJ_EINVAL; goto on_return;});
|
||||
|
||||
sess->default_port = (pj_uint16_t)default_port;
|
||||
|
||||
cnt = PJ_TURN_MAX_DNS_SRV_CNT;
|
||||
|
@ -1199,7 +1201,7 @@ PJ_DEF(pj_status_t) pj_turn_session_connection_bind(
|
|||
PJ_STUN_ATTR_CONNECTION_ID,
|
||||
conn_id);
|
||||
|
||||
conn_bind = PJ_POOL_ZALLOC_T(pool, struct conn_bind_t);
|
||||
conn_bind = PJ_POOL_ZALLOC_T(tdata->pool, struct conn_bind_t);
|
||||
conn_bind->id = conn_id;
|
||||
pj_sockaddr_cp(&conn_bind->peer_addr, peer_addr);
|
||||
conn_bind->peer_addr_len = addr_len;
|
||||
|
|
|
@ -1389,12 +1389,21 @@ static void turn_on_state(pj_turn_session *sess,
|
|||
&turn_sock->setting.tls_cfg.privkey_buf,
|
||||
&turn_sock->setting.tls_cfg.password,
|
||||
&turn_sock->cert);
|
||||
} else if (turn_sock->setting.tls_cfg.cert_lookup.type !=
|
||||
PJ_SSL_CERT_LOOKUP_NONE &&
|
||||
turn_sock->setting.tls_cfg.cert_lookup.keyword.slen)
|
||||
{
|
||||
status = pj_ssl_cert_load_from_store(
|
||||
turn_sock->pool,
|
||||
&turn_sock->setting.tls_cfg.cert_lookup,
|
||||
&turn_sock->cert);
|
||||
}
|
||||
if (status != PJ_SUCCESS) {
|
||||
turn_sock_destroy(turn_sock, status);
|
||||
pj_grp_lock_release(turn_sock->grp_lock);
|
||||
return;
|
||||
}
|
||||
|
||||
if (turn_sock->cert) {
|
||||
pj_turn_sock_tls_cfg_wipe_keys(&turn_sock->setting.tls_cfg);
|
||||
}
|
||||
|
|
|
@ -325,12 +325,14 @@ static void add_device(const char *dev_id, const char *url)
|
|||
{
|
||||
unsigned i;
|
||||
|
||||
pj_mutex_lock(upnp_mgr.mutex);
|
||||
|
||||
if (upnp_mgr.igd_cnt >= MAX_DEVS) {
|
||||
pj_mutex_unlock(upnp_mgr.mutex);
|
||||
PJ_LOG(3, (THIS_FILE, "Warning: Too many UPnP devices discovered"));
|
||||
return;
|
||||
}
|
||||
|
||||
pj_mutex_lock(upnp_mgr.mutex);
|
||||
for (i = 0; i < upnp_mgr.igd_cnt; i++) {
|
||||
if (!pj_strcmp2(&upnp_mgr.igd_devs[i].dev_id, dev_id) &&
|
||||
!pj_strcmp2(&upnp_mgr.igd_devs[i].url, url))
|
||||
|
@ -358,6 +360,8 @@ static void set_device_online(const char *dev_id)
|
|||
{
|
||||
unsigned i;
|
||||
|
||||
pj_mutex_lock(upnp_mgr.mutex);
|
||||
|
||||
for (i = 0; i < upnp_mgr.igd_cnt; i++) {
|
||||
struct igd *igd = &upnp_mgr.igd_devs[i];
|
||||
|
||||
|
@ -367,15 +371,15 @@ static void set_device_online(const char *dev_id)
|
|||
|
||||
if (upnp_mgr.primary_igd_idx < 0) {
|
||||
/* If we don't have a primary IGD, use this. */
|
||||
pj_mutex_lock(upnp_mgr.mutex);
|
||||
upnp_mgr.primary_igd_idx = i;
|
||||
pj_mutex_unlock(upnp_mgr.mutex);
|
||||
|
||||
PJ_LOG(4, (THIS_FILE, "Using primary IGD %s",
|
||||
upnp_mgr.igd_devs[i].dev_id.ptr));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pj_mutex_unlock(upnp_mgr.mutex);
|
||||
}
|
||||
|
||||
/* Update IGD status to offline. */
|
||||
|
@ -383,6 +387,8 @@ static void set_device_offline(const char *dev_id)
|
|||
{
|
||||
int i;
|
||||
|
||||
pj_mutex_lock(upnp_mgr.mutex);
|
||||
|
||||
for (i = 0; i < (int)upnp_mgr.igd_cnt; i++) {
|
||||
struct igd *igd = &upnp_mgr.igd_devs[i];
|
||||
|
||||
|
@ -390,7 +396,6 @@ static void set_device_offline(const char *dev_id)
|
|||
if (!pj_strcmp2(&igd->dev_id, dev_id) && igd->valid) {
|
||||
igd->alive = PJ_FALSE;
|
||||
|
||||
pj_mutex_lock(upnp_mgr.mutex);
|
||||
if (i == upnp_mgr.primary_igd_idx) {
|
||||
unsigned j;
|
||||
|
||||
|
@ -409,9 +414,10 @@ static void set_device_offline(const char *dev_id)
|
|||
(upnp_mgr.primary_igd_idx < 0? "(none)":
|
||||
igd->dev_id.ptr)));
|
||||
}
|
||||
pj_mutex_unlock(upnp_mgr.mutex);
|
||||
}
|
||||
}
|
||||
|
||||
pj_mutex_unlock(upnp_mgr.mutex);
|
||||
}
|
||||
|
||||
/* UPnP client callback. */
|
||||
|
@ -849,7 +855,6 @@ PJ_DEF(pj_status_t)pj_upnp_del_port_mapping(const pj_sockaddr *mapped_addr)
|
|||
}
|
||||
|
||||
igd = &upnp_mgr.igd_devs[upnp_mgr.primary_igd_idx];
|
||||
pj_mutex_unlock(upnp_mgr.mutex);
|
||||
|
||||
/* Compare IGD's public IP to the mapped public address. */
|
||||
pj_sockaddr_cp(&host_addr, mapped_addr);
|
||||
|
@ -870,7 +875,8 @@ PJ_DEF(pj_status_t)pj_upnp_del_port_mapping(const pj_sockaddr *mapped_addr)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
pj_mutex_unlock(upnp_mgr.mutex);
|
||||
|
||||
if (!igd) {
|
||||
/* Either the IGD we previously requested to add port mapping has become
|
||||
* offline, or the address is actually not a valid.
|
||||
|
|
|
@ -1034,8 +1034,8 @@ static void handle_peer_pkt(pj_turn_allocation *alloc,
|
|||
char peer_addr[80];
|
||||
pj_sockaddr_print(src_addr, peer_addr, sizeof(peer_addr), 3);
|
||||
PJ_LOG(4,(alloc->obj_name, "Client %s: discarded data from %s "
|
||||
"because it's too long (%ld bytes)",
|
||||
alloc->info, peer_addr, len));
|
||||
"because it's too long (%lu bytes)",
|
||||
alloc->info, peer_addr, (unsigned long)len));
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -49,8 +49,9 @@ static void dump_status(pj_turn_srv *srv)
|
|||
}
|
||||
|
||||
printf("Worker threads : %d\n", srv->core.thread_cnt);
|
||||
printf("Total mem usage: %u.%03uMB\n", (unsigned)(g_cp.used_size / 1000000),
|
||||
(unsigned)((g_cp.used_size % 1000000)/1000));
|
||||
/* Field used_size is deprecated by #3897 */
|
||||
//printf("Total mem usage: %u.%03uMB\n", (unsigned)(g_cp.used_size / 1000000),
|
||||
// (unsigned)((g_cp.used_size % 1000000)/1000));
|
||||
printf("UDP port range : %u %u %u (next/min/max)\n", srv->ports.next_udp,
|
||||
srv->ports.min_udp, srv->ports.max_udp);
|
||||
printf("TCP port range : %u %u %u (next/min/max)\n", srv->ports.next_tcp,
|
||||
|
|
|
@ -7,6 +7,9 @@
|
|||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
3A4E3B582B62025C0016735C /* MetalKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3A4E3B562B62025B0016735C /* MetalKit.framework */; };
|
||||
3A4E3B592B62025C0016735C /* Metal.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3A4E3B572B62025B0016735C /* Metal.framework */; };
|
||||
3A4E3BA52B734E9A0016735C /* Network.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3A4E3BA42B734E9A0016735C /* Network.framework */; };
|
||||
3A6FC61C25CBD4540065F472 /* ipjsua_swiftApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A6FC61B25CBD4540065F472 /* ipjsua_swiftApp.swift */; };
|
||||
3A6FC61E25CBD4540065F472 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A6FC61D25CBD4540065F472 /* ContentView.swift */; };
|
||||
3A6FC62025CBD4550065F472 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 3A6FC61F25CBD4550065F472 /* Assets.xcassets */; };
|
||||
|
@ -49,9 +52,24 @@
|
|||
3A6FC7F225CD1A3E0065F472 /* libwebrtc.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3A6FC7DE25CD1A3D0065F472 /* libwebrtc.a */; };
|
||||
3A6FC7F325CD1A3E0065F472 /* libpjmedia-codec.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3A6FC7DF25CD1A3D0065F472 /* libpjmedia-codec.a */; };
|
||||
3A6FC7F425CD1A3E0065F472 /* libpjmedia-audiodev.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3A6FC7E025CD1A3D0065F472 /* libpjmedia-audiodev.a */; };
|
||||
3AF9B5372B7B454D0043987D /* ipjsua_swiftVidTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AF9B5362B7B454D0043987D /* ipjsua_swiftVidTest.swift */; };
|
||||
3AF9B5392B7B454D0043987D /* ipjsua_swiftVidTestLaunchTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AF9B5382B7B454D0043987D /* ipjsua_swiftVidTestLaunchTests.swift */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
3AF9B53A2B7B454D0043987D /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 3A6FC61025CBD4540065F472 /* Project object */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = 3A6FC61725CBD4540065F472;
|
||||
remoteInfo = "ipjsua-swift";
|
||||
};
|
||||
/* End PBXContainerItemProxy section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
3A4E3B562B62025B0016735C /* MetalKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MetalKit.framework; path = System/Library/Frameworks/MetalKit.framework; sourceTree = SDKROOT; };
|
||||
3A4E3B572B62025B0016735C /* Metal.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Metal.framework; path = System/Library/Frameworks/Metal.framework; sourceTree = SDKROOT; };
|
||||
3A4E3BA42B734E9A0016735C /* Network.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Network.framework; path = System/Library/Frameworks/Network.framework; sourceTree = SDKROOT; };
|
||||
3A6FC61825CBD4540065F472 /* ipjsua-swift.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "ipjsua-swift.app"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
3A6FC61B25CBD4540065F472 /* ipjsua_swiftApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ipjsua_swiftApp.swift; sourceTree = "<group>"; };
|
||||
3A6FC61D25CBD4540065F472 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
|
||||
|
@ -97,6 +115,10 @@
|
|||
3A6FC7DE25CD1A3D0065F472 /* libwebrtc.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libwebrtc.a; sourceTree = "<group>"; };
|
||||
3A6FC7DF25CD1A3D0065F472 /* libpjmedia-codec.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libpjmedia-codec.a"; sourceTree = "<group>"; };
|
||||
3A6FC7E025CD1A3D0065F472 /* libpjmedia-audiodev.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libpjmedia-audiodev.a"; sourceTree = "<group>"; };
|
||||
3AF9B5342B7B454D0043987D /* ipjsua-swiftVidTest.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "ipjsua-swiftVidTest.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
3AF9B5362B7B454D0043987D /* ipjsua_swiftVidTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ipjsua_swiftVidTest.swift; sourceTree = "<group>"; };
|
||||
3AF9B5382B7B454D0043987D /* ipjsua_swiftVidTestLaunchTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ipjsua_swiftVidTestLaunchTests.swift; sourceTree = "<group>"; };
|
||||
3AF9B53F2B7B583C0043987D /* ipjsua-swift.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = "ipjsua-swift.xctestplan"; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
|
@ -135,12 +157,22 @@
|
|||
3A6FC7E725CD1A3E0065F472 /* libyuv.a in Frameworks */,
|
||||
3A6FC78325CBE3700065F472 /* Security.framework in Frameworks */,
|
||||
3A6FC7F425CD1A3E0065F472 /* libpjmedia-audiodev.a in Frameworks */,
|
||||
3A4E3B592B62025C0016735C /* Metal.framework in Frameworks */,
|
||||
3A4E3B582B62025C0016735C /* MetalKit.framework in Frameworks */,
|
||||
3A6FC7EA25CD1A3E0065F472 /* libpjnath.a in Frameworks */,
|
||||
3A6FC7E125CD1A3D0065F472 /* libpjsip-simple.a in Frameworks */,
|
||||
3A6FC78425CBE3700065F472 /* SystemConfiguration.framework in Frameworks */,
|
||||
3A6FC7F325CD1A3E0065F472 /* libpjmedia-codec.a in Frameworks */,
|
||||
3A6FC78525CBE3700065F472 /* UIKit.framework in Frameworks */,
|
||||
3A6FC78625CBE3700065F472 /* VideoToolbox.framework in Frameworks */,
|
||||
3A4E3BA52B734E9A0016735C /* Network.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
3AF9B5312B7B454D0043987D /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
@ -150,6 +182,8 @@
|
|||
3A6FC60F25CBD4540065F472 = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
3AF9B53F2B7B583C0043987D /* ipjsua-swift.xctestplan */,
|
||||
3AF9B5352B7B454D0043987D /* ipjsua-swiftVidTest */,
|
||||
3A6FC75A25CBD6CF0065F472 /* Frameworks */,
|
||||
3A6FC6AF25CBD5790065F472 /* Libraries */,
|
||||
3A6FC61A25CBD4540065F472 /* ipjsua-swift */,
|
||||
|
@ -161,6 +195,7 @@
|
|||
isa = PBXGroup;
|
||||
children = (
|
||||
3A6FC61825CBD4540065F472 /* ipjsua-swift.app */,
|
||||
3AF9B5342B7B454D0043987D /* ipjsua-swiftVidTest.xctest */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
|
@ -217,6 +252,9 @@
|
|||
3A6FC75A25CBD6CF0065F472 /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
3A4E3BA42B734E9A0016735C /* Network.framework */,
|
||||
3A4E3B572B62025B0016735C /* Metal.framework */,
|
||||
3A4E3B562B62025B0016735C /* MetalKit.framework */,
|
||||
3A6FC75B25CBD6E10065F472 /* AudioToolbox.framework */,
|
||||
3A6FC76B25CBD6E10065F472 /* AVFoundation.framework */,
|
||||
3A6FC76925CBD6E10065F472 /* CFNetwork.framework */,
|
||||
|
@ -238,6 +276,15 @@
|
|||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
3AF9B5352B7B454D0043987D /* ipjsua-swiftVidTest */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
3AF9B5362B7B454D0043987D /* ipjsua_swiftVidTest.swift */,
|
||||
3AF9B5382B7B454D0043987D /* ipjsua_swiftVidTestLaunchTests.swift */,
|
||||
);
|
||||
path = "ipjsua-swiftVidTest";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
|
@ -258,19 +305,41 @@
|
|||
productReference = 3A6FC61825CBD4540065F472 /* ipjsua-swift.app */;
|
||||
productType = "com.apple.product-type.application";
|
||||
};
|
||||
3AF9B5332B7B454D0043987D /* ipjsua-swiftVidTest */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 3AF9B53E2B7B454D0043987D /* Build configuration list for PBXNativeTarget "ipjsua-swiftVidTest" */;
|
||||
buildPhases = (
|
||||
3AF9B5302B7B454D0043987D /* Sources */,
|
||||
3AF9B5312B7B454D0043987D /* Frameworks */,
|
||||
3AF9B5322B7B454D0043987D /* Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
3AF9B53B2B7B454D0043987D /* PBXTargetDependency */,
|
||||
);
|
||||
name = "ipjsua-swiftVidTest";
|
||||
productName = "ipjsua-swiftVidTest";
|
||||
productReference = 3AF9B5342B7B454D0043987D /* ipjsua-swiftVidTest.xctest */;
|
||||
productType = "com.apple.product-type.bundle.ui-testing";
|
||||
};
|
||||
/* End PBXNativeTarget section */
|
||||
|
||||
/* Begin PBXProject section */
|
||||
3A6FC61025CBD4540065F472 /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastSwiftUpdateCheck = 1240;
|
||||
LastSwiftUpdateCheck = 1520;
|
||||
LastUpgradeCheck = 1240;
|
||||
TargetAttributes = {
|
||||
3A6FC61725CBD4540065F472 = {
|
||||
CreatedOnToolsVersion = 12.4;
|
||||
LastSwiftMigration = 1240;
|
||||
};
|
||||
3AF9B5332B7B454D0043987D = {
|
||||
CreatedOnToolsVersion = 15.2;
|
||||
TestTargetID = 3A6FC61725CBD4540065F472;
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = 3A6FC61325CBD4540065F472 /* Build configuration list for PBXProject "ipjsua-swift" */;
|
||||
|
@ -287,6 +356,7 @@
|
|||
projectRoot = "";
|
||||
targets = (
|
||||
3A6FC61725CBD4540065F472 /* ipjsua-swift */,
|
||||
3AF9B5332B7B454D0043987D /* ipjsua-swiftVidTest */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
@ -301,6 +371,13 @@
|
|||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
3AF9B5322B7B454D0043987D /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
|
@ -314,8 +391,25 @@
|
|||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
3AF9B5302B7B454D0043987D /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
3AF9B5392B7B454D0043987D /* ipjsua_swiftVidTestLaunchTests.swift in Sources */,
|
||||
3AF9B5372B7B454D0043987D /* ipjsua_swiftVidTest.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXTargetDependency section */
|
||||
3AF9B53B2B7B454D0043987D /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = 3A6FC61725CBD4540065F472 /* ipjsua-swift */;
|
||||
targetProxy = 3AF9B53A2B7B454D0043987D /* PBXContainerItemProxy */;
|
||||
};
|
||||
/* End PBXTargetDependency section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
3A6FC62525CBD4550065F472 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
|
@ -455,9 +549,11 @@
|
|||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
DEVELOPMENT_ASSET_PATHS = "\"ipjsua-swift/Preview Content\"";
|
||||
DEVELOPMENT_TEAM = 93NHJQ455P;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = 93NHJQ455P;
|
||||
ENABLE_PREVIEWS = YES;
|
||||
INFOPLIST_FILE = "ipjsua-swift/Info.plist";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
|
||||
|
@ -480,6 +576,8 @@
|
|||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.teluu.ipjsua-swift";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "Teluu Profile";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "ipjsua-swift/ipjsua-swift-Bridging-Header.h";
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 5.0;
|
||||
|
@ -493,9 +591,11 @@
|
|||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
DEVELOPMENT_ASSET_PATHS = "\"ipjsua-swift/Preview Content\"";
|
||||
DEVELOPMENT_TEAM = 93NHJQ455P;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = 93NHJQ455P;
|
||||
ENABLE_PREVIEWS = YES;
|
||||
INFOPLIST_FILE = "ipjsua-swift/Info.plist";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
|
||||
|
@ -518,12 +618,69 @@
|
|||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.teluu.ipjsua-swift";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "Teluu Profile";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "ipjsua-swift/ipjsua-swift-Bridging-Header.h";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
3AF9B53C2B7B454D0043987D /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = 93NHJQ455P;
|
||||
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu17;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
|
||||
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
|
||||
MARKETING_VERSION = 1.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.teluu.ipjsua-swiftVidTest";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "Teluu Profile";
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)";
|
||||
SWIFT_EMIT_LOC_STRINGS = NO;
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
TEST_TARGET_NAME = "ipjsua-swift";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
3AF9B53D2B7B454D0043987D /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = 93NHJQ455P;
|
||||
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu17;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
|
||||
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
|
||||
MARKETING_VERSION = 1.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.teluu.ipjsua-swiftVidTest";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "Teluu Profile";
|
||||
SWIFT_EMIT_LOC_STRINGS = NO;
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
TEST_TARGET_NAME = "ipjsua-swift";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
|
@ -545,6 +702,15 @@
|
|||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
3AF9B53E2B7B454D0043987D /* Build configuration list for PBXNativeTarget "ipjsua-swiftVidTest" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
3AF9B53C2B7B454D0043987D /* Debug */,
|
||||
3AF9B53D2B7B454D0043987D /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
};
|
||||
rootObject = 3A6FC61025CBD4540065F472 /* Project object */;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1420"
|
||||
version = "1.3">
|
||||
version = "1.7">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
|
@ -27,7 +27,24 @@
|
|||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<TestPlans>
|
||||
<TestPlanReference
|
||||
reference = "container:ipjsua-swift.xctestplan"
|
||||
default = "YES">
|
||||
</TestPlanReference>
|
||||
</TestPlans>
|
||||
<Testables>
|
||||
<TestableReference
|
||||
skipped = "NO"
|
||||
parallelizable = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "3AF9B5332B7B454D0043987D"
|
||||
BuildableName = "ipjsua-swiftVidTest.xctest"
|
||||
BlueprintName = "ipjsua-swiftVidTest"
|
||||
ReferencedContainer = "container:ipjsua-swift.xcodeproj">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
</Testables>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
{
|
||||
"configurations" : [
|
||||
{
|
||||
"id" : "A0480BD1-665B-4D82-9F04-A4890A775321",
|
||||
"name" : "Configuration 1",
|
||||
"options" : {
|
||||
|
||||
}
|
||||
}
|
||||
],
|
||||
"defaultOptions" : {
|
||||
"codeCoverage" : false,
|
||||
"targetForVariableExpansion" : {
|
||||
"containerPath" : "container:ipjsua-swift.xcodeproj",
|
||||
"identifier" : "3A6FC61725CBD4540065F472",
|
||||
"name" : "ipjsua-swift"
|
||||
}
|
||||
},
|
||||
"testTargets" : [
|
||||
{
|
||||
"parallelizable" : true,
|
||||
"target" : {
|
||||
"containerPath" : "container:ipjsua-swift.xcodeproj",
|
||||
"identifier" : "3AF9B5332B7B454D0043987D",
|
||||
"name" : "ipjsua-swiftVidTest"
|
||||
}
|
||||
}
|
||||
],
|
||||
"version" : 1
|
||||
}
|
|
@ -75,8 +75,9 @@ struct ContentView: View {
|
|||
var body: some View {
|
||||
VStack(alignment: .center) {
|
||||
HStack(alignment: .center) {
|
||||
Text(pjsip_vars.calling != true ? "Destination:" :
|
||||
pjsip_vars.vid_win != nil ? "Video" : "")
|
||||
if (!pjsip_vars.calling) {
|
||||
Text("Destination:")
|
||||
TextField(pjsip_vars.dest, text: $pjsip_vars.dest)
|
||||
.frame(minWidth:0, maxWidth:200)
|
||||
}
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
<string>Audio call permission</string>
|
||||
<key>NSCameraUsageDescription</key>
|
||||
<string>Video call permission</string>
|
||||
<key>NSLocalNetworkUsageDescription</key>
|
||||
<string>Local network permission</string>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
|
|
|
@ -54,6 +54,7 @@ struct ipjsua_swiftApp: App {
|
|||
pjsua_media_config_default(&media_cfg);
|
||||
|
||||
/* Initialize application callbacks */
|
||||
cfg.cb.on_incoming_call = on_incoming_call;
|
||||
cfg.cb.on_call_state = on_call_state;
|
||||
cfg.cb.on_call_media_state = on_call_media_state;
|
||||
|
||||
|
@ -64,10 +65,37 @@ struct ipjsua_swiftApp: App {
|
|||
var transport_id = pjsua_transport_id();
|
||||
var tcp_cfg = pjsua_transport_config();
|
||||
pjsua_transport_config_default(&tcp_cfg);
|
||||
tcp_cfg.port = 5060;
|
||||
tcp_cfg.port = 5080;
|
||||
status = pjsua_transport_create(PJSIP_TRANSPORT_TCP,
|
||||
&tcp_cfg, &transport_id);
|
||||
|
||||
/* Add local account */
|
||||
var aid = pjsua_acc_id();
|
||||
status = pjsua_acc_add_local(transport_id, pj_bool_t(PJ_TRUE.rawValue), &aid);
|
||||
|
||||
/* Use colorbar for local account and enable incoming video */
|
||||
var acc_cfg = pjsua_acc_config();
|
||||
var tmp_pool:UnsafeMutablePointer<pj_pool_t>? = nil;
|
||||
var info : [pjmedia_vid_dev_info] =
|
||||
Array(repeating: pjmedia_vid_dev_info(), count: 16);
|
||||
var count:UInt32 = UInt32(info.capacity);
|
||||
|
||||
tmp_pool = pjsua_pool_create("tmp-ipjsua", 1000, 1000);
|
||||
pjsua_acc_get_config(aid, tmp_pool, &acc_cfg);
|
||||
acc_cfg.vid_in_auto_show = pj_bool_t(PJ_TRUE.rawValue);
|
||||
|
||||
pjsua_vid_enum_devs(&info, &count);
|
||||
for i in 0..<count {
|
||||
let name: [CChar] = tupleToArray(tuple: info[Int(i)].name);
|
||||
if let dev_name = String(validatingUTF8: name) {
|
||||
if (dev_name == "Colorbar generator") {
|
||||
acc_cfg.vid_cap_dev = pjmedia_vid_dev_index(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
pjsua_acc_modify(aid, &acc_cfg);
|
||||
|
||||
/* Init account config */
|
||||
let id = strdup("Test<sip:test@sip.pjsip.org>");
|
||||
let username = strdup("test");
|
||||
|
@ -76,7 +104,6 @@ struct ipjsua_swiftApp: App {
|
|||
let registrar = strdup("sip:sip.pjsip.org");
|
||||
let proxy = strdup("sip:sip.pjsip.org;transport=tcp");
|
||||
|
||||
var acc_cfg = pjsua_acc_config();
|
||||
pjsua_acc_config_default(&acc_cfg);
|
||||
acc_cfg.id = pj_str(id);
|
||||
acc_cfg.cred_count = 1;
|
||||
|
@ -95,7 +122,9 @@ struct ipjsua_swiftApp: App {
|
|||
/* Free strings */
|
||||
free(id); free(username); free(passwd); free(realm);
|
||||
free(registrar); free(proxy);
|
||||
|
||||
|
||||
pj_pool_release(tmp_pool);
|
||||
|
||||
/* Start pjsua */
|
||||
status = pjsua_start();
|
||||
}
|
||||
|
@ -109,6 +138,19 @@ struct ipjsua_swiftApp: App {
|
|||
}
|
||||
}
|
||||
|
||||
private func on_incoming_call(acc_id: pjsua_acc_id, call_id: pjsua_call_id,
|
||||
rdata: UnsafeMutablePointer<pjsip_rx_data>?)
|
||||
{
|
||||
var opt = pjsua_call_setting();
|
||||
|
||||
pjsua_call_setting_default(&opt);
|
||||
opt.aud_cnt = 1;
|
||||
opt.vid_cnt = 1;
|
||||
|
||||
/* Automatically answer call with 200 */
|
||||
pjsua_call_answer2(call_id, &opt, 200, nil, nil);
|
||||
}
|
||||
|
||||
private func on_call_state(call_id: pjsua_call_id,
|
||||
e: UnsafeMutablePointer<pjsip_event>?)
|
||||
{
|
||||
|
@ -157,9 +199,25 @@ private func on_call_media_state(call_id: pjsua_call_id)
|
|||
let vid_win:UIView =
|
||||
Unmanaged<UIView>.fromOpaque(wi.hwnd.info.ios.window).takeUnretainedValue();
|
||||
|
||||
/* UIView update must be done in the main thread */
|
||||
DispatchQueue.main.sync {
|
||||
AppDelegate.Shared.pjsip_vars.vid_win = vid_win;
|
||||
/* For local loopback test, one acts as a transmitter,
|
||||
the other as a receiver.
|
||||
*/
|
||||
if (AppDelegate.Shared.pjsip_vars.vid_win == nil) {
|
||||
/* UIView update must be done in the main thread */
|
||||
DispatchQueue.main.sync {
|
||||
AppDelegate.Shared.pjsip_vars.vid_win = vid_win;
|
||||
}
|
||||
} else {
|
||||
if (AppDelegate.Shared.pjsip_vars.vid_win != vid_win) {
|
||||
/* Transmitter */
|
||||
var param = pjsua_call_vid_strm_op_param ();
|
||||
|
||||
pjsua_call_vid_strm_op_param_default(¶m);
|
||||
param.med_idx = 1;
|
||||
pjsua_call_set_vid_strm(call_id,
|
||||
PJSUA_CALL_VID_STRM_START_TRANSMIT,
|
||||
¶m);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -0,0 +1,112 @@
|
|||
//
|
||||
// ipjsua_swiftVidTest.swift
|
||||
// ipjsua-swiftVidTest
|
||||
//
|
||||
|
||||
import XCTest
|
||||
|
||||
final class ipjsua_swiftVidTest: XCTestCase {
|
||||
|
||||
override func setUpWithError() throws {
|
||||
// Put setup code here. This method is called before the invocation of each test method in the class.
|
||||
|
||||
// Add an interruption monitor to handle system alerts
|
||||
addUIInterruptionMonitor(withDescription: "Allow network permission") { (alert) -> Bool in
|
||||
print("UI alert: ", alert.description)
|
||||
if alert.buttons["Allow"].exists {
|
||||
alert.buttons["Allow"].tap()
|
||||
return true
|
||||
}
|
||||
if alert.buttons["OK"].exists {
|
||||
alert.buttons["OK"].tap()
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// In UI tests it is usually best to stop immediately when a failure occurs.
|
||||
continueAfterFailure = false
|
||||
|
||||
// In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this.
|
||||
}
|
||||
|
||||
override func tearDownWithError() throws {
|
||||
// Put teardown code here. This method is called after the invocation of each test method in the class.
|
||||
}
|
||||
|
||||
func testVideo() throws {
|
||||
// UI tests must launch the application that they test.
|
||||
let app = XCUIApplication()
|
||||
app.launch()
|
||||
|
||||
// Access the Destination text field
|
||||
let textField = app.textFields["sip:test@sip.pjsip.org"]
|
||||
|
||||
// Type localhost into the text field
|
||||
textField.tap()
|
||||
textField.tap(withNumberOfTaps: 3, numberOfTouches: 1)
|
||||
let dest = "sip:localhost:5080"
|
||||
textField.typeText(dest)
|
||||
|
||||
// Use XCTAssert to verify the text is correct
|
||||
XCTAssertEqual(textField.value as? String, dest)
|
||||
|
||||
// Click "Make call" button
|
||||
print("Making video call")
|
||||
app.buttons["Make call"].tap()
|
||||
|
||||
// Wait for video to appear
|
||||
let expectation = XCTestExpectation(description: "Wait for video")
|
||||
let label = app.staticTexts["Video"]
|
||||
waitForElement(label, timeout: 6)
|
||||
|
||||
expectation.fulfill()
|
||||
|
||||
// This is necessary to invoke UI interruption monitor above
|
||||
app.staticTexts["Video"].tap()
|
||||
|
||||
sleep(1)
|
||||
|
||||
// Capture a screenshot of the entire screen
|
||||
let fullScreenshot = app.windows.firstMatch.screenshot()
|
||||
// Save the screenshot to a file
|
||||
saveScreenshot(image: fullScreenshot)
|
||||
}
|
||||
|
||||
// Helper method to wait for an element to appear/exist
|
||||
func waitForElement(_ element: XCUIElement, timeout: TimeInterval)
|
||||
{
|
||||
let predicate = NSPredicate(format: "exists == 1")
|
||||
let expectation = XCTNSPredicateExpectation(predicate: predicate,
|
||||
object: element)
|
||||
|
||||
let result = XCTWaiter().wait(for: [expectation], timeout: timeout)
|
||||
XCTAssertEqual(result, .completed, "Element not found within " +
|
||||
"\(timeout) seconds")
|
||||
}
|
||||
|
||||
func saveScreenshot(image: XCUIScreenshot) {
|
||||
let pngData = image.pngRepresentation
|
||||
let documentsDirectory = FileManager.default.urls(
|
||||
for: .documentDirectory,
|
||||
in: .userDomainMask).first!
|
||||
let fileURL = documentsDirectory.appendingPathComponent("screenshot.png")
|
||||
|
||||
do {
|
||||
try pngData.write(to: fileURL)
|
||||
print("Screenshot saved to:", fileURL)
|
||||
} catch {
|
||||
XCTFail("Failed to save screenshot: \(error)")
|
||||
}
|
||||
}
|
||||
/*
|
||||
func testLaunchPerformance() throws {
|
||||
if #available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 7.0, *) {
|
||||
// This measures how long it takes to launch your application.
|
||||
measure(metrics: [XCTApplicationLaunchMetric()]) {
|
||||
XCUIApplication().launch()
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
//
|
||||
// ipjsua_swiftVidTestLaunchTests.swift
|
||||
// ipjsua-swiftVidTest
|
||||
//
|
||||
|
||||
import XCTest
|
||||
|
||||
final class ipjsua_swiftVidTestLaunchTests: XCTestCase {
|
||||
|
||||
override class var runsForEachTargetApplicationUIConfiguration: Bool {
|
||||
true
|
||||
}
|
||||
|
||||
override func setUpWithError() throws {
|
||||
continueAfterFailure = false
|
||||
}
|
||||
/*
|
||||
func testLaunch() throws {
|
||||
let app = XCUIApplication()
|
||||
app.launch()
|
||||
|
||||
// Insert steps here to perform after app launch but before taking a screenshot,
|
||||
// such as logging into a test account or navigating somewhere in the app
|
||||
|
||||
let attachment = XCTAttachment(screenshot: app.screenshot())
|
||||
attachment.name = "Launch Screen"
|
||||
attachment.lifetime = .keepAlways
|
||||
add(attachment)
|
||||
}
|
||||
*/
|
||||
}
|
|
@ -8,6 +8,9 @@
|
|||
|
||||
/* Begin PBXBuildFile section */
|
||||
3A31F1B21DA4F568007C23A3 /* libwebrtc.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3A31F1B11DA4F568007C23A3 /* libwebrtc.a */; };
|
||||
3A4E3B542B61FEAB0016735C /* Metal.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3A4E3B522B61FEAB0016735C /* Metal.framework */; };
|
||||
3A4E3B552B61FEAB0016735C /* MetalKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3A4E3B532B61FEAB0016735C /* MetalKit.framework */; };
|
||||
3A4E3B5B2B6205BA0016735C /* Network.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3A4E3B5A2B6205B90016735C /* Network.framework */; };
|
||||
3A6FDEF0223B3BEC001726FD /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3A6FDEEF223B3BEC001726FD /* Security.framework */; };
|
||||
3AA31FF618F3FB4C00112C3D /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3AA31FE918F3FB4C00112C3D /* AudioToolbox.framework */; };
|
||||
3AA31FF718F3FB4C00112C3D /* AVFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3AA31FEA18F3FB4C00112C3D /* AVFoundation.framework */; };
|
||||
|
@ -39,6 +42,9 @@
|
|||
3AF0582816F050780046B835 /* ipjsuaViewController_iPad.xib in Resources */ = {isa = PBXBuildFile; fileRef = 3AF0582616F050780046B835 /* ipjsuaViewController_iPad.xib */; };
|
||||
3AF253001EFBD15E00213893 /* libyuv.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3AF252FF1EFBD15E00213893 /* libyuv.a */; };
|
||||
3AF253021EFBD36E00213893 /* VideoToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3AF253011EFBD36E00213893 /* VideoToolbox.framework */; };
|
||||
3AF9B5422B8890880043987D /* PushKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3AF9B5412B8890880043987D /* PushKit.framework */; };
|
||||
3AF9B5462B8890F40043987D /* UserNotifications.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3AF9B5442B8890F40043987D /* UserNotifications.framework */; };
|
||||
3AF9B5482BA407AD0043987D /* CallKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3AF9B5472BA407AD0043987D /* CallKit.framework */; };
|
||||
7485A6AF1F09AAE500122F1A /* Reachability.m in Sources */ = {isa = PBXBuildFile; fileRef = 7485A6AE1F09AAE500122F1A /* Reachability.m */; };
|
||||
7485A6B11F09B2D500122F1A /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7485A6B01F09B2D500122F1A /* SystemConfiguration.framework */; };
|
||||
E5E991E61B67A45500017E67 /* libg7221codec.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E5E991D41B67A45500017E67 /* libg7221codec.a */; };
|
||||
|
@ -63,6 +69,9 @@
|
|||
|
||||
/* Begin PBXFileReference section */
|
||||
3A31F1B11DA4F568007C23A3 /* libwebrtc.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libwebrtc.a; sourceTree = "<group>"; };
|
||||
3A4E3B522B61FEAB0016735C /* Metal.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Metal.framework; path = System/Library/Frameworks/Metal.framework; sourceTree = SDKROOT; };
|
||||
3A4E3B532B61FEAB0016735C /* MetalKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MetalKit.framework; path = System/Library/Frameworks/MetalKit.framework; sourceTree = SDKROOT; };
|
||||
3A4E3B5A2B6205B90016735C /* Network.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Network.framework; path = System/Library/Frameworks/Network.framework; sourceTree = SDKROOT; };
|
||||
3A6FDEEF223B3BEC001726FD /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; };
|
||||
3AA31FE918F3FB4C00112C3D /* AudioToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = System/Library/Frameworks/AudioToolbox.framework; sourceTree = SDKROOT; };
|
||||
3AA31FEA18F3FB4C00112C3D /* AVFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVFoundation.framework; path = System/Library/Frameworks/AVFoundation.framework; sourceTree = SDKROOT; };
|
||||
|
@ -99,6 +108,11 @@
|
|||
3AF0582716F050780046B835 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/ipjsuaViewController_iPad.xib; sourceTree = "<group>"; };
|
||||
3AF252FF1EFBD15E00213893 /* libyuv.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libyuv.a; sourceTree = "<group>"; };
|
||||
3AF253011EFBD36E00213893 /* VideoToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = VideoToolbox.framework; path = System/Library/Frameworks/VideoToolbox.framework; sourceTree = SDKROOT; };
|
||||
3AF9B5402B88896D0043987D /* ipjsua.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = ipjsua.entitlements; sourceTree = "<group>"; };
|
||||
3AF9B5412B8890880043987D /* PushKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = PushKit.framework; path = System/Library/Frameworks/PushKit.framework; sourceTree = SDKROOT; };
|
||||
3AF9B5432B8890F40043987D /* UserNotificationsUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UserNotificationsUI.framework; path = System/Library/Frameworks/UserNotificationsUI.framework; sourceTree = SDKROOT; };
|
||||
3AF9B5442B8890F40043987D /* UserNotifications.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UserNotifications.framework; path = System/Library/Frameworks/UserNotifications.framework; sourceTree = SDKROOT; };
|
||||
3AF9B5472BA407AD0043987D /* CallKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CallKit.framework; path = System/Library/Frameworks/CallKit.framework; sourceTree = SDKROOT; };
|
||||
7485A6AD1F09AAE500122F1A /* Reachability.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Reachability.h; sourceTree = "<group>"; };
|
||||
7485A6AE1F09AAE500122F1A /* Reachability.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Reachability.m; sourceTree = "<group>"; };
|
||||
7485A6B01F09B2D500122F1A /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; };
|
||||
|
@ -132,6 +146,7 @@
|
|||
3AF253021EFBD36E00213893 /* VideoToolbox.framework in Frameworks */,
|
||||
E5E991EC1B67A45500017E67 /* libpjmedia-codec.a in Frameworks */,
|
||||
3AA31FF818F3FB4C00112C3D /* CFNetwork.framework in Frameworks */,
|
||||
3AF9B5422B8890880043987D /* PushKit.framework in Frameworks */,
|
||||
E5E991E61B67A45500017E67 /* libg7221codec.a in Frameworks */,
|
||||
E5E991EB1B67A45500017E67 /* libpjmedia-audiodev.a in Frameworks */,
|
||||
3AA31FFB18F3FB4C00112C3D /* CoreImage.framework in Frameworks */,
|
||||
|
@ -146,17 +161,22 @@
|
|||
E5E991EE1B67A45500017E67 /* libpjmedia.a in Frameworks */,
|
||||
E5E991EA1B67A45500017E67 /* libpjlib-util.a in Frameworks */,
|
||||
E5E991ED1B67A45500017E67 /* libpjmedia-videodev.a in Frameworks */,
|
||||
3AF9B5462B8890F40043987D /* UserNotifications.framework in Frameworks */,
|
||||
E5E991E81B67A45500017E67 /* libilbccodec.a in Frameworks */,
|
||||
3A4E3B5B2B6205BA0016735C /* Network.framework in Frameworks */,
|
||||
3AF9B5482BA407AD0043987D /* CallKit.framework in Frameworks */,
|
||||
3AA3200118F3FB4C00112C3D /* CoreGraphics.framework in Frameworks */,
|
||||
3AA31FF918F3FB4C00112C3D /* CoreAudio.framework in Frameworks */,
|
||||
3AA31FFD18F3FB4C00112C3D /* CoreVideo.framework in Frameworks */,
|
||||
3AA3200218F3FB4C00112C3D /* UIKit.framework in Frameworks */,
|
||||
3AA31FFA18F3FB4C00112C3D /* CoreFoundation.framework in Frameworks */,
|
||||
E5E991F01B67A45500017E67 /* libpjsip-simple.a in Frameworks */,
|
||||
3A4E3B542B61FEAB0016735C /* Metal.framework in Frameworks */,
|
||||
E5E991E91B67A45500017E67 /* libpj.a in Frameworks */,
|
||||
E5E991F71B67A45500017E67 /* libsrtp.a in Frameworks */,
|
||||
3AA31FFC18F3FB4C00112C3D /* CoreMedia.framework in Frameworks */,
|
||||
E5E991F21B67A45500017E67 /* libpjsip.a in Frameworks */,
|
||||
3A4E3B552B61FEAB0016735C /* MetalKit.framework in Frameworks */,
|
||||
3A31F1B21DA4F568007C23A3 /* libwebrtc.a in Frameworks */,
|
||||
E5E991F51B67A45500017E67 /* libresample.a in Frameworks */,
|
||||
E5E991F61B67A45500017E67 /* libspeex.a in Frameworks */,
|
||||
|
@ -202,6 +222,13 @@
|
|||
3AF0580716F050770046B835 /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
3AF9B5472BA407AD0043987D /* CallKit.framework */,
|
||||
3AF9B5442B8890F40043987D /* UserNotifications.framework */,
|
||||
3AF9B5432B8890F40043987D /* UserNotificationsUI.framework */,
|
||||
3AF9B5412B8890880043987D /* PushKit.framework */,
|
||||
3A4E3B5A2B6205B90016735C /* Network.framework */,
|
||||
3A4E3B522B61FEAB0016735C /* Metal.framework */,
|
||||
3A4E3B532B61FEAB0016735C /* MetalKit.framework */,
|
||||
3A6FDEEF223B3BEC001726FD /* Security.framework */,
|
||||
7485A6B01F09B2D500122F1A /* SystemConfiguration.framework */,
|
||||
3AF253011EFBD36E00213893 /* VideoToolbox.framework */,
|
||||
|
@ -225,6 +252,7 @@
|
|||
3AF0580E16F050770046B835 /* ipjsua */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
3AF9B5402B88896D0043987D /* ipjsua.entitlements */,
|
||||
3A92068D16F1D1A100D49F96 /* pjsua */,
|
||||
3AF0581716F050780046B835 /* ipjsuaAppDelegate.h */,
|
||||
3AF0581816F050780046B835 /* ipjsuaAppDelegate.m */,
|
||||
|
@ -313,6 +341,7 @@
|
|||
TargetAttributes = {
|
||||
3AF0580316F050770046B835 = {
|
||||
DevelopmentTeam = 93NHJQ455P;
|
||||
ProvisioningStyle = Manual;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
@ -500,7 +529,12 @@
|
|||
3AF0582C16F050780046B835 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
CODE_SIGN_ENTITLEMENTS = ipjsua/ipjsua.entitlements;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = 93NHJQ455P;
|
||||
GCC_PRECOMPILE_PREFIX_HEADER = YES;
|
||||
GCC_PREFIX_HEADER = "ipjsua/ipjsua-Prefix.pch";
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
|
@ -529,8 +563,11 @@
|
|||
"$(PROJECT_DIR)",
|
||||
);
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.teluu.${PRODUCT_NAME:rfc1034identifier}";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.teluupush.--PRODUCT-NAME-rfc1034identifier-";
|
||||
"PRODUCT_BUNDLE_IDENTIFIER[sdk=iphoneos*]" = com.teluupush.ipjsua;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "ipjsua Push";
|
||||
VALID_ARCHS = arm64;
|
||||
WRAPPER_EXTENSION = app;
|
||||
};
|
||||
|
@ -539,7 +576,12 @@
|
|||
3AF0582D16F050780046B835 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
CODE_SIGN_ENTITLEMENTS = ipjsua/ipjsua.entitlements;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = 93NHJQ455P;
|
||||
GCC_PRECOMPILE_PREFIX_HEADER = YES;
|
||||
GCC_PREFIX_HEADER = "ipjsua/ipjsua-Prefix.pch";
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
|
@ -567,8 +609,11 @@
|
|||
"$(PROJECT_DIR)",
|
||||
);
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.teluu.${PRODUCT_NAME:rfc1034identifier}";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.teluupush.--PRODUCT-NAME-rfc1034identifier-";
|
||||
"PRODUCT_BUNDLE_IDENTIFIER[sdk=iphoneos*]" = com.teluupush.ipjsua;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "ipjsua Push";
|
||||
VALID_ARCHS = arm64;
|
||||
WRAPPER_EXTENSION = app;
|
||||
};
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>AppIdentifierPrefix</key>
|
||||
<string>$(AppIdentifierPrefix)</string>
|
||||
<key>CFBundleDisplayName</key>
|
||||
<string>${PRODUCT_NAME}</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>aps-environment</key>
|
||||
<string>development</string>
|
||||
<key>com.apple.security.app-sandbox</key>
|
||||
<true/>
|
||||
<key>com.apple.security.device.audio-input</key>
|
||||
<true/>
|
||||
<key>com.apple.security.device.camera</key>
|
||||
<true/>
|
||||
<key>com.apple.security.network.client</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
|
@ -18,14 +18,23 @@
|
|||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#import <CallKit/CallKit.h>
|
||||
#import <PushKit/PushKit.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
#import <UserNotifications/UserNotifications.h>
|
||||
|
||||
@class ipjsuaViewController;
|
||||
|
||||
@interface ipjsuaAppDelegate : UIResponder <UIApplicationDelegate>
|
||||
@interface ipjsuaAppDelegate : UIResponder
|
||||
<UIApplicationDelegate, PKPushRegistryDelegate,
|
||||
UNUserNotificationCenterDelegate, CXProviderDelegate>
|
||||
|
||||
@property (strong, nonatomic) UIWindow *window;
|
||||
|
||||
@property (strong, nonatomic) PKPushRegistry *voipRegistry;
|
||||
@property (strong, nonatomic) NSMutableString *token;
|
||||
@property (strong, nonatomic) CXProvider *provider;
|
||||
|
||||
@property (strong, nonatomic) ipjsuaViewController *viewController;
|
||||
|
||||
@end
|
||||
|
|
|
@ -22,6 +22,8 @@
|
|||
#import <pjlib.h>
|
||||
#import <pjsua.h>
|
||||
#import <pj/log.h>
|
||||
#import <AVFoundation/AVFoundation.h>
|
||||
#import <CallKit/CallKit.h>
|
||||
|
||||
#include "../../pjsua_app.h"
|
||||
#include "../../pjsua_app_config.h"
|
||||
|
@ -33,14 +35,172 @@
|
|||
|
||||
#define THIS_FILE "ipjsuaAppDelegate.m"
|
||||
|
||||
#define KEEP_ALIVE_INTERVAL 600
|
||||
/* Specify if we use push notification. */
|
||||
#define USE_PUSH_NOTIFICATION 1
|
||||
|
||||
/* Specify the timeout (in sec) to wait for the incoming INVITE
|
||||
* to come after we receive push notification.
|
||||
*/
|
||||
#define MAX_INV_TIMEOUT 10
|
||||
|
||||
/* Account details. */
|
||||
#define SIP_DOMAIN "sip.pjsip.org"
|
||||
#define SIP_USER "test"
|
||||
#define SIP_PASSWD "test"
|
||||
|
||||
ipjsuaAppDelegate *app;
|
||||
static pjsua_app_cfg_t app_cfg;
|
||||
static bool isShuttingDown;
|
||||
static char **restartArgv;
|
||||
static int restartArgc;
|
||||
Reachability *internetReach;
|
||||
Reachability *internetReach;
|
||||
|
||||
/* Mapping between CallKit UUID and pjsua_call_id. */
|
||||
NSMutableDictionary<NSUUID *, NSNumber *> *call_map;
|
||||
|
||||
enum {
|
||||
REREGISTER = 1,
|
||||
ANSWER_CALL,
|
||||
END_CALL,
|
||||
ACTIVATE_AUDIO,
|
||||
DEACTIVATE_AUDIO,
|
||||
HANDLE_IP_CHANGE,
|
||||
HANDLE_ORI_CHANGE
|
||||
};
|
||||
|
||||
#define REGISTER_THREAD \
|
||||
static pj_thread_desc a_thread_desc; \
|
||||
static pj_thread_t *a_thread; \
|
||||
if (!pj_thread_is_registered()) { \
|
||||
pj_thread_register("ipjsua", a_thread_desc, &a_thread); \
|
||||
}
|
||||
|
||||
#define SCHEDULE_TIMER(action) \
|
||||
{ \
|
||||
REGISTER_THREAD \
|
||||
pjsua_schedule_timer2(pjsip_funcs, (void *)action, 0); \
|
||||
}
|
||||
|
||||
static void pjsip_funcs(void *user_data)
|
||||
{
|
||||
/* IMPORTANT:
|
||||
* We need to call PJSIP API from a separate thread since
|
||||
* PJSIP API can potentially block the main/GUI thread.
|
||||
* And make sure we don't use Apple's Dispatch / gcd since
|
||||
* it's incompatible with POSIX threads.
|
||||
* In this example, we take advantage of PJSUA's timer thread
|
||||
* to invoke PJSIP APIs. For a more complex application,
|
||||
* it is recommended to create your own separate thread
|
||||
* instead for this purpose.
|
||||
*/
|
||||
long code = (long)user_data & 0xF;
|
||||
if (code == REREGISTER) {
|
||||
for (unsigned i = 0; i < pjsua_acc_get_count(); ++i) {
|
||||
if (pjsua_acc_is_valid(i)) {
|
||||
pjsua_acc_set_registration(i, PJ_TRUE);
|
||||
}
|
||||
}
|
||||
} else if (code == ANSWER_CALL) {
|
||||
pj_status_t status;
|
||||
pjsua_call_id call_id = (pjsua_call_id)((long)user_data & 0xFF0) >> 4;
|
||||
|
||||
status = pjsua_call_answer(call_id, PJSIP_SC_OK, NULL, NULL);
|
||||
if (status != PJ_SUCCESS) {
|
||||
NSUUID *uuid =(__bridge NSUUID *)pjsua_call_get_user_data(call_id);
|
||||
if (uuid) {
|
||||
[app.provider reportCallWithUUID:uuid
|
||||
endedAtDate:[NSDate date]
|
||||
reason:CXCallEndedReasonFailed];
|
||||
}
|
||||
}
|
||||
} else if (code == END_CALL) {
|
||||
pj_status_t status;
|
||||
pjsua_call_id call_id = (pjsua_call_id)((long)user_data & 0xFF0) >> 4;
|
||||
|
||||
status = pjsua_call_hangup(call_id, PJSIP_SC_OK, NULL, NULL);
|
||||
if (status != PJ_SUCCESS) {
|
||||
NSUUID *uuid =(__bridge NSUUID *)pjsua_call_get_user_data(call_id);
|
||||
if (uuid) {
|
||||
[app.provider reportCallWithUUID:uuid
|
||||
endedAtDate:[NSDate date]
|
||||
reason:CXCallEndedReasonFailed];
|
||||
}
|
||||
}
|
||||
} else if (code == ACTIVATE_AUDIO) {
|
||||
pjsua_call_info call_info;
|
||||
pjsua_call_id ids[PJSUA_MAX_CALLS];
|
||||
unsigned count = PJSUA_MAX_CALLS;
|
||||
|
||||
/* If we use CallKit, sound device may not work until audio session
|
||||
* becomes active, so we need to force reopen sound device here.
|
||||
*/
|
||||
pjsua_set_no_snd_dev();
|
||||
pjsua_set_snd_dev(PJSUA_SND_DEFAULT_CAPTURE_DEV,
|
||||
PJSUA_SND_DEFAULT_PLAYBACK_DEV);
|
||||
|
||||
pjsua_enum_calls(ids, &count);
|
||||
for (unsigned i = 0; i < count; i++) {
|
||||
pjsua_call_get_info(i, &call_info);
|
||||
|
||||
for (unsigned mi = 0; mi < call_info.media_cnt; ++mi) {
|
||||
if (call_info.media[mi].type == PJMEDIA_TYPE_AUDIO &&
|
||||
(call_info.media[mi].status == PJSUA_CALL_MEDIA_ACTIVE ||
|
||||
call_info.media[mi].status == PJSUA_CALL_MEDIA_REMOTE_HOLD))
|
||||
{
|
||||
pjsua_conf_port_id call_conf_slot;
|
||||
call_conf_slot = call_info.media[mi].stream.aud.conf_slot;
|
||||
pjsua_conf_connect(0, call_conf_slot);
|
||||
pjsua_conf_connect(call_conf_slot, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (code == DEACTIVATE_AUDIO) {
|
||||
NSLog(@"Deactivating audio session, is sound active: %d",
|
||||
pjsua_snd_is_active());
|
||||
if (!pjsua_snd_is_active()) {
|
||||
[[AVAudioSession sharedInstance] setActive:NO
|
||||
withOptions:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation
|
||||
error:nil];
|
||||
}
|
||||
} else if (code == HANDLE_IP_CHANGE) {
|
||||
pjsua_ip_change_param param;
|
||||
pjsua_ip_change_param_default(¶m);
|
||||
pjsua_handle_ip_change(¶m);
|
||||
} else if (code == HANDLE_ORI_CHANGE) {
|
||||
#if PJSUA_HAS_VIDEO
|
||||
const pjmedia_orient pj_ori[4] =
|
||||
{
|
||||
PJMEDIA_ORIENT_ROTATE_90DEG, /* UIDeviceOrientationPortrait */
|
||||
PJMEDIA_ORIENT_ROTATE_270DEG, /* UIDeviceOrientationPortraitUpsideDown */
|
||||
PJMEDIA_ORIENT_ROTATE_180DEG, /* UIDeviceOrientationLandscapeLeft,
|
||||
home button on the right side */
|
||||
PJMEDIA_ORIENT_NATURAL /* UIDeviceOrientationLandscapeRight,
|
||||
home button on the left side */
|
||||
};
|
||||
static UIDeviceOrientation prev_ori = 0;
|
||||
UIDeviceOrientation dev_ori = [[UIDevice currentDevice] orientation];
|
||||
int i;
|
||||
|
||||
if (dev_ori == prev_ori) return;
|
||||
|
||||
NSLog(@"Device orientation changed: %d", (int)(prev_ori = dev_ori));
|
||||
|
||||
if (dev_ori >= UIDeviceOrientationPortrait &&
|
||||
dev_ori <= UIDeviceOrientationLandscapeRight)
|
||||
{
|
||||
/* Here we set the orientation for all video devices.
|
||||
* This may return failure for renderer devices or for
|
||||
* capture devices which do not support orientation setting,
|
||||
* we can simply ignore them.
|
||||
*/
|
||||
for (i = pjsua_vid_dev_count()-1; i >= 0; i--) {
|
||||
pjsua_vid_dev_set_setting(i, PJMEDIA_VID_DEV_CAP_ORIENTATION,
|
||||
&pj_ori[dev_ori-1], PJ_TRUE);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
- (void) updateWithReachability: (Reachability *)curReach
|
||||
{
|
||||
|
@ -48,18 +208,18 @@ Reachability *internetReach;
|
|||
BOOL connectionRequired = [curReach connectionRequired];
|
||||
switch (netStatus) {
|
||||
case NotReachable:
|
||||
PJ_LOG(3,("", "Access Not Available.."));
|
||||
NSLog(@"Access Not Available..");
|
||||
connectionRequired= NO;
|
||||
break;
|
||||
case ReachableViaWiFi:
|
||||
PJ_LOG(3,("", "Reachable WiFi.."));
|
||||
NSLog(@"Reachable WiFi..");
|
||||
break;
|
||||
case ReachableViaWWAN:
|
||||
PJ_LOG(3,("", "Reachable WWAN.."));
|
||||
NSLog(@"Reachable WWAN..");
|
||||
break;
|
||||
}
|
||||
if (connectionRequired) {
|
||||
PJ_LOG(3,("", "Connection Required"));
|
||||
NSLog(@"Connection Required");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -68,18 +228,34 @@ Reachability *internetReach;
|
|||
{
|
||||
Reachability* curReach = [note object];
|
||||
NSParameterAssert([curReach isKindOfClass: [Reachability class]]);
|
||||
PJ_LOG(3,("", "reachability changed.."));
|
||||
NSLog(@"reachability changed..");
|
||||
[self updateWithReachability: curReach];
|
||||
|
||||
if ([curReach currentReachabilityStatus] != NotReachable &&
|
||||
![curReach connectionRequired])
|
||||
{
|
||||
pjsua_ip_change_param param;
|
||||
pjsua_ip_change_param_default(¶m);
|
||||
pjsua_handle_ip_change(¶m);
|
||||
SCHEDULE_TIMER(HANDLE_IP_CHANGE);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)pushRegistry:(PKPushRegistry *)registry didUpdatePushCredentials:(PKPushCredentials *)credentials forType:(NSString *)type
|
||||
{
|
||||
if ([credentials.token length] == 0) {
|
||||
NSLog(@"voip token NULL");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Get device token */
|
||||
const char *data = [credentials.token bytes];
|
||||
self.token = [NSMutableString string];
|
||||
for (NSUInteger i = 0; i < [credentials.token length]; i++) {
|
||||
[self.token appendFormat:@"%02.2hhx", data[i]];
|
||||
}
|
||||
NSLog(@"VOIP Push Notification Token: %@", self.token);
|
||||
|
||||
/* Now start pjsua */
|
||||
[NSThread detachNewThreadSelector:@selector(pjsuaStart) toTarget:self withObject:nil];
|
||||
}
|
||||
|
||||
void displayLog(const char *msg, int len)
|
||||
{
|
||||
|
@ -171,6 +347,57 @@ static void pjsuaOnAppConfigCb(pjsua_app_config *cfg)
|
|||
object:[UIDevice currentDevice]];
|
||||
});
|
||||
|
||||
static char contact_uri_buf[1024];
|
||||
pjsua_acc_config cfg;
|
||||
|
||||
pjsua_acc_config_default(&cfg);
|
||||
cfg.id = pj_str("sip:" SIP_USER "@" SIP_DOMAIN);
|
||||
cfg.reg_uri = pj_str("sip:" SIP_DOMAIN ";transport=tcp");
|
||||
cfg.cred_count = 1;
|
||||
cfg.cred_info[0].realm = pj_str(SIP_DOMAIN);
|
||||
cfg.cred_info[0].scheme = pj_str("digest");
|
||||
cfg.cred_info[0].username = pj_str(SIP_USER);
|
||||
cfg.cred_info[0].data = pj_str(SIP_PASSWD);
|
||||
/* Uncomment this to enable video. Note that video can only
|
||||
* work in the foreground.
|
||||
*/
|
||||
// app_config_init_video(&cfg);
|
||||
|
||||
/* If we have Push Notification token, put it in the registration
|
||||
* Contact URI params.
|
||||
*/
|
||||
if ([self.token length]) {
|
||||
/* According to RFC 8599:
|
||||
* - pn-provider is the Push Notification Service provider. Here
|
||||
* we use APNS (Apple Push Notification Service).
|
||||
* - pn-param is composed of Team ID and Topic separated by
|
||||
* a period (.).
|
||||
* The Topic consists of the Bundle ID, the app's unique ID,
|
||||
* and the app's service value ("voip" for VoIP apps), separated
|
||||
* by a period (.).
|
||||
* - pn-prid is the PN token.
|
||||
*/
|
||||
NSDictionary *infoDictionary = [[NSBundle mainBundle] infoDictionary];
|
||||
NSString *bundleID = infoDictionary[@"CFBundleIdentifier"];
|
||||
NSString *teamID = infoDictionary[@"AppIdentifierPrefix"];
|
||||
NSLog(@"Team ID from settings: %@", teamID);
|
||||
|
||||
pj_ansi_snprintf(contact_uri_buf, sizeof(contact_uri_buf),
|
||||
";pn-provider=apns"
|
||||
";pn-param=%s%s.voip"
|
||||
";pn-prid=%s",
|
||||
(teamID? [teamID UTF8String]: "93NHJQ455P."),
|
||||
[bundleID UTF8String],
|
||||
[self.token UTF8String]);
|
||||
cfg.reg_contact_uri_params = pj_str(contact_uri_buf);
|
||||
}
|
||||
status = pjsua_acc_add(&cfg, PJ_TRUE, NULL);
|
||||
if (status != PJ_SUCCESS) {
|
||||
char errmsg[PJ_ERR_MSG_SIZE];
|
||||
pj_strerror(status, errmsg, sizeof(errmsg));
|
||||
displayMsg(errmsg);
|
||||
}
|
||||
|
||||
status = pjsua_app_run(PJ_TRUE);
|
||||
if (status != PJ_SUCCESS) {
|
||||
char errmsg[PJ_ERR_MSG_SIZE];
|
||||
|
@ -187,6 +414,116 @@ static void pjsuaOnAppConfigCb(pjsua_app_config *cfg)
|
|||
restartArgc = 0;
|
||||
}
|
||||
|
||||
- (void) provider:(CXProvider *) provider
|
||||
didActivateAudioSession:(AVAudioSession *) audioSession
|
||||
{
|
||||
NSLog(@"Did activate Audio Session");
|
||||
|
||||
pjsua_schedule_timer2(pjsip_funcs, (void *)ACTIVATE_AUDIO, 0);
|
||||
}
|
||||
|
||||
- (void) provider:(CXProvider *) provider
|
||||
didDectivateAudioSession:(AVAudioSession *) audioSession
|
||||
{
|
||||
NSLog(@"Did deactivate Audio Session");
|
||||
}
|
||||
|
||||
- (void)provider:(CXProvider *)provider
|
||||
performAnswerCallAction:(CXAnswerCallAction *)action
|
||||
{
|
||||
NSLog(@"Perform answer call %@", action.callUUID.UUIDString);
|
||||
|
||||
/* User has answered the call, but we may need to wait for
|
||||
* the incoming INVITE to come.
|
||||
*/
|
||||
for (int i = MAX_INV_TIMEOUT * 1000 / 100; i >= 0; i--) {
|
||||
if (call_map[action.callUUID].intValue != PJSUA_INVALID_ID) break;
|
||||
[NSThread sleepForTimeInterval:0.1];
|
||||
}
|
||||
|
||||
[action fulfill];
|
||||
|
||||
pjsua_call_id call_id = call_map[action.callUUID].intValue;
|
||||
if (call_id == PJSUA_INVALID_ID) {
|
||||
[app.provider reportCallWithUUID:action.callUUID
|
||||
endedAtDate:[NSDate date]
|
||||
reason:CXCallEndedReasonFailed];
|
||||
return;
|
||||
}
|
||||
|
||||
long code = (long)ANSWER_CALL | (call_id << 4);
|
||||
pjsua_schedule_timer2(pjsip_funcs, (void *)code, 0);
|
||||
}
|
||||
|
||||
- (void)provider:(CXProvider *)provider
|
||||
performEndCallAction:(CXEndCallAction *)action
|
||||
{
|
||||
NSLog(@"Perform end call %@", action.callUUID.UUIDString);
|
||||
|
||||
/* User has answered the call, but we may need to wait for
|
||||
* the incoming INVITE to come.
|
||||
*/
|
||||
for (int i = MAX_INV_TIMEOUT * 1000 / 100; i >= 0; i--) {
|
||||
if (call_map[action.callUUID].intValue != PJSUA_INVALID_ID) break;
|
||||
[NSThread sleepForTimeInterval:0.1];
|
||||
}
|
||||
|
||||
[action fulfill];
|
||||
|
||||
pjsua_call_id call_id = call_map[action.callUUID].intValue;
|
||||
if (call_id == PJSUA_INVALID_ID) {
|
||||
[app.provider reportCallWithUUID:action.callUUID
|
||||
endedAtDate:[NSDate date]
|
||||
reason:CXCallEndedReasonFailed];
|
||||
return;
|
||||
}
|
||||
|
||||
long code = (long)END_CALL | (call_id << 4);
|
||||
pjsua_schedule_timer2(pjsip_funcs, (void *)code, 0);
|
||||
}
|
||||
|
||||
- (void)pushRegistry:(PKPushRegistry *)registry
|
||||
didReceiveIncomingPushWithPayload:(PKPushPayload *)payload
|
||||
forType:(PKPushType)type withCompletionHandler:(void (^)(void))completion
|
||||
{
|
||||
/* Handle incoming VoIP push notification. */
|
||||
NSUUID *uuid = [NSUUID UUID];
|
||||
call_map[uuid] = @(PJSUA_INVALID_ID);
|
||||
NSLog(@"Receiving push notification %@", uuid.UUIDString);
|
||||
|
||||
/* Re-register, so the server will send us the suspended INVITE. */
|
||||
SCHEDULE_TIMER(REREGISTER);
|
||||
|
||||
/* Activate audio session. */
|
||||
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
|
||||
NSError *error = nil;
|
||||
if (![audioSession setCategory:AVAudioSessionCategoryPlayAndRecord
|
||||
mode:AVAudioSessionModeVoiceChat
|
||||
options:0 error:&error])
|
||||
{
|
||||
NSLog(@"Error setting up audio session: %@", error.localizedDescription);
|
||||
}
|
||||
if (![audioSession setActive:YES error:&error]) {
|
||||
NSLog(@"Error activating audio session: %@", error.localizedDescription);
|
||||
}
|
||||
|
||||
/* Report the incoming call to the system using CallKit. */
|
||||
CXCallUpdate *callUpdate = [[CXCallUpdate alloc] init];
|
||||
[self.provider reportNewIncomingCallWithUUID:uuid
|
||||
update:callUpdate
|
||||
completion:^(NSError * _Nullable error)
|
||||
{
|
||||
if (error) {
|
||||
NSLog(@"Error reporting incoming call: %@",
|
||||
error.localizedDescription);
|
||||
[call_map removeObjectForKey:uuid];
|
||||
}
|
||||
}];
|
||||
|
||||
/* Call the completion handler when you have finished processing the incoming call. */
|
||||
completion();
|
||||
}
|
||||
|
||||
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
|
||||
{
|
||||
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
|
||||
|
@ -198,7 +535,62 @@ static void pjsuaOnAppConfigCb(pjsua_app_config *cfg)
|
|||
}
|
||||
self.window.rootViewController = self.viewController;
|
||||
[self.window makeKeyAndVisible];
|
||||
|
||||
|
||||
#if USE_PUSH_NOTIFICATION
|
||||
call_map = [NSMutableDictionary dictionary];
|
||||
|
||||
/* Set up a push notification registry for Voice over IP (VoIP). */
|
||||
self.voipRegistry = [[PKPushRegistry alloc] initWithQueue:dispatch_get_main_queue()];
|
||||
self.voipRegistry.delegate = self;
|
||||
self.voipRegistry.desiredPushTypes = [NSSet setWithObject:PKPushTypeVoIP];
|
||||
|
||||
/* Request permission for push notifications. */
|
||||
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
|
||||
center.delegate = self;
|
||||
[center requestAuthorizationWithOptions:(UNAuthorizationOptionAlert |
|
||||
UNAuthorizationOptionBadge |
|
||||
UNAuthorizationOptionSound)
|
||||
completionHandler:^(BOOL granted, NSError * _Nullable error)
|
||||
{
|
||||
NSLog(@"Notification request %sgranted", (granted ? "" : "not"));
|
||||
|
||||
if (granted) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[application registerForRemoteNotifications];
|
||||
});
|
||||
}
|
||||
}];
|
||||
|
||||
/* Note that opening audio device when in the background will not trigger
|
||||
* permission request, so we won't be able to use audio device.
|
||||
* Thus, we need to request permission now.
|
||||
*/
|
||||
[[AVAudioSession sharedInstance] requestRecordPermission:^(BOOL granted)
|
||||
{
|
||||
NSLog(@"Microphone access %sgranted", (granted ? "" : "not"));
|
||||
}];
|
||||
|
||||
/* We need to request local network access permission as well to
|
||||
* immediately send media traffic when in the background.
|
||||
* Due to its complexity, the code is not included here in the sample app.
|
||||
* Please refer to the Apple "Local Network Privacy" FAQ for more details.
|
||||
*/
|
||||
|
||||
/* Create CallKit provider. */
|
||||
CXProviderConfiguration *configuration = [[CXProviderConfiguration alloc]
|
||||
initWithLocalizedName:@"ipjsua"];
|
||||
configuration.maximumCallGroups = 1;
|
||||
configuration.maximumCallsPerCallGroup = 1;
|
||||
self.provider = [[CXProvider alloc] initWithConfiguration:configuration];
|
||||
[self.provider setDelegate:self queue:nil];
|
||||
#else
|
||||
/* Start pjsua app thread immediately, otherwise we do it after push
|
||||
* notification setup completes.
|
||||
*/
|
||||
[NSThread detachNewThreadSelector:@selector(pjsuaStart) toTarget:self
|
||||
withObject:nil];
|
||||
#endif
|
||||
|
||||
/* Observe the kNetworkReachabilityChangedNotification. When that
|
||||
* notification is posted, the method "reachabilityChanged" will be called.
|
||||
*/
|
||||
|
@ -211,9 +603,6 @@ static void pjsuaOnAppConfigCb(pjsua_app_config *cfg)
|
|||
[self updateWithReachability: internetReach];
|
||||
|
||||
app = self;
|
||||
|
||||
/* Start pjsua app thread */
|
||||
[NSThread detachNewThreadSelector:@selector(pjsuaStart) toTarget:self withObject:nil];
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
@ -226,78 +615,14 @@ static void pjsuaOnAppConfigCb(pjsua_app_config *cfg)
|
|||
|
||||
- (void)orientationChanged:(NSNotification *)note
|
||||
{
|
||||
#if PJSUA_HAS_VIDEO
|
||||
const pjmedia_orient pj_ori[4] =
|
||||
{
|
||||
PJMEDIA_ORIENT_ROTATE_90DEG, /* UIDeviceOrientationPortrait */
|
||||
PJMEDIA_ORIENT_ROTATE_270DEG, /* UIDeviceOrientationPortraitUpsideDown */
|
||||
PJMEDIA_ORIENT_ROTATE_180DEG, /* UIDeviceOrientationLandscapeLeft,
|
||||
home button on the right side */
|
||||
PJMEDIA_ORIENT_NATURAL /* UIDeviceOrientationLandscapeRight,
|
||||
home button on the left side */
|
||||
};
|
||||
static pj_thread_desc a_thread_desc;
|
||||
static pj_thread_t *a_thread;
|
||||
static UIDeviceOrientation prev_ori = 0;
|
||||
UIDeviceOrientation dev_ori = [[UIDevice currentDevice] orientation];
|
||||
int i;
|
||||
|
||||
if (dev_ori == prev_ori) return;
|
||||
|
||||
NSLog(@"Device orientation changed: %d", (int)(prev_ori = dev_ori));
|
||||
|
||||
if (dev_ori >= UIDeviceOrientationPortrait &&
|
||||
dev_ori <= UIDeviceOrientationLandscapeRight)
|
||||
{
|
||||
if (!pj_thread_is_registered()) {
|
||||
pj_thread_register("ipjsua", a_thread_desc, &a_thread);
|
||||
}
|
||||
|
||||
/* Here we set the orientation for all video devices.
|
||||
* This may return failure for renderer devices or for
|
||||
* capture devices which do not support orientation setting,
|
||||
* we can simply ignore them.
|
||||
*/
|
||||
for (i = pjsua_vid_dev_count()-1; i >= 0; i--) {
|
||||
pjsua_vid_dev_set_setting(i, PJMEDIA_VID_DEV_CAP_ORIENTATION,
|
||||
&pj_ori[dev_ori-1], PJ_TRUE);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
- (void)keepAlive {
|
||||
static pj_thread_desc a_thread_desc;
|
||||
static pj_thread_t *a_thread;
|
||||
int i;
|
||||
|
||||
if (!pj_thread_is_registered()) {
|
||||
pj_thread_register("ipjsua", a_thread_desc, &a_thread);
|
||||
}
|
||||
|
||||
/* Since iOS requires that the minimum keep alive interval is 600s,
|
||||
* application needs to make sure that the account's registration
|
||||
* timeout is long enough.
|
||||
*/
|
||||
for (i = 0; i < (int)pjsua_acc_get_count(); ++i) {
|
||||
if (pjsua_acc_is_valid(i)) {
|
||||
pjsua_acc_set_registration(i, PJ_TRUE);
|
||||
}
|
||||
}
|
||||
SCHEDULE_TIMER(HANDLE_ORI_CHANGE);
|
||||
}
|
||||
|
||||
- (void)applicationDidEnterBackground:(UIApplication *)application
|
||||
{
|
||||
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
|
||||
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
|
||||
[self performSelectorOnMainThread:@selector(keepAlive) withObject:nil waitUntilDone:YES];
|
||||
|
||||
#if 0
|
||||
/* setKeepAliveTimeout is deprecated. Use PushKit instead. */
|
||||
[application setKeepAliveTimeout:KEEP_ALIVE_INTERVAL handler: ^{
|
||||
[self performSelectorOnMainThread:@selector(keepAlive) withObject:nil waitUntilDone:YES];
|
||||
}];
|
||||
#endif
|
||||
SCHEDULE_TIMER(REREGISTER);
|
||||
/* Allow the re-registration to complete. */
|
||||
[NSThread sleepForTimeInterval:0.3];
|
||||
}
|
||||
|
||||
- (void)applicationWillEnterForeground:(UIApplication *)application
|
||||
|
@ -316,27 +641,44 @@ static void pjsuaOnAppConfigCb(pjsua_app_config *cfg)
|
|||
}
|
||||
|
||||
|
||||
pj_bool_t reportCallState(pjsua_call_id call_id)
|
||||
{
|
||||
pjsua_call_info info;
|
||||
|
||||
pjsua_call_get_info(call_id, &info);
|
||||
|
||||
if (info.state == PJSIP_INV_STATE_DISCONNECTED) {
|
||||
NSUUID *uuid = (__bridge NSUUID *)pjsua_call_get_user_data(call_id);
|
||||
if (uuid && call_map[uuid].intValue == call_id) {
|
||||
[app.provider reportCallWithUUID:uuid
|
||||
endedAtDate:[NSDate date]
|
||||
reason:CXCallEndedReasonRemoteEnded];
|
||||
[call_map removeObjectForKey:uuid];
|
||||
}
|
||||
|
||||
/* Check if we need to deactivate audio session. Note that sound device
|
||||
* will only be closed after pjsua_media_config.snd_auto_close_time.
|
||||
*/
|
||||
pjsua_schedule_timer2(pjsip_funcs, (void *)DEACTIVATE_AUDIO, 1500);
|
||||
}
|
||||
|
||||
return PJ_FALSE;
|
||||
}
|
||||
|
||||
pj_bool_t showNotification(pjsua_call_id call_id)
|
||||
{
|
||||
/* This is deprecated. Use VoIP Push Notifications with PushKit
|
||||
* framework instead.
|
||||
*/
|
||||
#if 0
|
||||
// Create a new notification
|
||||
UILocalNotification* alert = [[UILocalNotification alloc] init];
|
||||
if (alert)
|
||||
{
|
||||
alert.repeatInterval = 0;
|
||||
alert.alertBody = @"Incoming call received...";
|
||||
/* This action just brings the app to the FG, it doesn't
|
||||
* automatically answer the call (unless you specify the
|
||||
* --auto-answer option).
|
||||
*/
|
||||
alert.alertAction = @"Activate app";
|
||||
|
||||
dispatch_async(dispatch_get_main_queue(),
|
||||
^{[[UIApplication sharedApplication]
|
||||
presentLocalNotificationNow:alert];});
|
||||
#if USE_PUSH_NOTIFICATION
|
||||
NSLog(@"Receiving incoming call %d", call_id);
|
||||
|
||||
for (NSUUID *uuid in call_map) {
|
||||
if (call_map[uuid].intValue == PJSUA_INVALID_ID) {
|
||||
NSLog(@"Associating incoming call %d with UUID %@",
|
||||
call_id, uuid.UUIDString);
|
||||
call_map[uuid] = @(call_id);
|
||||
pjsua_call_set_user_data(call_id, (__bridge void *)uuid);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -47,6 +47,7 @@ static void stereo_demo();
|
|||
|
||||
#ifdef USE_GUI
|
||||
pj_bool_t showNotification(pjsua_call_id call_id);
|
||||
pj_bool_t reportCallState(pjsua_call_id call_id);
|
||||
#endif
|
||||
|
||||
static void ringback_start(pjsua_call_id call_id);
|
||||
|
@ -171,6 +172,10 @@ static void on_call_state(pjsua_call_id call_id, pjsip_event *e)
|
|||
|
||||
PJ_UNUSED_ARG(e);
|
||||
|
||||
#ifdef USE_GUI
|
||||
reportCallState(call_id);
|
||||
#endif
|
||||
|
||||
pjsua_call_get_info(call_id, &call_info);
|
||||
|
||||
if (call_info.state == PJSIP_INV_STATE_DISCONNECTED) {
|
||||
|
@ -666,6 +671,40 @@ static void on_buddy_state(pjsua_buddy_id buddy_id)
|
|||
}
|
||||
|
||||
|
||||
/*
|
||||
* Handler on buddy dialog event state changed.
|
||||
*/
|
||||
static void on_buddy_dlg_event_state(pjsua_buddy_id buddy_id)
|
||||
{
|
||||
pjsua_buddy_dlg_event_info info;
|
||||
pjsua_buddy_get_dlg_event_info(buddy_id, &info);
|
||||
|
||||
PJ_LOG(3,(THIS_FILE, "%.*s dialog-info-state: %.*s, "
|
||||
"dialog-info-entity: %.*s, dialog-id: %.*s, "
|
||||
"dialog-call-id: %.*s, dialog-direction: %.*s, "
|
||||
"dialog-state: %.*s, dialog-duration: %.*s, "
|
||||
"local-identity: %.*s, local-target-uri: %.*s, "
|
||||
"remote-identity: %.*s, remote-target-uri: %.*s, "
|
||||
"dialog-local-tag: %.*s, dialog-remote-tag: %.*s, "
|
||||
"subscription state: %s (last termination reason code=%d %.*s)",
|
||||
(int)info.uri.slen, info.uri.ptr,
|
||||
(int)info.dialog_info_state.slen, info.dialog_info_state.ptr,
|
||||
(int)info.dialog_info_entity.slen, info.dialog_info_entity.ptr,
|
||||
(int)info.dialog_id.slen, info.dialog_id.ptr,
|
||||
(int)info.dialog_call_id.slen, info.dialog_call_id.ptr,
|
||||
(int)info.dialog_direction.slen, info.dialog_direction.ptr,
|
||||
(int)info.dialog_state.slen, info.dialog_state.ptr,
|
||||
(int)info.dialog_duration.slen, info.dialog_duration.ptr,
|
||||
(int)info.local_identity.slen, info.local_identity.ptr,
|
||||
(int)info.local_target_uri.slen, info.local_target_uri.ptr,
|
||||
(int)info.remote_identity.slen, info.remote_identity.ptr,
|
||||
(int)info.remote_target_uri.slen, info.remote_target_uri.ptr,
|
||||
(int)info.dialog_local_tag.slen, info.dialog_local_tag.ptr,
|
||||
(int)info.dialog_remote_tag.slen, info.dialog_remote_tag.ptr,
|
||||
info.sub_state_name, info.sub_term_code,
|
||||
(int)info.sub_term_reason.slen, info.sub_term_reason.ptr));
|
||||
}
|
||||
|
||||
/*
|
||||
* Subscription state has changed.
|
||||
*/
|
||||
|
@ -696,11 +735,36 @@ static void on_buddy_evsub_state(pjsua_buddy_id buddy_id,
|
|||
|
||||
}
|
||||
|
||||
static void on_buddy_evsub_dlg_event_state(pjsua_buddy_id buddy_id,
|
||||
pjsip_evsub *sub,
|
||||
pjsip_event *event)
|
||||
{
|
||||
char event_info[80];
|
||||
|
||||
PJ_UNUSED_ARG(sub);
|
||||
|
||||
event_info[0] = '\0';
|
||||
|
||||
if (event->type == PJSIP_EVENT_TSX_STATE &&
|
||||
event->body.tsx_state.type == PJSIP_EVENT_RX_MSG)
|
||||
{
|
||||
pjsip_rx_data *rdata = event->body.tsx_state.src.rdata;
|
||||
snprintf(event_info, sizeof(event_info),
|
||||
" (RX %s)",
|
||||
pjsip_rx_data_get_info(rdata));
|
||||
}
|
||||
|
||||
PJ_LOG(4,(THIS_FILE,
|
||||
"Buddy %d: dialog event subscription state: %s (event: %s%s)",
|
||||
buddy_id, pjsip_evsub_get_state_name(sub),
|
||||
pjsip_event_str(event->type), event_info));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Incoming IM message (i.e. MESSAGE request)!
|
||||
*/
|
||||
static void on_pager(pjsua_call_id call_id, const pj_str_t *from,
|
||||
static void on_pager(pjsua_call_id call_id, const pj_str_t *from,
|
||||
const pj_str_t *to, const pj_str_t *contact,
|
||||
const pj_str_t *mime_type, const pj_str_t *text)
|
||||
{
|
||||
|
@ -1060,6 +1124,11 @@ void on_ip_change_progress(pjsua_ip_change_op op,
|
|||
|
||||
if (status == PJ_SUCCESS) {
|
||||
switch (op) {
|
||||
case PJSUA_IP_CHANGE_OP_SHUTDOWN_TP:
|
||||
pj_ansi_snprintf(info_str, sizeof(info_str),
|
||||
"TCP/TLS transports shutdown");
|
||||
break;
|
||||
|
||||
case PJSUA_IP_CHANGE_OP_RESTART_LIS:
|
||||
pjsua_transport_get_info(info->lis_restart.transport_id, &tp_info);
|
||||
pj_ansi_snprintf(info_str, sizeof(info_str),
|
||||
|
@ -1106,7 +1175,10 @@ void on_ip_change_progress(pjsua_ip_change_op op,
|
|||
case PJSUA_IP_CHANGE_OP_COMPLETED:
|
||||
pj_ansi_snprintf(info_str, sizeof(info_str),
|
||||
"done");
|
||||
break;
|
||||
default:
|
||||
pj_ansi_snprintf(info_str, sizeof(info_str),
|
||||
"unknown-op");
|
||||
break;
|
||||
}
|
||||
PJ_LOG(3,(THIS_FILE, "IP change progress report : %s", info_str));
|
||||
|
@ -1385,7 +1457,10 @@ static pj_status_t app_init(void)
|
|||
app_config.cfg.cb.on_reg_state = &on_reg_state;
|
||||
app_config.cfg.cb.on_incoming_subscribe = &on_incoming_subscribe;
|
||||
app_config.cfg.cb.on_buddy_state = &on_buddy_state;
|
||||
app_config.cfg.cb.on_buddy_dlg_event_state = &on_buddy_dlg_event_state;
|
||||
app_config.cfg.cb.on_buddy_evsub_state = &on_buddy_evsub_state;
|
||||
app_config.cfg.cb.on_buddy_evsub_dlg_event_state =
|
||||
&on_buddy_evsub_dlg_event_state;
|
||||
app_config.cfg.cb.on_pager = &on_pager;
|
||||
app_config.cfg.cb.on_typing = &on_typing;
|
||||
app_config.cfg.cb.on_call_transfer_status = &on_call_transfer_status;
|
||||
|
@ -1928,6 +2003,9 @@ static pj_status_t app_init(void)
|
|||
pjsua_call_setting_default(&call_opt);
|
||||
call_opt.aud_cnt = app_config.aud_cnt;
|
||||
call_opt.vid_cnt = app_config.vid.vid_cnt;
|
||||
if (app_config.enable_loam) {
|
||||
call_opt.flag |= PJSUA_CALL_NO_SDP_OFFER;
|
||||
}
|
||||
|
||||
#if defined(PJSIP_HAS_TLS_TRANSPORT) && PJSIP_HAS_TLS_TRANSPORT!=0
|
||||
/* Wipe out TLS key settings in transport configs */
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
#define CMD_QUIT 110
|
||||
#define CMD_RESTART 120
|
||||
#define CMD_HANDLE_IP_CHANGE 130
|
||||
#define CMD_TOGGLE_SDP_OFFER 140
|
||||
|
||||
/* call level 2 command */
|
||||
#define CMD_CALL_NEW ((CMD_CALL*10)+1)
|
||||
|
@ -2086,6 +2087,19 @@ static pj_status_t cmd_show_current_call(pj_cli_cmd_val *cval)
|
|||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
static pj_status_t cmd_toggle_call_sdp_offer(pj_cli_cmd_val* cval)
|
||||
{
|
||||
char out_str[64];
|
||||
app_config.enable_loam = !app_config.enable_loam;
|
||||
|
||||
pj_ansi_snprintf(out_str, sizeof(out_str),
|
||||
"Subsequent calls and UPDATEs will contain SDP offer: %s\n",
|
||||
app_config.enable_loam ? "No" : "Yes");
|
||||
pj_cli_sess_write_msg(cval->sess, out_str, pj_ansi_strlen(out_str));
|
||||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
/* Call handler */
|
||||
pj_status_t cmd_call_handler(pj_cli_cmd_val *cval)
|
||||
{
|
||||
|
@ -2094,6 +2108,14 @@ pj_status_t cmd_call_handler(pj_cli_cmd_val *cval)
|
|||
|
||||
CHECK_PJSUA_RUNNING();
|
||||
|
||||
/* Update call setting */
|
||||
pjsua_call_setting_default(&call_opt);
|
||||
call_opt.aud_cnt = app_config.aud_cnt;
|
||||
call_opt.vid_cnt = app_config.vid.vid_cnt;
|
||||
if (app_config.enable_loam) {
|
||||
call_opt.flag |= PJSUA_CALL_NO_SDP_OFFER;
|
||||
}
|
||||
|
||||
switch(cmd_id) {
|
||||
case CMD_CALL_NEW:
|
||||
status = cmd_make_single_call(cval);
|
||||
|
@ -3221,12 +3243,17 @@ static pj_status_t add_other_command(pj_cli_t *c)
|
|||
char* ip_change_command =
|
||||
"<CMD name='ip_change' id='130' desc='Handle IP change'/>";
|
||||
|
||||
char* toggle_sdp_offer_command =
|
||||
"<CMD name='toggle_sdp_offer' sc='o' id='140' "
|
||||
"desc='Toggle SDP offer use on subsequent calls and UPDATEs' />";
|
||||
|
||||
pj_status_t status;
|
||||
pj_str_t sleep_xml = pj_str(sleep_command);
|
||||
pj_str_t network_xml = pj_str(network_command);
|
||||
pj_str_t shutdown_xml = pj_str(shutdown_command);
|
||||
pj_str_t restart_xml = pj_str(restart_command);
|
||||
pj_str_t ip_change_xml = pj_str(ip_change_command);
|
||||
pj_str_t toggle_sdp_offer_xml = pj_str(toggle_sdp_offer_command);
|
||||
|
||||
status = pj_cli_add_cmd_from_xml(c, NULL,
|
||||
&sleep_xml, cmd_sleep_handler,
|
||||
|
@ -3257,6 +3284,13 @@ static pj_status_t add_other_command(pj_cli_t *c)
|
|||
status = pj_cli_add_cmd_from_xml(c, NULL,
|
||||
&ip_change_xml, cmd_ip_change_handler,
|
||||
NULL, NULL);
|
||||
if (status != PJ_SUCCESS)
|
||||
return status;
|
||||
|
||||
status = pj_cli_add_cmd_from_xml(c, NULL,
|
||||
&toggle_sdp_offer_xml,
|
||||
cmd_toggle_call_sdp_offer,
|
||||
NULL, NULL);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
|
|
@ -77,6 +77,8 @@ typedef struct pjsua_app_config
|
|||
pj_bool_t no_refersub;
|
||||
pj_bool_t ipv6;
|
||||
pj_bool_t enable_qos;
|
||||
pj_bool_t no_mci;
|
||||
pj_bool_t enable_loam;
|
||||
pj_bool_t no_tcp;
|
||||
pj_bool_t no_udp;
|
||||
pj_bool_t use_tls;
|
||||
|
|
|
@ -94,6 +94,7 @@ static void usage(void)
|
|||
puts (" --ipv6 Create SIP IPv6 transports.");
|
||||
#endif
|
||||
puts (" --set-qos Enable QoS tagging for SIP and media.");
|
||||
puts (" --no-mci Disable message composition indication (RFC 3994)");
|
||||
puts (" --local-port=port Set TCP/UDP port. This implicitly enables both ");
|
||||
puts (" TCP and UDP transports on the specified port, unless");
|
||||
puts (" if TCP or UDP is disabled.");
|
||||
|
@ -392,7 +393,7 @@ static pj_status_t parse_args(int argc, char *argv[],
|
|||
OPT_TLS_NEG_TIMEOUT, OPT_TLS_CIPHER,
|
||||
OPT_CAPTURE_DEV, OPT_PLAYBACK_DEV,
|
||||
OPT_CAPTURE_LAT, OPT_PLAYBACK_LAT, OPT_NO_TONES, OPT_JB_MAX_SIZE,
|
||||
OPT_STDOUT_REFRESH, OPT_STDOUT_REFRESH_TEXT, OPT_IPV6, OPT_QOS,
|
||||
OPT_STDOUT_REFRESH, OPT_STDOUT_REFRESH_TEXT, OPT_IPV6, OPT_QOS, OPT_MCI,
|
||||
#ifdef _IONBF
|
||||
OPT_STDOUT_NO_BUF,
|
||||
#endif
|
||||
|
@ -533,6 +534,7 @@ static pj_status_t parse_args(int argc, char *argv[],
|
|||
{ "ipv6", 0, 0, OPT_IPV6},
|
||||
#endif
|
||||
{ "set-qos", 0, 0, OPT_QOS},
|
||||
{ "no-mci", 0, 0, OPT_MCI},
|
||||
{ "use-timer", 1, 0, OPT_TIMER},
|
||||
{ "timer-se", 1, 0, OPT_TIMER_SE},
|
||||
{ "timer-min-se", 1, 0, OPT_TIMER_MIN_SE},
|
||||
|
@ -1466,6 +1468,9 @@ static pj_status_t parse_args(int argc, char *argv[],
|
|||
cfg->udp_cfg.qos_params.flags = PJ_QOS_PARAM_HAS_DSCP;
|
||||
cfg->udp_cfg.qos_params.dscp_val = 0x18;
|
||||
break;
|
||||
case OPT_MCI:
|
||||
cfg->no_mci = PJ_TRUE;
|
||||
break;
|
||||
case OPT_VIDEO:
|
||||
cfg->vid.vid_cnt = 1;
|
||||
cfg->vid.in_auto_show = PJ_TRUE;
|
||||
|
@ -1979,6 +1984,11 @@ int write_settings(pjsua_app_config *config, char *buf, pj_size_t max)
|
|||
pj_strcat2(&cfg, "--set-qos\n");
|
||||
}
|
||||
|
||||
/* Message Composition Indication */
|
||||
if (config->no_mci) {
|
||||
pj_strcat2(&cfg, "--no-mci\n");
|
||||
}
|
||||
|
||||
/* UDP Transport. */
|
||||
pj_ansi_snprintf(line, sizeof(line), "--local-port %d\n",
|
||||
config->udp_cfg.port);
|
||||
|
|
|
@ -236,6 +236,8 @@ static void keystroke_help()
|
|||
puts("| a Answer call | i Send IM | !a Modify accnt. |");
|
||||
puts("| h Hangup call (ha=all) | s Subscribe presence | rr (Re-)register |");
|
||||
puts("| H Hold call | u Unsubscribe presence | ru Unregister |");
|
||||
puts("| o Toggle call SDP offer | D Subscribe dlg event | |");
|
||||
puts("| | Du Unsub dlg event | |");
|
||||
puts("| v re-inVite (release hold) | t Toggle online status | > Cycle next ac.|");
|
||||
puts("| U send UPDATE | T Set online status | < Cycle prev ac.|");
|
||||
puts("| ],[ Select next/prev call +--------------------------+-------------------+");
|
||||
|
@ -732,6 +734,9 @@ static void ui_make_new_call()
|
|||
|
||||
pjsua_msg_data_init(&msg_data_);
|
||||
TEST_MULTIPART(&msg_data_);
|
||||
if (app_config.enable_loam) {
|
||||
call_opt.flag |= PJSUA_CALL_NO_SDP_OFFER;
|
||||
}
|
||||
pjsua_call_make_call(current_acc, &tmp, &call_opt, NULL,
|
||||
&msg_data_, ¤t_call);
|
||||
|
||||
|
@ -771,6 +776,10 @@ static void ui_make_multi_call()
|
|||
tmp = pj_str(result.uri_result);
|
||||
}
|
||||
|
||||
if (app_config.enable_loam) {
|
||||
call_opt.flag |= PJSUA_CALL_NO_SDP_OFFER;
|
||||
}
|
||||
|
||||
for (i=0; i<my_atoi(menuin); ++i) {
|
||||
pj_status_t status;
|
||||
|
||||
|
@ -822,26 +831,30 @@ static void ui_send_instant_message()
|
|||
|
||||
|
||||
/* Send typing indication. */
|
||||
if (i != -1)
|
||||
pjsua_call_send_typing_ind(i, PJ_TRUE, NULL);
|
||||
else {
|
||||
pj_str_t tmp_uri = pj_str(uri);
|
||||
pjsua_im_typing(current_acc, &tmp_uri, PJ_TRUE, NULL);
|
||||
if (!app_config.no_mci) {
|
||||
if (i != -1)
|
||||
pjsua_call_send_typing_ind(i, PJ_TRUE, NULL);
|
||||
else {
|
||||
pj_str_t tmp_uri = pj_str(uri);
|
||||
pjsua_im_typing(current_acc, &tmp_uri, PJ_TRUE, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/* Input the IM . */
|
||||
if (!simple_input("Message", text, sizeof(text))) {
|
||||
/*
|
||||
* Cancelled.
|
||||
* Send typing notification too, saying we're not typing.
|
||||
*/
|
||||
if (i != -1)
|
||||
pjsua_call_send_typing_ind(i, PJ_FALSE, NULL);
|
||||
else {
|
||||
pj_str_t tmp_uri = pj_str(uri);
|
||||
pjsua_im_typing(current_acc, &tmp_uri, PJ_FALSE, NULL);
|
||||
if (!app_config.no_mci) {
|
||||
/*
|
||||
* Cancelled.
|
||||
* Send typing notification too, saying we're not typing.
|
||||
*/
|
||||
if (i != -1)
|
||||
pjsua_call_send_typing_ind(i, PJ_FALSE, NULL);
|
||||
else {
|
||||
pj_str_t tmp_uri = pj_str(uri);
|
||||
pjsua_im_typing(current_acc, &tmp_uri, PJ_FALSE, NULL);
|
||||
}
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
tmp = pj_str(text);
|
||||
|
@ -991,7 +1004,10 @@ static void ui_add_buddy()
|
|||
pj_bzero(&buddy_cfg, sizeof(pjsua_buddy_config));
|
||||
|
||||
buddy_cfg.uri = pj_str(buf);
|
||||
buddy_cfg.subscribe = PJ_TRUE;
|
||||
/* Only one subscription can be active, so we need to disable this
|
||||
* to allow user to choose between presence or dialog event.
|
||||
*/
|
||||
// buddy_cfg.subscribe = PJ_TRUE;
|
||||
|
||||
status = pjsua_buddy_add(&buddy_cfg, &buddy_id);
|
||||
if (status == PJ_SUCCESS) {
|
||||
|
@ -1072,6 +1088,11 @@ static void ui_delete_account()
|
|||
}
|
||||
}
|
||||
|
||||
static void ui_unset_loam_mode()
|
||||
{
|
||||
app_config.enable_loam = PJ_FALSE;
|
||||
}
|
||||
|
||||
static void ui_call_hold()
|
||||
{
|
||||
if (current_call != -1) {
|
||||
|
@ -1090,6 +1111,9 @@ static void ui_call_reinvite()
|
|||
static void ui_send_update()
|
||||
{
|
||||
if (current_call != -1) {
|
||||
if (app_config.enable_loam) {
|
||||
call_opt.flag |= PJSUA_CALL_NO_SDP_OFFER;
|
||||
}
|
||||
pjsua_call_update2(current_call, &call_opt, NULL);
|
||||
} else {
|
||||
PJ_LOG(3,(THIS_FILE, "No current call"));
|
||||
|
@ -1434,6 +1458,18 @@ static void ui_send_arbitrary_request()
|
|||
}
|
||||
}
|
||||
|
||||
static void ui_toggle_call_sdp_offer()
|
||||
{
|
||||
app_config.enable_loam = !app_config.enable_loam;
|
||||
|
||||
printf("Subsequent calls and UPDATEs will contain SDP offer: ");
|
||||
if (app_config.enable_loam) {
|
||||
printf("NO.\n");
|
||||
} else {
|
||||
printf("YES.\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void ui_echo(char menuin[])
|
||||
{
|
||||
if (pj_ansi_strnicmp(menuin, "echo", 4)==0) {
|
||||
|
@ -1496,6 +1532,32 @@ static void ui_subscribe(char menuin[])
|
|||
}
|
||||
}
|
||||
|
||||
static void ui_subscribe_dlg_event(pj_bool_t sub)
|
||||
{
|
||||
char buf[128];
|
||||
input_result result;
|
||||
|
||||
ui_input_url("(un)Subscribe dialog event of", buf, sizeof(buf), &result,
|
||||
PJ_TRUE);
|
||||
if (result.nb_result != PJSUA_APP_NO_NB) {
|
||||
if (result.nb_result == -1) {
|
||||
int i, count;
|
||||
count = pjsua_get_buddy_count();
|
||||
for (i=0; i<count; ++i)
|
||||
pjsua_buddy_subscribe_dlg_event(i, sub);
|
||||
} else if (result.nb_result == 0) {
|
||||
puts("Sorry, can only subscribe to buddy's dialog event, "
|
||||
"not from existing call");
|
||||
} else {
|
||||
pjsua_buddy_subscribe_dlg_event(result.nb_result-1, sub);
|
||||
}
|
||||
|
||||
} else if (result.uri_result) {
|
||||
puts("Sorry, can only subscribe to buddy's dialog event, "
|
||||
"not arbitrary URL (for now)");
|
||||
}
|
||||
}
|
||||
|
||||
static void ui_register(char menuin[])
|
||||
{
|
||||
switch (menuin[1]) {
|
||||
|
@ -1786,8 +1848,6 @@ static void ui_handle_ip_change()
|
|||
status = pjsua_handle_ip_change(¶m);
|
||||
if (status != PJ_SUCCESS) {
|
||||
pjsua_perror(THIS_FILE, "IP change failed", status);
|
||||
} else {
|
||||
PJ_LOG(3,(THIS_FILE, "IP change succeeded"));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1907,6 +1967,13 @@ void legacy_main(void)
|
|||
ui_call_hold();
|
||||
break;
|
||||
|
||||
case 'o':
|
||||
/*
|
||||
* Toggle call SDP offer
|
||||
*/
|
||||
ui_toggle_call_sdp_offer();
|
||||
break;
|
||||
|
||||
case 'v':
|
||||
#if PJSUA_HAS_VIDEO
|
||||
if (menuin[1]=='i' && menuin[2]=='d' && menuin[3]==' ') {
|
||||
|
@ -1987,6 +2054,11 @@ void legacy_main(void)
|
|||
ui_subscribe(menuin);
|
||||
break;
|
||||
|
||||
case 'D':
|
||||
/* Subscribe/unsubscribe dialog event */
|
||||
ui_subscribe_dlg_event(menuin[1] != 'u');
|
||||
break;
|
||||
|
||||
case 'r':
|
||||
ui_register(menuin);
|
||||
break;
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
3A4E3B5E2B6206E50016735C /* Metal.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3A4E3B5C2B6206E50016735C /* Metal.framework */; };
|
||||
3A4E3B5F2B6206E50016735C /* MetalKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3A4E3B5D2B6206E50016735C /* MetalKit.framework */; };
|
||||
3AEC29312995BF1400F59EA0 /* VideoToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3AEC29302995BF1400F59EA0 /* VideoToolbox.framework */; };
|
||||
3AEC29332995BF4C00F59EA0 /* CoreMedia.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3AEC29322995BF4C00F59EA0 /* CoreMedia.framework */; };
|
||||
C337417325BADEEE007785D7 /* Model.swift in Sources */ = {isa = PBXBuildFile; fileRef = C337417225BADEEE007785D7 /* Model.swift */; };
|
||||
|
@ -46,6 +48,8 @@
|
|||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
3A4E3B5C2B6206E50016735C /* Metal.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Metal.framework; path = System/Library/Frameworks/Metal.framework; sourceTree = SDKROOT; };
|
||||
3A4E3B5D2B6206E50016735C /* MetalKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MetalKit.framework; path = System/Library/Frameworks/MetalKit.framework; sourceTree = SDKROOT; };
|
||||
3AEC29302995BF1400F59EA0 /* VideoToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = VideoToolbox.framework; path = System/Library/Frameworks/VideoToolbox.framework; sourceTree = SDKROOT; };
|
||||
3AEC29322995BF4C00F59EA0 /* CoreMedia.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreMedia.framework; path = System/Library/Frameworks/CoreMedia.framework; sourceTree = SDKROOT; };
|
||||
C337417225BADEEE007785D7 /* Model.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Model.swift; sourceTree = "<group>"; };
|
||||
|
@ -94,6 +98,7 @@
|
|||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
3A4E3B5F2B6206E50016735C /* MetalKit.framework in Frameworks */,
|
||||
C351398125A5F70D00A090AA /* libg7221codec.a in Frameworks */,
|
||||
C351398225A5F70D00A090AA /* libgsmcodec.a in Frameworks */,
|
||||
C351398325A5F70D00A090AA /* libilbccodec.a in Frameworks */,
|
||||
|
@ -112,6 +117,7 @@
|
|||
C351398E25A5F70D00A090AA /* libpjsua.a in Frameworks */,
|
||||
C351398F25A5F70D00A090AA /* libpjsua2.a in Frameworks */,
|
||||
C351399025A5F70D00A090AA /* libresample.a in Frameworks */,
|
||||
3A4E3B5E2B6206E50016735C /* Metal.framework in Frameworks */,
|
||||
C351399125A5F70D00A090AA /* libspeex.a in Frameworks */,
|
||||
C351399225A5F70D00A090AA /* libsrtp.a in Frameworks */,
|
||||
C351399325A5F70D00A090AA /* libwebrtc.a in Frameworks */,
|
||||
|
@ -188,6 +194,8 @@
|
|||
C3B8521725A5EC380037A8AB /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
3A4E3B5C2B6206E50016735C /* Metal.framework */,
|
||||
3A4E3B5D2B6206E50016735C /* MetalKit.framework */,
|
||||
3AEC29322995BF4C00F59EA0 /* CoreMedia.framework */,
|
||||
3AEC29302995BF1400F59EA0 /* VideoToolbox.framework */,
|
||||
C3B8524625A5ED6D0037A8AB /* AudioToolbox.framework */,
|
||||
|
|
|
@ -207,7 +207,7 @@ class Chat(gui.ChatObserver):
|
|||
# it is a temporary one and not really registered to acc
|
||||
bud = None
|
||||
try:
|
||||
bud = self._acc.findBuddy(uri_str)
|
||||
bud = self._acc.findBuddy2(uri_str)
|
||||
except:
|
||||
bud = buddy.Buddy(None)
|
||||
bud_cfg = pj.BuddyConfig()
|
||||
|
|
|
@ -212,9 +212,9 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
|
|||
|
||||
[[package]]
|
||||
name = "shlex"
|
||||
version = "1.1.0"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3"
|
||||
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
|
|
|
@ -900,8 +900,9 @@ static void destroy_app()
|
|||
if (app.pool) {
|
||||
pj_pool_release(app.pool);
|
||||
app.pool = NULL;
|
||||
PJ_LOG(3,(THIS_FILE, "Peak memory size: %luMB",
|
||||
app.cp.peak_used_size / 1000000));
|
||||
/* Field peak_used_size is deprecated by #3897 */
|
||||
//PJ_LOG(3,(THIS_FILE, "Peak memory size: %luMB",
|
||||
// app.cp.peak_used_size / 1000000));
|
||||
pj_caching_pool_destroy(&app.cp);
|
||||
}
|
||||
|
||||
|
|
|
@ -205,11 +205,7 @@ void MyCall::onCallMediaState(OnCallMediaStateParam &prm)
|
|||
med_port = new MyAudioMediaPort();
|
||||
|
||||
MediaFormatAudio fmt;
|
||||
fmt.type = PJMEDIA_TYPE_AUDIO;
|
||||
fmt.clockRate = 16000;
|
||||
fmt.channelCount = 1;
|
||||
fmt.bitsPerSample = 16;
|
||||
fmt.frameTimeUsec = 20000;
|
||||
fmt.init(PJMEDIA_FORMAT_PCM, 16000, 1, 20000, 16);
|
||||
|
||||
med_port->createPort("med_port", fmt);
|
||||
|
||||
|
|
|
@ -1420,6 +1420,11 @@ static void call_on_media_update( pjsip_inv_session *inv,
|
|||
pjmedia_sdp_neg_get_active_local(inv->neg, &local_sdp);
|
||||
pjmedia_sdp_neg_get_active_remote(inv->neg, &remote_sdp);
|
||||
|
||||
if (local_sdp->media[0]->desc.port == 0) {
|
||||
PJ_LOG(3, (THIS_FILE, "Audio media inactive"));
|
||||
return;
|
||||
}
|
||||
|
||||
status = pjmedia_stream_info_from_sdp(&audio->si, inv->pool, app.med_endpt,
|
||||
local_sdp, remote_sdp, 0);
|
||||
if (status != PJ_SUCCESS) {
|
||||
|
@ -1789,9 +1794,9 @@ static void print_avg_stat(void)
|
|||
min_stat.tx.loss, avg_stat.tx.loss, max_stat.tx.loss,
|
||||
"packets",
|
||||
|
||||
min_stat.tx.loss*100.0/(min_stat.tx.pkt+min_stat.tx.loss),
|
||||
avg_stat.tx.loss*100.0/(avg_stat.tx.pkt+avg_stat.tx.loss),
|
||||
max_stat.tx.loss*100.0/(max_stat.tx.pkt+max_stat.tx.loss),
|
||||
min_stat.tx.loss*100.0/(min_stat.tx.pkt),
|
||||
avg_stat.tx.loss*100.0/(avg_stat.tx.pkt),
|
||||
max_stat.tx.loss*100.0/(max_stat.tx.pkt),
|
||||
"%",
|
||||
|
||||
min_stat.tx.dup, avg_stat.tx.dup, max_stat.tx.dup,
|
||||
|
|
|
@ -203,11 +203,11 @@ static void print_call(int call_index)
|
|||
good_number(ipbytes, sizeof(ipbytes), audio->rtcp.stat.tx.bytes + audio->rtcp.stat.tx.pkt * 32),
|
||||
"",
|
||||
audio->rtcp.stat.tx.loss,
|
||||
audio->rtcp.stat.tx.loss * 100.0 / (audio->rtcp.stat.tx.pkt + audio->rtcp.stat.tx.loss),
|
||||
audio->rtcp.stat.tx.loss * 100.0 / (audio->rtcp.stat.tx.pkt),
|
||||
audio->rtcp.stat.tx.dup,
|
||||
audio->rtcp.stat.tx.dup * 100.0 / (audio->rtcp.stat.tx.pkt + audio->rtcp.stat.tx.loss),
|
||||
audio->rtcp.stat.tx.dup * 100.0 / (audio->rtcp.stat.tx.pkt),
|
||||
audio->rtcp.stat.tx.reorder,
|
||||
audio->rtcp.stat.tx.reorder * 100.0 / (audio->rtcp.stat.tx.pkt + audio->rtcp.stat.tx.loss),
|
||||
audio->rtcp.stat.tx.reorder * 100.0 / (audio->rtcp.stat.tx.pkt),
|
||||
"",
|
||||
audio->rtcp.stat.tx.loss_period.min / 1000.0,
|
||||
audio->rtcp.stat.tx.loss_period.mean / 1000.0,
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue