Compare commits

...

85 Commits

Author SHA1 Message Date
Nanang Izzuddin 1dab9b63ac
Add TLS/SSL backend: Windows Schannel (#3867) 2024-05-08 10:25:03 +07:00
Nanang Izzuddin 30829f03a7
Update Android JNI audio dev to use 16bit PCM only (#3945) 2024-05-08 09:09:21 +07:00
sauwming 24ac5875ff
Fixed CI Mac build failure (#3947) 2024-05-07 10:29:43 +08:00
Nanang Izzuddin ca2dacf024
Print log on successful send (#3942) 2024-05-07 09:22:35 +07:00
sauwming f406002f68
Fix warning of uninitialized value in fuzz-crypto (#3946) 2024-05-07 08:02:17 +08:00
Nanang Izzuddin f38d781a82
Fix bad address length check in pj_ioqueue_sendto(). (#3941) 2024-04-29 15:01:38 +07:00
sauwming 4f3df90a3e
Fixed PJSUA2 API to get/set Opus config (#3935) 2024-04-23 17:01:38 +08:00
sauwming 472bda5087
Support Push Notification in iOS sample app (#3913) 2024-04-23 12:59:52 +08:00
sauwming 0d2ebdc7e3
Fixed incorrect SDP buffer length calculation (#3924) 2024-04-17 11:22:14 +08:00
sauwming c5bc3d1ef5
Add function to initialize MediaFormat audio & video (#3925) 2024-04-17 11:21:57 +08:00
sauwming 72d885d5d7
Add check in siprtp sample app for inactive audio media (#3927) 2024-04-17 11:21:39 +08:00
Amilcar Ubiera 12d0468cb6
Fix to ext_fmts accessed out of stack scope. (#3916) 2024-04-15 10:25:30 +08:00
Amilcar Ubiera 6d114d71d5
pjsua_acc: Fix warnings for comparison between ‘pjsua_nat64_opt’ and ‘enum pjsua_ipv6_use’ (#3915) 2024-04-05 14:05:36 +08:00
sauwming e7e7f28f16
Improve IP address change IPv4 <-> IPv6 (#3910) 2024-04-03 18:04:51 +08:00
sauwming 86b7dd48b5
Fixed DTLS clock stoppage race (#3905) 2024-04-01 10:52:31 +08:00
sauwming 51e52062e1
Fixed Metal renderer memory leak (#3909) 2024-03-29 10:05:02 +08:00
Nanang Izzuddin 478aeb95e9
Fix data race reported by ThreadSanitizer in caching pool (#3897) 2024-03-26 15:20:44 +07:00
sauwming c0de1a4224
Prevent race condition in DTLS media stop (#3901) 2024-03-26 11:52:54 +08:00
Santiago De la Cruz 427a2b3ab8
Add some missing unlocks (#3893) 2024-03-26 11:52:13 +08:00
Amilcar Ubiera ca4b078cc1
Fix warnings for 32-bit compiler and misc fixes. (#3896) 2024-03-25 11:28:36 +08:00
Goodicus a7c4d83807
Enable Late Offer Answer Mode (LOAM) feature in the pjsua (#3869) 2024-03-21 16:58:24 +07:00
naf cfde494dc3
Add missing openssl SECLEVEL=0 support (#3890)
Previous SECLEVEL support allowed for levels 1-5.
However, openssl defines levels 0-5. [1]

Recent openssl versions (3.0+) have moved previous
popular ciphers/key lengths (i.e. RSA1024withSHA1)
into level 0, so it is now a reasonable choice to use.

Add support for level 0.

[1] https://www.openssl.org/docs/man3.2/man3/SSL_CTX_set_security_level.html
2024-03-19 15:02:07 +07:00
Nanang Izzuddin a974061441
Update listener restart in IP change: don't create/restart listener if currently no listener, also update docs that bound address setting will be reset. (#3873) 2024-03-15 09:41:16 +07:00
Andreas Wehrmann ed40439b0d
add missing unlock (#3885) 2024-03-15 10:01:08 +08:00
Fil 70332e3510
Rephrase some type definitions in the docs for a better understanding (#3880) 2024-03-12 10:28:42 +08:00
sauwming c36802585d
Fixed ioqueue backend selection configure script (#3878) 2024-03-06 13:27:37 +08:00
Nanang Izzuddin 7d2248f38a
Add checks in restarting listeners in IP change scenario (#3872) 2024-03-06 12:21:34 +07:00
sauwming 9e6a63e42f
Modified DTLS cert signature algorithm used (#3876) 2024-03-05 12:46:57 +08:00
sauwming 5ef8463d56
Video CI test on iOS device (#3868) 2024-02-27 13:01:06 +08:00
sauwming 2d6a9d4442
Check the availability of Metal device (#3871) 2024-02-27 12:54:00 +08:00
Goodicus b0be1706ea
Add an option to disable Message Composition Indication feature (MCI) (#3866) 2024-02-22 14:01:25 +08:00
Akos Denke 7178ab01a8
Add extra logging for dummy resample imp (#3863) 2024-02-21 16:32:16 +08:00
Jannis Muething fc3b03c937
Secure random number generator for SRTP key when using PJ_SSL_SOCK_IMP_APPLE (#3860) 2024-02-15 11:25:16 +08:00
Nanang Izzuddin beb06a57ca
Fix bad mem access in cancelling a timer, move _timer_id validation earlier. (#3854) 2024-02-07 15:28:32 +07:00
sauwming f33d5fc555
Activate Bitrise iOS build test (#3845) 2024-01-31 11:14:51 +08:00
sauwming a32d7c2907
Prevent data race in PJSIP presence (#3847) 2024-01-31 09:09:51 +08:00
sauwming 776c70ef01
Fixed missing unlocks in dialog event (#3849) 2024-01-30 17:29:51 +08:00
sauwming 0de8fef515
Fixed SWIG Python build failure on Mac (#3848) 2024-01-30 17:29:25 +08:00
sauwming e12a8d17a0
Fixed dialog event Coverity warnings (#3846) 2024-01-30 13:01:25 +08:00
Goodicus d692a9940f
Implement Dialog Event subscription (client only) (#3754) 2024-01-29 14:28:15 +08:00
sauwming b3ea8a29ac
Add Metal renderer for Mac and iOS (#3841) 2024-01-29 09:28:10 +08:00
Nanang Izzuddin e2b7d73ef5
Update SECURITY.md (#3840) 2024-01-24 10:34:25 +07:00
dependabot[bot] ce8d20cadf
Bump shlex from 1.1.0 to 1.3.0 in /pjsip-apps/src/rust/demo (#3839) 2024-01-23 14:55:36 +08:00
Nanang Izzuddin 569aac1b1c
Potential issues when IPv6 is disabled (#3835) 2024-01-23 12:52:53 +07:00
sauwming 712b06407f
Fixed thread leak in Mac OS (#3838) 2024-01-23 09:33:44 +08:00
sauwming d762276861
Fixed deprecation warnings on Mac and iOS (#3837) 2024-01-22 16:26:23 +08:00
Amilcar Ubiera 53d96cd5b8
pjsua_handle_ip_change: Added missing null check for on_ip_changed_progress callback (#3830) 2024-01-17 14:19:30 +07:00
sauwming 98d51a0e58
Fixed account's route set update when modifying account (#3825) 2024-01-16 10:12:09 +08:00
Riza Sulistyo b6cc71ad19
Retransmit 2xx response when transport is closed (#3828) 2024-01-15 08:57:46 +07:00
sauwming f2055ef7a3
Fixed issues when adding new media and deinitializing media (#3821) 2024-01-12 15:26:29 +08:00
sauwming 19c018affd
Fixed Service-Route update upon registration (#3823) 2024-01-10 16:55:23 +08:00
Brad Smith 26bdf998f0
Adjust code to support LibreSSL without the ASN1 macros (#3822) 2024-01-09 11:48:33 +08:00
sauwming ca0c4403ec
Fixed TURN session use after free (#3814) 2024-01-05 15:09:19 +08:00
sauwming 3ed76a11c0
Fixed data races in UPnP (#3819) 2024-01-05 15:08:59 +08:00
sauwming 86e22f4329
Enable PendingJob use on Python (#3817) 2024-01-03 19:05:46 +08:00
sauwming c6fd43208d
Fixed bug in pjsua_call_answer() (#3818) 2024-01-03 13:26:43 +08:00
Riza Sulistyo 4dfbdf7b1f
Terminate client transaction upon transport error (#3806)
* Terminate client transaction upon transport error
* Fixed UAS tsx tp error handling and PJSIP test
2024-01-02 15:57:45 +08:00
Florian Xaver 71e7087836
Fix answering a re-INVITE (#3770) 2024-01-02 13:33:16 +08:00
Nanang Izzuddin a31d048ecb
Fix parsing IPv6 TURN server in PJSUA (#3796) 2024-01-02 11:54:21 +08:00
Nanang Izzuddin 8e9857a81e
Miscelaneous Coverity fixes (#3792)
* Fix CID: 1527652, 1524421, 1524414, 1524392
* Fixed UPnP data races
2024-01-02 11:53:57 +08:00
Riza Sulistyo b981b45183
Fix return value for pjsua_set_snd_dev2() with no sound device option (#3809)
* Fix return value for pjsua_set_snd_dev2() with no sound device option

* Move initialization

* modification based on comments
2023-12-28 12:20:38 +07:00
sauwming 42a3e78d75
Fixed deprecation of Account.findBuddy() in pygui sample app (#3815) 2023-12-27 19:31:36 +08:00
sauwming 033e4d7ae3
Fixed printf format warnings (#3813) 2023-12-27 10:32:32 +08:00
sauwming 5601a20c1e
Fixed CI build failure due to Python setup (#3811) 2023-12-26 14:37:53 +08:00
sauwming ca2e450edf
Prevent immediate tsx termination upon transport error (#3805) 2023-12-18 11:56:43 +08:00
Gregor Jasny 48f3723d71
build: use C++ compiler for linking (#3766) 2023-12-15 22:12:32 +08:00
sauwming 043926a584
Fixed SDP media transport protocol info parsing (#3802) 2023-12-14 12:22:14 +08:00
sauwming 378e97ca10
Fixed deadlock between stream and ICE (#3801) 2023-12-14 12:15:58 +08:00
Brad Smith 4140143493
Switch LibreSSL code path to utilizing OpenSSL 1.1 API (#3758) 2023-12-12 12:50:56 +08:00
Olle Axelsson 5229ce2473
Use of uninitialized values (#3794) 2023-12-12 10:08:25 +08:00
Santiago De la Cruz 648aa3c3f0
pjsua: fix deadlock setting null sound device (#3799) 2023-12-11 17:08:57 +08:00
Riza Sulistyo 78b73c977d
Fix inaccurate TX packet loss percentage and stats calculation in samples (#3791) 2023-11-29 17:37:32 +07:00
Nanang Izzuddin 04f81212a3
Reset stored remote name in dialog (dlg->initial_dest) if transport is server. (#3783) 2023-11-24 14:46:31 +07:00
Florian Xaver f9ed97b87d
Fix transport loop (#3773)
Transport "loop" need set the `base.grp_lock`, as also shown in
`transport_adapter_sample.c` to have destroying of the loop transport
working.

Issue #3771
2023-11-24 09:08:35 +07:00
Ihor Olkhovskyi 9287ac21e6
add PJSUA_DETECT_MERGED_REQUEST parameter (#3784) 2023-11-22 15:22:48 +08:00
Nanang Izzuddin e235868cef
Add option to shutdown all transports on IP change (#3781) 2023-11-21 09:23:31 +07:00
silentindark 6157218806
Fix warnings (#3782) 2023-11-20 12:38:55 +08:00
silentindark c224f26420
Fix warnings (#3778) 2023-11-16 15:30:03 +08:00
jimying 5188d056a7
base64: support encode/decode with URL and Filename Safe Alphabet (#3748) 2023-11-16 13:52:06 +07:00
sauwming ca5255795a
Add SIP transport data received callback (#3751) 2023-11-06 20:17:49 +08:00
Brad Smith da91020a44
sdp.c: don't pass NULL pointer to log string format (#3757) 2023-11-03 19:15:07 +08:00
Gregor Jasny cf4f2d84dc
Hide private symbols (#3756) 2023-11-03 12:14:36 +08:00
sauwming 58a101c945
Fixed race condition in ACK handling of INVITE message (#3752) 2023-11-03 11:55:21 +08:00
sauwming 528f90adfb
Check for buffer EOF in scanner (#3753) 2023-11-03 11:40:51 +08:00
Riza Sulistyo b3e5f76788 Changed version to 2.14-dev 2023-11-01 16:45:39 +07:00
155 changed files with 8362 additions and 953 deletions

View File

@ -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

View File

@ -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

View File

@ -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-----
```

View File

@ -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"

View File

@ -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"

View File

@ -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@

View File

@ -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

View File

@ -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);
/**

View File

@ -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);

View File

@ -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);
}

View File

@ -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

View File

@ -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);
}
}

View File

@ -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;
}

View File

@ -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);

View File

@ -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>

View File

@ -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:

View File

@ -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

View File

@ -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)) {

View File

@ -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;

View File

@ -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.
*

View File

@ -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()."));

View File

@ -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;

View File

@ -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.

View File

@ -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;
};

View File

@ -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);

View File

@ -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, &param) == 0) {
CFRunLoopRun();
pthread_join(thread, NULL);
}
PJ_UNUSED_ARG(pool);

View File

@ -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));

View File

@ -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)));
}
}

View File

@ -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";

View File

@ -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_;

View File

@ -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);

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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;
}

View File

@ -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;
}
}

View File

@ -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(&param);
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(&param.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, &param, &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(&param);
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(&param.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, &param, &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(&param);
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(&param.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, &param, &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(&param);
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(&param.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, &param, &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"));

View File

@ -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);

View File

@ -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
#

View File

@ -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.
*/

View File

@ -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);

View File

@ -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,

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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"

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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(&param->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,
&param->window_hide);
}
if (param->flags & PJMEDIA_VID_DEV_CAP_ORIENTATION) {
metal_stream_set_cap(&strm->base, PJMEDIA_VID_DEV_CAP_ORIENTATION,
&param->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 */

View File

@ -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

View File

@ -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))

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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) {

View File

@ -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

View File

@ -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);

View File

@ -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;

View File

@ -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"));

View File

@ -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));

View File

@ -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);
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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;

View File

@ -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;

View File

@ -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,

View File

@ -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 */

View File

@ -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;
}

View File

@ -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;

View File

@ -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);
}

View File

@ -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.

View File

@ -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;
}

View File

@ -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,

View File

@ -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 */;

View File

@ -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

View File

@ -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
}

View File

@ -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)
}

View File

@ -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>

View File

@ -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(&param);
param.med_idx = 1;
pjsua_call_set_vid_strm(call_id,
PJSUA_CALL_VID_STRM_START_TRANSMIT,
&param);
}
}
}
break;

View File

@ -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 its 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()
}
}
}
*/
}

View File

@ -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)
}
*/
}

View File

@ -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;
};

View File

@ -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>

View File

@ -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>

View File

@ -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

View File

@ -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(&param);
pjsua_handle_ip_change(&param);
} 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(&param);
pjsua_handle_ip_change(&param);
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

View File

@ -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 */

View File

@ -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;
}

View File

@ -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;

View File

@ -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);

View File

@ -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_, &current_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(&param);
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;

View File

@ -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 */,

View File

@ -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()

View File

@ -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"

View File

@ -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);
}

View File

@ -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);

View File

@ -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,

View File

@ -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