├── .circleci
└── config.yml
├── .gitmodules
├── .travis.yml
├── LICENSE
├── README.md
├── astyle
└── astylerc
└── toxcam
├── avatar.png
├── loop_services.sh
├── loop_tor_services.sh
├── scripts
├── get_cpu_temp.sh
├── get_gpu_temp.sh
├── linux
│ ├── get_cpu_temp.sh
│ └── get_gpu_temp.sh
├── raspi
│ ├── get_cpu_temp.sh
│ └── get_gpu_temp.sh
├── set_os_dir.sh
└── single_shot.sh
├── toxcam.c
└── update_from_ci.sh
/.circleci/config.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | jobs:
3 | build:
4 | working_directory: /home/ubuntu
5 | docker:
6 | - image: ubuntu:16.04
7 | environment:
8 | - MAKEFLAGS: ""
9 | - CIRCLE_ARTIFACTS: "/tmp/artifacts"
10 | - WRKDIR: "/home/ubuntu"
11 | ## ----------- RASPI cross compile ----------------
12 | - RASPI_PATH: "/home/ubuntu/cc/tools/arm-bcm2708/arm-rpi-4.9.3-linux-gnueabihf/bin:$PATH"
13 | - RASPI_SYSROOT_: "/home/ubuntu/cc/tools/arm-bcm2708/arm-rpi-4.9.3-linux-gnueabihf/arm-linux-gnueabihf/sysroot"
14 | - RASPI_TOOL_PREFIX: arm-linux-gnueabihf
15 | - RASPI_INSTALL_DEST: "/home/ubuntu/installdest/"
16 | - RASPI_TARGET_: arm-linux-gnueabi
17 | - RASPI_HOST_: arm-linux-gnueabi
18 | - RASPI_CXX: $RASPI_TOOL_PREFIX-g++
19 | - RASPI_AR: $RASPI_TOOL_PREFIX-ar
20 | - RASPI_RANLIB: $RASPI_TOOL_PREFIX-ranlib
21 | - RASPI_CC: $RASPI_TOOL_PREFIX-gcc
22 | - RASPI_LD: $RASPI_TOOL_PREFIX-ld
23 | - RASPI_PKG_CONFIG_PATH: "/home/ubuntu/cc/tools/arm-bcm2708/arm-rpi-4.9.3-linux-gnueabihf/arm-linux-gnueabihf/sysroot/usr/lib/pkgconfig"
24 | - RASPI_s_: "/home/ubuntu/src/"
25 | - RASPI_PKGSDIR: "/home/ubuntu/pkgs/"
26 | - CF2: " -O3 -g -fPIC -marm -march=armv8-a+crc -mtune=cortex-a53 -mfpu=neon-fp-armv8 -mfloat-abi=hard -ftree-vectorize "
27 | - CF3: " -funsafe-math-optimizations "
28 | # c-toxcore version used
29 | - CTOXCORE_VERSION_HASH: "zoff99/toxcore_v1.0.10__toxav_h264_001"
30 | # c-toxcore repo used
31 | # CTOXCORE_URL: "https://github.com/TokTok/c-toxcore"
32 | - CTOXCORE_URL: "https://github.com/zoff99/c-toxcore_team"
33 | - LIBSODIUM_VERSION: "tags/1.0.16"
34 | - LIBSODIUM_BRANCH: "1.0.16"
35 | - RASPBERRRY_TOOLS_HASH: d820ab9c21969013b4e56c7e9cba25518afcdd44
36 |
37 | steps:
38 | # ubuntu removed "sudo" from minimal docker image starting with 16.0.4 :-(
39 | - run: apt-get update && apt-get install -y sudo lsb-release && rm -rf /var/lib/apt/lists/*
40 | - run: sudo apt update
41 | # to make circleCI tools work properly ---
42 | - run: sudo apt -qq install -y git ssh tar gzip ca-certificates
43 | # to make circleCI tools work properly ---
44 | - checkout
45 | - run: uname -a;pwd;df -h;id -a;lsb_release --all
46 | - run:
47 | command: |
48 | sudo DEBIAN_FRONTEND=noninteractive apt-get -qq install -y cmake
49 | sudo DEBIAN_FRONTEND=noninteractive apt-get -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" -qq install -y libtool autotools-dev automake checkinstall check git yasm libv4lconvert0 libv4l-dev
50 | sudo DEBIAN_FRONTEND=noninteractive apt-get -qq install -y libopus-dev libvpx-dev pkg-config
51 | sudo DEBIAN_FRONTEND=noninteractive apt-get -qq install -y libasound2-dev
52 | sudo DEBIAN_FRONTEND=noninteractive apt-get -qq install -y linux-generic
53 | sudo DEBIAN_FRONTEND=noninteractive apt-get -qq install -y libjpeg-dev
54 | sudo DEBIAN_FRONTEND=noninteractive apt-get -qq install -y libpulse-dev
55 | sudo DEBIAN_FRONTEND=noninteractive apt-get -qq install -y libconfig-dev
56 | sudo DEBIAN_FRONTEND=noninteractive apt-get -qq install -y astyle gawk sed bc
57 | sudo bash -c "echo '::1 localhost ipv6-localhost ipv6-loopback' >> /etc/hosts"
58 | gcc --version
59 | astyle --version
60 | cmake --version
61 |
62 | - run:
63 | command: |
64 | mkdir -p "$CIRCLE_ARTIFACTS"
65 | echo aaa > "$CIRCLE_ARTIFACTS"/blub.txt
66 | ls -al "$CIRCLE_ARTIFACTS"/blub.txt
67 |
68 | - run:
69 | command: |
70 | ### ------- compile and install libsodium -------
71 | cd "$WRKDIR";rm -Rf libsodium
72 | cd "$WRKDIR";git clone --depth=1 --branch="$LIBSODIUM_BRANCH" https://github.com/jedisct1/libsodium.git ./libsodium
73 | cd "$WRKDIR";cd libsodium/ ; ./autogen.sh
74 | cd "$WRKDIR";cd libsodium/ ; ./configure && make check
75 | cd "$WRKDIR";cd libsodium/ ; sudo bash -c "printf 'y\naa\n\n' | checkinstall --install --pkgname libsodium --pkgversion 1.0.0 --nodoc --deldesc=no --pkglicense='GPL2'"
76 | cd "$WRKDIR";cd libsodium/ ; sudo ldconfig
77 | cd "$WRKDIR";cd libsodium ; sudo ldconfig -v 2>/dev/null | grep sodium
78 | ## --- now again to save the artefact ---
79 | cd "$WRKDIR";cd libsodium ; export INSTALL_DEST=/home/ubuntu/installdest_linux/ ; rm -Rf "$INSTALL_DEST"
80 | cd "$WRKDIR";cd libsodium ; export INSTALL_DEST=/home/ubuntu/installdest_linux/ ; mkdir -p "$INSTALL_DEST"/usr ; ./configure --prefix="$INSTALL_DEST"/usr
81 | cd "$WRKDIR";cd libsodium ; export INSTALL_DEST=/home/ubuntu/installdest_linux/ ; make install ; ls -alR "$INSTALL_DEST"/usr
82 | cd "$WRKDIR";mkdir -p $CIRCLE_ARTIFACTS/ubuntu_14_04_binaries
83 | cd "$WRKDIR";export INSTALL_DEST=/home/ubuntu/installdest_linux/ ; cd "$INSTALL_DEST" ; tar -czvf $CIRCLE_ARTIFACTS/ubuntu_14_04_binaries/pkg_libsodium.tar.gz *
84 | ## --- now again to save the artefact ---
85 | ### ------- compile and install libsodium -------
86 |
87 | - run:
88 | command: |
89 | ### ------------ compile and install nasm ------------
90 | cd "$WRKDIR";rm -Rf nasm
91 | cd "$WRKDIR";git clone http://repo.or.cz/nasm.git
92 | cd "$WRKDIR";cd nasm;git checkout nasm-2.13.03
93 | cd "$WRKDIR";cd nasm;./autogen.sh
94 | cd "$WRKDIR";cd nasm;./configure --prefix=/home/ubuntu/installdest_linux/usr
95 | cd "$WRKDIR";cd nasm;make clean
96 | cd "$WRKDIR";cd nasm;make -j4
97 | cd "$WRKDIR";cd nasm;touch nasm.1
98 | cd "$WRKDIR";cd nasm;touch ndisasm.1
99 | cd "$WRKDIR";cd nasm;make install
100 | ### ------------ compile and install nasm ------------
101 |
102 |
103 | - run:
104 | command: |
105 | ### ------------ compile and install x264 ------------
106 | cd "$WRKDIR";git clone git://git.videolan.org/x264.git
107 | cd "$WRKDIR";cd x264
108 | cd "$WRKDIR";cd x264;git checkout stable
109 | export PATH=/home/ubuntu/installdest_linux/usr/bin:/home/ubuntu/installdest_linux/bin:$PATH
110 | cd "$WRKDIR";cd x264;./configure --prefix=/home/ubuntu/installdest_linux/usr --disable-opencl --enable-shared --enable-static --disable-avs --disable-cli
111 | cd "$WRKDIR";cd x264;make clean
112 | cd "$WRKDIR";cd x264;make -j4
113 | cd "$WRKDIR";cd x264;make install
114 | ### ------------ compile and install x264 ------------
115 |
116 | - run:
117 | command: |
118 | ### ------------ compile and install libav ------------
119 | cd "$WRKDIR";git clone https://github.com/libav/libav
120 | cd "$WRKDIR";cd libav
121 | cd "$WRKDIR";cd libav;git checkout v12.3
122 | cd "$WRKDIR";cd libav;./configure --prefix=/home/ubuntu/installdest_linux/usr --disable-devices --disable-programs \
123 | --disable-doc --disable-avdevice --disable-avformat \
124 | --disable-swscale \
125 | --disable-avfilter --disable-network --disable-everything \
126 | --disable-bzlib \
127 | --disable-libxcb-shm \
128 | --disable-libxcb-xfixes \
129 | --enable-parser=h264 \
130 | --enable-runtime-cpudetect \
131 | --enable-decoder=h264_vdpau \
132 | --enable-vdpau \
133 | --enable-gpl --enable-decoder=h264
134 | cd "$WRKDIR";cd libav;make clean
135 | cd "$WRKDIR";cd libav;make -j4
136 | cd "$WRKDIR";cd libav;make install
137 | ### ------------ compile and install libav ------------
138 |
139 |
140 | - run:
141 | command: |
142 | ### ------------ compile and install c-toxcore ------------
143 | cd "$WRKDIR";rm -Rf c-toxcore
144 | cd "$WRKDIR";git clone https://github.com/zoff99/c-toxcore_team ./c-toxcore
145 | export PKG_CONFIG_PATH=/home/ubuntu/installdest_linux/usr/lib/pkgconfig
146 | cd "$WRKDIR";cd c-toxcore ; git checkout zoff99/toxcore_v1.0.10__toxav_h264_001
147 | cd "$WRKDIR";cd c-toxcore ; export CFLAGS=" -D_GNU_SOURCE -I/home/ubuntu/installdest_linux/usr/include/ -O3 -g -fstack-protector-all "
148 | cd "$WRKDIR";cd c-toxcore ; export LDFLAGS=-L/home/ubuntu/installdest_linux/usr/lib
149 | cd "$WRKDIR";cd c-toxcore ; ./autogen.sh
150 | cd "$WRKDIR";cd c-toxcore ; ./configure --prefix=/home/ubuntu/installdest_linux/usr/ --disable-soname-versions --disable-testing --disable-shared || cat config.log
151 | cd "$WRKDIR";cd c-toxcore ; make -j 4
152 | cd "$WRKDIR";cd c-toxcore ; make install
153 | ### ------------ compile and install c-toxcore ------------
154 |
155 | - run:
156 | command: |
157 | cd /home/ubuntu/installdest_linux/ ; find .
158 |
159 | - run:
160 | command: |
161 | set -x
162 | cd "$WRKDIR";cd toxcam ; rm -fv toxcam toxcam_static
163 | cd "$WRKDIR";cd toxcam ; gcc -O3 -fPIC -I/home/ubuntu/installdest_linux/usr/include/ -L/home/ubuntu/installdest_linux/usr/lib -o toxcam toxcam.c -std=gnu99 -lsodium -ltoxcore -ltoxav -lpthread -lvpx -lv4lconvert -lx264 -lavcodec -lavutil -lavresample -lm -lrt
164 | cd "$WRKDIR";cd toxcam ; ldd toxcam
165 | cd "$WRKDIR";cd toxcam ; gcc -g -O3 -Wall -Wextra -Wpedantic -L/home/ubuntu/installdest_linux/usr/lib -I/home/ubuntu/installdest_linux/usr/include/ -o toxcam_static toxcam.c -static -std=gnu99 -lsodium -ltoxcore -ltoxav -ltoxgroup -ltoxmessenger -ltoxfriends -ltoxnetcrypto -ltoxdht -ltoxnetwork -ltoxcrypto -lsodium -lpthread -static-libgcc -static-libstdc++ -lopus -lvpx -lm -lpthread -lv4lconvert -lx264 -lavcodec -lavutil -lavresample -ljpeg -lm -lrt
166 | cd "$WRKDIR";cd toxcam ; ls -al toxcam toxcam_static
167 | cd "$WRKDIR";mkdir -p $CIRCLE_ARTIFACTS/ubuntu_14_04_binaries/
168 | cd "$WRKDIR";cp -av toxcam/toxcam $CIRCLE_ARTIFACTS/ubuntu_14_04_binaries/
169 | cd "$WRKDIR";cp -av toxcam/toxcam_static $CIRCLE_ARTIFACTS/ubuntu_14_04_binaries/
170 |
171 | - run:
172 | command: |
173 | cd toxcam ; ./toxcam_static
174 | background: true
175 |
176 | - run:
177 | command: |
178 | cd "$WRKDIR";sleep 10
179 | cd "$WRKDIR";cd toxcam ; cat ./toxcam.log
180 | cd "$WRKDIR";cd toxcam ; cat ./toxcam.log | grep '\-\-MyToxID\-\-:' | cut -d':' -f 3
181 | cd "$WRKDIR";sleep 10
182 | #- sleep 240
183 | cd "$WRKDIR";cd toxcam ; cat ./toxcam.log
184 |
185 | # Save artifacts
186 | - store_artifacts:
187 | path: /tmp/artifacts
188 |
189 | workflows:
190 | version: 2
191 | build-deploy:
192 | jobs:
193 | - build
194 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "c-toxcore"]
2 | path = c-toxcore
3 | url = https://github.com/TokTok/c-toxcore
4 | [submodule "libsodium"]
5 | path = libsodium
6 | url = https://github.com/jedisct1/libsodium
7 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: c
2 | cache: false
3 | sudo: true
4 | dist: trusty
5 |
6 | addons:
7 | apt:
8 | sources:
9 | - avsm
10 | packages:
11 | - check
12 | - libcv-dev # For av_test.
13 | - libhighgui-dev # For av_test.
14 | - libopencv-contrib-dev # For av_test.
15 | - libsndfile1-dev # For av_test.
16 | - libvpx-dev
17 | - opam # For apidsl and Frama-C.
18 | - portaudio19-dev # For av_test.
19 | - texinfo # For libconfig.
20 |
21 | script:
22 | - sudo apt-get update
23 | - sudo apt-get install cmake
24 | - aptitude search 4l|grep -i convert ; echo exit 0
25 | - aptitude search 4l|grep -i v4l ; echo exit 0
26 | - sudo apt-get install build-essential libtool autotools-dev automake checkinstall check git yasm
27 | - sudo apt-get install libv4lconvert0
28 | - sudo apt-get install libv4l-dev
29 | - sudo apt-get install libjpeg-dev
30 | - sudo apt-get install libvpx-dev
31 | - sudo apt-get install pkg-config
32 | - sudo apt-get install linux-generic
33 | - sudo bash -c "echo '::1 localhost ipv6-localhost ipv6-loopback' >> /etc/hosts" # ipv6 localhost entry
34 |
35 | - gcc --version ; echo exit 0
36 | - clang --version ; echo exit 0
37 |
38 | ### submodules ----------------
39 | - git submodule add --force https://github.com/TokTok/c-toxcore c-toxcore ; echo ok
40 | - git submodule add --force https://github.com/jedisct1/libsodium libsodium ; echo ok
41 | - git submodule init ; git submodule update ; echo ok
42 | - cd c-toxcore/ ; git checkout a096c71db867ac83fc3e01e0fbe98573d20f9286
43 | - cd ..
44 | - cd libsodium/ ; git checkout tags/1.0.11
45 | - cd ..
46 | ### submodules ----------------
47 |
48 | ### ------- compile and install libsodium -------
49 | - cd libsodium/ ; ./autogen.sh
50 | - ./configure && make check
51 | - sudo bash -c "printf 'y\naa\n\n' | checkinstall --install --pkgname libsodium --pkgversion 1.0.11 --nodoc --deldesc=no --pkglicense='GPL2'"
52 | - sudo ldconfig
53 | - sudo ldconfig -v 2>/dev/null | grep sodium
54 | - cd ..
55 | ### ------- compile and install libsodium -------
56 |
57 | ### ------- compile and install libopus -------
58 | - wget http://downloads.xiph.org/releases/opus/opus-1.1.3.tar.gz -O opus.tgz
59 | - tar -xzvf opus.tgz
60 | - rm opus.tgz
61 | - ls -al
62 | - mv -v opus* libopus
63 | - cd libopus/ # autogen ?
64 | - ./configure && make check
65 | - sudo bash -c "printf 'y\naa\n\n' | checkinstall --install --pkgname libopus --pkgversion 1.1.3 --nodoc --deldesc=no --pkglicense='GPL2'"
66 | - sudo ldconfig
67 | - sudo ldconfig -v 2>/dev/null | grep opus
68 | - cd ..
69 | ### ------- compile and install libopus -------
70 |
71 | ### ------------ compile and install c-toxcore ------------
72 | - cd c-toxcore ; cmake -DWARNINGS=OFF .
73 | - make
74 | #- sudo make install
75 | - sudo bash -c "printf 'y\naa\n\n' | checkinstall --install --pkgname toxcore --pkgversion 0.1.2 --nodoc --deldesc=no --pkglicense='GPL2'"
76 | - sudo ldconfig -v 2>/dev/null | grep toxcore
77 | ### ------------ run tests
78 | #- make test ARGS="-V" ; ex1=$? ; if [ $ex1 -ne 0 ]; then sleep 60; make test ARGS="-V" ; exit $? ; fi
79 | - cd ..
80 | ### ------------ compile and install c-toxcore ------------
81 |
82 | - cd toxcam ; gcc -O2 -fPIC -Wall -Wextra -o toxcam toxcam.c -std=gnu99 -lsodium -I/usr/local/include/ -ltoxcore -ltoxav -lpthread -lvpx -lv4lconvert
83 | - ldd toxcam ; echo exit 0
84 | - find / -name '*libjpeg*' 2> /dev/null ; echo exit 0
85 | - gcc -O2 -Wall -Wextra -o toxcam_static toxcam.c -static -std=gnu99 -L/usr/local/lib -I/usr/local/include/ -lsodium -ltoxcore -ltoxav -ltoxgroup -ltoxmessenger -ltoxfriends -ltoxnetcrypto -ltoxdht -ltoxnetwork -ltoxcrypto -lsodium -lpthread -static-libgcc -static-libstdc++ -lopus -lvpx -lm -lpthread -lv4lconvert -ljpeg -lm -lrt
86 | - ls -al toxcam toxcam_static
87 |
88 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU GENERAL PUBLIC LICENSE
2 | Version 2, June 1991
3 |
4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
6 | Everyone is permitted to copy and distribute verbatim copies
7 | of this license document, but changing it is not allowed.
8 |
9 | Preamble
10 |
11 | The licenses for most software are designed to take away your
12 | freedom to share and change it. By contrast, the GNU General Public
13 | License is intended to guarantee your freedom to share and change free
14 | software--to make sure the software is free for all its users. This
15 | General Public License applies to most of the Free Software
16 | Foundation's software and to any other program whose authors commit to
17 | using it. (Some other Free Software Foundation software is covered by
18 | the GNU Lesser General Public License instead.) You can apply it to
19 | your programs, too.
20 |
21 | When we speak of free software, we are referring to freedom, not
22 | price. Our General Public Licenses are designed to make sure that you
23 | have the freedom to distribute copies of free software (and charge for
24 | this service if you wish), that you receive source code or can get it
25 | if you want it, that you can change the software or use pieces of it
26 | in new free programs; and that you know you can do these things.
27 |
28 | To protect your rights, we need to make restrictions that forbid
29 | anyone to deny you these rights or to ask you to surrender the rights.
30 | These restrictions translate to certain responsibilities for you if you
31 | distribute copies of the software, or if you modify it.
32 |
33 | For example, if you distribute copies of such a program, whether
34 | gratis or for a fee, you must give the recipients all the rights that
35 | you have. You must make sure that they, too, receive or can get the
36 | source code. And you must show them these terms so they know their
37 | rights.
38 |
39 | We protect your rights with two steps: (1) copyright the software, and
40 | (2) offer you this license which gives you legal permission to copy,
41 | distribute and/or modify the software.
42 |
43 | Also, for each author's protection and ours, we want to make certain
44 | that everyone understands that there is no warranty for this free
45 | software. If the software is modified by someone else and passed on, we
46 | want its recipients to know that what they have is not the original, so
47 | that any problems introduced by others will not reflect on the original
48 | authors' reputations.
49 |
50 | Finally, any free program is threatened constantly by software
51 | patents. We wish to avoid the danger that redistributors of a free
52 | program will individually obtain patent licenses, in effect making the
53 | program proprietary. To prevent this, we have made it clear that any
54 | patent must be licensed for everyone's free use or not licensed at all.
55 |
56 | The precise terms and conditions for copying, distribution and
57 | modification follow.
58 |
59 | GNU GENERAL PUBLIC LICENSE
60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
61 |
62 | 0. This License applies to any program or other work which contains
63 | a notice placed by the copyright holder saying it may be distributed
64 | under the terms of this General Public License. The "Program", below,
65 | refers to any such program or work, and a "work based on the Program"
66 | means either the Program or any derivative work under copyright law:
67 | that is to say, a work containing the Program or a portion of it,
68 | either verbatim or with modifications and/or translated into another
69 | language. (Hereinafter, translation is included without limitation in
70 | the term "modification".) Each licensee is addressed as "you".
71 |
72 | Activities other than copying, distribution and modification are not
73 | covered by this License; they are outside its scope. The act of
74 | running the Program is not restricted, and the output from the Program
75 | is covered only if its contents constitute a work based on the
76 | Program (independent of having been made by running the Program).
77 | Whether that is true depends on what the Program does.
78 |
79 | 1. You may copy and distribute verbatim copies of the Program's
80 | source code as you receive it, in any medium, provided that you
81 | conspicuously and appropriately publish on each copy an appropriate
82 | copyright notice and disclaimer of warranty; keep intact all the
83 | notices that refer to this License and to the absence of any warranty;
84 | and give any other recipients of the Program a copy of this License
85 | along with the Program.
86 |
87 | You may charge a fee for the physical act of transferring a copy, and
88 | you may at your option offer warranty protection in exchange for a fee.
89 |
90 | 2. You may modify your copy or copies of the Program or any portion
91 | of it, thus forming a work based on the Program, and copy and
92 | distribute such modifications or work under the terms of Section 1
93 | above, provided that you also meet all of these conditions:
94 |
95 | a) You must cause the modified files to carry prominent notices
96 | stating that you changed the files and the date of any change.
97 |
98 | b) You must cause any work that you distribute or publish, that in
99 | whole or in part contains or is derived from the Program or any
100 | part thereof, to be licensed as a whole at no charge to all third
101 | parties under the terms of this License.
102 |
103 | c) If the modified program normally reads commands interactively
104 | when run, you must cause it, when started running for such
105 | interactive use in the most ordinary way, to print or display an
106 | announcement including an appropriate copyright notice and a
107 | notice that there is no warranty (or else, saying that you provide
108 | a warranty) and that users may redistribute the program under
109 | these conditions, and telling the user how to view a copy of this
110 | License. (Exception: if the Program itself is interactive but
111 | does not normally print such an announcement, your work based on
112 | the Program is not required to print an announcement.)
113 |
114 | These requirements apply to the modified work as a whole. If
115 | identifiable sections of that work are not derived from the Program,
116 | and can be reasonably considered independent and separate works in
117 | themselves, then this License, and its terms, do not apply to those
118 | sections when you distribute them as separate works. But when you
119 | distribute the same sections as part of a whole which is a work based
120 | on the Program, the distribution of the whole must be on the terms of
121 | this License, whose permissions for other licensees extend to the
122 | entire whole, and thus to each and every part regardless of who wrote it.
123 |
124 | Thus, it is not the intent of this section to claim rights or contest
125 | your rights to work written entirely by you; rather, the intent is to
126 | exercise the right to control the distribution of derivative or
127 | collective works based on the Program.
128 |
129 | In addition, mere aggregation of another work not based on the Program
130 | with the Program (or with a work based on the Program) on a volume of
131 | a storage or distribution medium does not bring the other work under
132 | the scope of this License.
133 |
134 | 3. You may copy and distribute the Program (or a work based on it,
135 | under Section 2) in object code or executable form under the terms of
136 | Sections 1 and 2 above provided that you also do one of the following:
137 |
138 | a) Accompany it with the complete corresponding machine-readable
139 | source code, which must be distributed under the terms of Sections
140 | 1 and 2 above on a medium customarily used for software interchange; or,
141 |
142 | b) Accompany it with a written offer, valid for at least three
143 | years, to give any third party, for a charge no more than your
144 | cost of physically performing source distribution, a complete
145 | machine-readable copy of the corresponding source code, to be
146 | distributed under the terms of Sections 1 and 2 above on a medium
147 | customarily used for software interchange; or,
148 |
149 | c) Accompany it with the information you received as to the offer
150 | to distribute corresponding source code. (This alternative is
151 | allowed only for noncommercial distribution and only if you
152 | received the program in object code or executable form with such
153 | an offer, in accord with Subsection b above.)
154 |
155 | The source code for a work means the preferred form of the work for
156 | making modifications to it. For an executable work, complete source
157 | code means all the source code for all modules it contains, plus any
158 | associated interface definition files, plus the scripts used to
159 | control compilation and installation of the executable. However, as a
160 | special exception, the source code distributed need not include
161 | anything that is normally distributed (in either source or binary
162 | form) with the major components (compiler, kernel, and so on) of the
163 | operating system on which the executable runs, unless that component
164 | itself accompanies the executable.
165 |
166 | If distribution of executable or object code is made by offering
167 | access to copy from a designated place, then offering equivalent
168 | access to copy the source code from the same place counts as
169 | distribution of the source code, even though third parties are not
170 | compelled to copy the source along with the object code.
171 |
172 | 4. You may not copy, modify, sublicense, or distribute the Program
173 | except as expressly provided under this License. Any attempt
174 | otherwise to copy, modify, sublicense or distribute the Program is
175 | void, and will automatically terminate your rights under this License.
176 | However, parties who have received copies, or rights, from you under
177 | this License will not have their licenses terminated so long as such
178 | parties remain in full compliance.
179 |
180 | 5. You are not required to accept this License, since you have not
181 | signed it. However, nothing else grants you permission to modify or
182 | distribute the Program or its derivative works. These actions are
183 | prohibited by law if you do not accept this License. Therefore, by
184 | modifying or distributing the Program (or any work based on the
185 | Program), you indicate your acceptance of this License to do so, and
186 | all its terms and conditions for copying, distributing or modifying
187 | the Program or works based on it.
188 |
189 | 6. Each time you redistribute the Program (or any work based on the
190 | Program), the recipient automatically receives a license from the
191 | original licensor to copy, distribute or modify the Program subject to
192 | these terms and conditions. You may not impose any further
193 | restrictions on the recipients' exercise of the rights granted herein.
194 | You are not responsible for enforcing compliance by third parties to
195 | this License.
196 |
197 | 7. If, as a consequence of a court judgment or allegation of patent
198 | infringement or for any other reason (not limited to patent issues),
199 | conditions are imposed on you (whether by court order, agreement or
200 | otherwise) that contradict the conditions of this License, they do not
201 | excuse you from the conditions of this License. If you cannot
202 | distribute so as to satisfy simultaneously your obligations under this
203 | License and any other pertinent obligations, then as a consequence you
204 | may not distribute the Program at all. For example, if a patent
205 | license would not permit royalty-free redistribution of the Program by
206 | all those who receive copies directly or indirectly through you, then
207 | the only way you could satisfy both it and this License would be to
208 | refrain entirely from distribution of the Program.
209 |
210 | If any portion of this section is held invalid or unenforceable under
211 | any particular circumstance, the balance of the section is intended to
212 | apply and the section as a whole is intended to apply in other
213 | circumstances.
214 |
215 | It is not the purpose of this section to induce you to infringe any
216 | patents or other property right claims or to contest validity of any
217 | such claims; this section has the sole purpose of protecting the
218 | integrity of the free software distribution system, which is
219 | implemented by public license practices. Many people have made
220 | generous contributions to the wide range of software distributed
221 | through that system in reliance on consistent application of that
222 | system; it is up to the author/donor to decide if he or she is willing
223 | to distribute software through any other system and a licensee cannot
224 | impose that choice.
225 |
226 | This section is intended to make thoroughly clear what is believed to
227 | be a consequence of the rest of this License.
228 |
229 | 8. If the distribution and/or use of the Program is restricted in
230 | certain countries either by patents or by copyrighted interfaces, the
231 | original copyright holder who places the Program under this License
232 | may add an explicit geographical distribution limitation excluding
233 | those countries, so that distribution is permitted only in or among
234 | countries not thus excluded. In such case, this License incorporates
235 | the limitation as if written in the body of this License.
236 |
237 | 9. The Free Software Foundation may publish revised and/or new versions
238 | of the General Public License from time to time. Such new versions will
239 | be similar in spirit to the present version, but may differ in detail to
240 | address new problems or concerns.
241 |
242 | Each version is given a distinguishing version number. If the Program
243 | specifies a version number of this License which applies to it and "any
244 | later version", you have the option of following the terms and conditions
245 | either of that version or of any later version published by the Free
246 | Software Foundation. If the Program does not specify a version number of
247 | this License, you may choose any version ever published by the Free Software
248 | Foundation.
249 |
250 | 10. If you wish to incorporate parts of the Program into other free
251 | programs whose distribution conditions are different, write to the author
252 | to ask for permission. For software which is copyrighted by the Free
253 | Software Foundation, write to the Free Software Foundation; we sometimes
254 | make exceptions for this. Our decision will be guided by the two goals
255 | of preserving the free status of all derivatives of our free software and
256 | of promoting the sharing and reuse of software generally.
257 |
258 | NO WARRANTY
259 |
260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
268 | REPAIR OR CORRECTION.
269 |
270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
278 | POSSIBILITY OF SUCH DAMAGES.
279 |
280 | END OF TERMS AND CONDITIONS
281 |
282 | How to Apply These Terms to Your New Programs
283 |
284 | If you develop a new program, and you want it to be of the greatest
285 | possible use to the public, the best way to achieve this is to make it
286 | free software which everyone can redistribute and change under these terms.
287 |
288 | To do so, attach the following notices to the program. It is safest
289 | to attach them to the start of each source file to most effectively
290 | convey the exclusion of warranty; and each file should have at least
291 | the "copyright" line and a pointer to where the full notice is found.
292 |
293 | {description}
294 | Copyright (C) {year} {fullname}
295 |
296 | This program is free software; you can redistribute it and/or modify
297 | it under the terms of the GNU General Public License as published by
298 | the Free Software Foundation; either version 2 of the License, or
299 | (at your option) any later version.
300 |
301 | This program is distributed in the hope that it will be useful,
302 | but WITHOUT ANY WARRANTY; without even the implied warranty of
303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
304 | GNU General Public License for more details.
305 |
306 | You should have received a copy of the GNU General Public License along
307 | with this program; if not, write to the Free Software Foundation, Inc.,
308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
309 |
310 | Also add information on how to contact you by electronic and paper mail.
311 |
312 | If the program is interactive, make it output a short notice like this
313 | when it starts in an interactive mode:
314 |
315 | Gnomovision version 69, Copyright (C) year name of author
316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
317 | This is free software, and you are welcome to redistribute it
318 | under certain conditions; type `show c' for details.
319 |
320 | The hypothetical commands `show w' and `show c' should show the appropriate
321 | parts of the General Public License. Of course, the commands you use may
322 | be called something other than `show w' and `show c'; they could even be
323 | mouse-clicks or menu items--whatever suits your program.
324 |
325 | You should also get your employer (if you work as a programmer) or your
326 | school, if any, to sign a "copyright disclaimer" for the program, if
327 | necessary. Here is a sample; alter the names:
328 |
329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program
330 | `Gnomovision' (which makes passes at compilers) written by James Hacker.
331 |
332 | {signature of Ty Coon}, 1 April 1989
333 | Ty Coon, President of Vice
334 |
335 | This General Public License does not permit incorporating your program into
336 | proprietary programs. If your program is a subroutine library, you may
337 | consider it more useful to permit linking proprietary applications with the
338 | library. If this is what you want to do, use the GNU Lesser General
339 | Public License instead of this License.
340 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ToxCam
2 |
3 | You can take a PC or RaspberryPi with a camera on it and watch the
4 | camera stream from anywhere without a central server
5 |
6 | Build Status
7 | =
8 | **CircleCI:** [](https://circleci.com/gh/zoff99/ToxCam)
9 | **Travis:** [](https://travis-ci.org/zoff99/ToxCam)
10 |
11 |
12 | Development Snapshot Version (Linux)
13 | =
14 | the latest Development Snapshot can be downloaded from CircleCI, [here](https://circleci.com/api/v1/project/zoff99/ToxCam/latest/artifacts/0/$CIRCLE_ARTIFACTS/ubuntu_14_04_binaries/toxcam_static?filter=successful&branch=master)
15 |
16 | Development Snapshot Version (Raspberry PI)
17 | =
18 | the latest Development Snapshot can be downloaded from CircleCI, [here](https://circleci.com/api/v1/project/zoff99/ToxCam/latest/artifacts/0/$CIRCLE_ARTIFACTS/RASPI/toxcam_static?filter=successful&branch=master)
19 |
20 | install on PI
21 | =
22 |
23 | ```
24 | # as user pi:
25 | git clone https://github.com/zoff99/ToxCam
26 | cd ToxCam/toxcam
27 | chmod u+rwx loop_services.sh loop_tor_services.sh update_from_ci.sh scripts/*.sh
28 | ./update_from_ci.sh
29 | ```
30 | ```
31 | sudo apt-get install luvcview
32 | sudo sed -i -e "s#exit 0#su - pi bash -c '/home/pi/ToxCam/toxcam/loop_services.sh' > /dev/null 2>/dev/null \&\nexit 0#" /etc/rc.local
33 | ```
34 |
35 | then reboot
36 | now ToxCam should be active already. get the ToxID
37 |
38 | ```
39 | cat /home/pi/ToxCam/toxcam/toxcam.log|grep MyToxID|cut -d: -f3
40 | ```
41 |
42 | note down the ToxID of your ToxCam and add it as friend from another ToxClient.
43 |
44 |
45 | install on PI with Tor
46 | =
47 |
48 | ```
49 | # as user pi:
50 | git clone https://github.com/zoff99/ToxCam
51 | cd ToxCam/toxcam
52 | chmod u+rwx loop_services.sh loop_tor_services.sh update_from_ci.sh scripts/*.sh
53 | ./update_from_ci.sh
54 | ```
55 | ```
56 | sudo apt-get install luvcview
57 | sudo apt-get install tor tor-arm
58 | sudo sed -i -e "s#exit 0#su - pi bash -c '/home/pi/ToxCam/toxcam/loop_tor_services.sh' > /dev/null 2>/dev/null \&\nexit 0#" /etc/rc.local
59 | ```
60 |
61 | then reboot
62 | now ToxCam should be active already. get the ToxID
63 |
64 | ```
65 | cat /home/pi/ToxCam/toxcam/toxcam.log|grep MyToxID|cut -d: -f3
66 | ```
67 |
68 | note down the ToxID of your ToxCam and add it as friend from another ToxClient.
69 |
--------------------------------------------------------------------------------
/astyle/astylerc:
--------------------------------------------------------------------------------
1 | # Bracket Style Options
2 | --style=allman
3 |
4 | # Tab Options
5 | --indent=spaces=4
6 |
7 | # Indentation Options
8 | --indent-switches
9 | #--indent-preproc-block
10 |
11 | # Padding Options
12 | --pad-header
13 | --break-blocks
14 | --pad-oper
15 | --delete-empty-lines
16 | --unpad-paren
17 | --align-pointer=name
18 | --align-reference=name
19 |
20 | # Formatting Options
21 | --add-brackets
22 | --convert-tabs
23 | --max-code-length=120
24 |
25 | # Other Options
26 | --preserve-date
27 | --formatted
28 | --lineend=linux
29 |
--------------------------------------------------------------------------------
/toxcam/avatar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zoff99/ToxCam/a605bd5aa4ae7aa84178950b600822070fd93230/toxcam/avatar.png
--------------------------------------------------------------------------------
/toxcam/loop_services.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | cd $(dirname "$0")
4 |
5 | while [ 1 == 1 ]; do
6 | #####################################################
7 | # pick first available video device
8 | # change for your needs here!
9 | video_device=$(ls -1 /dev/video*|tail -1)
10 | #
11 | #####################################################
12 |
13 | v4l2-ctl -d "$video_device" -v width=1280,height=720,pixelformat=YV12
14 | # v4l2-ctl -d "$video_device" -v width=640,height=480,pixelformat=YV12
15 | v4l2-ctl -d "$video_device" -p 15
16 |
17 | prog="./toxcam"
18 | if [ -e ./toxcam_static ]; then
19 | prog="./toxcam_static"
20 | fi
21 | chmod u+x "$prog"
22 |
23 | "$prog" -f -2 -b 200 -q 60 -d "$video_device" > /dev/null 2> /dev/null
24 | sleep 10
25 | done
26 |
27 |
--------------------------------------------------------------------------------
/toxcam/loop_tor_services.sh:
--------------------------------------------------------------------------------
1 |
2 | #! /bin/bash
3 |
4 | #####################################################
5 | # pick first available video device
6 | # change for your needs here!
7 | video_device=$(ls -1 /dev/video*|tail -1)
8 | #
9 | #####################################################
10 |
11 | cd $(dirname "$0")
12 |
13 | while [ 1 == 1 ]; do
14 | ./toxcam_static -2 -T -d "$video_device" # > /dev/null 2> /dev/null
15 | sleep 10
16 | done
17 |
--------------------------------------------------------------------------------
/toxcam/scripts/get_cpu_temp.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | _dir=$(dirname "${0}")
4 | _scr=$(basename "$0")
5 | . "$_dir"/set_os_dir.sh
6 | . "$_dir"/"$_OS_DIR_"/"$_scr"
7 |
--------------------------------------------------------------------------------
/toxcam/scripts/get_gpu_temp.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | _dir=$(dirname "${0}")
4 | _scr=$(basename "$0")
5 | . "$_dir"/set_os_dir.sh
6 | . "$_dir"/"$_OS_DIR_"/"$_scr"
7 |
--------------------------------------------------------------------------------
/toxcam/scripts/linux/get_cpu_temp.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
--------------------------------------------------------------------------------
/toxcam/scripts/linux/get_gpu_temp.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
--------------------------------------------------------------------------------
/toxcam/scripts/raspi/get_cpu_temp.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | cpu1=$(
4 | * in 2017
5 | *
6 | * dirty hack (echobot and toxic were used as blueprint)
7 | *
8 | *
9 | * compile on linux (dynamic):
10 | * gcc -O2 -fPIC -Wall -Wextra -Wpedantic -o toxdoorspy toxdoorspy.c -std=gnu99 -lsodium -I/usr/local/include/ -ltoxcore -ltoxav -lpthread -lvpx -lv4lconvert
11 | * compile for debugging (dynamic):
12 | * gcc -O0 -g -fPIC -Wall -Wextra -Wpedantic -o toxdoorspy toxdoorspy.c -std=gnu99 -lsodium -I/usr/local/include/ -ltoxcore -ltoxav -lpthread -lvpx -lv4lconvert
13 | *
14 | * compile on linux (static):
15 | * gcc -O2 -Wall -Wextra -Wpedantic -o toxdoorspy_static toxdoorspy.c -static -std=gnu99 -L/usr/local/lib -I/usr/local/include/ \
16 | -lsodium -ltoxcore -ltoxav -ltoxgroup -ltoxmessenger -ltoxfriends -ltoxnetcrypto \
17 | -ltoxdht -ltoxnetwork -ltoxcrypto -lsodium -lpthread -static-libgcc -static-libstdc++ \
18 | -lopus -lvpx -lm -lpthread -lv4lconvert
19 | *
20 | *
21 | *
22 | */
23 |
24 | #define _GNU_SOURCE
25 |
26 |
27 | #include
28 | #include
29 | #include
30 | #include
31 | #include
32 | #include
33 | #include
34 | #include
35 |
36 | #include
37 | #include
38 | #include
39 | #include
40 | #include
41 | #include
42 | #include
43 | #include
44 | #include
45 | #include
46 |
47 | #include
48 | #include
49 | #ifdef TOX_HAVE_TOXUTIL
50 | #include
51 | #endif
52 | #include
53 |
54 |
55 |
56 | #include
57 | #include
58 |
59 |
60 | /*
61 | * ------------------------------------------------------------
62 | * TOXCORE compatibility layer --------------------------------
63 | * ------------------------------------------------------------
64 | */
65 | #ifndef TOXCOMPAT_H_
66 | #define TOXCOMPAT_H_
67 |
68 | #endif
69 | /*
70 | * ------------------------------------------------------------
71 | * TOXCORE compatibility layer --------------------------------
72 | * ------------------------------------------------------------
73 | */
74 |
75 |
76 | // --------- change nospam ---------
77 | // #define CHANGE_NOSPAM_REGULARLY 1
78 | // --------- change nospam ---------
79 |
80 |
81 |
82 |
83 | #include
84 | #include
85 | #include
86 |
87 | #define V4LCONVERT 1
88 | // #define HAVE_SOUND 1
89 |
90 | #ifdef HAVE_SOUND
91 | #include
92 | #endif
93 |
94 |
95 |
96 | #ifdef V4LCONVERT
97 | #include
98 | #endif
99 |
100 | #ifdef V4LCONVERT
101 | static struct v4lconvert_data *v4lconvert_data;
102 | #endif
103 |
104 |
105 |
106 | // ----------- version -----------
107 | // ----------- version -----------
108 | #define VERSION_MAJOR 0
109 | #define VERSION_MINOR 99
110 | #define VERSION_PATCH 19
111 | static const char global_version_string[] = "0.99.19";
112 | // ----------- version -----------
113 | // ----------- version -----------
114 |
115 | typedef struct DHT_node
116 | {
117 | const char *ip;
118 | uint16_t port;
119 | const char key_hex[TOX_PUBLIC_KEY_SIZE * 2 + 1];
120 | unsigned char key_bin[TOX_PUBLIC_KEY_SIZE];
121 | } DHT_node;
122 |
123 |
124 |
125 | #define MAX_AVATAR_FILE_SIZE 65536
126 | #define TOXIC_MAX_NAME_LENGTH 32 /* Must be <= TOX_MAX_NAME_LENGTH */
127 | #define TIME_STR_SIZE 32
128 | #define MAX_STR_SIZE 200
129 |
130 | #define CURRENT_LOG_LEVEL 9 // 0 -> error, 1 -> warn, 2 -> info, 9 -> debug
131 |
132 | #define KiB 1024
133 | #define MiB 1048576 /* 1024^2 */
134 | #define GiB 1073741824 /* 1024^3 */
135 |
136 | #define seconds_since_last_mod 1 // how long to wait before we process image files in seconds
137 | #define MAX_FILES 6 // how many filetransfers to/from 1 friend at the same time?
138 | #define MAX_RESEND_FILE_BEFORE_ASK 6
139 | #define AUTO_RESEND_SECONDS 60*5 // resend for this much seconds before asking again [5 min]
140 | #define VIDEO_BUFFER_COUNT 4
141 | uint32_t DEFAULT_GLOBAL_VID_BITRATE = 900; // kbit/sec
142 | int32_t RC_MAX_QUANTIZER = 56; // valid values between 10 - 56
143 | #define DEFAULT_GLOBAL_AUD_BITRATE 6 // kbit/sec
144 | #define DEFAULT_GLOBAL_MIN_VID_BITRATE 90 // kbit/sec
145 | #define DEFAULT_GLOBAL_MIN_AUD_BITRATE 6 // kbit/sec
146 | // 250=4fps, 500=2fps, 160=6fps, 90=11fps // default video fps (sleep in msecs.)
147 | int DEFAULT_FPS_SLEEP_MS = 10;
148 | #define PROXY_PORT_TOR_DEFAULT 9050
149 | #define RECONNECT_AFTER_OFFLINE_SECONDS 90 // 90s offline and we try to reconnect
150 |
151 | #define CLEAR(x) memset(&(x), 0, sizeof(x))
152 | #define c_sleep(x) usleep(1000*x)
153 |
154 | typedef enum FILE_TRANSFER_STATE
155 | {
156 | FILE_TRANSFER_INACTIVE, // == 0 , this is important
157 | FILE_TRANSFER_PAUSED,
158 | FILE_TRANSFER_PENDING,
159 | FILE_TRANSFER_STARTED,
160 | } FILE_TRANSFER_STATE;
161 |
162 | typedef enum FILE_TRANSFER_DIRECTION
163 | {
164 | FILE_TRANSFER_SEND,
165 | FILE_TRANSFER_RECV
166 | } FILE_TRANSFER_DIRECTION;
167 |
168 | struct FileTransfer
169 | {
170 | FILE *file;
171 | FILE_TRANSFER_STATE state;
172 | FILE_TRANSFER_DIRECTION direction;
173 | uint8_t file_type;
174 | char file_name[TOX_MAX_FILENAME_LENGTH + 1];
175 | char file_path[PATH_MAX + 1]; /* Not used by senders */
176 | double bps;
177 | uint32_t filenum;
178 | uint32_t friendnum;
179 | size_t index;
180 | uint64_t file_size;
181 | uint64_t position;
182 | time_t last_keep_alive; /* The last time we sent or received data */
183 | uint32_t line_id;
184 | uint8_t file_id[TOX_FILE_ID_LENGTH];
185 | };
186 |
187 |
188 | struct LastOnline
189 | {
190 | uint64_t last_on;
191 | struct tm tm;
192 | char hour_min_str[TIME_STR_SIZE]; /* holds 24-hour time string e.g. "15:43:24" */
193 | };
194 |
195 | struct GroupChatInvite
196 | {
197 | char *key;
198 | uint16_t length;
199 | uint8_t type;
200 | bool pending;
201 | };
202 |
203 | typedef struct
204 | {
205 | char name[TOXIC_MAX_NAME_LENGTH + 1];
206 | int namelength;
207 | char statusmsg[TOX_MAX_STATUS_MESSAGE_LENGTH + 1];
208 | size_t statusmsg_len;
209 | char pub_key[TOX_PUBLIC_KEY_SIZE];
210 | char pubkey_string[(TOX_ADDRESS_SIZE * 2 + 1)];
211 | char worksubdir[MAX_STR_SIZE];
212 | uint32_t num;
213 | bool active;
214 | TOX_CONNECTION connection_status;
215 | bool is_typing;
216 | uint8_t status;
217 | struct LastOnline last_online;
218 | int have_resumed_fts; // wait with new FTs until all old FTs have been started (to resume) including avatars!
219 | struct FileTransfer file_receiver[MAX_FILES];
220 | struct FileTransfer file_sender[MAX_FILES];
221 | char last_answer[100];
222 | int waiting_for_answer; // 0 -> no, 1 -> waiting for answer, 2 -> got answer
223 | time_t auto_resend_start_time;
224 | // mz_zip_archive zip_archive;
225 | } ToxicFriend;
226 |
227 | typedef struct
228 | {
229 | char name[TOXIC_MAX_NAME_LENGTH + 1];
230 | int namelength;
231 | char pub_key[TOX_PUBLIC_KEY_SIZE];
232 | uint32_t num;
233 | bool active;
234 | uint64_t last_on;
235 | } BlockedFriend;
236 |
237 | typedef struct
238 | {
239 | int num_selected;
240 | size_t num_friends;
241 | size_t num_online;
242 | size_t max_idx; /* 1 + the index of the last friend in list */
243 | uint32_t *index;
244 | ToxicFriend *list;
245 | } FriendsList;
246 |
247 |
248 | static struct Avatar
249 | {
250 | char name[TOX_MAX_FILENAME_LENGTH + 1];
251 | size_t name_len;
252 | char path[PATH_MAX + 1];
253 | size_t path_len;
254 | off_t size;
255 | } Avatar;
256 |
257 | typedef struct
258 | {
259 | bool incoming;
260 | uint32_t state;
261 | uint32_t audio_bit_rate;
262 | uint32_t video_bit_rate;
263 | pthread_mutex_t arb_mutex[1];
264 | } CallControl;
265 |
266 |
267 | struct buffer
268 | {
269 | void *start;
270 | size_t length;
271 | };
272 |
273 | typedef struct TOXCAM_AV_VIDEO_FRAME
274 | {
275 | uint16_t w, h;
276 | uint8_t *y, *u, *v;
277 | // uint8_t bit_depth;
278 | } toxcam_av_video_frame;
279 |
280 |
281 |
282 | void on_avatar_chunk_request(Tox *m, struct FileTransfer *ft, uint64_t position, size_t length);
283 | int avatar_send(Tox *m, uint32_t friendnum);
284 | struct FileTransfer *new_file_transfer(uint32_t friendnum, uint32_t filenum, FILE_TRANSFER_DIRECTION direction,
285 | uint8_t type);
286 | void kill_all_file_transfers_friend(Tox *m, uint32_t friendnum);
287 | int has_reached_max_file_transfer_for_friend(uint32_t num);
288 | static int find_friend_in_friendlist(uint32_t friendnum);
289 | int is_friend_online(Tox *tox, uint32_t num);
290 | void av_local_disconnect(ToxAV *av, uint32_t num);
291 | void run_cmd_return_output(const char *command, char *output, int lastline);
292 | void save_resumable_fts(Tox *m, uint32_t friendnum);
293 | void resume_resumable_fts(Tox *m, uint32_t friendnum);
294 | void left_top_bar_into_yuv_frame(int bar_start_x_pix, int bar_start_y_pix, int bar_w_pix, int bar_h_pix, uint8_t r,
295 | uint8_t g, uint8_t b);
296 | void print_font_char(int start_x_pix, int start_y_pix, int font_char_num, uint8_t col_value);
297 | void text_on_yuf_frame_xy(int start_x_pix, int start_y_pix, const char *text);
298 | void blinking_dot_on_frame_xy(int start_x_pix, int start_y_pix, int *state);
299 | void black_yuf_frame_xy();
300 | void rbg_to_yuv(uint8_t r, uint8_t g, uint8_t b, uint8_t *y, uint8_t *u, uint8_t *v);
301 | void set_color_in_yuv_frame_xy(uint8_t *yuv_frame, int px_x, int px_y, int frame_w, int frame_h, uint8_t r, uint8_t g,
302 | uint8_t b);
303 |
304 |
305 | const char *savedata_filename = "savedata.tox";
306 | const char *savedata_tmp_filename = "savedata.tox.tmp";
307 | const char *log_filename = "toxcam.log";
308 | const char *my_avatar_filename = "avatar.png";
309 |
310 | char *v4l2_device; // video device filename
311 |
312 | const char *shell_cmd__single_shot = "./scripts/single_shot.sh 2> /dev/null";
313 | const char *shell_cmd__get_cpu_temp = "./scripts/get_cpu_temp.sh 2> /dev/null";
314 | const char *shell_cmd__get_gpu_temp = "./scripts/get_gpu_temp.sh 2> /dev/null";
315 | const char *shell_cmd__get_my_number_of_open_files = "cat /proc/sys/fs/file-nr 2> /dev/null";
316 | int global_want_restart = 0;
317 | const char *global_timestamp_format = "%H:%M:%S";
318 | const char *global_long_timestamp_format = "%Y-%m-%d %H:%M:%S";
319 | const char *global_overlay_timestamp_format = "%Y-%m-%d %H:%M:%S";
320 | uint64_t global_start_time;
321 | int global_cam_device_fd = 0;
322 | uint32_t n_buffers;
323 | struct buffer *buffers = NULL;
324 | uint16_t video_width = 0;
325 | uint16_t video_height = 0;
326 | struct v4l2_format format;
327 | struct v4l2_format dest_format;
328 | toxcam_av_video_frame av_video_frame;
329 | vpx_image_t input;
330 | int global_video_active = 0;
331 | int global_send_first_frame = 0;
332 | int switch_nodelist_2 = 0;
333 | int video_high = 0;
334 | int switch_tcponly = 0;
335 | int use_tor = 0;
336 | time_t my_last_offline_timestamp = -1;
337 | time_t my_last_online_timestamp = -1;
338 |
339 |
340 | uint32_t global_audio_bit_rate;
341 | uint32_t global_video_bit_rate;
342 | ToxAV *mytox_av = NULL;
343 | int tox_loop_running = 1;
344 | int global_blink_state = 0;
345 |
346 | int toxav_video_thread_stop = 0;
347 | int toxav_iterate_thread_stop = 0;
348 |
349 | // -- hardcoded --
350 | // -- hardcoded --
351 | // -- hardcoded --
352 | uint32_t friend_to_send_video_to = -1;
353 | // -- hardcoded --
354 | // -- hardcoded --
355 | // -- hardcoded --
356 |
357 | int video_call_enabled = 1;
358 | uint32_t global_last_change_nospam_ts = 0;
359 | #define CHANGE_NOSPAM_REGULAR_INTERVAL_SECS (3600) // 1h
360 |
361 |
362 | TOX_CONNECTION my_connection_status = TOX_CONNECTION_NONE;
363 | FILE *logfile = NULL;
364 | FriendsList Friends;
365 |
366 | void dbg(int level, const char *fmt, ...)
367 | {
368 | char *level_and_format = NULL;
369 | char *fmt_copy = NULL;
370 |
371 | if (fmt == NULL)
372 | {
373 | return;
374 | }
375 |
376 | if (strlen(fmt) < 1)
377 | {
378 | return;
379 | }
380 |
381 | if (!logfile)
382 | {
383 | return;
384 | }
385 |
386 | if ((level < 0) || (level > 9))
387 | {
388 | level = 0;
389 | }
390 |
391 | level_and_format = malloc(strlen(fmt) + 3 + 1);
392 |
393 | if (!level_and_format)
394 | {
395 | // dbg(9, stderr, "free:000a\n");
396 | return;
397 | }
398 |
399 | fmt_copy = level_and_format + 2;
400 | strcpy(fmt_copy, fmt);
401 | level_and_format[1] = ':';
402 |
403 | if (level == 0)
404 | {
405 | level_and_format[0] = 'E';
406 | }
407 | else if (level == 1)
408 | {
409 | level_and_format[0] = 'W';
410 | }
411 | else if (level == 2)
412 | {
413 | level_and_format[0] = 'I';
414 | }
415 | else
416 | {
417 | level_and_format[0] = 'D';
418 | }
419 |
420 | level_and_format[(strlen(fmt) + 2)] = '\0'; // '\0' or '\n'
421 | level_and_format[(strlen(fmt) + 3)] = '\0';
422 | time_t t3 = time(NULL);
423 | struct tm tm3 = *localtime(&t3);
424 | char *level_and_format_2 = malloc(strlen(level_and_format) + 5 + 3 + 3 + 1 + 3 + 3 + 3 + 1);
425 | level_and_format_2[0] = '\0';
426 | snprintf(level_and_format_2, (strlen(level_and_format) + 5 + 3 + 3 + 1 + 3 + 3 + 3 + 1),
427 | "%04d-%02d-%02d %02d:%02d:%02d:%s",
428 | tm3.tm_year + 1900, tm3.tm_mon + 1, tm3.tm_mday,
429 | tm3.tm_hour, tm3.tm_min, tm3.tm_sec, level_and_format);
430 |
431 | if (level <= CURRENT_LOG_LEVEL)
432 | {
433 | va_list ap;
434 | va_start(ap, fmt);
435 | vfprintf(logfile, level_and_format_2, ap);
436 | va_end(ap);
437 | }
438 |
439 | // dbg(9, "free:001\n");
440 | if (level_and_format)
441 | {
442 | // dbg(9, "free:001.a\n");
443 | free(level_and_format);
444 | }
445 |
446 | if (level_and_format_2)
447 | {
448 | free(level_and_format_2);
449 | }
450 |
451 | // dbg(9, "free:002\n");
452 | }
453 |
454 |
455 | uint32_t generate_random_uint32()
456 | {
457 | // HINT: this is not perfectly randon, FIX ME!
458 | uint32_t r;
459 | struct timeval time;
460 | gettimeofday(&time, NULL);
461 | srand((time.tv_sec * 1000) + (time.tv_usec / 1000));
462 | rand();
463 | rand();
464 | r = rand();
465 | return r;
466 | }
467 |
468 |
469 |
470 |
471 |
472 |
473 | // linked list ----------
474 | typedef struct ll_node
475 | {
476 | void *val;
477 | struct ll_node *next;
478 | } ll_node_t;
479 |
480 |
481 | void ll_fill_val(void **val, size_t data_size, void *data)
482 | {
483 | if (*val != NULL)
484 | {
485 | free(*val);
486 | *val = NULL;
487 | }
488 |
489 | *val = malloc(data_size);
490 | memcpy(*val, data, data_size);
491 | }
492 |
493 |
494 | // add to the beginning of the list
495 | void ll_push(ll_node_t **head, size_t data_size, void *data)
496 | {
497 | ll_node_t *new_node;
498 | new_node = calloc(1, sizeof(ll_node_t));
499 | ll_fill_val(&(new_node->val), data_size, data);
500 | new_node->next = *head;
501 | *head = new_node;
502 | }
503 |
504 | void *ll_pop(ll_node_t **head)
505 | {
506 | void *retval = NULL;
507 | ll_node_t *next_node = NULL;
508 |
509 | if (*head == NULL)
510 | {
511 | return NULL;
512 | }
513 |
514 | next_node = (*head)->next;
515 | retval = (*head)->val;
516 | free(*head);
517 | *head = next_node;
518 | return retval;
519 | }
520 |
521 | void ll_free_val(void *val)
522 | {
523 | if (val != NULL)
524 | {
525 | free(val);
526 | val = NULL;
527 | }
528 | }
529 |
530 | void *ll_remove_by_index(ll_node_t **head, int n)
531 | {
532 | int i = 0;
533 | void *retval = NULL;
534 | ll_node_t *current = *head;
535 | ll_node_t *temp_node = NULL;
536 |
537 | if (n == 0)
538 | {
539 | return ll_pop(head);
540 | }
541 |
542 | for (i = 0; i < n - 1; i++)
543 | {
544 | if (current->next == NULL)
545 | {
546 | return NULL;
547 | }
548 |
549 | current = current->next;
550 | }
551 |
552 | temp_node = current->next;
553 |
554 | if (temp_node != NULL)
555 | {
556 | retval = temp_node->val;
557 | current->next = temp_node->next;
558 | free(temp_node);
559 | }
560 |
561 | return retval;
562 | }
563 |
564 | #if 0
565 | void ll_print_list(ll_node_t *head)
566 | {
567 | ll_node_t *current = head;
568 | int i = 0;
569 |
570 | while (current != NULL)
571 | {
572 | dbg(9, "element #%d=%p\n", i, current->val);
573 | i++;
574 | current = current->next;
575 | }
576 | }
577 | #endif
578 |
579 | ll_node_t *resumable_filetransfers = NULL;
580 |
581 | // linked list ----------
582 |
583 |
584 |
585 |
586 |
587 |
588 |
589 |
590 |
591 | time_t get_unix_time(void)
592 | {
593 | return time(NULL);
594 | }
595 |
596 | void yieldcpu(uint32_t ms)
597 | {
598 | usleep(1000 * ms);
599 | }
600 |
601 |
602 | int get_number_in_string(const char *str, int default_value)
603 | {
604 | int number;
605 |
606 | while (!(*str >= '0' && *str <= '9') && (*str != '-') && (*str != '+'))
607 | {
608 | str++;
609 | }
610 |
611 | if (sscanf(str, "%d", &number) == 1)
612 | {
613 | return number;
614 | }
615 |
616 | // no int found, return default value
617 | return default_value;
618 | }
619 |
620 |
621 | void tox_log_cb__custom(Tox *tox, TOX_LOG_LEVEL level, const char *file, uint32_t line, const char *func,
622 | const char *message, void *user_data)
623 | {
624 | dbg(9, "%d:%s:%d:%s:%s\n", (int)level, file, (int)line, func, message);
625 | }
626 |
627 |
628 | Tox *create_tox()
629 | {
630 | Tox *tox;
631 | struct Tox_Options options;
632 | /*
633 | TOX_ERR_OPTIONS_NEW err_options;
634 | struct Tox_Options options = tox_options_new(&err_options);
635 | if (err_options != TOX_ERR_OPTIONS_NEW_OK)
636 | {
637 | dbg(0, "tox_options_new error\n");
638 | }
639 | */
640 | tox_options_default(&options);
641 | // ----------------------------------------------
642 | // uint16_t tcp_port = 33445; // act as TCP relay
643 | uint16_t tcp_port = 0; // DON'T act as TCP relay
644 | // ----------------------------------------------
645 |
646 | // ----------------------------------------------
647 | if (switch_tcponly == 0)
648 | {
649 | options.udp_enabled = true; // UDP mode
650 | dbg(0, "setting UDP mode\n");
651 | }
652 | else
653 | {
654 | options.udp_enabled = false; // TCP mode
655 | dbg(0, "setting TCP mode\n");
656 | }
657 |
658 | // ----------------------------------------------
659 | options.ipv6_enabled = false;
660 | options.local_discovery_enabled = true;
661 | options.hole_punching_enabled = false;
662 | options.tcp_port = tcp_port;
663 |
664 | if (use_tor == 1)
665 | {
666 | dbg(0, "setting Tor Relay mode\n");
667 | options.udp_enabled = false; // TCP mode
668 | dbg(0, "setting TCP mode\n");
669 | const char *proxy_host = "127.0.0.1";
670 | dbg(0, "setting proxy_host %s\n", proxy_host);
671 | uint16_t proxy_port = PROXY_PORT_TOR_DEFAULT;
672 | dbg(0, "setting proxy_port %d\n", (int)proxy_port);
673 | options.proxy_type = TOX_PROXY_TYPE_SOCKS5;
674 | options.proxy_host = proxy_host;
675 | options.proxy_port = proxy_port;
676 | }
677 | else
678 | {
679 | options.proxy_type = TOX_PROXY_TYPE_NONE;
680 | }
681 |
682 | // ------------------------------------------------------------
683 | // set our own handler for c-toxcore logging messages!!
684 | options.log_callback = tox_log_cb__custom;
685 | // ------------------------------------------------------------
686 | FILE *f = fopen(savedata_filename, "rb");
687 |
688 | if (f)
689 | {
690 | fseek(f, 0, SEEK_END);
691 | long fsize = ftell(f);
692 | fseek(f, 0, SEEK_SET);
693 | uint8_t *savedata = malloc(fsize);
694 | size_t dummy = fread(savedata, fsize, 1, f);
695 |
696 | if (dummy < 1)
697 | {
698 | dbg(0, "reading savedata failed\n");
699 | }
700 |
701 | fclose(f);
702 | options.savedata_type = TOX_SAVEDATA_TYPE_TOX_SAVE;
703 | options.savedata_data = savedata;
704 | options.savedata_length = fsize;
705 | #ifdef TOX_HAVE_TOXUTIL
706 | tox = tox_utils_new(&options, NULL);
707 | #else
708 | tox = tox_new(&options, NULL);
709 | #endif
710 | free((void *)savedata);
711 | }
712 | else
713 | {
714 | #ifdef TOX_HAVE_TOXUTIL
715 | tox = tox_utils_new(&options, NULL);
716 | #else
717 | tox = tox_new(&options, NULL);
718 | #endif
719 | }
720 |
721 | bool local_discovery_enabled = tox_options_get_local_discovery_enabled(&options);
722 | dbg(9, "local discovery enabled = %d\n", (int)local_discovery_enabled);
723 | return tox;
724 | }
725 |
726 | void replace_bad_char_from_string(char *str, const char replace_with)
727 | {
728 | // win32: '\ / : * ? " < > |'
729 | char bad_chars[] = "/:*?<>|\"";
730 | int i;
731 | int j;
732 |
733 | if ((str) && (strlen(str) > 0))
734 | {
735 | for (i = 0; (int)i < (int)strlen(str) ; i++)
736 | {
737 | for (j = 0; (int)j < (int)strlen(bad_chars); j++)
738 | if (str[i] == bad_chars[j])
739 | {
740 | str[i] = replace_with;
741 | }
742 | }
743 | }
744 | }
745 |
746 |
747 | void update_savedata_file(const Tox *tox)
748 | {
749 | size_t size = tox_get_savedata_size(tox);
750 | char *savedata = malloc(size);
751 | tox_get_savedata(tox, (uint8_t *)savedata);
752 | FILE *f = fopen(savedata_tmp_filename, "wb");
753 | fwrite(savedata, size, 1, f);
754 | fclose(f);
755 | rename(savedata_tmp_filename, savedata_filename);
756 | free(savedata);
757 | }
758 |
759 | off_t file_size(const char *path)
760 | {
761 | struct stat st;
762 |
763 | if (stat(path, &st) == -1)
764 | {
765 | return 0;
766 | }
767 |
768 | return st.st_size;
769 | }
770 |
771 | int bin_id_to_string(const char *bin_id, size_t bin_id_size, char *output, size_t output_size)
772 | {
773 | if (bin_id_size != TOX_ADDRESS_SIZE || output_size < (TOX_ADDRESS_SIZE * 2 + 1))
774 | {
775 | return -1;
776 | }
777 |
778 | size_t i;
779 |
780 | for (i = 0; i < TOX_ADDRESS_SIZE; ++i)
781 | {
782 | snprintf(&output[i * 2], output_size - (i * 2), "%02X", bin_id[i] & 0xff);
783 | }
784 |
785 | return 0;
786 | }
787 |
788 | void random_char(char *output, int len)
789 | {
790 | int i;
791 | srandom(time(NULL));
792 |
793 | for (i = 0; i < len - 1; i++)
794 | {
795 | output[i] = (unsigned char)(rand() % 255 + 1);
796 | }
797 |
798 | output[len - 1] = '\0';
799 | }
800 |
801 | void bin_id_to_string_all(const char *bin_id, size_t bin_id_size, char *output, size_t output_size)
802 | {
803 | if (bin_id)
804 | {
805 | size_t i;
806 |
807 | for (i = 0; i < bin_id_size; ++i)
808 | {
809 | snprintf(&output[i * 2], output_size - (i * 2), "%02X", bin_id[i] & 0xff);
810 | }
811 | }
812 | }
813 |
814 |
815 | size_t get_file_name(char *namebuf, size_t bufsize, const char *pathname)
816 | {
817 | int len = strlen(pathname) - 1;
818 | char *path = strdup(pathname);
819 |
820 | if (path == NULL)
821 | {
822 | // TODO
823 | }
824 |
825 | while (len >= 0 && pathname[len] == '/')
826 | {
827 | path[len--] = '\0';
828 | }
829 |
830 | char *finalname = strdup(path);
831 |
832 | if (finalname == NULL)
833 | {
834 | // TODO
835 | }
836 |
837 | const char *basenm = strrchr(path, '/');
838 |
839 | if (basenm != NULL)
840 | {
841 | if (basenm[1])
842 | {
843 | strcpy(finalname, &basenm[1]);
844 | }
845 | }
846 |
847 | snprintf(namebuf, bufsize, "%s", finalname);
848 | free(finalname);
849 | free(path);
850 | return strlen(namebuf);
851 | }
852 |
853 | void shuffle(int *array, size_t n)
854 | {
855 | struct timeval tv;
856 | gettimeofday(&tv, NULL);
857 | int usec = tv.tv_usec;
858 | srand48(usec);
859 |
860 | if (n > 1)
861 | {
862 | size_t i;
863 |
864 | for (i = n - 1; i > 0; i--)
865 | {
866 | size_t j = (unsigned int)(drand48() * (i + 1));
867 | int t = array[j];
868 | array[j] = array[i];
869 | array[i] = t;
870 | }
871 | }
872 | }
873 |
874 |
875 | void bootstap_nodes(Tox *tox, DHT_node nodes[], int number_of_nodes, int add_as_tcp_relay)
876 | {
877 | bool res = 0;
878 | size_t i = 0;
879 | int random_order_nodenums[number_of_nodes];
880 |
881 | for (size_t j = 0; (int)j < (int)number_of_nodes; j++)
882 | {
883 | random_order_nodenums[j] = (int)j;
884 | }
885 |
886 | shuffle(random_order_nodenums, number_of_nodes);
887 |
888 | for (size_t j = 0; (int)j < (int)number_of_nodes; j++)
889 | {
890 | i = (size_t)random_order_nodenums[j];
891 | res = sodium_hex2bin(nodes[i].key_bin, sizeof(nodes[i].key_bin),
892 | nodes[i].key_hex, sizeof(nodes[i].key_hex) - 1, NULL, NULL, NULL);
893 | // dbg(9, "sodium_hex2bin:res=%d\n", res);
894 | TOX_ERR_BOOTSTRAP error;
895 | res = tox_bootstrap(tox, nodes[i].ip, nodes[i].port, nodes[i].key_bin, &error);
896 |
897 | if (res != true)
898 | {
899 | if (error == TOX_ERR_BOOTSTRAP_OK)
900 | {
901 | // dbg(9, "bootstrap:%s %d [FALSE]res=TOX_ERR_BOOTSTRAP_OK\n", nodes[i].ip, nodes[i].port);
902 | }
903 | else if (error == TOX_ERR_BOOTSTRAP_NULL)
904 | {
905 | // dbg(9, "bootstrap:%s %d [FALSE]res=TOX_ERR_BOOTSTRAP_NULL\n", nodes[i].ip, nodes[i].port);
906 | }
907 | else if (error == TOX_ERR_BOOTSTRAP_BAD_HOST)
908 | {
909 | // dbg(9, "bootstrap:%s %d [FALSE]res=TOX_ERR_BOOTSTRAP_BAD_HOST\n", nodes[i].ip, nodes[i].port);
910 | }
911 | else if (error == TOX_ERR_BOOTSTRAP_BAD_PORT)
912 | {
913 | // dbg(9, "bootstrap:%s %d [FALSE]res=TOX_ERR_BOOTSTRAP_BAD_PORT\n", nodes[i].ip, nodes[i].port);
914 | }
915 | }
916 | else
917 | {
918 | // dbg(9, "bootstrap:%s %d [TRUE]res=%d\n", nodes[i].ip, nodes[i].port, res);
919 | }
920 |
921 | if ((add_as_tcp_relay == 1) || (switch_tcponly == 1))
922 | {
923 | res = tox_add_tcp_relay(tox, nodes[i].ip, nodes[i].port, nodes[i].key_bin, &error); // use also as TCP relay
924 |
925 | if (res != true)
926 | {
927 | if (error == TOX_ERR_BOOTSTRAP_OK)
928 | {
929 | // dbg(9, "add_tcp_relay:%s %d [FALSE]res=TOX_ERR_BOOTSTRAP_OK\n", nodes[i].ip, nodes[i].port);
930 | }
931 | else if (error == TOX_ERR_BOOTSTRAP_NULL)
932 | {
933 | // dbg(9, "add_tcp_relay:%s %d [FALSE]res=TOX_ERR_BOOTSTRAP_NULL\n", nodes[i].ip, nodes[i].port);
934 | }
935 | else if (error == TOX_ERR_BOOTSTRAP_BAD_HOST)
936 | {
937 | // dbg(9, "add_tcp_relay:%s %d [FALSE]res=TOX_ERR_BOOTSTRAP_BAD_HOST\n", nodes[i].ip, nodes[i].port);
938 | }
939 | else if (error == TOX_ERR_BOOTSTRAP_BAD_PORT)
940 | {
941 | // dbg(9, "add_tcp_relay:%s %d [FALSE]res=TOX_ERR_BOOTSTRAP_BAD_PORT\n", nodes[i].ip, nodes[i].port);
942 | }
943 | }
944 | else
945 | {
946 | // dbg(9, "add_tcp_relay:%s %d [TRUE]res=%d\n", nodes[i].ip, nodes[i].port, res);
947 | }
948 | }
949 | else
950 | {
951 | dbg(2, "Not adding any TCP relays\n");
952 | }
953 | }
954 | }
955 |
956 |
957 | void bootstrap(Tox *tox)
958 | {
959 | // these nodes seem to be faster!!
960 | DHT_node nodes1[] =
961 | {
962 | {"178.62.250.138", 33445, "788236D34978D1D5BD822F0A5BEBD2C53C64CC31CD3149350EE27D4D9A2F9B6B", {0}},
963 | {"51.15.37.145", 33445, "6FC41E2BD381D37E9748FC0E0328CE086AF9598BECC8FEB7DDF2E440475F300E", {0}},
964 | {"130.133.110.14", 33445, "461FA3776EF0FA655F1A05477DF1B3B614F7D6B124F7DB1DD4FE3C08B03B640F", {0}},
965 | {"23.226.230.47", 33445, "A09162D68618E742FFBCA1C2C70385E6679604B2D80EA6E84AD0996A1AC8A074", {0}},
966 | {"163.172.136.118", 33445, "2C289F9F37C20D09DA83565588BF496FAB3764853FA38141817A72E3F18ACA0B", {0}},
967 | {"217.182.143.254", 443, "7AED21F94D82B05774F697B209628CD5A9AD17E0C073D9329076A4C28ED28147", {0}},
968 | {"185.14.30.213", 443, "2555763C8C460495B14157D234DD56B86300A2395554BCAE4621AC345B8C1B1B", {0}},
969 | {"136.243.141.187", 443, "6EE1FADE9F55CC7938234CC07C864081FC606D8FE7B751EDA217F268F1078A39", {0}},
970 | {"128.199.199.197", 33445, "B05C8869DBB4EDDD308F43C1A974A20A725A36EACCA123862FDE9945BF9D3E09", {0}},
971 | {"198.46.138.44", 33445, "F404ABAA1C99A9D37D61AB54898F56793E1DEF8BD46B1038B9D822E8460FAB67", {0}}
972 | };
973 | // more nodes here, but maybe some issues
974 | DHT_node nodes2[] =
975 | {
976 | {"178.62.250.138", 33445, "788236D34978D1D5BD822F0A5BEBD2C53C64CC31CD3149350EE27D4D9A2F9B6B", {0}},
977 | {"136.243.141.187", 443, "6EE1FADE9F55CC7938234CC07C864081FC606D8FE7B751EDA217F268F1078A39", {0}},
978 | {"185.14.30.213", 443, "2555763C8C460495B14157D234DD56B86300A2395554BCAE4621AC345B8C1B1B", {0}},
979 | {"198.46.138.44", 33445, "F404ABAA1C99A9D37D61AB54898F56793E1DEF8BD46B1038B9D822E8460FAB67", {0}},
980 | {"51.15.37.145", 33445, "6FC41E2BD381D37E9748FC0E0328CE086AF9598BECC8FEB7DDF2E440475F300E", {0}},
981 | {"130.133.110.14", 33445, "461FA3776EF0FA655F1A05477DF1B3B614F7D6B124F7DB1DD4FE3C08B03B640F", {0}},
982 | {"205.185.116.116", 33445, "A179B09749AC826FF01F37A9613F6B57118AE014D4196A0E1105A98F93A54702", {0}},
983 | {"198.98.51.198", 33445, "1D5A5F2F5D6233058BF0259B09622FB40B482E4FA0931EB8FD3AB8E7BF7DAF6F", {0}},
984 | {"108.61.165.198", 33445, "8E7D0B859922EF569298B4D261A8CCB5FEA14FB91ED412A7603A585A25698832", {0}},
985 | {"194.249.212.109", 33445, "3CEE1F054081E7A011234883BC4FC39F661A55B73637A5AC293DDF1251D9432B", {0}},
986 | {"185.25.116.107", 33445, "DA4E4ED4B697F2E9B000EEFE3A34B554ACD3F45F5C96EAEA2516DD7FF9AF7B43", {0}},
987 | {"5.189.176.217", 5190, "2B2137E094F743AC8BD44652C55F41DFACC502F125E99E4FE24D40537489E32F", {0}},
988 | {"217.182.143.254", 2306, "7AED21F94D82B05774F697B209628CD5A9AD17E0C073D9329076A4C28ED28147", {0}},
989 | {"104.223.122.15", 33445, "0FB96EEBFB1650DDB52E70CF773DDFCABE25A95CC3BB50FC251082E4B63EF82A", {0}},
990 | {"tox.verdict.gg", 33445, "1C5293AEF2114717547B39DA8EA6F1E331E5E358B35F9B6B5F19317911C5F976", {0}},
991 | {"d4rk4.ru", 1813, "53737F6D47FA6BD2808F378E339AF45BF86F39B64E79D6D491C53A1D522E7039", {0}},
992 | {"104.233.104.126", 33445, "EDEE8F2E839A57820DE3DA4156D88350E53D4161447068A3457EE8F59F362414", {0}},
993 | {"51.254.84.212", 33445, "AEC204B9A4501412D5F0BB67D9C81B5DB3EE6ADA64122D32A3E9B093D544327D", {0}},
994 | {"88.99.133.52", 33445, "2D320F971EF2CA18004416C2AAE7BA52BF7949DB34EA8E2E21AF67BD367BE211", {0}},
995 | {"185.58.206.164", 33445, "24156472041E5F220D1FA11D9DF32F7AD697D59845701CDD7BE7D1785EB9DB39", {0}},
996 | {"92.54.84.70", 33445, "5625A62618CB4FCA70E147A71B29695F38CC65FF0CBD68AD46254585BE564802", {0}},
997 | {"195.93.190.6", 33445, "FB4CE0DDEFEED45F26917053E5D24BDDA0FA0A3D83A672A9DA2375928B37023D", {0}},
998 | {"tox.uplinklabs.net", 33445, "1A56EA3EDF5DF4C0AEABBF3C2E4E603890F87E983CAC8A0D532A335F2C6E3E1F", {0}},
999 | {"toxnode.nek0.net", 33445, "20965721D32CE50C3E837DD75B33908B33037E6225110BFF209277AEAF3F9639", {0}},
1000 | {"95.215.44.78", 33445, "672DBE27B4ADB9D5FB105A6BB648B2F8FDB89B3323486A7A21968316E012023C", {0}},
1001 | {"163.172.136.118", 33445, "2C289F9F37C20D09DA83565588BF496FAB3764853FA38141817A72E3F18ACA0B", {0}},
1002 | {"sorunome.de", 33445, "02807CF4F8BB8FB390CC3794BDF1E8449E9A8392C5D3F2200019DA9F1E812E46", {0}},
1003 | {"37.97.185.116", 33445, "E59A0E71ADA20D35BD1B0957059D7EF7E7792B3D680AE25C6F4DBBA09114D165", {0}},
1004 | {"193.124.186.205", 5228, "9906D65F2A4751068A59D30505C5FC8AE1A95E0843AE9372EAFA3BAB6AC16C2C", {0}},
1005 | {"80.87.193.193", 33445, "B38255EE4B054924F6D79A5E6E5889EC94B6ADF6FE9906F97A3D01E3D083223A", {0}},
1006 | {"initramfs.io", 33445, "3F0A45A268367C1BEA652F258C85F4A66DA76BCAA667A49E770BCC4917AB6A25", {0}},
1007 | {"hibiki.eve.moe", 33445, "D3EB45181B343C2C222A5BCF72B760638E15ED87904625AAD351C594EEFAE03E", {0}},
1008 | {"tox.deadteam.org", 33445, "C7D284129E83877D63591F14B3F658D77FF9BA9BA7293AEB2BDFBFE1A803AF47", {0}},
1009 | {"46.229.52.198", 33445, "813C8F4187833EF0655B10F7752141A352248462A567529A38B6BBF73E979307", {0}},
1010 | {"node.tox.ngc.network", 33445, "A856243058D1DE633379508ADCAFCF944E40E1672FF402750EF712E30C42012A", {0}},
1011 | {"144.217.86.39", 33445, "7E5668E0EE09E19F320AD47902419331FFEE147BB3606769CFBE921A2A2FD34C", {0}},
1012 | {"185.14.30.213", 443, "2555763C8C460495B14157D234DD56B86300A2395554BCAE4621AC345B8C1B1B", {0}},
1013 | {"77.37.160.178", 33440, "CE678DEAFA29182EFD1B0C5B9BC6999E5A20B50A1A6EC18B91C8EBB591712416", {0}},
1014 | {"85.21.144.224", 33445, "8F738BBC8FA9394670BCAB146C67A507B9907C8E564E28C2B59BEBB2FF68711B", {0}},
1015 | {"tox.natalenko.name", 33445, "1CB6EBFD9D85448FA70D3CAE1220B76BF6FCE911B46ACDCF88054C190589650B", {0}},
1016 | {"37.187.122.30", 33445, "BEB71F97ED9C99C04B8489BB75579EB4DC6AB6F441B603D63533122F1858B51D", {0}},
1017 | {"completelyunoriginal.moe", 33445, "FBC7DED0B0B662D81094D91CC312D6CDF12A7B16C7FFB93817143116B510C13E", {0}},
1018 | {"136.243.141.187", 443, "6EE1FADE9F55CC7938234CC07C864081FC606D8FE7B751EDA217F268F1078A39", {0}},
1019 | {"tox.abilinski.com", 33445, "0E9D7FEE2AA4B42A4C18FE81C038E32FFD8D907AAA7896F05AA76C8D31A20065", {0}},
1020 | {"95.215.46.114", 33445, "5823FB947FF24CF83DDFAC3F3BAA18F96EA2018B16CC08429CB97FA502F40C23", {0}},
1021 | {"51.15.54.207", 33445, "1E64DBA45EC810C0BF3A96327DC8A9D441AB262C14E57FCE11ECBCE355305239", {0}}
1022 | };
1023 | // only nodes.tox.chat
1024 | DHT_node nodes3[] =
1025 | {
1026 | {"51.15.37.145", 33445, "6FC41E2BD381D37E9748FC0E0328CE086AF9598BECC8FEB7DDF2E440475F300E", {0}}
1027 | };
1028 |
1029 | if (switch_nodelist_2 == 0)
1030 | {
1031 | dbg(9, "nodeslist:1\n");
1032 | bootstap_nodes(tox, nodes1, (int)(sizeof(nodes1) / sizeof(DHT_node)), 1);
1033 | }
1034 | else if (switch_nodelist_2 == 2)
1035 | {
1036 | dbg(9, "nodeslist:3\n");
1037 | bootstap_nodes(tox, nodes3, (int)(sizeof(nodes3) / sizeof(DHT_node)), 0);
1038 | }
1039 | else // (switch_nodelist_2 == 1)
1040 | {
1041 | dbg(9, "nodeslist:2\n");
1042 | bootstap_nodes(tox, nodes2, (int)(sizeof(nodes2) / sizeof(DHT_node)), 1);
1043 | }
1044 | }
1045 |
1046 |
1047 | void reconnect(Tox *tox)
1048 | {
1049 | bootstrap(tox);
1050 | // -------- try to go online --------
1051 | long long unsigned int cur_time = time(NULL);
1052 | uint8_t off = 1;
1053 | long long loop_counter = 0;
1054 | long long overall_loop_counter = 0;
1055 |
1056 | while (1)
1057 | {
1058 | tox_iterate(tox, NULL);
1059 | usleep(tox_iteration_interval(tox) * 1000);
1060 |
1061 | if (tox_self_get_connection_status(tox) && off)
1062 | {
1063 | dbg(2, "Reconnect: Tox online, took %llu seconds\n", time(NULL) - cur_time);
1064 | off = 0;
1065 | break;
1066 | }
1067 |
1068 | c_sleep(20);
1069 | loop_counter++;
1070 | overall_loop_counter++;
1071 |
1072 | if (overall_loop_counter > (100 * 20)) // 40 secs
1073 | {
1074 | dbg(2, "Reconnect: Giving up after %llu seconds\n", time(NULL) - cur_time);
1075 | break;
1076 | }
1077 |
1078 | if (loop_counter > (50 * 20))
1079 | {
1080 | loop_counter = 0;
1081 | // if not yet online, bootstrap every 20 seconds
1082 | dbg(2, "Reconnect: Tox NOT online yet, bootstrapping again\n");
1083 | bootstrap(tox);
1084 | }
1085 | }
1086 |
1087 | // -------- try to go online --------
1088 | }
1089 |
1090 |
1091 | void check_online_status(Tox *tox)
1092 | {
1093 | if (my_connection_status == TOX_CONNECTION_NONE)
1094 | {
1095 | if ((get_unix_time() - my_last_offline_timestamp) > RECONNECT_AFTER_OFFLINE_SECONDS)
1096 | {
1097 | // we are offline for too long, try to reconnect
1098 | reconnect(tox);
1099 | }
1100 | }
1101 | }
1102 |
1103 |
1104 | // fill string with toxid in upper case hex.
1105 | // size of toxid_str needs to be: [TOX_ADDRESS_SIZE*2 + 1] !!
1106 | void get_my_toxid(Tox *tox, char *toxid_str)
1107 | {
1108 | uint8_t tox_id_bin[TOX_ADDRESS_SIZE];
1109 | tox_self_get_address(tox, tox_id_bin);
1110 | char tox_id_hex_local[TOX_ADDRESS_SIZE * 2 + 1];
1111 | sodium_bin2hex(tox_id_hex_local, sizeof(tox_id_hex_local), tox_id_bin, sizeof(tox_id_bin));
1112 |
1113 | for (size_t i = 0; i < sizeof(tox_id_hex_local) - 1; i ++)
1114 | {
1115 | tox_id_hex_local[i] = toupper(tox_id_hex_local[i]);
1116 | }
1117 |
1118 | snprintf(toxid_str, (size_t)(TOX_ADDRESS_SIZE * 2 + 1), "%s", (const char *)tox_id_hex_local);
1119 | }
1120 |
1121 | void print_tox_id(Tox *tox)
1122 | {
1123 | char tox_id_hex[TOX_ADDRESS_SIZE * 2 + 1];
1124 | get_my_toxid(tox, tox_id_hex);
1125 |
1126 | if (logfile)
1127 | {
1128 | dbg(2, "--MyToxID--:%s\n", tox_id_hex);
1129 | int fd = fileno(logfile);
1130 | fsync(fd);
1131 | }
1132 | }
1133 |
1134 | int is_friend_online(Tox *tox, uint32_t num)
1135 | {
1136 | int j = find_friend_in_friendlist(num);
1137 |
1138 | switch (Friends.list[j].connection_status)
1139 | {
1140 | case TOX_CONNECTION_NONE:
1141 | return 0;
1142 | break;
1143 |
1144 | case TOX_CONNECTION_TCP:
1145 | return 1;
1146 | break;
1147 |
1148 | case TOX_CONNECTION_UDP:
1149 | return 1;
1150 | break;
1151 |
1152 | default:
1153 | return 0;
1154 | break;
1155 | }
1156 | }
1157 |
1158 | static int find_friend_in_friendlist(uint32_t friendnum)
1159 | {
1160 | int i;
1161 |
1162 | for (i = 0; i <= Friends.max_idx; ++i)
1163 | {
1164 | if (Friends.list[i].num == friendnum)
1165 | {
1166 | return i;
1167 | }
1168 | }
1169 |
1170 | return -1;
1171 | }
1172 |
1173 | static void update_friend_last_online(uint32_t num, time_t timestamp)
1174 | {
1175 | int friendlistnum = find_friend_in_friendlist(num);
1176 | Friends.list[friendlistnum].last_online.last_on = timestamp;
1177 | Friends.list[friendlistnum].last_online.tm = *localtime((const time_t *)×tamp);
1178 | /* if the format changes make sure TIME_STR_SIZE is the correct size !! */
1179 | strftime(Friends.list[friendlistnum].last_online.hour_min_str, TIME_STR_SIZE, global_timestamp_format,
1180 | &Friends.list[friendlistnum].last_online.tm);
1181 | }
1182 |
1183 | void send_file_to_friend_real(Tox *m, uint32_t num, const char *filename, int resume, uint8_t *fileid_resume)
1184 | {
1185 | // ------- hack to send file --------
1186 | // ------- hack to send file --------
1187 | const char *errmsg = NULL;
1188 | char path[MAX_STR_SIZE];
1189 | snprintf(path, sizeof(path), "%s", filename);
1190 | dbg(2, "send_file_to_friend_real:path=%s\n", path);
1191 | FILE *file_to_send = fopen(path, "r");
1192 |
1193 | if (file_to_send == NULL)
1194 | {
1195 | dbg(0, "send_file_to_friend_real:error opening file\n");
1196 | return;
1197 | }
1198 |
1199 | off_t filesize = file_size(path);
1200 |
1201 | if (filesize == 0)
1202 | {
1203 | dbg(0, "send_file_to_friend_real:filesize 0\n");
1204 | fclose(file_to_send);
1205 | return;
1206 | }
1207 |
1208 | char file_name[TOX_MAX_FILENAME_LENGTH];
1209 | size_t namelen = get_file_name(file_name, sizeof(file_name), path);
1210 | TOX_ERR_FILE_SEND err;
1211 | char *o = calloc(1, (size_t)TOX_FILE_ID_LENGTH);
1212 | uint32_t filenum = -1;
1213 |
1214 | if (resume == 0)
1215 | {
1216 | dbg(9, "resume == 0\n");
1217 | random_char(o, (int)TOX_FILE_ID_LENGTH);
1218 | filenum = tox_file_send(m, num, TOX_FILE_KIND_DATA, (uint64_t)filesize, (uint8_t *)o,
1219 | (uint8_t *)file_name, namelen, &err);
1220 | }
1221 | else
1222 | {
1223 | dbg(9, "resume == 1\n");
1224 | filenum = tox_file_send(m, num, TOX_FILE_KIND_DATA, (uint64_t)filesize, fileid_resume,
1225 | (uint8_t *)file_name, namelen, &err);
1226 | }
1227 |
1228 | dbg(2, "send_file_to_friend:tox_file_send=%s filenum=%d\n", file_name, (int)filenum);
1229 |
1230 | if (err != TOX_ERR_FILE_SEND_OK)
1231 | {
1232 | dbg(0, "send_file_to_friend_real: ! TOX_ERR_FILE_SEND_OK\n");
1233 | goto on_send_error;
1234 | }
1235 |
1236 | dbg(2, "send_file_to_friend_real(1):tox_file_send=%s filenum=%d\n", file_name, (int)filenum);
1237 | struct FileTransfer *ft = new_file_transfer(num, filenum, FILE_TRANSFER_SEND, TOX_FILE_KIND_DATA);
1238 | dbg(2, "send_file_to_friend_real(2):tox_file_send=%s filenum=%d\n", file_name, (int)filenum);
1239 |
1240 | if (!ft)
1241 | {
1242 | dbg(0, "send_file_to_friend_real:ft=NULL\n");
1243 | err = TOX_ERR_FILE_SEND_TOO_MANY;
1244 | goto on_send_error;
1245 | }
1246 |
1247 | memcpy(ft->file_name, file_name, namelen + 1);
1248 | ft->file = file_to_send;
1249 | ft->file_size = filesize;
1250 |
1251 | if (resume == 0)
1252 | {
1253 | dbg(9, "resume == 0\n");
1254 | memcpy(ft->file_id, o, (size_t)TOX_FILE_ID_LENGTH);
1255 | }
1256 | else
1257 | {
1258 | dbg(9, "resume == 1\n");
1259 | memcpy(ft->file_id, fileid_resume, (size_t)TOX_FILE_ID_LENGTH);
1260 | }
1261 |
1262 | dbg(0, "send_file_to_friend_real:tox_file_get_file_id num=%d filenum=%d\n", (int)num, (int)filenum);
1263 | dbg(0, "send_file_to_friend_real:file_id_resume=%d ft->file_id=%d\n", (int)fileid_resume, (int)ft->file_id);
1264 | dbg(0, "send_file_to_friend_real:o=%d ft->file_id=%d\n", (int)o, (int)ft->file_id);
1265 | char file_id_str[TOX_FILE_ID_LENGTH * 2 + 1];
1266 | bin_id_to_string_all((char *)ft->file_id, (size_t)TOX_FILE_ID_LENGTH, file_id_str,
1267 | (size_t)(TOX_FILE_ID_LENGTH * 2 + 1));
1268 | dbg(2, "send_file_to_friend_real:file_id=%s\n", file_id_str);
1269 | bin_id_to_string_all((char *)fileid_resume, (size_t)TOX_FILE_ID_LENGTH, file_id_str,
1270 | (size_t)(TOX_FILE_ID_LENGTH * 2 + 1));
1271 | dbg(2, "send_file_to_friend_real:fileid_resume=%s\n", file_id_str);
1272 | bin_id_to_string_all((char *)o, (size_t)TOX_FILE_ID_LENGTH, file_id_str, (size_t)(TOX_FILE_ID_LENGTH * 2 + 1));
1273 | dbg(2, "send_file_to_friend_real:o=%s\n", file_id_str);
1274 | free(o);
1275 | o = NULL;
1276 | return;
1277 | on_send_error:
1278 | free(o);
1279 | o = NULL;
1280 |
1281 | switch (err)
1282 | {
1283 | case TOX_ERR_FILE_SEND_FRIEND_NOT_FOUND:
1284 | errmsg = "File transfer failed: Invalid friend.";
1285 | break;
1286 |
1287 | case TOX_ERR_FILE_SEND_FRIEND_NOT_CONNECTED:
1288 | errmsg = "File transfer failed: Friend is offline.";
1289 | break;
1290 |
1291 | case TOX_ERR_FILE_SEND_NAME_TOO_LONG:
1292 | errmsg = "File transfer failed: Filename is too long.";
1293 | break;
1294 |
1295 | case TOX_ERR_FILE_SEND_TOO_MANY:
1296 | errmsg = "File transfer failed: Too many concurrent file transfers.";
1297 | break;
1298 |
1299 | default:
1300 | errmsg = "File transfer failed.";
1301 | break;
1302 | }
1303 |
1304 | dbg(0, "send_file_to_friend_real:ft error=%s\n", errmsg);
1305 | tox_file_control(m, num, filenum, TOX_FILE_CONTROL_CANCEL, NULL);
1306 | fclose(file_to_send);
1307 | // ------- hack to send file --------
1308 | // ------- hack to send file --------
1309 | }
1310 |
1311 | void resume_file_to_friend(Tox *m, uint32_t num, struct FileTransfer *ft)
1312 | {
1313 | char *file_name_incl_full_path = NULL;
1314 | int j = find_friend_in_friendlist(ft->friendnum);
1315 |
1316 | if (j > -1)
1317 | {
1318 | file_name_incl_full_path = malloc(300);
1319 | snprintf(file_name_incl_full_path, 299, "%s/%s", (const char *)Friends.list[j].worksubdir, ft->file_name);
1320 | dbg(2, "resume_file_to_friend:full path=%s\n", file_name_incl_full_path);
1321 | char file_id_str[TOX_FILE_ID_LENGTH * 2 + 1];
1322 | bin_id_to_string_all((char *)ft->file_id, (size_t)TOX_FILE_ID_LENGTH, file_id_str,
1323 | (size_t)(TOX_FILE_ID_LENGTH * 2 + 1));
1324 | dbg(2, "resume_file_to_friend:file_id=%d file_id_bin=%d\n", (int)file_id_str, (int)ft->file_id);
1325 | dbg(2, "resume_file_to_friend:file_id=%s\n", file_id_str);
1326 | dbg(2, "resume_file_to_friend:path=%s friendnum=%d filenum=%d\n", file_name_incl_full_path, (int)ft->friendnum,
1327 | (int)ft->filenum);
1328 | send_file_to_friend_real(m, ft->friendnum, file_name_incl_full_path, 1, ft->file_id);
1329 | }
1330 | else
1331 | {
1332 | dbg(0, "resume_file_to_friend:friend %d not found in friendlist\n", (int)ft->friendnum);
1333 | }
1334 | }
1335 |
1336 | void send_file_to_friend(Tox *m, uint32_t num, const char *filename)
1337 | {
1338 | send_file_to_friend_real(m, num, filename, 0, NULL);
1339 | }
1340 |
1341 |
1342 | int copy_file(const char *from, const char *to)
1343 | {
1344 | int fd_to, fd_from;
1345 | char buf[4096];
1346 | ssize_t nread;
1347 | int saved_errno;
1348 | fd_from = open(from, O_RDONLY);
1349 |
1350 | if (fd_from < 0)
1351 | {
1352 | dbg(0, "copy_file:002\n");
1353 | return -1;
1354 | }
1355 |
1356 | fd_to = open(to, O_WRONLY | O_CREAT | O_EXCL, 0666);
1357 |
1358 | if (fd_to < 0)
1359 | {
1360 | dbg(0, "copy_file:003\n");
1361 | goto out_error;
1362 | }
1363 |
1364 | while (nread = read(fd_from, buf, sizeof buf), nread > 0)
1365 | {
1366 | char *out_ptr = buf;
1367 | ssize_t nwritten;
1368 |
1369 | do
1370 | {
1371 | nwritten = write(fd_to, out_ptr, nread);
1372 |
1373 | if (nwritten >= 0)
1374 | {
1375 | nread -= nwritten;
1376 | out_ptr += nwritten;
1377 | }
1378 | else if (errno != EINTR)
1379 | {
1380 | dbg(0, "copy_file:004\n");
1381 | goto out_error;
1382 | }
1383 | }
1384 | while (nread > 0);
1385 | }
1386 |
1387 | if (nread == 0)
1388 | {
1389 | if (close(fd_to) < 0)
1390 | {
1391 | fd_to = -1;
1392 | dbg(0, "copy_file:005\n");
1393 | goto out_error;
1394 | }
1395 |
1396 | close(fd_from);
1397 | /* Success! */
1398 | return 0;
1399 | }
1400 |
1401 | out_error:
1402 | saved_errno = errno;
1403 | close(fd_from);
1404 |
1405 | if (fd_to >= 0)
1406 | {
1407 | close(fd_to);
1408 | }
1409 |
1410 | dbg(0, "copy_file:009\n");
1411 | errno = saved_errno;
1412 | return -1;
1413 | }
1414 |
1415 |
1416 |
1417 | char *copy_file_to_friend_subdir(int friendlistnum, const char *file_with_path, const char *filename)
1418 | {
1419 | }
1420 |
1421 | int have_resumed_fts_friend(uint32_t friendnum)
1422 | {
1423 | int j = find_friend_in_friendlist(friendnum);
1424 |
1425 | if (Friends.list[j].have_resumed_fts == 1)
1426 | {
1427 | return 1;
1428 | }
1429 | else
1430 | {
1431 | return 0;
1432 | }
1433 | }
1434 |
1435 | void send_file_to_all_friends(Tox *m, const char *file_with_path, const char *filename)
1436 | {
1437 | }
1438 |
1439 | void on_tox_friend_status(Tox *tox, uint32_t friend_number, TOX_USER_STATUS status, void *user_data)
1440 | {
1441 | dbg(2, "on_tox_friend_status:friendnum=%d status=%d\n", (int)friend_number, (int)status);
1442 | }
1443 |
1444 | void friendlist_onConnectionChange(Tox *m, uint32_t num, TOX_CONNECTION connection_status, void *user_data)
1445 | {
1446 | int friendlistnum = find_friend_in_friendlist(num);
1447 | dbg(2, "friendlist_onConnectionChange:*ENTER*:friendnum=%d %d\n", (int)num, (int)connection_status);
1448 | Friends.list[friendlistnum].connection_status = connection_status;
1449 | update_friend_last_online(num, get_unix_time());
1450 |
1451 | if (is_friend_online(m, num) == 1)
1452 | {
1453 | dbg(0, "friend %d just got online\n", num);
1454 | resume_resumable_fts(m, num);
1455 |
1456 | if (avatar_send(m, num) == -1)
1457 | {
1458 | dbg(0, "avatar_send failed for friend %d\n", num);
1459 | }
1460 | }
1461 | else
1462 | {
1463 | dbg(0, "friend %d went *OFFLINE*\n", num);
1464 | // save all resumeable FTs
1465 | save_resumable_fts(m, num);
1466 | // friend went offline -> cancel all filetransfers
1467 | kill_all_file_transfers_friend(m, num);
1468 |
1469 | // friend went offline -> hang up on all calls
1470 | if (friend_to_send_video_to == num)
1471 | {
1472 | av_local_disconnect(mytox_av, num);
1473 | }
1474 | }
1475 |
1476 | dbg(2, "friendlist_onConnectionChange:*READY*:friendnum=%d %d\n", (int)num, (int)connection_status);
1477 | }
1478 |
1479 | void friendlist_onFriendAdded(Tox *m, uint32_t num, bool sort)
1480 | {
1481 | // dbg(9, "friendlist_onFriendAdded:001\n");
1482 | if (Friends.max_idx == 0)
1483 | {
1484 | // dbg(9, "friendlist_onFriendAdded:001.a malloc 1 friend struct, max_id=%d, num=%d\n", (int)Friends.max_idx, (int)num);
1485 | Friends.list = malloc(sizeof(ToxicFriend));
1486 | }
1487 | else
1488 | {
1489 | // dbg(9, "friendlist_onFriendAdded:001.b realloc %d friend struct, max_id=%d, num=%d\n", (int)(Friends.max_idx + 1), (int)Friends.max_idx, (int)num);
1490 | Friends.list = realloc(Friends.list, ((Friends.max_idx + 1) * sizeof(ToxicFriend)));
1491 | }
1492 |
1493 | // dbg(9, "friendlist_onFriendAdded:001.c set friend to all 0 values\n");
1494 | memset(&Friends.list[Friends.max_idx], 0, sizeof(ToxicFriend)); // fill friend with "0" bytes
1495 | // dbg(2, "friendlist_onFriendAdded:003:%d\n", (int)Friends.max_idx);
1496 | Friends.list[Friends.max_idx].num = num;
1497 | Friends.list[Friends.max_idx].active = true;
1498 | Friends.list[Friends.max_idx].connection_status = TOX_CONNECTION_NONE;
1499 | Friends.list[Friends.max_idx].status = TOX_USER_STATUS_NONE;
1500 | Friends.list[Friends.max_idx].waiting_for_answer = 0;
1501 | Friends.list[Friends.max_idx].auto_resend_start_time = 0;
1502 | Friends.list[Friends.max_idx].have_resumed_fts = 0;
1503 | TOX_ERR_FRIEND_GET_PUBLIC_KEY pkerr;
1504 | tox_friend_get_public_key(m, num, (uint8_t *) Friends.list[Friends.max_idx].pub_key, &pkerr);
1505 |
1506 | if (pkerr != TOX_ERR_FRIEND_GET_PUBLIC_KEY_OK)
1507 | {
1508 | dbg(0, "tox_friend_get_public_key failed (error %d)\n", pkerr);
1509 | }
1510 |
1511 | bin_id_to_string(Friends.list[Friends.max_idx].pub_key, (size_t) TOX_ADDRESS_SIZE,
1512 | Friends.list[Friends.max_idx].pubkey_string, (size_t)(TOX_ADDRESS_SIZE * 2 + 1));
1513 | // dbg(2, "friend pubkey=%s\n", Friends.list[Friends.max_idx].pubkey_string);
1514 | TOX_ERR_FRIEND_GET_LAST_ONLINE loerr;
1515 | time_t t = tox_friend_get_last_online(m, num, &loerr);
1516 |
1517 | if (loerr != TOX_ERR_FRIEND_GET_LAST_ONLINE_OK)
1518 | {
1519 | t = 0;
1520 | }
1521 |
1522 | update_friend_last_online(num, t);
1523 | Friends.max_idx++;
1524 | }
1525 |
1526 | // after you are finished call free_friendlist_nums !
1527 | uint32_t *load_friendlist_nums(Tox *m)
1528 | {
1529 | size_t numfriends = tox_self_get_friend_list_size(m);
1530 | uint32_t *friend_list = malloc(numfriends * sizeof(uint32_t));
1531 | tox_self_get_friend_list(m, friend_list);
1532 | return friend_list;
1533 | }
1534 |
1535 | void free_friendlist_nums(void *friend_list)
1536 | {
1537 | if (friend_list)
1538 | {
1539 | free(friend_list);
1540 | friend_list = NULL;
1541 | }
1542 | }
1543 |
1544 | static void load_friendlist(Tox *m)
1545 | {
1546 | size_t i;
1547 | // TODO
1548 | size_t numfriends = tox_self_get_friend_list_size(m);
1549 | uint32_t *friend_lookup_list = load_friendlist_nums(m);
1550 |
1551 | for (i = 0; i < numfriends; ++i)
1552 | {
1553 | friendlist_onFriendAdded(m, friend_lookup_list[i], false);
1554 | dbg(2, "loading friend num:%d pubkey=%s\n", (int)friend_lookup_list[i],
1555 | Friends.list[Friends.max_idx - 1].pubkey_string);
1556 | }
1557 |
1558 | free_friendlist_nums((void *) friend_lookup_list);
1559 | }
1560 |
1561 |
1562 |
1563 |
1564 | void close_file_transfer(Tox *m, struct FileTransfer *ft, int CTRL)
1565 | {
1566 | dbg(9, "close_file_transfer:001\n");
1567 |
1568 | if (!ft)
1569 | {
1570 | return;
1571 | }
1572 |
1573 | if (ft->state == FILE_TRANSFER_INACTIVE)
1574 | {
1575 | return;
1576 | }
1577 |
1578 | if (ft->file)
1579 | {
1580 | fclose(ft->file);
1581 | }
1582 |
1583 | if (CTRL >= 0)
1584 | {
1585 | tox_file_control(m, ft->friendnum, ft->filenum, (TOX_FILE_CONTROL) CTRL, NULL);
1586 | }
1587 |
1588 | memset(ft, 0, sizeof(struct FileTransfer));
1589 | ft->state = FILE_TRANSFER_INACTIVE; // == 0
1590 | }
1591 |
1592 | int has_reached_max_file_transfer_for_friend(uint32_t num)
1593 | {
1594 | int active_ft = 0;
1595 | int friendlistnum = find_friend_in_friendlist(num);
1596 | int i;
1597 |
1598 | for (i = 0; i < MAX_FILES; ++i)
1599 | {
1600 | struct FileTransfer *ft_send = &Friends.list[friendlistnum].file_sender[i];
1601 |
1602 | if (ft_send->state != FILE_TRANSFER_INACTIVE)
1603 | {
1604 | if (ft_send->file_name != NULL)
1605 | {
1606 | active_ft++;
1607 | }
1608 | }
1609 | }
1610 |
1611 | if (active_ft < MAX_FILES)
1612 | {
1613 | return 0;
1614 | }
1615 | else
1616 | {
1617 | // have reached max filetransfers already
1618 | return 1;
1619 | }
1620 | }
1621 |
1622 | struct FileTransfer *get_file_transfer_from_filename_struct(int friendlistnum, const char *filename)
1623 | {
1624 | size_t i;
1625 |
1626 | for (i = 0; i < MAX_FILES; ++i)
1627 | {
1628 | struct FileTransfer *ft_send = &Friends.list[friendlistnum].file_sender[i];
1629 |
1630 | if (ft_send->state != FILE_TRANSFER_INACTIVE)
1631 | {
1632 | if (ft_send->file_name != NULL)
1633 | {
1634 | if ((strlen(ft_send->file_name) > 0) && (filename != NULL) && (strlen(filename) > 0))
1635 | {
1636 | if (strncmp((char *)ft_send->file_name, filename, strlen(ft_send->file_name)) == 0)
1637 | {
1638 | // dbg(9, "found ft by filename:%s\n", ft_send->file_name);
1639 | return ft_send;
1640 | }
1641 | }
1642 | }
1643 | }
1644 | }
1645 |
1646 | return NULL;
1647 | }
1648 |
1649 |
1650 | struct FileTransfer *get_file_transfer_struct(uint32_t friendnum, uint32_t filenum)
1651 | {
1652 | size_t i;
1653 | int friendlistnum = find_friend_in_friendlist(friendnum);
1654 |
1655 | for (i = 0; i < MAX_FILES; ++i)
1656 | {
1657 | struct FileTransfer *ft_send = &Friends.list[friendlistnum].file_sender[i];
1658 |
1659 | if (ft_send->state != FILE_TRANSFER_INACTIVE && ft_send->filenum == filenum)
1660 | {
1661 | return ft_send;
1662 | }
1663 |
1664 | struct FileTransfer *ft_recv = &Friends.list[friendlistnum].file_receiver[i];
1665 |
1666 | if (ft_recv->state != FILE_TRANSFER_INACTIVE && ft_recv->filenum == filenum)
1667 | {
1668 | return ft_recv;
1669 | }
1670 | }
1671 |
1672 | return NULL;
1673 | }
1674 |
1675 | //
1676 | // cut message at 999 chars length !!
1677 | //
1678 | void send_text_message_to_friend(Tox *tox, uint32_t friend_number, const char *fmt, ...)
1679 | {
1680 | char msg2[1000];
1681 | size_t length = 0;
1682 |
1683 | if (fmt == NULL)
1684 | {
1685 | dbg(9, "send_text_message_to_friend:no message to send\n");
1686 | return;
1687 | }
1688 |
1689 | va_list ap;
1690 | va_start(ap, fmt);
1691 | vsnprintf(msg2, 999, fmt, ap);
1692 | va_end(ap);
1693 | length = (size_t)strlen(msg2);
1694 | tox_friend_send_message(tox, friend_number, TOX_MESSAGE_TYPE_NORMAL, (uint8_t *)msg2, length, NULL);
1695 | }
1696 |
1697 | void change_nospam_to_new_random_value(Tox *tox)
1698 | {
1699 | dbg(9, "change_nospam_to_new_random_value\n");
1700 | global_last_change_nospam_ts = (uint32_t)get_unix_time();
1701 | tox_self_set_nospam(tox, generate_random_uint32());
1702 | update_savedata_file(tox);
1703 | print_tox_id(tox);
1704 | }
1705 |
1706 |
1707 | void friend_request_cb(Tox *tox, const uint8_t *public_key, const uint8_t *message, size_t length,
1708 | void *user_data)
1709 | {
1710 | uint32_t friendnum = tox_friend_add_norequest(tox, public_key, NULL);
1711 | dbg(2, "add friend:002:friendnum=%d max_id=%d\n", friendnum, (int)Friends.max_idx);
1712 | friendlist_onFriendAdded(tox, friendnum, 0);
1713 | update_savedata_file(tox);
1714 | }
1715 |
1716 | /* ssssshhh I stole this from ToxBot, don't tell anyone.. */
1717 | /* ssssshhh and I stole this from EchoBot, don't tell anyone.. */
1718 | static void get_elapsed_time_str(char *buf, int bufsize, uint64_t secs)
1719 | {
1720 | long unsigned int minutes = (secs % 3600) / 60;
1721 | long unsigned int hours = (secs / 3600) % 24;
1722 | long unsigned int days = (secs / 3600) / 24;
1723 | snprintf(buf, bufsize, "%lud %luh %lum", days, hours, minutes);
1724 | }
1725 |
1726 | //
1727 | // lastline param ignored for now!!
1728 | //
1729 | void run_cmd_return_output(const char *command, char *output, int lastline)
1730 | {
1731 | FILE *fp = NULL;
1732 | char path[1035];
1733 | char *pos = NULL;
1734 |
1735 | if (!output)
1736 | {
1737 | return;
1738 | }
1739 |
1740 | /* Open the command for reading. */
1741 | fp = popen(command, "r");
1742 |
1743 | if (fp == NULL)
1744 | {
1745 | dbg(0, "Failed to run command: %s errno=%d error=%s\n", command, errno, strerror(errno));
1746 | output[0] = '\0';
1747 | return;
1748 | }
1749 |
1750 | /* Read the output a line at a time - output it. */
1751 | while (fgets(path, sizeof(path) - 1, fp) != NULL)
1752 | {
1753 | snprintf(output, 299, "%s", (const char *)path);
1754 | }
1755 |
1756 | if (strlen(output) > 1)
1757 | {
1758 | if ((pos = strchr(output, '\n')) != NULL)
1759 | {
1760 | *pos = '\0';
1761 | }
1762 | }
1763 |
1764 | /* close */
1765 | pclose(fp);
1766 | }
1767 |
1768 | void remove_friend(Tox *tox, uint32_t friend_number)
1769 | {
1770 | TOX_ERR_FRIEND_DELETE error;
1771 | #ifdef TOX_HAVE_TOXUTIL
1772 | tox_utils_friend_delete(tox, friend_number, &error);
1773 | #else
1774 | tox_friend_delete(tox, friend_number, &error);
1775 | #endif
1776 | }
1777 |
1778 | void cmd_delfriend(Tox *tox, uint32_t friend_number, const char *message)
1779 | {
1780 | uint32_t del_friend_number = -1;
1781 |
1782 | if (friend_number != del_friend_number)
1783 | {
1784 | // remove_friend(tox, del_friend_number);
1785 | }
1786 | }
1787 |
1788 | void cmd_stats(Tox *tox, uint32_t friend_number)
1789 | {
1790 | switch (my_connection_status)
1791 | {
1792 | case TOX_CONNECTION_NONE:
1793 | send_text_message_to_friend(tox, friend_number, "toxcam status:offline");
1794 | break;
1795 |
1796 | case TOX_CONNECTION_TCP:
1797 | send_text_message_to_friend(tox, friend_number, "toxcam status:Online, using TCP");
1798 | break;
1799 |
1800 | case TOX_CONNECTION_UDP:
1801 | send_text_message_to_friend(tox, friend_number, "toxcam status:Online, using UDP");
1802 | break;
1803 |
1804 | default:
1805 | send_text_message_to_friend(tox, friend_number, "toxcam status:*unknown*");
1806 | break;
1807 | }
1808 |
1809 | // ----- uptime -----
1810 | char time_str[200];
1811 | uint64_t cur_time = time(NULL);
1812 | get_elapsed_time_str(time_str, sizeof(time_str), cur_time - global_start_time);
1813 | send_text_message_to_friend(tox, friend_number, "Uptime: %s", time_str);
1814 | // ----- uptime -----
1815 | char output_str[1000];
1816 | run_cmd_return_output(shell_cmd__get_my_number_of_open_files, output_str, 1);
1817 |
1818 | if (strlen(output_str) > 0)
1819 | {
1820 | send_text_message_to_friend(tox, friend_number, "toxcam open files:%s", output_str);
1821 | }
1822 | else
1823 | {
1824 | send_text_message_to_friend(tox, friend_number, "ERROR getting open files");
1825 | }
1826 |
1827 | // --- temp ---
1828 | run_cmd_return_output(shell_cmd__get_cpu_temp, output_str, 1);
1829 |
1830 | if (strlen(output_str) > 0)
1831 | {
1832 | send_text_message_to_friend(tox, friend_number, "toxcam Cpu temp:%s\xC2\xB0%s", output_str, "C");
1833 | }
1834 | else
1835 | {
1836 | send_text_message_to_friend(tox, friend_number, "ERROR getting Cpu temp");
1837 | }
1838 |
1839 | run_cmd_return_output(shell_cmd__get_gpu_temp, output_str, 1);
1840 |
1841 | if (strlen(output_str) > 0)
1842 | {
1843 | send_text_message_to_friend(tox, friend_number, "toxcam GPU temp:%s\xC2\xB0%s", output_str, "C");
1844 | }
1845 | else
1846 | {
1847 | send_text_message_to_friend(tox, friend_number, "ERROR getting GPU temp");
1848 | }
1849 |
1850 | // --- temp ---
1851 | char tox_id_hex[TOX_ADDRESS_SIZE * 2 + 1];
1852 | get_my_toxid(tox, tox_id_hex);
1853 | send_text_message_to_friend(tox, friend_number, "tox:%s", tox_id_hex);
1854 | }
1855 |
1856 | void cmd_kamft(Tox *tox, uint32_t friend_number)
1857 | {
1858 | send_text_message_to_friend(tox, friend_number, "killing all filetransfers to you ...");
1859 | kill_all_file_transfers_friend(tox, friend_number);
1860 | }
1861 |
1862 | void cmd_snap(Tox *tox, uint32_t friend_number)
1863 | {
1864 | send_text_message_to_friend(tox, friend_number, "*Feature DISABLED*");
1865 |
1866 | if (1 == 1 + 1)
1867 | {
1868 | send_text_message_to_friend(tox, friend_number, "capture single shot, and send to all friends ...");
1869 | char output_str[1000];
1870 | run_cmd_return_output(shell_cmd__single_shot, output_str, 1);
1871 | #if 0
1872 |
1873 | if (strlen(output_str) > 0)
1874 | {
1875 | // send_text_message_to_friend(tox, friend_number, "toxcam:%s", output_str);
1876 | }
1877 | else
1878 | {
1879 | send_text_message_to_friend(tox, friend_number, "ERROR running snap command");
1880 | }
1881 |
1882 | #endif
1883 | send_text_message_to_friend(tox, friend_number, "... capture single shot, ready!");
1884 | }
1885 | }
1886 |
1887 | void cmd_friends(Tox *tox, uint32_t friend_number)
1888 | {
1889 | size_t i;
1890 | // TODO
1891 | size_t numfriends = tox_self_get_friend_list_size(tox);
1892 | int j = -1;
1893 |
1894 | for (i = 0; i < numfriends; ++i)
1895 | {
1896 | j = find_friend_in_friendlist((uint32_t) i);
1897 |
1898 | if (j > -1)
1899 | {
1900 | send_text_message_to_friend(tox, friend_number, "%d:friend", j);
1901 | send_text_message_to_friend(tox, friend_number, "%d tox:%s", j, (const char *)Friends.list[j].pubkey_string);
1902 | send_text_message_to_friend(tox, friend_number, "%d:last online (in client local time):%s", j,
1903 | (const char *)Friends.list[j].last_online.hour_min_str);
1904 |
1905 | switch (Friends.list[j].connection_status)
1906 | {
1907 | case TOX_CONNECTION_NONE:
1908 | send_text_message_to_friend(tox, friend_number, "%d:%s", j, "status:offline");
1909 | break;
1910 |
1911 | case TOX_CONNECTION_TCP:
1912 | send_text_message_to_friend(tox, friend_number, "%d:%s", j, "status:Online, using TCP");
1913 | break;
1914 |
1915 | case TOX_CONNECTION_UDP:
1916 | send_text_message_to_friend(tox, friend_number, "%d:%s", j, "status:Online, using UDP");
1917 | break;
1918 |
1919 | default:
1920 | send_text_message_to_friend(tox, friend_number, "%d:%s", j, "status:*unknown*");
1921 | break;
1922 | }
1923 | }
1924 | }
1925 | }
1926 |
1927 | void cmd_restart(Tox *tox, uint32_t friend_number)
1928 | {
1929 | send_text_message_to_friend(tox, friend_number, "toxcam services will restart ...");
1930 | global_want_restart = 1;
1931 | }
1932 |
1933 |
1934 | void cmd_vcm(Tox *tox, uint32_t friend_number)
1935 | {
1936 | // send_text_message_to_friend(tox, friend_number, "video-call-me not yet implemented!");
1937 | dbg(9, "cmd_vcm:001\n");
1938 |
1939 | if (global_video_active == 1)
1940 | {
1941 | send_text_message_to_friend(tox, friend_number, "there is already a video session active");
1942 | dbg(9, "fnum=%d msg=there is already a video session active\n", (int)friend_number);
1943 | }
1944 | else
1945 | {
1946 | send_text_message_to_friend(tox, friend_number, "i am trying to send my video ...");
1947 | dbg(9, "fnum=%d msg=i am trying to send my video ...\n", (int)friend_number);
1948 |
1949 | if (mytox_av != NULL)
1950 | {
1951 | dbg(9, "cmd_vcm:003\n");
1952 | global_video_bit_rate = DEFAULT_GLOBAL_VID_BITRATE;
1953 | friend_to_send_video_to = friend_number;
1954 | dbg(9, "cmd_vcm:004\n");
1955 | TOXAV_ERR_CALL error = 0;
1956 | toxav_call(mytox_av, friend_number, global_audio_bit_rate, global_video_bit_rate, &error);
1957 | // toxav_call(mytox_av, friend_number, 0, 40, &error);
1958 | dbg(9, "cmd_vcm:005\n");
1959 |
1960 | if (error != TOXAV_ERR_CALL_OK)
1961 | {
1962 | switch (error)
1963 | {
1964 | case TOXAV_ERR_CALL_MALLOC:
1965 | dbg(0, "toxav_call (1):TOXAV_ERR_CALL_MALLOC\n");
1966 | break;
1967 |
1968 | case TOXAV_ERR_CALL_SYNC:
1969 | dbg(0, "toxav_call (1):TOXAV_ERR_CALL_SYNC\n");
1970 | break;
1971 |
1972 | case TOXAV_ERR_CALL_FRIEND_NOT_FOUND:
1973 | dbg(0, "toxav_call (1):TOXAV_ERR_CALL_FRIEND_NOT_FOUND\n");
1974 | break;
1975 |
1976 | case TOXAV_ERR_CALL_FRIEND_NOT_CONNECTED:
1977 | dbg(0, "toxav_call (1):TOXAV_ERR_CALL_FRIEND_NOT_CONNECTED\n");
1978 | break;
1979 |
1980 | case TOXAV_ERR_CALL_FRIEND_ALREADY_IN_CALL:
1981 | dbg(0, "toxav_call (1):TOXAV_ERR_CALL_FRIEND_ALREADY_IN_CALL\n");
1982 | break;
1983 |
1984 | case TOXAV_ERR_CALL_INVALID_BIT_RATE:
1985 | dbg(0, "toxav_call (1):TOXAV_ERR_CALL_INVALID_BIT_RATE\n");
1986 | break;
1987 |
1988 | default:
1989 | dbg(0, "toxav_call (1):*unknown error*\n");
1990 | break;
1991 | }
1992 | }
1993 | }
1994 | else
1995 | {
1996 | dbg(9, "cmd_vcm:006\n");
1997 | send_text_message_to_friend(tox, friend_number, "sending video failed:toxav==NULL");
1998 | }
1999 | }
2000 |
2001 | dbg(9, "cmd_vcm:099\n");
2002 | }
2003 |
2004 | void send_help_to_friend(Tox *tox, uint32_t friend_number)
2005 | {
2006 | send_text_message_to_friend(tox, friend_number,
2007 | "=========================\nToxCam version:%s\n=========================", global_version_string);
2008 | // send_text_message_to_friend(tox, friend_number, " commands are:");
2009 | // send_text_message_to_friend(tox, friend_number, " .help --> show this help");
2010 | send_text_message_to_friend(tox, friend_number, " .stats --> show ToxCam status");
2011 | send_text_message_to_friend(tox, friend_number, " .friends --> show ToxCam Friends");
2012 | send_text_message_to_friend(tox, friend_number, " .snap --> snap a single still image");
2013 | send_text_message_to_friend(tox, friend_number, " .restart --> restart ToxCam system");
2014 | send_text_message_to_friend(tox, friend_number, " .vcm --> videocall me");
2015 | send_text_message_to_friend(tox, friend_number, " .fps --> set delay in ms between sent frames");
2016 | }
2017 |
2018 | //void start_zipfile(mz_zip_archive *pZip, size_t size_pZip, const char* zip_file_full_path)
2019 | //{
2020 | //}
2021 | //void add_file_to_zipfile(mz_zip_archive *pZip, const char* file_to_add_full_path, const char* filename_in_zipfile)
2022 | //{
2023 | //}
2024 | //void finish_zipfile(mz_zip_archive *pZip)
2025 | //{
2026 | //}
2027 |
2028 | void friend_message_cb(Tox *tox, uint32_t friend_number, TOX_MESSAGE_TYPE type, const uint8_t *message,
2029 | size_t length, void *user_data)
2030 | {
2031 | int j;
2032 | int send_back = 0;
2033 |
2034 | if (type == TOX_MESSAGE_TYPE_NORMAL)
2035 | {
2036 | if (message != NULL)
2037 | {
2038 | j = find_friend_in_friendlist(friend_number);
2039 | dbg(2, "message from friend:%d msg:%s\n", (int)friend_number, (char *)message);
2040 |
2041 | if (strncmp((char *)message, ".help", strlen((char *)".help")) == 0)
2042 | {
2043 | send_help_to_friend(tox, friend_number);
2044 | }
2045 | else if (strncmp((char *)message, ".stats", strlen((char *)".stats")) == 0)
2046 | {
2047 | cmd_stats(tox, friend_number);
2048 | }
2049 | else if (strncmp((char *)message, ".friends", strlen((char *)".friends")) == 0)
2050 | {
2051 | cmd_friends(tox, friend_number);
2052 | }
2053 | else if (strncmp((char *)message, ".snap", strlen((char *)".snap")) == 0)
2054 | {
2055 | cmd_snap(tox, friend_number);
2056 | }
2057 | else if (strncmp((char *)message, ".restart", strlen((char *)".restart")) == 0) // restart toxcam processes (no reboot)
2058 | {
2059 | cmd_restart(tox, friend_number);
2060 | }
2061 | else if (strncmp((char *)message, ".vcm", strlen((char *)".vcm")) == 0) // video call me!
2062 | {
2063 | cmd_vcm(tox, friend_number);
2064 | }
2065 | else if (strncmp((char *)message, ".fps ", strlen((char *)".fps ")) == 0) // set 1000/fps
2066 | {
2067 | if (strlen(message) > 5)
2068 | {
2069 | int num_new = get_number_in_string(message, (int)DEFAULT_FPS_SLEEP_MS);
2070 |
2071 | if ((num_new >= 1) && (num_new <= 1000))
2072 | {
2073 | DEFAULT_FPS_SLEEP_MS = num_new;
2074 | dbg(9, "setting wait in ms: %d\n", (int)DEFAULT_FPS_SLEEP_MS);
2075 | }
2076 | }
2077 | }
2078 | else
2079 | {
2080 | if (Friends.list[j].waiting_for_answer == 1)
2081 | {
2082 | // we want to get user feedback
2083 | snprintf(Friends.list[j].last_answer, 99, (char *)message);
2084 | Friends.list[j].waiting_for_answer = 2;
2085 |
2086 | if (Friends.list[j].last_answer)
2087 | {
2088 | dbg(2, "got answer from friend:%d answer:%s\n", (int)friend_number, Friends.list[j].last_answer);
2089 | }
2090 | else
2091 | {
2092 | dbg(2, "got answer from friend:%d answer:NULL\n", (int)friend_number);
2093 | }
2094 | }
2095 | else
2096 | {
2097 | // send_back = 1;
2098 | // unknown command, just send "help / usage"
2099 | send_help_to_friend(tox, friend_number);
2100 | }
2101 | }
2102 | }
2103 | else
2104 | {
2105 | dbg(2, "message from friend:%d msg:NULL\n", (int)friend_number);
2106 | }
2107 | }
2108 | else
2109 | {
2110 | dbg(2, "message from friend:%d\n", (int)friend_number);
2111 | }
2112 |
2113 | if (send_back == 1)
2114 | {
2115 | tox_friend_send_message(tox, friend_number, type, message, length, NULL);
2116 | }
2117 | }
2118 |
2119 |
2120 |
2121 | void on_file_recv_chunk(Tox *m, uint32_t friendnumber, uint32_t filenumber, uint64_t position,
2122 | const uint8_t *data, size_t length, void *user_data)
2123 | {
2124 | struct FileTransfer *ft = get_file_transfer_struct(friendnumber, filenumber);
2125 |
2126 | if (!ft)
2127 | {
2128 | return;
2129 | }
2130 | }
2131 |
2132 |
2133 | void on_file_recv(Tox *m, uint32_t friendnumber, uint32_t filenumber, uint32_t kind, uint64_t file_size,
2134 | const uint8_t *filename, size_t filename_length, void *userdata)
2135 | {
2136 | /* We don't care about receiving avatars */
2137 | if (kind != TOX_FILE_KIND_DATA)
2138 | {
2139 | tox_file_control(m, friendnumber, filenumber, TOX_FILE_CONTROL_CANCEL, NULL);
2140 | dbg(9, "on_file_recv:002:cancel incoming avatar\n");
2141 | return;
2142 | }
2143 | else
2144 | {
2145 | // cancel all filetransfers. we don't want to receive files
2146 | tox_file_control(m, friendnumber, filenumber, TOX_FILE_CONTROL_CANCEL, NULL);
2147 | dbg(9, "on_file_recv:003:cancel incoming file\n");
2148 | return;
2149 | }
2150 | }
2151 |
2152 | void save_resumable_fts(Tox *m, uint32_t friendnum)
2153 | {
2154 | size_t i;
2155 | int friendlistnum = find_friend_in_friendlist(friendnum);
2156 |
2157 | for (i = 0; i < MAX_FILES; ++i)
2158 | {
2159 | // for now save only sending FTs
2160 | struct FileTransfer *ft = &Friends.list[friendlistnum].file_sender[i];
2161 |
2162 | if (ft->state != FILE_TRANSFER_INACTIVE)
2163 | {
2164 | dbg(9, "save_resumable_fts:saving sender FT i=%d ftnum=%d for friendnum:#%d pos=%d filesize=%d\n", i, (int)ft->filenum,
2165 | (int)friendnum, (int)ft->position, (int)ft->file_size);
2166 | ll_push(&resumable_filetransfers, sizeof(struct FileTransfer), ft);
2167 | dbg(9, "save_resumable_fts:pushed struct=%p\n", resumable_filetransfers->val);
2168 | }
2169 | }
2170 |
2171 | Friends.list[friendlistnum].have_resumed_fts = 0;
2172 | }
2173 |
2174 |
2175 |
2176 | void resume_resumable_fts(Tox *m, uint32_t friendnum)
2177 | {
2178 | dbg(9, "resume_resumable_fts:001\n");
2179 | ll_node_t *saved_ft_list = resumable_filetransfers;
2180 | int i = 0;
2181 |
2182 | while (saved_ft_list != NULL)
2183 | {
2184 | dbg(9, "resume_resumable_fts:element #%d=%p\n", i, saved_ft_list->val);
2185 |
2186 | if (saved_ft_list->val != NULL)
2187 | {
2188 | struct FileTransfer *ft = (struct FileTransfer *)saved_ft_list->val;
2189 |
2190 | if (ft->friendnum == friendnum)
2191 | {
2192 | dbg(9, "resume_resumable_fts:**found element #%d=%p\n", i, saved_ft_list->val);
2193 | resume_file_to_friend(m, ft->filenum, ft);
2194 | // now remove element, and start loop again
2195 | ll_remove_by_index(&resumable_filetransfers, i);
2196 | saved_ft_list = resumable_filetransfers;
2197 | i = 0;
2198 | continue;
2199 | }
2200 | }
2201 |
2202 | i++;
2203 | saved_ft_list = saved_ft_list->next;
2204 | }
2205 |
2206 | int j = find_friend_in_friendlist(friendnum);
2207 |
2208 | if (j > -1)
2209 | {
2210 | Friends.list[j].have_resumed_fts = 1;
2211 | }
2212 | }
2213 |
2214 |
2215 |
2216 | void on_file_chunk_request(Tox *tox, uint32_t friendnumber, uint32_t filenumber, uint64_t position,
2217 | size_t length, void *userdata)
2218 | {
2219 | // dbg(9, "on_file_chunk_request:001:friendnum=%d filenum=%d position=%ld len=%d\n", (int)friendnumber, (int)filenumber, (long)position, (int)length);
2220 | struct FileTransfer *ft = get_file_transfer_struct(friendnumber, filenumber);
2221 |
2222 | if (!ft)
2223 | {
2224 | dbg(0, "on_file_chunk_request:003 ft=NULL\n");
2225 | return;
2226 | }
2227 |
2228 | if (ft->file_type == TOX_FILE_KIND_AVATAR)
2229 | {
2230 | on_avatar_chunk_request(tox, ft, position, length);
2231 | return;
2232 | }
2233 |
2234 | if (ft->state != FILE_TRANSFER_STARTED)
2235 | {
2236 | dbg(0, "on_file_chunk_request:005 !FILE_TRANSFER_STARTED\n");
2237 | return;
2238 | }
2239 |
2240 | if (length == 0)
2241 | {
2242 | dbg(2, "File '%s' successfully sent, ft->state=%d\n", ft->file_name, (int)ft->state);
2243 | char origname[300];
2244 | snprintf(origname, 299, "%s", (const char *)ft->file_name);
2245 | close_file_transfer(tox, ft, -1);
2246 | // also remove the file from disk
2247 | int friendlist_num = find_friend_in_friendlist(friendnumber);
2248 | char longname[300];
2249 | snprintf(longname, 299, "%s/%s", (const char *)Friends.list[friendlist_num].worksubdir, origname);
2250 | dbg(2, "delete file %s\n", longname);
2251 | unlink(longname);
2252 | return;
2253 | }
2254 |
2255 | if (ft->file == NULL)
2256 | {
2257 | dbg(0, "File transfer for '%s' failed: Null file pointer\n", ft->file_name);
2258 | close_file_transfer(tox, ft, TOX_FILE_CONTROL_CANCEL);
2259 | return;
2260 | }
2261 |
2262 | if (ft->position != position)
2263 | {
2264 | if (fseek(ft->file, position, SEEK_SET) == -1)
2265 | {
2266 | dbg(0, "File transfer for '%s' failed: Seek fail\n", ft->file_name);
2267 | close_file_transfer(tox, ft, TOX_FILE_CONTROL_CANCEL);
2268 | return;
2269 | }
2270 |
2271 | ft->position = position;
2272 | }
2273 |
2274 | uint8_t send_data[length];
2275 | size_t send_length = fread(send_data, 1, sizeof(send_data), ft->file);
2276 |
2277 | if (send_length != length)
2278 | {
2279 | dbg(0, "File transfer for '%s' failed: Read fail\n", ft->file_name);
2280 | close_file_transfer(tox, ft, TOX_FILE_CONTROL_CANCEL);
2281 | return;
2282 | }
2283 |
2284 | TOX_ERR_FILE_SEND_CHUNK err;
2285 | tox_file_send_chunk(tox, friendnumber, filenumber, position, send_data, send_length, &err);
2286 |
2287 | if (err != TOX_ERR_FILE_SEND_CHUNK_OK)
2288 | {
2289 | dbg(0, "tox_file_send_chunk failed in chat callback (error %d)\n", err);
2290 | }
2291 |
2292 | ft->position += send_length;
2293 | ft->bps += send_length;
2294 | ft->last_keep_alive = get_unix_time();
2295 | }
2296 |
2297 |
2298 | void on_avatar_file_control(Tox *m, struct FileTransfer *ft, TOX_FILE_CONTROL control)
2299 | {
2300 | switch (control)
2301 | {
2302 | case TOX_FILE_CONTROL_RESUME:
2303 | if (ft->state == FILE_TRANSFER_PENDING)
2304 | {
2305 | ft->state = FILE_TRANSFER_STARTED;
2306 | }
2307 | else if (ft->state == FILE_TRANSFER_PAUSED)
2308 | {
2309 | ft->state = FILE_TRANSFER_STARTED;
2310 | }
2311 |
2312 | break;
2313 |
2314 | case TOX_FILE_CONTROL_PAUSE:
2315 | ft->state = FILE_TRANSFER_PAUSED;
2316 | break;
2317 |
2318 | case TOX_FILE_CONTROL_CANCEL:
2319 | close_file_transfer(m, ft, -1);
2320 | break;
2321 | }
2322 | }
2323 |
2324 |
2325 | void on_file_control(Tox *m, uint32_t friendnumber, uint32_t filenumber, TOX_FILE_CONTROL control,
2326 | void *userdata)
2327 | {
2328 | struct FileTransfer *ft = get_file_transfer_struct(friendnumber, filenumber);
2329 |
2330 | if (!ft)
2331 | {
2332 | return;
2333 | }
2334 |
2335 | if (ft->file_type == TOX_FILE_KIND_AVATAR)
2336 | {
2337 | on_avatar_file_control(m, ft, control);
2338 | return;
2339 | }
2340 |
2341 | dbg(9, "on_file_control:002:file in/out\n");
2342 |
2343 | switch (control)
2344 | {
2345 | case TOX_FILE_CONTROL_RESUME:
2346 | {
2347 | dbg(9, "on_file_control:003:TOX_FILE_CONTROL_RESUME\n");
2348 | ft->last_keep_alive = get_unix_time();
2349 |
2350 | /* transfer is accepted */
2351 | if (ft->state == FILE_TRANSFER_PENDING)
2352 | {
2353 | ft->state = FILE_TRANSFER_STARTED;
2354 | dbg(9, "on_file_control:004:pending -> started\n");
2355 | }
2356 | else if (ft->state == FILE_TRANSFER_PAUSED)
2357 | {
2358 | /* transfer is resumed */
2359 | ft->state = FILE_TRANSFER_STARTED;
2360 | dbg(9, "on_file_control:005:paused -> started\n");
2361 | }
2362 |
2363 | break;
2364 | }
2365 |
2366 | case TOX_FILE_CONTROL_PAUSE:
2367 | {
2368 | dbg(9, "on_file_control:006:TOX_FILE_CONTROL_PAUSE\n");
2369 | ft->state = FILE_TRANSFER_PAUSED;
2370 | break;
2371 | }
2372 |
2373 | case TOX_FILE_CONTROL_CANCEL:
2374 | {
2375 | dbg(1, "File transfer for '%s' was aborted\n", ft->file_name);
2376 | close_file_transfer(m, ft, -1);
2377 | break;
2378 | }
2379 | }
2380 | }
2381 |
2382 |
2383 |
2384 | void on_avatar_chunk_request(Tox *m, struct FileTransfer *ft, uint64_t position, size_t length)
2385 | {
2386 | dbg(9, "on_avatar_chunk_request:001\n");
2387 |
2388 | if (ft->state != FILE_TRANSFER_STARTED)
2389 | {
2390 | dbg(0, "on_avatar_chunk_request:001a:!FILE_TRANSFER_STARTED\n");
2391 | return;
2392 | }
2393 |
2394 | if (length == 0)
2395 | {
2396 | close_file_transfer(m, ft, -1);
2397 | return;
2398 | }
2399 |
2400 | if (ft->file == NULL)
2401 | {
2402 | close_file_transfer(m, ft, TOX_FILE_CONTROL_CANCEL);
2403 | return;
2404 | }
2405 |
2406 | if (ft->position != position)
2407 | {
2408 | if (fseek(ft->file, position, SEEK_SET) == -1)
2409 | {
2410 | close_file_transfer(m, ft, TOX_FILE_CONTROL_CANCEL);
2411 | return;
2412 | }
2413 |
2414 | ft->position = position;
2415 | }
2416 |
2417 | uint8_t send_data[length];
2418 | size_t send_length = fread(send_data, 1, sizeof(send_data), ft->file);
2419 |
2420 | if (send_length != length)
2421 | {
2422 | close_file_transfer(m, ft, TOX_FILE_CONTROL_CANCEL);
2423 | return;
2424 | }
2425 |
2426 | TOX_ERR_FILE_SEND_CHUNK err;
2427 | tox_file_send_chunk(m, ft->friendnum, ft->filenum, position, send_data, send_length, &err);
2428 |
2429 | if (err != TOX_ERR_FILE_SEND_CHUNK_OK)
2430 | {
2431 | dbg(0, "tox_file_send_chunk failed in avatar callback (error %d)\n", err);
2432 | }
2433 |
2434 | ft->position += send_length;
2435 | ft->last_keep_alive = get_unix_time();
2436 | }
2437 |
2438 |
2439 | void self_connection_status_cb(Tox *tox, TOX_CONNECTION connection_status, void *user_data)
2440 | {
2441 | switch (connection_status)
2442 | {
2443 | case TOX_CONNECTION_NONE:
2444 | dbg(2, "Offline\n");
2445 | my_connection_status = TOX_CONNECTION_NONE;
2446 | my_last_offline_timestamp = get_unix_time();
2447 | break;
2448 |
2449 | case TOX_CONNECTION_TCP:
2450 | dbg(2, "Online, using TCP\n");
2451 | my_connection_status = TOX_CONNECTION_TCP;
2452 | my_last_online_timestamp = get_unix_time();
2453 | break;
2454 |
2455 | case TOX_CONNECTION_UDP:
2456 | dbg(2, "Online, using UDP\n");
2457 | my_connection_status = TOX_CONNECTION_UDP;
2458 | my_last_online_timestamp = get_unix_time();
2459 | break;
2460 | }
2461 | }
2462 |
2463 |
2464 | static struct FileTransfer *new_file_sender(uint32_t friendnum, uint32_t filenum, uint8_t type)
2465 | {
2466 | size_t i;
2467 | dbg(9, "new_file_sender:001 friendnum=%d filenum=%d type=%d\n", (int)friendnum, (int) filenum, (int) type);
2468 | int friendlistnum = find_friend_in_friendlist(friendnum);
2469 |
2470 | for (i = 0; i < MAX_FILES; ++i)
2471 | {
2472 | struct FileTransfer *ft = &Friends.list[friendlistnum].file_sender[i];
2473 | dbg(9, "new_file_sender:002 i=%d\n", (int)i);
2474 |
2475 | if (ft->state == FILE_TRANSFER_INACTIVE)
2476 | {
2477 | dbg(9, "new_file_sender:003:reusing sender i=%d\n", (int)i);
2478 | memset(ft, 0, sizeof(struct FileTransfer));
2479 | // ft->state = FILE_TRANSFER_INACTIVE; // == 0
2480 | ft->index = i;
2481 | ft->friendnum = friendnum;
2482 | ft->filenum = filenum;
2483 | ft->file_type = type;
2484 | ft->last_keep_alive = get_unix_time();
2485 | ft->state = FILE_TRANSFER_PENDING;
2486 | ft->direction = FILE_TRANSFER_SEND;
2487 | dbg(9, "new_file_sender:003 i=%d\n", (int)i);
2488 | return ft;
2489 | }
2490 | }
2491 |
2492 | return NULL;
2493 | }
2494 |
2495 |
2496 |
2497 | static struct FileTransfer *new_file_receiver(uint32_t friendnum, uint32_t filenum, uint8_t type)
2498 | {
2499 | size_t i;
2500 | int friendlistnum = find_friend_in_friendlist(friendnum);
2501 |
2502 | for (i = 0; i < MAX_FILES; ++i)
2503 | {
2504 | struct FileTransfer *ft = &Friends.list[friendlistnum].file_receiver[i];
2505 |
2506 | if (ft->state == FILE_TRANSFER_INACTIVE)
2507 | {
2508 | memset(ft, 0, sizeof(struct FileTransfer));
2509 | // ft->state = FILE_TRANSFER_INACTIVE; // == 0
2510 | ft->index = i;
2511 | ft->friendnum = friendnum;
2512 | ft->filenum = filenum;
2513 | ft->file_type = type;
2514 | ft->last_keep_alive = get_unix_time();
2515 | ft->state = FILE_TRANSFER_PENDING;
2516 | ft->direction = FILE_TRANSFER_RECV;
2517 | return ft;
2518 | }
2519 | }
2520 |
2521 | return NULL;
2522 | }
2523 |
2524 |
2525 | struct FileTransfer *new_file_transfer(uint32_t friendnum, uint32_t filenum,
2526 | FILE_TRANSFER_DIRECTION direction, uint8_t type)
2527 | {
2528 | if (direction == FILE_TRANSFER_RECV)
2529 | {
2530 | return new_file_receiver(friendnum, filenum, type);
2531 | }
2532 |
2533 | if (direction == FILE_TRANSFER_SEND)
2534 | {
2535 | return new_file_sender(friendnum, filenum, type);
2536 | }
2537 |
2538 | return NULL;
2539 | }
2540 |
2541 |
2542 | int avatar_send(Tox *m, uint32_t friendnum)
2543 | {
2544 | dbg(2, "avatar_send:001 friendnum=%d\n", (int)friendnum);
2545 | dbg(2, "avatar_send:002 %d %s %d\n", (int)Avatar.size, Avatar.name, (int)Avatar.name_len);
2546 | TOX_ERR_FILE_SEND err;
2547 | uint32_t filenum = tox_file_send(m, friendnum, TOX_FILE_KIND_AVATAR, (size_t) Avatar.size,
2548 | NULL, (uint8_t *) Avatar.name, Avatar.name_len, &err);
2549 | dbg(2, "avatar_send:tox_file_send=%s filenum=%d\n", (const char *)Avatar.name, (int)filenum);
2550 |
2551 | if (Avatar.size == 0)
2552 | {
2553 | return 0;
2554 | }
2555 |
2556 | if (err != TOX_ERR_FILE_SEND_OK)
2557 | {
2558 | dbg(0, "avatar_send:tox_file_send failed for _friendnumber %d (error %d)\n", friendnum, err);
2559 | return -1;
2560 | }
2561 |
2562 | dbg(2, "avatar_send(1):tox_file_send=%s filenum=%d\n", (const char *)Avatar.name, (int)filenum);
2563 | struct FileTransfer *ft = new_file_transfer(friendnum, filenum, FILE_TRANSFER_SEND, TOX_FILE_KIND_AVATAR);
2564 | dbg(2, "avatar_send(2):tox_file_send=%s filenum=%d\n", (const char *)Avatar.name, (int)filenum);
2565 |
2566 | if (!ft)
2567 | {
2568 | dbg(0, "avatar_send:003:ft=NULL\n");
2569 | return -1;
2570 | }
2571 |
2572 | ft->file = fopen(Avatar.path, "r");
2573 |
2574 | if (ft->file == NULL)
2575 | {
2576 | dbg(0, "avatar_send:004:ft->file=NULL\n");
2577 | return -1;
2578 | }
2579 |
2580 | snprintf(ft->file_name, sizeof(ft->file_name), "%s", Avatar.name);
2581 | ft->file_size = Avatar.size;
2582 | return 0;
2583 | }
2584 |
2585 |
2586 | int check_file_signature(const char *signature, size_t size, FILE *fp)
2587 | {
2588 | char buf[size];
2589 |
2590 | if (fread(buf, size, 1, fp) != 1)
2591 | {
2592 | return -1;
2593 | }
2594 |
2595 | int ret = memcmp(signature, buf, size);
2596 |
2597 | if (fseek(fp, 0L, SEEK_SET) == -1)
2598 | {
2599 | return -1;
2600 | }
2601 |
2602 | return ret == 0 ? 0 : 1;
2603 | }
2604 |
2605 |
2606 | void kill_all_file_transfers_friend(Tox *m, uint32_t friendnum)
2607 | {
2608 | }
2609 | void kill_all_file_transfers(Tox *m)
2610 | {
2611 | }
2612 |
2613 |
2614 | int avatar_set(Tox *m, const char *path, size_t path_len)
2615 | {
2616 | dbg(2, "avatar_set:001\n");
2617 |
2618 | if (path_len == 0 || path_len >= sizeof(Avatar.path))
2619 | {
2620 | return -1;
2621 | }
2622 |
2623 | dbg(9, "avatar_set:002\n");
2624 | FILE *fp = fopen(path, "rb");
2625 |
2626 | if (fp == NULL)
2627 | {
2628 | return -1;
2629 | }
2630 |
2631 | char PNG_signature[8] = {0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A};
2632 |
2633 | if (check_file_signature(PNG_signature, sizeof(PNG_signature), fp) != 0)
2634 | {
2635 | fclose(fp);
2636 | return -1;
2637 | }
2638 |
2639 | fclose(fp);
2640 | dbg(9, "avatar_set:003\n");
2641 | off_t size = file_size(path);
2642 |
2643 | if (size == 0 || size > MAX_AVATAR_FILE_SIZE)
2644 | {
2645 | return -1;
2646 | }
2647 |
2648 | dbg(9, "avatar_set:004\n");
2649 | get_file_name(Avatar.name, sizeof(Avatar.name), path);
2650 | Avatar.name_len = strlen(Avatar.name);
2651 | snprintf(Avatar.path, sizeof(Avatar.path), "%s", path);
2652 | Avatar.path_len = path_len;
2653 | Avatar.size = size;
2654 | dbg(9, "avatar_set:099\n");
2655 | return 0;
2656 | }
2657 |
2658 | static void avatar_clear(void)
2659 | {
2660 | memset(&Avatar, 0, sizeof(struct Avatar));
2661 | }
2662 |
2663 | void avatar_unset(Tox *m)
2664 | {
2665 | avatar_clear();
2666 | }
2667 |
2668 | int check_number_of_files_to_resend_to_friend(Tox *m, uint32_t friendnum, int friendlistnum)
2669 | {
2670 | }
2671 | void resend_zip_files_and_send(Tox *m, uint32_t friendnum, int friendlistnum)
2672 | {
2673 | }
2674 | void process_friends_dir(Tox *m, uint32_t friendnum, int friendlistnum)
2675 | {
2676 | }
2677 | void check_friends_dir(Tox *m)
2678 | {
2679 | }
2680 | void check_dir(Tox *m)
2681 | {
2682 | }
2683 |
2684 |
2685 | char *get_current_time_date_formatted()
2686 | {
2687 | time_t t;
2688 | struct tm *tm = NULL;
2689 | const int max_size_datetime_str = 100;
2690 | char *str_date_time = malloc(max_size_datetime_str);
2691 | memset(str_date_time, 0, 100);
2692 | t = time(NULL);
2693 | tm = localtime(&t);
2694 | strftime(str_date_time, max_size_datetime_str, global_overlay_timestamp_format, tm);
2695 | // dbg(9, "str_date_time=%s\n", str_date_time);
2696 | return str_date_time;
2697 | }
2698 |
2699 |
2700 | // ------------------- V4L2 stuff ---------------------
2701 | // ------------------- V4L2 stuff ---------------------
2702 | // ------------------- V4L2 stuff ---------------------
2703 |
2704 |
2705 | static int xioctl(int fh, unsigned long request, void *arg)
2706 | {
2707 | int r;
2708 |
2709 | do
2710 | {
2711 | r = ioctl(fh, request, arg);
2712 | }
2713 | while (-1 == r && EINTR == errno);
2714 |
2715 | return r;
2716 | }
2717 |
2718 |
2719 |
2720 | int init_cam()
2721 | {
2722 | int video_dev_open_error = 0;
2723 | int fd;
2724 |
2725 | if ((fd = open(v4l2_device, O_RDWR)) < 0)
2726 | {
2727 | dbg(0, "error opening video device[1]\n");
2728 | video_dev_open_error = 1;
2729 | }
2730 |
2731 | if (video_dev_open_error == 1)
2732 | {
2733 | sleep(20); // sleep 20 seconds
2734 |
2735 | if ((fd = open(v4l2_device, O_RDWR)) < 0)
2736 | {
2737 | dbg(0, "error opening video device[2]\n");
2738 | video_dev_open_error = 1;
2739 | }
2740 | else
2741 | {
2742 | video_dev_open_error = 0;
2743 | }
2744 | }
2745 |
2746 | struct v4l2_capability cap;
2747 |
2748 | struct v4l2_cropcap cropcap;
2749 |
2750 | // struct v4l2_crop crop;
2751 | if (ioctl(fd, VIDIOC_QUERYCAP, &cap) < 0)
2752 | {
2753 | dbg(0, "VIDIOC_QUERYCAP\n");
2754 | }
2755 |
2756 | if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE))
2757 | {
2758 | dbg(0, "The device does not handle single-planar video capture.\n");
2759 | }
2760 |
2761 | if (!(cap.capabilities & V4L2_CAP_STREAMING))
2762 | {
2763 | dbg(0, "The device does not support streaming i/o.\n");
2764 | }
2765 |
2766 | /* Select video input, video standard and tune here. */
2767 | CLEAR(cropcap);
2768 | cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
2769 |
2770 | if (0 == xioctl(fd, VIDIOC_CROPCAP, &cropcap))
2771 | {
2772 | #if 0
2773 | crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
2774 | crop.c = cropcap.defrect; /* reset to full area */
2775 | /* Scale the width and height to 50 % of their original size and center the output. */
2776 | crop.c.width = crop.c.width / 2;
2777 | crop.c.height = crop.c.height / 2;
2778 | crop.c.left = crop.c.left + crop.c.width / 2;
2779 | crop.c.top = crop.c.top + crop.c.height / 2;
2780 |
2781 | if (-1 == xioctl(fd, VIDIOC_S_CROP, &crop))
2782 | {
2783 | switch (errno)
2784 | {
2785 | case EINVAL:
2786 | dbg(0, "Cropping not supported (1)\n");
2787 | break;
2788 |
2789 | default:
2790 | dbg(0, "some error on croping setup\n");
2791 | break;
2792 | }
2793 | }
2794 |
2795 | #endif
2796 | }
2797 | else
2798 | {
2799 | dbg(0, "Cropping not supported (2)\n");
2800 | }
2801 |
2802 | #ifdef V4LCONVERT
2803 | v4lconvert_data = v4lconvert_create(fd);
2804 | #endif
2805 | CLEAR(format);
2806 | CLEAR(dest_format);
2807 | format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
2808 | format.fmt.pix.pixelformat = V4L2_PIX_FMT_YUV420;
2809 | format.fmt.pix.width = 1920;
2810 | format.fmt.pix.height = 1080;
2811 | dest_format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
2812 | dest_format.fmt.pix.pixelformat = V4L2_PIX_FMT_YUV420;
2813 | dest_format.fmt.pix.width = format.fmt.pix.width;
2814 | dest_format.fmt.pix.height = format.fmt.pix.height;
2815 |
2816 | if (format.fmt.pix.pixelformat == V4L2_PIX_FMT_YUV420)
2817 | {
2818 | dbg(2, "Video format(wanted): V4L2_PIX_FMT_YUV420\n");
2819 | }
2820 | else if (format.fmt.pix.pixelformat == V4L2_PIX_FMT_MJPEG)
2821 | {
2822 | dbg(2, "Video format(wanted): V4L2_PIX_FMT_MJPEG\n");
2823 | }
2824 | else
2825 | {
2826 | dbg(2, "Video format(wanted): %u\n", format.fmt.pix.pixelformat);
2827 | }
2828 |
2829 | // Get <-> Set ??
2830 | if (-1 == xioctl(fd, VIDIOC_G_FMT, &format))
2831 | {
2832 | dbg(0, "VIDIOC_G_FMT\n");
2833 | }
2834 |
2835 | if (format.fmt.pix.pixelformat == V4L2_PIX_FMT_YUV420)
2836 | {
2837 | dbg(2, "Video format(got): V4L2_PIX_FMT_YUV420\n");
2838 | }
2839 | else if (format.fmt.pix.pixelformat == V4L2_PIX_FMT_MJPEG)
2840 | {
2841 | dbg(2, "Video format(got): V4L2_PIX_FMT_MJPEG\n");
2842 | }
2843 | else
2844 | {
2845 | dbg(2, "Video format(got): %u\n", format.fmt.pix.pixelformat);
2846 | }
2847 |
2848 | if (video_high == 1)
2849 | {
2850 | format.fmt.pix.width = 1280;
2851 | format.fmt.pix.height = 720;
2852 | }
2853 | else
2854 | {
2855 | format.fmt.pix.width = 640;
2856 | format.fmt.pix.height = 480;
2857 | }
2858 |
2859 | video_width = format.fmt.pix.width;
2860 | video_height = format.fmt.pix.height;
2861 | dbg(2, "Video size(wanted): %u %u\n", video_width, video_height);
2862 |
2863 | if (-1 == xioctl(fd, VIDIOC_S_FMT, &format))
2864 | {
2865 | dbg(0, "VIDIOC_S_FMT\n");
2866 | }
2867 |
2868 | if (-1 == xioctl(fd, VIDIOC_G_FMT, &format))
2869 | {
2870 | dbg(0, "VIDIOC_G_FMT\n");
2871 | }
2872 |
2873 | video_width = format.fmt.pix.width;
2874 | video_height = format.fmt.pix.height;
2875 | dbg(2, "Video size(got): %u %u\n", video_width, video_height);
2876 | dest_format.fmt.pix.width = format.fmt.pix.width;
2877 | dest_format.fmt.pix.height = format.fmt.pix.height;
2878 | /* Buggy driver paranoia. */
2879 | /*
2880 | min = fmt.fmt.pix.width * 2;
2881 | if (fmt.fmt.pix.bytesperline < min)
2882 | fmt.fmt.pix.bytesperline = min;
2883 | min = fmt.fmt.pix.bytesperline * fmt.fmt.pix.height;
2884 | if (fmt.fmt.pix.sizeimage < min)
2885 | fmt.fmt.pix.sizeimage = min;
2886 | */
2887 | // HINT: set camera device fps -----------------------
2888 | struct v4l2_streamparm *setfps;
2889 | setfps = (struct v4l2_streamparm *)calloc(1, sizeof(struct v4l2_streamparm));
2890 |
2891 | if (setfps)
2892 | {
2893 | memset(setfps, 0, sizeof(struct v4l2_streamparm));
2894 | setfps->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
2895 | setfps->parm.capture.timeperframe.numerator = 1;
2896 | setfps->parm.capture.timeperframe.denominator = 30;
2897 |
2898 | if (-1 == xioctl(fd, VIDIOC_S_PARM, setfps))
2899 | {
2900 | dbg(0, "VIDIOC_S_PARM:30fps -> Error\n");
2901 | setfps->parm.capture.timeperframe.denominator = 15;
2902 |
2903 | if (-1 == xioctl(fd, VIDIOC_S_PARM, setfps))
2904 | {
2905 | dbg(0, "VIDIOC_S_PARM:15fps -> Error\n");
2906 | setfps->parm.capture.timeperframe.denominator = 10;
2907 |
2908 | if (-1 == xioctl(fd, VIDIOC_S_PARM, setfps))
2909 | {
2910 | dbg(0, "VIDIOC_S_PARM:10fps -> Error\n");
2911 | }
2912 | }
2913 | }
2914 |
2915 | free(setfps);
2916 | setfps = NULL;
2917 | }
2918 |
2919 | // HINT: set camera device fps -----------------------
2920 | struct v4l2_requestbuffers bufrequest;
2921 | CLEAR(bufrequest);
2922 | bufrequest.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
2923 | bufrequest.memory = V4L2_MEMORY_MMAP;
2924 | bufrequest.count = VIDEO_BUFFER_COUNT;
2925 | dbg(0, "VIDIOC_REQBUFS want type=%d\n", (int)bufrequest.type);
2926 |
2927 | if (-1 == xioctl(fd, VIDIOC_REQBUFS, &bufrequest))
2928 | {
2929 | if (EINVAL == errno)
2930 | {
2931 | dbg(0, "%s does not support x i/o\n", v4l2_device);
2932 | }
2933 | else
2934 | {
2935 | // dbg(0, "VIDIOC_REQBUFS error %d, %s\n", errno, strerror(errno));
2936 | // try again ...
2937 | if (-1 == xioctl(fd, VIDIOC_REQBUFS, &bufrequest))
2938 | {
2939 | if (EINVAL == errno)
2940 | {
2941 | dbg(0, "[2nd] %s does not support x i/o\n", v4l2_device);
2942 | }
2943 | else
2944 | {
2945 | dbg(0, "[2nd] VIDIOC_REQBUFS error %d, %s\n", errno, strerror(errno));
2946 | }
2947 | }
2948 | }
2949 | }
2950 |
2951 | dbg(0, "VIDIOC_REQBUFS got type=%d\n", (int)bufrequest.type);
2952 |
2953 | if (bufrequest.count < 2)
2954 | {
2955 | dbg(0, "Insufficient buffer memory on %s\n", v4l2_device);
2956 | }
2957 |
2958 | buffers = calloc(bufrequest.count, sizeof(*buffers));
2959 |
2960 | for (n_buffers = 0; n_buffers < bufrequest.count; ++n_buffers)
2961 | {
2962 | struct v4l2_buffer bufferinfo;
2963 | CLEAR(bufferinfo);
2964 | bufferinfo.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
2965 | bufferinfo.memory = V4L2_MEMORY_MMAP;
2966 | bufferinfo.index = n_buffers;
2967 |
2968 | if (-1 == xioctl(fd, VIDIOC_QUERYBUF, &bufferinfo))
2969 | {
2970 | dbg(9, "VIDIOC_QUERYBUF (2) error %d, %s\n", errno, strerror(errno));
2971 | }
2972 |
2973 | /*
2974 | if (ioctl(fd, VIDIOC_QUERYBUF, &bufferinfo) < 0)
2975 | {
2976 | dbg(0, "VIDIOC_QUERYBUF %d %s\n", errno, strerror(errno));
2977 | }
2978 | */
2979 | buffers[n_buffers].length = bufferinfo.length;
2980 | buffers[n_buffers].start = mmap(NULL /* start anywhere */, bufferinfo.length, PROT_READ | PROT_WRITE /* required */,
2981 | MAP_SHARED /* recommended */, fd, bufferinfo.m.offset);
2982 |
2983 | if (MAP_FAILED == buffers[n_buffers].start)
2984 | {
2985 | dbg(0, "mmap error %d, %s\n", errno, strerror(errno));
2986 | }
2987 | }
2988 |
2989 | return fd;
2990 | }
2991 |
2992 |
2993 | int v4l_startread()
2994 | {
2995 | dbg(9, "start cam\n");
2996 | size_t i;
2997 | enum v4l2_buf_type type;
2998 |
2999 | for (i = 0; i < n_buffers; ++i)
3000 | {
3001 | struct v4l2_buffer buf;
3002 | dbg(9, "buffer (1) %d of %d\n", i, n_buffers);
3003 | CLEAR(buf);
3004 | buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
3005 | buf.memory = V4L2_MEMORY_MMAP;
3006 | buf.index = i;
3007 |
3008 | if (-1 == xioctl(global_cam_device_fd, VIDIOC_QBUF, &buf))
3009 | {
3010 | dbg(9, "VIDIOC_QBUF (3) error %d, %s\n", errno, strerror(errno));
3011 | return 0;
3012 | }
3013 | }
3014 |
3015 | type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
3016 |
3017 | if (-1 == xioctl(global_cam_device_fd, VIDIOC_STREAMON, &type))
3018 | {
3019 | dbg(9, "VIDIOC_STREAMON error %d, %s\n", errno, strerror(errno));
3020 | return 0;
3021 | }
3022 |
3023 | return 1;
3024 | }
3025 |
3026 |
3027 | int v4l_endread()
3028 | {
3029 | dbg(9, "stop webcam\n");
3030 | enum v4l2_buf_type type;
3031 | type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
3032 |
3033 | if (-1 == xioctl(global_cam_device_fd, VIDIOC_STREAMOFF, &type))
3034 | {
3035 | dbg(9, "VIDIOC_STREAMOFF error %d, %s\n", errno, strerror(errno));
3036 | return 0;
3037 | }
3038 |
3039 | return 1;
3040 | }
3041 |
3042 |
3043 | void yuv422to420(uint8_t *plane_y, uint8_t *plane_u, uint8_t *plane_v, uint8_t *input, uint16_t width, uint16_t height)
3044 | {
3045 | uint8_t *end = input + width * height * 2;
3046 |
3047 | while (input != end)
3048 | {
3049 | uint8_t *line_end = input + width * 2;
3050 |
3051 | while (input != line_end)
3052 | {
3053 | *plane_y++ = *input++;
3054 | *plane_v++ = *input++;
3055 | *plane_y++ = *input++;
3056 | *plane_u++ = *input++;
3057 | }
3058 |
3059 | line_end = input + width * 2;
3060 |
3061 | while (input != line_end)
3062 | {
3063 | *plane_y++ = *input++;
3064 | input++; // u
3065 | *plane_y++ = *input++;
3066 | input++; // v
3067 | }
3068 | }
3069 | }
3070 |
3071 |
3072 | int v4l_getframe(uint8_t *y, uint8_t *u, uint8_t *v, uint16_t width, uint16_t height)
3073 | {
3074 | if (width != video_width || height != video_height)
3075 | {
3076 | dbg(9, "V4L:\twidth/height mismatch %u %u != %u %u\n", width, height, video_width, video_height);
3077 | return 0;
3078 | }
3079 |
3080 | struct v4l2_buffer buf;
3081 |
3082 | CLEAR(buf);
3083 |
3084 | buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
3085 |
3086 | buf.memory = V4L2_MEMORY_MMAP; // V4L2_MEMORY_USERPTR;
3087 |
3088 | if (-1 == ioctl(global_cam_device_fd, VIDIOC_DQBUF, &buf))
3089 | {
3090 | switch (errno)
3091 | {
3092 | case EINTR:
3093 | case EAGAIN:
3094 | return 0;
3095 |
3096 | case EIO:
3097 |
3098 | /* Could ignore EIO, see spec. */
3099 |
3100 | /* fall through */
3101 | default:
3102 | dbg(9, "VIDIOC_DQBUF error %d, %s\n", errno, strerror(errno));
3103 | return -1;
3104 | }
3105 | }
3106 |
3107 | /*for (i = 0; i < n_buffers; ++i)
3108 | if (buf.m.userptr == (unsigned long)buffers[i].start
3109 | && buf.length == buffers[i].length)
3110 | break;
3111 |
3112 | if(i >= n_buffers) {
3113 | dbg(9, "fatal error\n");
3114 | return 0;
3115 | }*/
3116 | // dbg(9, "buf.index=%d\n", (int)buf.index);
3117 | void *data = (void *)buffers[buf.index].start; // length = buf.bytesused //(void*)buf.m.userptr
3118 | /* assumes planes are continuous memory */
3119 | #ifdef V4LCONVERT
3120 | // dbg(9, "V4LCONVERT\n");
3121 | int result = v4lconvert_convert(v4lconvert_data, &format, &dest_format, data, buf.bytesused, y,
3122 | (video_width * video_height * 3) / 2);
3123 |
3124 | if (result == -1)
3125 | {
3126 | dbg(0, "v4lconvert_convert error %s\n", v4lconvert_get_error_message(v4lconvert_data));
3127 | }
3128 |
3129 | #else
3130 | dbg(9, "convert2\n");
3131 |
3132 | if (format.fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV)
3133 | {
3134 | dbg(9, "yuv422to420\n");
3135 | yuv422to420(y, u, v, data, video_width, video_height);
3136 | }
3137 | else
3138 | {
3139 | }
3140 |
3141 | #endif
3142 |
3143 | if (-1 == xioctl(global_cam_device_fd, VIDIOC_QBUF, &buf))
3144 | {
3145 | dbg(9, "VIDIOC_QBUF (1) error %d, %s\n", errno, strerror(errno));
3146 | }
3147 |
3148 | #ifdef V4LCONVERT
3149 | return (result == -1 ? 0 : 1);
3150 | #else
3151 | return 1;
3152 | #endif
3153 | }
3154 |
3155 |
3156 | void close_cam()
3157 | {
3158 | #ifdef V4LCONVERT
3159 | v4lconvert_destroy(v4lconvert_data);
3160 | #endif
3161 | size_t i;
3162 |
3163 | for (i = 0; i < n_buffers; ++i)
3164 | {
3165 | if (-1 == munmap(buffers[i].start, buffers[i].length))
3166 | {
3167 | dbg(9, "munmap error\n");
3168 | }
3169 | }
3170 |
3171 | close(global_cam_device_fd);
3172 | }
3173 |
3174 | // ------------------- V4L2 stuff ---------------------
3175 | // ------------------- V4L2 stuff ---------------------
3176 | // ------------------- V4L2 stuff ---------------------
3177 |
3178 |
3179 |
3180 | // ------------------ Tox AV stuff --------------------
3181 | // ------------------ Tox AV stuff --------------------
3182 | // ------------------ Tox AV stuff --------------------
3183 |
3184 | static void t_toxav_call_cb(ToxAV *av, uint32_t friend_number, bool audio_enabled, bool video_enabled, void *user_data)
3185 | {
3186 | if (global_video_active == 1)
3187 | {
3188 | dbg(9, "Call already active\n");
3189 | }
3190 | else
3191 | {
3192 | dbg(9, "Handling CALL callback friendnum=%d audio_enabled=%d video_enabled=%d\n", (int)friend_number,
3193 | (int)audio_enabled, (int)video_enabled);
3194 | ((CallControl *)user_data)->incoming = true;
3195 | TOXAV_ERR_ANSWER err;
3196 | global_video_bit_rate = DEFAULT_GLOBAL_VID_BITRATE;
3197 | int audio_bitrate = DEFAULT_GLOBAL_AUD_BITRATE;
3198 | int video_bitrate = global_video_bit_rate;
3199 | friend_to_send_video_to = friend_number;
3200 | global_video_active = 1;
3201 | global_send_first_frame = 2;
3202 | dbg(9, "Handling CALL callback friendnum=%d audio_bitrate=%d video_bitrate=%d\n", (int)friend_number,
3203 | (int)audio_bitrate, (int)video_bitrate);
3204 | toxav_answer(av, friend_number, audio_bitrate, video_bitrate, &err);
3205 | #ifdef HAVE_TOXAV_OPTION_SET
3206 | TOXAV_ERR_OPTION_SET error2;
3207 | // toxav_option_set(av, friend_number, TOXAV_ENCODER_VP8_QUALITY, (int32_t)TOXAV_ENCODER_VP8_QUALITY_NORMAL, &error2);
3208 | toxav_option_set(av, friend_number, TOXAV_ENCODER_RC_MAX_QUANTIZER, (int32_t)RC_MAX_QUANTIZER, &error2);
3209 | dbg(9, "Call with friend state:(1)set TOXAV_ENCODER_RC_MAX_QUANTIZER to %d res=%d\n",
3210 | (int)RC_MAX_QUANTIZER,
3211 | (int)error2);
3212 | #endif
3213 | }
3214 | }
3215 |
3216 | static void t_toxav_call_state_cb(ToxAV *av, uint32_t friend_number, uint32_t state, void *user_data)
3217 | {
3218 | dbg(9, "Handling CALL STATE callback: %d friend_number=%d\n", state, (int)friend_number);
3219 | ((CallControl *)user_data)->state = state;
3220 |
3221 | if (state & TOXAV_FRIEND_CALL_STATE_FINISHED)
3222 | {
3223 | dbg(9, "Call with friend %d finished\n", friend_number);
3224 | global_video_active = 0;
3225 | return;
3226 | }
3227 | else if (state & TOXAV_FRIEND_CALL_STATE_ERROR)
3228 | {
3229 | dbg(9, "Call with friend %d errored\n", friend_number);
3230 | global_video_active = 0;
3231 | return;
3232 | }
3233 | else if (state & TOXAV_FRIEND_CALL_STATE_SENDING_A)
3234 | {
3235 | dbg(9, "Call with friend state:TOXAV_FRIEND_CALL_STATE_SENDING_A\n");
3236 | }
3237 | else if (state & TOXAV_FRIEND_CALL_STATE_SENDING_V)
3238 | {
3239 | dbg(9, "Call with friend state:TOXAV_FRIEND_CALL_STATE_SENDING_V\n");
3240 | }
3241 | else if (state & TOXAV_FRIEND_CALL_STATE_ACCEPTING_A)
3242 | {
3243 | dbg(9, "Call with friend state:TOXAV_FRIEND_CALL_STATE_ACCEPTING_A\n");
3244 | }
3245 | else if (state & TOXAV_FRIEND_CALL_STATE_ACCEPTING_V)
3246 | {
3247 | dbg(9, "Call with friend state:TOXAV_FRIEND_CALL_STATE_ACCEPTING_V\n");
3248 | }
3249 |
3250 | #ifdef HAVE_TOXAV_OPTION_SET
3251 | TOXAV_ERR_OPTION_SET error2;
3252 | // toxav_option_set(av, friend_number, TOXAV_ENCODER_VP8_QUALITY, (int32_t)TOXAV_ENCODER_VP8_QUALITY_NORMAL, &error2);
3253 | toxav_option_set(av, friend_number, TOXAV_ENCODER_RC_MAX_QUANTIZER, (int32_t)RC_MAX_QUANTIZER, &error2);
3254 | dbg(9, "Call with friend state:(0)set TOXAV_ENCODER_RC_MAX_QUANTIZER to %d res=%d\n",
3255 | (int)RC_MAX_QUANTIZER,
3256 | (int)error2);
3257 | #endif
3258 | dbg(9, "t_toxav_call_state_cb:002\n");
3259 | int send_audio = (state & TOXAV_FRIEND_CALL_STATE_SENDING_A) && (state & TOXAV_FRIEND_CALL_STATE_ACCEPTING_A);
3260 | int send_video = state & TOXAV_FRIEND_CALL_STATE_SENDING_V && (state & TOXAV_FRIEND_CALL_STATE_ACCEPTING_V);
3261 | dbg(9, "t_toxav_call_state_cb:002a send_audio=%d send_video=%d global_video_bit_rate=%d\n", send_audio, send_video,
3262 | (int)global_video_bit_rate);
3263 | TOXAV_ERR_BIT_RATE_SET bitrate_err = 0;
3264 | // ** // toxav_bit_rate_set(av, friend_number, 0, send_video ? global_video_bit_rate : 0, &bitrate_err);
3265 | dbg(9, "t_toxav_call_state_cb:004\n");
3266 |
3267 | if (bitrate_err)
3268 | {
3269 | dbg(9, "ToxAV:Error setting/changing video bitrate\n");
3270 | }
3271 |
3272 | if (send_video == 1)
3273 | {
3274 | dbg(9, "t_toxav_call_state_cb:004\n");
3275 | global_video_active = 1;
3276 | global_send_first_frame = 2;
3277 | }
3278 | else
3279 | {
3280 | dbg(9, "t_toxav_call_state_cb:005\n");
3281 | global_video_active = 0;
3282 | global_send_first_frame = 0;
3283 | }
3284 |
3285 | dbg(9, "Call state for friend %d changed to %d, audio=%d, video=%d\n", friend_number, state, send_audio, send_video);
3286 | }
3287 |
3288 | static void t_toxav_bit_rate_status_cb(ToxAV *av, uint32_t friend_number,
3289 | uint32_t audio_bit_rate, uint32_t video_bit_rate,
3290 | void *user_data)
3291 | {
3292 | dbg(0, "t_toxav_bit_rate_status_cb:001 video_bit_rate=%d\n", (int)video_bit_rate);
3293 | dbg(0, "t_toxav_bit_rate_status_cb:001 audio_bit_rate=%d\n", (int)audio_bit_rate);
3294 | TOXAV_ERR_BIT_RATE_SET error = 0;
3295 | uint32_t video_bit_rate_ = video_bit_rate;
3296 |
3297 | if (video_bit_rate < DEFAULT_GLOBAL_MIN_VID_BITRATE)
3298 | {
3299 | video_bit_rate_ = DEFAULT_GLOBAL_MIN_VID_BITRATE;
3300 | }
3301 |
3302 | // toxav_bit_rate_set(av, friend_number, audio_bit_rate, video_bit_rate_, &error);
3303 |
3304 | if (error != 0)
3305 | {
3306 | dbg(0, "ToxAV:Setting new Video bitrate has failed with error #%u\n", error);
3307 | }
3308 | else
3309 | {
3310 | global_video_bit_rate = video_bit_rate_;
3311 | }
3312 |
3313 | dbg(2, "suggested bit rates: audio: %d video: %d\n", audio_bit_rate, video_bit_rate);
3314 | dbg(2, "actual bit rates: audio: %d video: %d\n", global_audio_bit_rate, global_video_bit_rate);
3315 | }
3316 |
3317 |
3318 | static void t_toxav_receive_audio_frame_cb(ToxAV *av, uint32_t friend_number,
3319 | int16_t const *pcm,
3320 | size_t sample_count,
3321 | uint8_t channels,
3322 | uint32_t sampling_rate,
3323 | void *user_data)
3324 | {
3325 | if (global_video_active == 1)
3326 | {
3327 | if (friend_to_send_video_to == friend_number)
3328 | {
3329 | }
3330 | else
3331 | {
3332 | // wrong friend
3333 | }
3334 | }
3335 | else
3336 | {
3337 | }
3338 |
3339 | // CallControl *cc = (CallControl *)user_data;
3340 | // frame *f = (frame *)malloc(sizeof(uint16_t) + sample_count * sizeof(int16_t) * channels);
3341 | // memcpy(f->data, pcm, sample_count * sizeof(int16_t) * channels);
3342 | // f->size = sample_count;
3343 | // pthread_mutex_lock(cc->arb_mutex);
3344 | // free(rb_write(cc->arb, f));
3345 | // pthread_mutex_unlock(cc->arb_mutex);
3346 | }
3347 |
3348 |
3349 | static void t_toxav_receive_video_frame_cb(ToxAV *av, uint32_t friend_number,
3350 | uint16_t width, uint16_t height,
3351 | uint8_t const *y, uint8_t const *u, uint8_t const *v,
3352 | int32_t ystride, int32_t ustride, int32_t vstride,
3353 | void *user_data)
3354 | {
3355 | if (global_video_active == 1)
3356 | {
3357 | if (friend_to_send_video_to == friend_number)
3358 | {
3359 | }
3360 | else
3361 | {
3362 | // wrong friend
3363 | }
3364 | }
3365 | else
3366 | {
3367 | }
3368 |
3369 | // ystride = abs(ystride);
3370 | // ustride = abs(ustride);
3371 | // vstride = abs(vstride);
3372 | // uint16_t *img_data = (uint16_t *)malloc(height * width * 6);
3373 | // unsigned long int i, j;
3374 | // for (i = 0; i < height; ++i)
3375 | // {
3376 | // for (j = 0; j < width; ++j)
3377 | // {
3378 | // uint8_t *point = (uint8_t *) img_data + 3 * ((i * width) + j);
3379 | // int yx = y[(i * ystride) + j];
3380 | // int ux = u[((i / 2) * ustride) + (j / 2)];
3381 | // int vx = v[((i / 2) * vstride) + (j / 2)];
3382 | // point[0] = YUV2R(yx, ux, vx);
3383 | // point[1] = YUV2G(yx, ux, vx);
3384 | // point[2] = YUV2B(yx, ux, vx);
3385 | // }
3386 | // }
3387 | // CvMat mat = cvMat(height, width, CV_8UC3, img_data);
3388 | // CvSize sz;
3389 | // sz.height = height;
3390 | // sz.width = width;
3391 | // IplImage *header = cvCreateImageHeader(sz, 1, 3);
3392 | // IplImage *img = cvGetImage(&mat, header);
3393 | // cvShowImage(vdout, img);
3394 | // free(img_data);
3395 | }
3396 |
3397 | void set_av_video_frame()
3398 | {
3399 | vpx_img_alloc(&input, VPX_IMG_FMT_I420, video_width, video_height, 1);
3400 | av_video_frame.y = input.planes[0]; /**< Y (Luminance) plane and VPX_PLANE_PACKED */
3401 | av_video_frame.u = input.planes[1]; /**< U (Chroma) plane */
3402 | av_video_frame.v = input.planes[2]; /**< V (Chroma) plane */
3403 | av_video_frame.w = input.d_w;
3404 | av_video_frame.h = input.d_h;
3405 | //av_video_frame.bit_depth = input.bit_depth;
3406 | dbg(2, "ToxVideo:av_video_frame set\n");
3407 | }
3408 |
3409 | void *thread_av(void *data)
3410 | {
3411 | ToxAV *av = (ToxAV *) data;
3412 | pthread_t id = pthread_self();
3413 | pthread_mutex_t av_thread_lock;
3414 |
3415 | if (pthread_mutex_init(&av_thread_lock, NULL) != 0)
3416 | {
3417 | dbg(0, "Error creating av_thread_lock\n");
3418 | }
3419 | else
3420 | {
3421 | dbg(2, "av_thread_lock created successfully\n");
3422 | }
3423 |
3424 | dbg(2, "AV Thread #%d: starting\n", (int) id);
3425 |
3426 | if (video_call_enabled == 1)
3427 | {
3428 | global_cam_device_fd = init_cam();
3429 | dbg(2, "AV Thread #%d: init cam\n", (int) id);
3430 | set_av_video_frame();
3431 | // start streaming
3432 | v4l_startread();
3433 | }
3434 |
3435 | while (toxav_iterate_thread_stop != 1)
3436 | {
3437 | if (global_video_active == 1)
3438 | {
3439 | pthread_mutex_lock(&av_thread_lock);
3440 | // dbg(9, "AV Thread #%d:get frame\n", (int) id);
3441 | // capturing is enabled, capture frames
3442 | int r = v4l_getframe(av_video_frame.y, av_video_frame.u, av_video_frame.v,
3443 | av_video_frame.w, av_video_frame.h);
3444 |
3445 | if (r == 1)
3446 | {
3447 | if (global_send_first_frame > 0)
3448 | {
3449 | black_yuf_frame_xy();
3450 | global_send_first_frame--;
3451 | }
3452 |
3453 | // "0" -> [48]
3454 | // "9" -> [57]
3455 | // ":" -> [58]
3456 | char *date_time_str = get_current_time_date_formatted();
3457 |
3458 | if (date_time_str)
3459 | {
3460 | text_on_yuf_frame_xy(10, 10, date_time_str);
3461 | free(date_time_str);
3462 | }
3463 |
3464 | blinking_dot_on_frame_xy(20, 30, &global_blink_state);
3465 |
3466 | if (friend_to_send_video_to != -1)
3467 | {
3468 | // dbg(9, "AV Thread #%d:send frame to friend num=%d\n", (int) id, (int)friend_to_send_video_to);
3469 | TOXAV_ERR_SEND_FRAME error = 0;
3470 | toxav_video_send_frame(av, friend_to_send_video_to, av_video_frame.w, av_video_frame.h,
3471 | av_video_frame.y, av_video_frame.u, av_video_frame.v, &error);
3472 |
3473 | if (error)
3474 | {
3475 | if (error == TOXAV_ERR_SEND_FRAME_SYNC)
3476 | {
3477 | //debug_notice("uToxVideo:\tVid Frame sync error: w=%u h=%u\n", av_video_frame.w,
3478 | // av_video_frame.h);
3479 | dbg(0, "TOXAV_ERR_SEND_FRAME_SYNC\n");
3480 | }
3481 | else if (error == TOXAV_ERR_SEND_FRAME_PAYLOAD_TYPE_DISABLED)
3482 | {
3483 | //debug_error("uToxVideo:\tToxAV disagrees with our AV state for friend %lu, self %u, friend %u\n",
3484 | // i, friend[i].call_state_self, friend[i].call_state_friend);
3485 | dbg(0, "TOXAV_ERR_SEND_FRAME_PAYLOAD_TYPE_DISABLED\n");
3486 | }
3487 | else
3488 | {
3489 | //debug_error("uToxVideo:\ttoxav_send_video error friend: %i error: %u\n",
3490 | // friend[i].number, error);
3491 | dbg(0, "ToxVideo:toxav_send_video error %u\n", error);
3492 | // *TODO* if these keep piling up --> just disconnect the call!!
3493 | // *TODO* if these keep piling up --> just disconnect the call!!
3494 | // *TODO* if these keep piling up --> just disconnect the call!!
3495 | }
3496 | }
3497 | }
3498 | }
3499 | else if (r == -1)
3500 | {
3501 | // debug_error("uToxVideo:\tErr... something really bad happened trying to get this frame, I'm just going "
3502 | // "to plots now!\n");
3503 | //video_device_stop();
3504 | //close_video_device(video_device);
3505 | dbg(0, "ToxVideo:something really bad happened trying to get this frame\n");
3506 | }
3507 |
3508 | pthread_mutex_unlock(&av_thread_lock);
3509 | // yieldcpu(1000); // 1 frame every 1 seconds!!
3510 | yieldcpu(DEFAULT_FPS_SLEEP_MS); /* ~4 frames per second */
3511 | // yieldcpu(80); /* ~12 frames per second */
3512 | // yieldcpu(40); /* 60fps = 16.666ms || 25 fps = 40ms || the data quality is SO much better at 25... */
3513 | }
3514 | else
3515 | {
3516 | yieldcpu(100);
3517 | }
3518 | }
3519 |
3520 | if (video_call_enabled == 1)
3521 | {
3522 | // end streaming
3523 | v4l_endread();
3524 | }
3525 |
3526 | dbg(2, "ToxVideo:Clean thread exit!\n");
3527 | }
3528 |
3529 |
3530 | void *thread_video_av(void *data)
3531 | {
3532 | ToxAV *av = (ToxAV *) data;
3533 | pthread_t id = pthread_self();
3534 | pthread_mutex_t av_thread_lock;
3535 |
3536 | if (pthread_mutex_init(&av_thread_lock, NULL) != 0)
3537 | {
3538 | dbg(0, "Error creating video av_thread_lock\n");
3539 | }
3540 | else
3541 | {
3542 | dbg(2, "av_thread_lock video created successfully\n");
3543 | }
3544 |
3545 | dbg(2, "AV video Thread #%d: starting\n", (int) id);
3546 |
3547 | while (toxav_video_thread_stop != 1)
3548 | {
3549 | pthread_mutex_lock(&av_thread_lock);
3550 | toxav_iterate(av);
3551 | // dbg(9, "AV video Thread #%d running ...", (int) id);
3552 | pthread_mutex_unlock(&av_thread_lock);
3553 | // usleep(toxav_iteration_interval(av) * 1000);
3554 | usleep(4 * 1000);
3555 | }
3556 |
3557 | dbg(2, "ToxVideo:Clean video thread exit!\n");
3558 | }
3559 |
3560 |
3561 | void av_local_disconnect(ToxAV *av, uint32_t num)
3562 | {
3563 | dbg(9, "av_local_disconnect\n");
3564 | TOXAV_ERR_CALL_CONTROL error = 0;
3565 | toxav_call_control(av, num, TOXAV_CALL_CONTROL_CANCEL, &error);
3566 | global_video_active = 0;
3567 | global_send_first_frame = 0;
3568 | friend_to_send_video_to = -1;
3569 | }
3570 |
3571 |
3572 | // ------------------ Tox AV stuff --------------------
3573 | // ------------------ Tox AV stuff --------------------
3574 | // ------------------ Tox AV stuff --------------------
3575 |
3576 |
3577 |
3578 | // ------------------ YUV420 overlay hack -------------
3579 | // ------------------ YUV420 overlay hack -------------
3580 | // ------------------ YUV420 overlay hack -------------
3581 |
3582 |
3583 |
3584 |
3585 | /**
3586 | * 8x8 monochrome bitmap fonts for rendering
3587 | * Author: Daniel Hepper
3588 | *
3589 | * License: Public Domain
3590 | *
3591 | * Based on:
3592 | * // Summary: font8x8.h
3593 | * // 8x8 monochrome bitmap fonts for rendering
3594 | * //
3595 | * // Author:
3596 | * // Marcel Sondaar
3597 | * // International Business Machines (public domain VGA fonts)
3598 | * //
3599 | * // License:
3600 | * // Public Domain
3601 | *
3602 | * Fetched from: http://dimensionalrift.homelinux.net/combuster/mos3/?p=viewsource&file=/modules/gfx/font8_8.asm
3603 | **/
3604 |
3605 | // Constant: font8x8_basic
3606 | // Contains an 8x8 font map for unicode points U+0000 - U+007F (basic latin)
3607 | char font8x8_basic[128][8] =
3608 | {
3609 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0000 (nul)
3610 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0001
3611 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0002
3612 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0003
3613 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0004
3614 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0005
3615 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0006
3616 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0007
3617 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0008
3618 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0009
3619 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000A
3620 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000B
3621 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000C
3622 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000D
3623 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000E
3624 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000F
3625 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0010
3626 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0011
3627 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0012
3628 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0013
3629 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0014
3630 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0015
3631 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0016
3632 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0017
3633 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0018
3634 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0019
3635 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001A
3636 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001B
3637 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001C
3638 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001D
3639 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001E
3640 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001F
3641 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0020 (space)
3642 | { 0x18, 0x3C, 0x3C, 0x18, 0x18, 0x00, 0x18, 0x00}, // U+0021 (!)
3643 | { 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0022 (")
3644 | { 0x36, 0x36, 0x7F, 0x36, 0x7F, 0x36, 0x36, 0x00}, // U+0023 (#)
3645 | { 0x0C, 0x3E, 0x03, 0x1E, 0x30, 0x1F, 0x0C, 0x00}, // U+0024 ($)
3646 | { 0x00, 0x63, 0x33, 0x18, 0x0C, 0x66, 0x63, 0x00}, // U+0025 (%)
3647 | { 0x1C, 0x36, 0x1C, 0x6E, 0x3B, 0x33, 0x6E, 0x00}, // U+0026 (&)
3648 | { 0x06, 0x06, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0027 (')
3649 | { 0x18, 0x0C, 0x06, 0x06, 0x06, 0x0C, 0x18, 0x00}, // U+0028 (()
3650 | { 0x06, 0x0C, 0x18, 0x18, 0x18, 0x0C, 0x06, 0x00}, // U+0029 ())
3651 | { 0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00}, // U+002A (*)
3652 | { 0x00, 0x0C, 0x0C, 0x3F, 0x0C, 0x0C, 0x00, 0x00}, // U+002B (+)
3653 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x06}, // U+002C (,)
3654 | { 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00}, // U+002D (-)
3655 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x00}, // U+002E (.)
3656 | { 0x60, 0x30, 0x18, 0x0C, 0x06, 0x03, 0x01, 0x00}, // U+002F (/)
3657 | { 0x3E, 0x63, 0x73, 0x7B, 0x6F, 0x67, 0x3E, 0x00}, // U+0030 (0)
3658 | { 0x0C, 0x0E, 0x0C, 0x0C, 0x0C, 0x0C, 0x3F, 0x00}, // U+0031 (1)
3659 | { 0x1E, 0x33, 0x30, 0x1C, 0x06, 0x33, 0x3F, 0x00}, // U+0032 (2)
3660 | { 0x1E, 0x33, 0x30, 0x1C, 0x30, 0x33, 0x1E, 0x00}, // U+0033 (3)
3661 | { 0x38, 0x3C, 0x36, 0x33, 0x7F, 0x30, 0x78, 0x00}, // U+0034 (4)
3662 | { 0x3F, 0x03, 0x1F, 0x30, 0x30, 0x33, 0x1E, 0x00}, // U+0035 (5)
3663 | { 0x1C, 0x06, 0x03, 0x1F, 0x33, 0x33, 0x1E, 0x00}, // U+0036 (6)
3664 | { 0x3F, 0x33, 0x30, 0x18, 0x0C, 0x0C, 0x0C, 0x00}, // U+0037 (7)
3665 | { 0x1E, 0x33, 0x33, 0x1E, 0x33, 0x33, 0x1E, 0x00}, // U+0038 (8)
3666 | { 0x1E, 0x33, 0x33, 0x3E, 0x30, 0x18, 0x0E, 0x00}, // U+0039 (9)
3667 | { 0x00, 0x0C, 0x0C, 0x00, 0x00, 0x0C, 0x0C, 0x00}, // U+003A (:)
3668 | { 0x00, 0x0C, 0x0C, 0x00, 0x00, 0x0C, 0x0C, 0x06}, // U+003B (//)
3669 | { 0x18, 0x0C, 0x06, 0x03, 0x06, 0x0C, 0x18, 0x00}, // U+003C (<)
3670 | { 0x00, 0x00, 0x3F, 0x00, 0x00, 0x3F, 0x00, 0x00}, // U+003D (=)
3671 | { 0x06, 0x0C, 0x18, 0x30, 0x18, 0x0C, 0x06, 0x00}, // U+003E (>)
3672 | { 0x1E, 0x33, 0x30, 0x18, 0x0C, 0x00, 0x0C, 0x00}, // U+003F (?)
3673 | { 0x3E, 0x63, 0x7B, 0x7B, 0x7B, 0x03, 0x1E, 0x00}, // U+0040 (@)
3674 | { 0x0C, 0x1E, 0x33, 0x33, 0x3F, 0x33, 0x33, 0x00}, // U+0041 (A)
3675 | { 0x3F, 0x66, 0x66, 0x3E, 0x66, 0x66, 0x3F, 0x00}, // U+0042 (B)
3676 | { 0x3C, 0x66, 0x03, 0x03, 0x03, 0x66, 0x3C, 0x00}, // U+0043 (C)
3677 | { 0x1F, 0x36, 0x66, 0x66, 0x66, 0x36, 0x1F, 0x00}, // U+0044 (D)
3678 | { 0x7F, 0x46, 0x16, 0x1E, 0x16, 0x46, 0x7F, 0x00}, // U+0045 (E)
3679 | { 0x7F, 0x46, 0x16, 0x1E, 0x16, 0x06, 0x0F, 0x00}, // U+0046 (F)
3680 | { 0x3C, 0x66, 0x03, 0x03, 0x73, 0x66, 0x7C, 0x00}, // U+0047 (G)
3681 | { 0x33, 0x33, 0x33, 0x3F, 0x33, 0x33, 0x33, 0x00}, // U+0048 (H)
3682 | { 0x1E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // U+0049 (I)
3683 | { 0x78, 0x30, 0x30, 0x30, 0x33, 0x33, 0x1E, 0x00}, // U+004A (J)
3684 | { 0x67, 0x66, 0x36, 0x1E, 0x36, 0x66, 0x67, 0x00}, // U+004B (K)
3685 | { 0x0F, 0x06, 0x06, 0x06, 0x46, 0x66, 0x7F, 0x00}, // U+004C (L)
3686 | { 0x63, 0x77, 0x7F, 0x7F, 0x6B, 0x63, 0x63, 0x00}, // U+004D (M)
3687 | { 0x63, 0x67, 0x6F, 0x7B, 0x73, 0x63, 0x63, 0x00}, // U+004E (N)
3688 | { 0x1C, 0x36, 0x63, 0x63, 0x63, 0x36, 0x1C, 0x00}, // U+004F (O)
3689 | { 0x3F, 0x66, 0x66, 0x3E, 0x06, 0x06, 0x0F, 0x00}, // U+0050 (P)
3690 | { 0x1E, 0x33, 0x33, 0x33, 0x3B, 0x1E, 0x38, 0x00}, // U+0051 (Q)
3691 | { 0x3F, 0x66, 0x66, 0x3E, 0x36, 0x66, 0x67, 0x00}, // U+0052 (R)
3692 | { 0x1E, 0x33, 0x07, 0x0E, 0x38, 0x33, 0x1E, 0x00}, // U+0053 (S)
3693 | { 0x3F, 0x2D, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // U+0054 (T)
3694 | { 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x3F, 0x00}, // U+0055 (U)
3695 | { 0x33, 0x33, 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x00}, // U+0056 (V)
3696 | { 0x63, 0x63, 0x63, 0x6B, 0x7F, 0x77, 0x63, 0x00}, // U+0057 (W)
3697 | { 0x63, 0x63, 0x36, 0x1C, 0x1C, 0x36, 0x63, 0x00}, // U+0058 (X)
3698 | { 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x0C, 0x1E, 0x00}, // U+0059 (Y)
3699 | { 0x7F, 0x63, 0x31, 0x18, 0x4C, 0x66, 0x7F, 0x00}, // U+005A (Z)
3700 | { 0x1E, 0x06, 0x06, 0x06, 0x06, 0x06, 0x1E, 0x00}, // U+005B ([)
3701 | { 0x03, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x40, 0x00}, // U+005C (\)
3702 | { 0x1E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1E, 0x00}, // U+005D (])
3703 | { 0x08, 0x1C, 0x36, 0x63, 0x00, 0x00, 0x00, 0x00}, // U+005E (^)
3704 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF}, // U+005F (_)
3705 | { 0x0C, 0x0C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0060 (`)
3706 | { 0x00, 0x00, 0x1E, 0x30, 0x3E, 0x33, 0x6E, 0x00}, // U+0061 (a)
3707 | { 0x07, 0x06, 0x06, 0x3E, 0x66, 0x66, 0x3B, 0x00}, // U+0062 (b)
3708 | { 0x00, 0x00, 0x1E, 0x33, 0x03, 0x33, 0x1E, 0x00}, // U+0063 (c)
3709 | { 0x38, 0x30, 0x30, 0x3e, 0x33, 0x33, 0x6E, 0x00}, // U+0064 (d)
3710 | { 0x00, 0x00, 0x1E, 0x33, 0x3f, 0x03, 0x1E, 0x00}, // U+0065 (e)
3711 | { 0x1C, 0x36, 0x06, 0x0f, 0x06, 0x06, 0x0F, 0x00}, // U+0066 (f)
3712 | { 0x00, 0x00, 0x6E, 0x33, 0x33, 0x3E, 0x30, 0x1F}, // U+0067 (g)
3713 | { 0x07, 0x06, 0x36, 0x6E, 0x66, 0x66, 0x67, 0x00}, // U+0068 (h)
3714 | { 0x0C, 0x00, 0x0E, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // U+0069 (i)
3715 | { 0x30, 0x00, 0x30, 0x30, 0x30, 0x33, 0x33, 0x1E}, // U+006A (j)
3716 | { 0x07, 0x06, 0x66, 0x36, 0x1E, 0x36, 0x67, 0x00}, // U+006B (k)
3717 | { 0x0E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // U+006C (l)
3718 | { 0x00, 0x00, 0x33, 0x7F, 0x7F, 0x6B, 0x63, 0x00}, // U+006D (m)
3719 | { 0x00, 0x00, 0x1F, 0x33, 0x33, 0x33, 0x33, 0x00}, // U+006E (n)
3720 | { 0x00, 0x00, 0x1E, 0x33, 0x33, 0x33, 0x1E, 0x00}, // U+006F (o)
3721 | { 0x00, 0x00, 0x3B, 0x66, 0x66, 0x3E, 0x06, 0x0F}, // U+0070 (p)
3722 | { 0x00, 0x00, 0x6E, 0x33, 0x33, 0x3E, 0x30, 0x78}, // U+0071 (q)
3723 | { 0x00, 0x00, 0x3B, 0x6E, 0x66, 0x06, 0x0F, 0x00}, // U+0072 (r)
3724 | { 0x00, 0x00, 0x3E, 0x03, 0x1E, 0x30, 0x1F, 0x00}, // U+0073 (s)
3725 | { 0x08, 0x0C, 0x3E, 0x0C, 0x0C, 0x2C, 0x18, 0x00}, // U+0074 (t)
3726 | { 0x00, 0x00, 0x33, 0x33, 0x33, 0x33, 0x6E, 0x00}, // U+0075 (u)
3727 | { 0x00, 0x00, 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x00}, // U+0076 (v)
3728 | { 0x00, 0x00, 0x63, 0x6B, 0x7F, 0x7F, 0x36, 0x00}, // U+0077 (w)
3729 | { 0x00, 0x00, 0x63, 0x36, 0x1C, 0x36, 0x63, 0x00}, // U+0078 (x)
3730 | { 0x00, 0x00, 0x33, 0x33, 0x33, 0x3E, 0x30, 0x1F}, // U+0079 (y)
3731 | { 0x00, 0x00, 0x3F, 0x19, 0x0C, 0x26, 0x3F, 0x00}, // U+007A (z)
3732 | { 0x38, 0x0C, 0x0C, 0x07, 0x0C, 0x0C, 0x38, 0x00}, // U+007B ({)
3733 | { 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00}, // U+007C (|)
3734 | { 0x07, 0x0C, 0x0C, 0x38, 0x0C, 0x0C, 0x07, 0x00}, // U+007D (})
3735 | { 0x6E, 0x3B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+007E (~)
3736 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} // U+007F
3737 | };
3738 |
3739 |
3740 |
3741 | // "0" -> [48]
3742 | // "9" -> [57]
3743 | // ":" -> [58]
3744 |
3745 |
3746 | void print_font_char(int start_x_pix, int start_y_pix, int font_char_num, uint8_t col_value)
3747 | {
3748 | int font_w = 8;
3749 | int font_h = 8;
3750 | uint8_t *y_plane = av_video_frame.y;
3751 | // uint8_t col_value = 0; // black
3752 | char *bitmap = font8x8_basic[font_char_num];
3753 | int k;
3754 | int j;
3755 | int offset = 0;
3756 | int set = 0;
3757 |
3758 | for (k = 0; k < font_h; k++)
3759 | {
3760 | y_plane = av_video_frame.y + ((start_y_pix + k) * av_video_frame.w);
3761 | y_plane = y_plane + start_x_pix;
3762 |
3763 | for (j = 0; j < font_w; j++)
3764 | {
3765 | set = bitmap[k] & 1 << j;
3766 |
3767 | if (set)
3768 | {
3769 | *y_plane = col_value; // set luma value
3770 | }
3771 |
3772 | y_plane = y_plane + 1;
3773 | }
3774 | }
3775 | }
3776 |
3777 | void black_yuf_frame_xy()
3778 | {
3779 | const uint8_t r = 0;
3780 | const uint8_t g = 0;
3781 | const uint8_t b = 0;
3782 | left_top_bar_into_yuv_frame(0, 0, av_video_frame.w, av_video_frame.h, r, g, b);
3783 | }
3784 |
3785 | void blinking_dot_on_frame_xy(int start_x_pix, int start_y_pix, int *state)
3786 | {
3787 | uint8_t r;
3788 | uint8_t g;
3789 | uint8_t b;
3790 |
3791 | if (*state == 0)
3792 | {
3793 | *state = 1;
3794 | r = 255;
3795 | g = 0;
3796 | b = 0;
3797 | left_top_bar_into_yuv_frame(start_x_pix, start_y_pix, 30, 30, r, g, b);
3798 | }
3799 | else if (*state == 1)
3800 | {
3801 | r = 255;
3802 | g = 255;
3803 | b = 0;
3804 | *state = 2;
3805 | left_top_bar_into_yuv_frame(start_x_pix, start_y_pix, 30, 30, r, g, b);
3806 | }
3807 | else
3808 | {
3809 | r = 0;
3810 | g = 255;
3811 | b = 0;
3812 | *state = 0;
3813 | left_top_bar_into_yuv_frame(start_x_pix, start_y_pix, 30, 30, r, g, b);
3814 | }
3815 | }
3816 |
3817 |
3818 | void set_color_in_yuv_frame_xy(uint8_t *yuv_frame, int px_x, int px_y, int frame_w, int frame_h, uint8_t r, uint8_t g,
3819 | uint8_t b)
3820 | {
3821 | int size_total = frame_w * frame_h;
3822 | uint8_t y;
3823 | uint8_t u;
3824 | uint8_t v;
3825 | rbg_to_yuv(r, g, b, &y, &u, &v);
3826 | yuv_frame[px_y * frame_w + px_x] = y;
3827 | yuv_frame[(px_y / 2) * (frame_w / 2) + (px_x / 2) + size_total] = u;
3828 | yuv_frame[(px_y / 2) * (frame_w / 2) + (px_x / 2) + size_total + (size_total / 4)] = v;
3829 | }
3830 |
3831 |
3832 |
3833 | #define CLIP(X) ( (X) > 255 ? 255 : (X) < 0 ? 0 : X)
3834 |
3835 | // RGB -> YUV
3836 | #define RGB2Y(R, G, B) CLIP(( ( 66 * (R) + 129 * (G) + 25 * (B) + 128) >> 8) + 16)
3837 | #define RGB2U(R, G, B) CLIP(( ( -38 * (R) - 74 * (G) + 112 * (B) + 128) >> 8) + 128)
3838 | #define RGB2V(R, G, B) CLIP(( ( 112 * (R) - 94 * (G) - 18 * (B) + 128) >> 8) + 128)
3839 |
3840 | // YUV -> RGB
3841 | #define C(Y) ( (Y) - 16 )
3842 | #define D(U) ( (U) - 128 )
3843 | #define E(V) ( (V) - 128 )
3844 |
3845 | #define YUV2R(Y, U, V) CLIP(( 298 * C(Y) + 409 * E(V) + 128) >> 8)
3846 | #define YUV2G(Y, U, V) CLIP(( 298 * C(Y) - 100 * D(U) - 208 * E(V) + 128) >> 8)
3847 | #define YUV2B(Y, U, V) CLIP(( 298 * C(Y) + 516 * D(U) + 128) >> 8)
3848 |
3849 | void rbg_to_yuv(uint8_t r, uint8_t g, uint8_t b, uint8_t *y, uint8_t *u, uint8_t *v)
3850 | {
3851 | *y = RGB2Y(r, g, b);
3852 | *u = RGB2U(r, g, b);
3853 | *v = RGB2V(r, g, b);
3854 | }
3855 |
3856 | void text_on_yuf_frame_xy(int start_x_pix, int start_y_pix, const char *text)
3857 | {
3858 | int carriage = 0;
3859 | const int letter_width = 8;
3860 | const int letter_spacing = 1;
3861 | int block_needed_width = 2 + 2 + (strlen(text) * (letter_width + letter_spacing));
3862 | left_top_bar_into_yuv_frame(start_x_pix, start_y_pix, block_needed_width, 12, 255, 255, 255);
3863 | int looper;
3864 |
3865 | for (looper = 0; (int)looper < (int)strlen(text); looper++)
3866 | {
3867 | uint8_t c = text[looper];
3868 |
3869 | if ((c > 0) && (c < 127))
3870 | {
3871 | print_font_char((12 + ((letter_width + letter_spacing) * carriage)), 12, c, 0);
3872 | }
3873 | else
3874 | {
3875 | // leave a blank
3876 | }
3877 |
3878 | carriage++;
3879 | }
3880 | }
3881 |
3882 | void left_top_bar_into_yuv_frame(int bar_start_x_pix, int bar_start_y_pix, int bar_w_pix, int bar_h_pix, uint8_t r,
3883 | uint8_t g, uint8_t b)
3884 | {
3885 | // int bar_width = bar_w_pix; // 150; // should be mulitple of 2 !!
3886 | // int bar_height = bar_h_pix; // 20; // should be mulitple of 2 !!
3887 | // int bar_start_x = bar_start_x_pix; // 10; // should be mulitple of 2 !! (zero is also ok)
3888 | // int bar_start_y = bar_start_y_pix; // 10; // should be mulitple of 2 !! (zero is also ok)
3889 | // uint8_t *y_plane = av_video_frame.y;
3890 | int k;
3891 | int j;
3892 | // int offset = 0;
3893 |
3894 | for (k = 0; k < bar_h_pix; k++)
3895 | {
3896 | // y_plane = av_video_frame.y + ((bar_start_y + k) * av_video_frame.w);
3897 | // y_plane = y_plane + bar_start_x;
3898 | for (j = 0; j < bar_w_pix; j++)
3899 | {
3900 | // ******** // *y_plane = col_value; // luma value to 255 (white)
3901 | set_color_in_yuv_frame_xy(av_video_frame.y, (bar_start_x_pix + j), (bar_start_y_pix + k),
3902 | av_video_frame.w, av_video_frame.h, r, g, b);
3903 | // y_plane = y_plane + 1;
3904 | }
3905 | }
3906 | }
3907 |
3908 | // ------------------ YUV420 overlay hack -------------
3909 | // ------------------ YUV420 overlay hack -------------
3910 | // ------------------ YUV420 overlay hack -------------
3911 |
3912 |
3913 |
3914 | // ------------------ alsa recording ------------------
3915 | // ------------------ alsa recording ------------------
3916 | // ------------------ alsa recording ------------------
3917 |
3918 | #ifdef HAVE_SOUND
3919 |
3920 |
3921 | short audio_buf[128];
3922 | snd_pcm_t *audio_capture_handle;
3923 | // const char *audio_device = "plughw:0,0";
3924 | // const char *audio_device = "hw:CARD=U0x46d0x991,DEV=0";
3925 | const char *audio_device = "default";
3926 | // sysdefault:CARD
3927 |
3928 | void record_from_sound_device()
3929 | {
3930 | int i;
3931 | int err;
3932 |
3933 | for (i = 0; i < 10; ++i)
3934 | {
3935 | if ((err = snd_pcm_readi(audio_capture_handle, audio_buf, 128)) != 128)
3936 | {
3937 | dbg(9, "read from audio interface failed (%s)\n", snd_strerror(err));
3938 | }
3939 | }
3940 | }
3941 |
3942 | void close_sound_device()
3943 | {
3944 | snd_pcm_close(audio_capture_handle);
3945 | }
3946 |
3947 | void init_sound_device()
3948 | {
3949 | int i;
3950 | int err;
3951 | snd_pcm_hw_params_t *hw_params;
3952 |
3953 | if ((err = snd_pcm_open(&audio_capture_handle, audio_device, SND_PCM_STREAM_CAPTURE, 0)) < 0)
3954 | {
3955 | dbg(9, "cannot open audio device %s (%s)\n",
3956 | audio_device,
3957 | snd_strerror(err));
3958 | //exit (1);
3959 | }
3960 |
3961 | if ((err = snd_pcm_hw_params_malloc(&hw_params)) < 0)
3962 | {
3963 | dbg(9, "cannot allocate hardware parameter structure (%s)\n",
3964 | snd_strerror(err));
3965 | //exit (1);
3966 | }
3967 |
3968 | if ((err = snd_pcm_hw_params_any(audio_capture_handle, hw_params)) < 0)
3969 | {
3970 | dbg(9, "cannot initialize hardware parameter structure (%s)\n",
3971 | snd_strerror(err));
3972 | //exit (1);
3973 | }
3974 |
3975 | if ((err = snd_pcm_hw_params_set_access(audio_capture_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0)
3976 | {
3977 | dbg(9, "cannot set access type (%s)\n",
3978 | snd_strerror(err));
3979 | //exit (1);
3980 | }
3981 |
3982 | if ((err = snd_pcm_hw_params_set_format(audio_capture_handle, hw_params, SND_PCM_FORMAT_S16_LE)) < 0)
3983 | {
3984 | dbg(9, "cannot set sample format (%s)\n",
3985 | snd_strerror(err));
3986 | //exit (1);
3987 | }
3988 |
3989 | unsigned int actualRate = 44100;
3990 | dbg(9, "sound: wanted audio rate:%d\n", actualRate);
3991 |
3992 | if ((err = snd_pcm_hw_params_set_rate_near(audio_capture_handle, hw_params, &actualRate, 0)) < 0)
3993 | {
3994 | dbg(9, "cannot set sample rate (%s)\n",
3995 | snd_strerror(err));
3996 | //exit (1);
3997 | }
3998 |
3999 | dbg(9, "sound: got audio rate:%d\n", actualRate);
4000 |
4001 | // 1 -> mono, 2 -> stereo
4002 | if ((err = snd_pcm_hw_params_set_channels(audio_capture_handle, hw_params, 1)) < 0)
4003 | {
4004 | dbg(9, "cannot set channel count (%s)\n",
4005 | snd_strerror(err));
4006 | //exit (1);
4007 | }
4008 |
4009 | if ((err = snd_pcm_hw_params(audio_capture_handle, hw_params)) < 0)
4010 | {
4011 | dbg(9, "cannot set parameters (%s)\n",
4012 | snd_strerror(err));
4013 | //exit (1);
4014 | }
4015 |
4016 | snd_pcm_hw_params_free(hw_params);
4017 |
4018 | if ((err = snd_pcm_prepare(audio_capture_handle)) < 0)
4019 | {
4020 | dbg(9, "cannot prepare audio interface for use (%s)\n",
4021 | snd_strerror(err));
4022 | //exit (1);
4023 | }
4024 | }
4025 |
4026 | #endif
4027 |
4028 | // ------------------ alsa recording ------------------
4029 | // ------------------ alsa recording ------------------
4030 | // ------------------ alsa recording ------------------
4031 |
4032 |
4033 | void sigint_handler(int signo)
4034 | {
4035 | if (signo == SIGINT)
4036 | {
4037 | printf("received SIGINT, pid=%d\n", getpid());
4038 | tox_loop_running = 0;
4039 | }
4040 | }
4041 |
4042 | int main(int argc, char *argv[])
4043 | {
4044 | global_want_restart = 0;
4045 | global_video_active = 0;
4046 | global_send_first_frame = 0;
4047 | my_last_offline_timestamp = -1;
4048 | my_last_online_timestamp = -1;
4049 | // valid audio bitrates: [ bit_rate < 6 || bit_rate > 510 ]
4050 | global_audio_bit_rate = DEFAULT_GLOBAL_AUD_BITRATE;
4051 | global_video_bit_rate = DEFAULT_GLOBAL_VID_BITRATE;
4052 | video_high = 0;
4053 | logfile = fopen(log_filename, "wb");
4054 | setvbuf(logfile, NULL, _IONBF, 0);
4055 | v4l2_device = malloc(400);
4056 | memset(v4l2_device, 0, 400);
4057 | snprintf(v4l2_device, 399, "%s", "/dev/video0");
4058 | int aflag = 0;
4059 | char *cvalue = NULL;
4060 | int index;
4061 | int opt;
4062 | const char *short_opt = "hvd:tT23b:fq:";
4063 | struct option long_opt[] =
4064 | {
4065 | {"help", no_argument, NULL, 'h'},
4066 | {"version", no_argument, NULL, 'v'},
4067 | {"videodevice", required_argument, NULL, 'd'},
4068 | {NULL, 0, NULL, 0 }
4069 | };
4070 |
4071 | while ((opt = getopt_long(argc, argv, short_opt, long_opt, NULL)) != -1)
4072 | {
4073 | switch (opt)
4074 | {
4075 | case -1: /* no more arguments */
4076 | case 0: /* long options toggles */
4077 | break;
4078 |
4079 | case 'a':
4080 | aflag = 1;
4081 | break;
4082 |
4083 | case '2':
4084 | switch_nodelist_2 = 1;
4085 | break;
4086 |
4087 | case '3':
4088 | switch_nodelist_2 = 2;
4089 | break;
4090 |
4091 | case 't':
4092 | switch_tcponly = 1;
4093 | break;
4094 |
4095 | case 'T':
4096 | use_tor = 1;
4097 | break;
4098 |
4099 | case 'f':
4100 | video_high = 1;
4101 | break;
4102 |
4103 | case 'q':
4104 | RC_MAX_QUANTIZER = (int32_t)atoi(optarg);
4105 | dbg(3, "Using max quantizer: %d\n", (int)RC_MAX_QUANTIZER);
4106 | break;
4107 |
4108 | case 'd':
4109 | snprintf(v4l2_device, 399, "%s", optarg);
4110 | // printf("Using Videodevice: %s\n", v4l2_device);
4111 | dbg(3, "Using Videodevice: %s\n", v4l2_device);
4112 | break;
4113 |
4114 | case 'b':
4115 | DEFAULT_GLOBAL_VID_BITRATE = (uint32_t)atoi(optarg);
4116 | dbg(3, "Using Videobitrate: %d\n", (int)DEFAULT_GLOBAL_VID_BITRATE);
4117 | global_video_bit_rate = DEFAULT_GLOBAL_VID_BITRATE;
4118 | break;
4119 |
4120 | case 'v':
4121 | printf("ToxCam version: %s\n", global_version_string);
4122 |
4123 | if (logfile)
4124 | {
4125 | fclose(logfile);
4126 | logfile = NULL;
4127 | }
4128 |
4129 | return (0);
4130 | break;
4131 |
4132 | case 'h':
4133 | printf("Usage: %s [OPTIONS]\n", argv[0]);
4134 | printf(" -d, --videodevice devicefile file\n");
4135 | printf(" -b bitrate video bitrate in kbit/s\n");
4136 | printf(" -q quality 20 - 65 (20 is super high)\n");
4137 | printf(" -f use 720p video mode\n");
4138 | printf(" -t, tcp only mode\n");
4139 | printf(" -T, use TOR as Relay\n");
4140 | printf(" -2, use alternate bootnode list\n");
4141 | printf(" -3, use only nodes.tox.chat as bootnode\n");
4142 | printf(" -v, --version show version\n");
4143 | printf(" -h, --help print this help and exit\n");
4144 | printf("\n");
4145 |
4146 | if (logfile)
4147 | {
4148 | fclose(logfile);
4149 | logfile = NULL;
4150 | }
4151 |
4152 | return (0);
4153 |
4154 | case ':':
4155 | case '?':
4156 | fprintf(stderr, "Try `%s --help' for more information.\n", argv[0]);
4157 |
4158 | if (logfile)
4159 | {
4160 | fclose(logfile);
4161 | logfile = NULL;
4162 | }
4163 |
4164 | return (-2);
4165 |
4166 | default:
4167 | fprintf(stderr, "%s: invalid option -- %c\n", argv[0], opt);
4168 | fprintf(stderr, "Try `%s --help' for more information.\n", argv[0]);
4169 |
4170 | if (logfile)
4171 | {
4172 | fclose(logfile);
4173 | logfile = NULL;
4174 | }
4175 |
4176 | return (-2);
4177 | }
4178 | }
4179 |
4180 | Tox *tox = create_tox();
4181 | global_start_time = time(NULL);
4182 | const char *name = "ToxCam";
4183 | tox_self_set_name(tox, (uint8_t *)name, strlen(name), NULL);
4184 | const char *status_message = "This is your ToxCam";
4185 | tox_self_set_status_message(tox, (uint8_t *)status_message, strlen(status_message), NULL);
4186 | Friends.max_idx = 0;
4187 | bootstrap(tox);
4188 | print_tox_id(tox);
4189 | // init callbacks ----------------------------------
4190 | tox_callback_friend_request(tox, friend_request_cb);
4191 | tox_callback_friend_message(tox, friend_message_cb);
4192 | tox_callback_friend_status(tox, on_tox_friend_status);
4193 | tox_callback_self_connection_status(tox, self_connection_status_cb);
4194 | tox_callback_file_chunk_request(tox, on_file_chunk_request);
4195 | tox_callback_file_recv_control(tox, on_file_control);
4196 | tox_callback_file_recv(tox, on_file_recv);
4197 | tox_callback_file_recv_chunk(tox, on_file_recv_chunk);
4198 | // init callbacks ----------------------------------
4199 | // init toxutil callbacks ----------------------------------
4200 | #ifdef TOX_HAVE_TOXUTIL
4201 | tox_utils_callback_friend_connection_status(tox, friendlist_onConnectionChange);
4202 | tox_callback_friend_connection_status(tox, tox_utils_friend_connection_status_cb);
4203 | tox_callback_friend_lossless_packet(tox, tox_utils_friend_lossless_packet_cb);
4204 | #else
4205 | tox_callback_friend_connection_status(tox, friendlist_onConnectionChange);
4206 | #endif
4207 | // init toxutil callbacks ----------------------------------
4208 | update_savedata_file(tox);
4209 | load_friendlist(tox);
4210 | char path[300];
4211 | snprintf(path, sizeof(path), "%s", my_avatar_filename);
4212 | int len = strlen(path) - 1;
4213 | avatar_set(tox, path, len);
4214 | // -------- try to go online --------
4215 | long long unsigned int cur_time = time(NULL);
4216 | uint8_t off = 1;
4217 | long long loop_counter = 0;
4218 |
4219 | while (1)
4220 | {
4221 | tox_iterate(tox, NULL);
4222 | usleep(tox_iteration_interval(tox) * 1000);
4223 |
4224 | if (tox_self_get_connection_status(tox) && off)
4225 | {
4226 | dbg(2, "Tox online, took %llu seconds\n", time(NULL) - cur_time);
4227 | off = 0;
4228 | break;
4229 | }
4230 |
4231 | c_sleep(20);
4232 | loop_counter++;
4233 |
4234 | if (loop_counter > (50 * 20))
4235 | {
4236 | loop_counter = 0;
4237 | // if not yet online, bootstrap every 20 seconds
4238 | dbg(2, "Tox NOT online yet, bootstrapping again\n");
4239 | bootstrap(tox);
4240 | }
4241 | }
4242 |
4243 | // -------- try to go online --------
4244 | TOXAV_ERR_NEW rc;
4245 | dbg(2, "new Tox AV\n");
4246 | mytox_av = toxav_new(tox, &rc);
4247 |
4248 | if (rc != TOXAV_ERR_NEW_OK)
4249 | {
4250 | dbg(0, "Error at toxav_new: %d\n", rc);
4251 | }
4252 |
4253 | CallControl mytox_CC;
4254 | memset(&mytox_CC, 0, sizeof(CallControl));
4255 | // init AV callbacks -------------------------------
4256 | toxav_callback_call(mytox_av, t_toxav_call_cb, &mytox_CC);
4257 | toxav_callback_call_state(mytox_av, t_toxav_call_state_cb, &mytox_CC);
4258 | //toxav_callback_bit_rate_status(mytox_av, t_toxav_bit_rate_status_cb, &mytox_CC);
4259 | toxav_callback_video_receive_frame(mytox_av, t_toxav_receive_video_frame_cb, &mytox_CC);
4260 | toxav_callback_audio_receive_frame(mytox_av, t_toxav_receive_audio_frame_cb, &mytox_CC);
4261 | // init AV callbacks -------------------------------
4262 | // start toxav thread ------------------------------
4263 | pthread_t tid[2]; // 0 -> toxav_iterate thread, 1 -> video send thread
4264 | // start toxav thread ------------------------------
4265 | toxav_iterate_thread_stop = 0;
4266 |
4267 | if (pthread_create(&(tid[0]), NULL, thread_av, (void *)mytox_av) != 0)
4268 | {
4269 | dbg(0, "AV iterate Thread create failed");
4270 | }
4271 | else
4272 | {
4273 | pthread_setname_np(tid[0], "t_av");
4274 | dbg(2, "AV iterate Thread successfully created");
4275 | }
4276 |
4277 | toxav_video_thread_stop = 0;
4278 |
4279 | if (pthread_create(&(tid[1]), NULL, thread_video_av, (void *)mytox_av) != 0)
4280 | {
4281 | dbg(0, "AV video Thread create failed");
4282 | }
4283 | else
4284 | {
4285 | dbg(2, "AV video Thread successfully created");
4286 | pthread_setname_np(tid[1], "t_video_av");
4287 | }
4288 |
4289 | // start toxav thread ------------------------------
4290 | // start audio recoding stuff ----------------------
4291 | #ifdef HAVE_SOUND
4292 | init_sound_device();
4293 | record_from_sound_device();
4294 | close_sound_device();
4295 | #endif
4296 | // start audio recoding stuff ----------------------
4297 | tox_loop_running = 1;
4298 | signal(SIGINT, sigint_handler);
4299 | pthread_setname_np(pthread_self(), "t_main");
4300 |
4301 | while (tox_loop_running)
4302 | {
4303 | tox_iterate(tox, NULL);
4304 | // usleep(tox_iteration_interval(tox) * 1000);
4305 | usleep(5 * 1000); // hardcode to 5ms
4306 | #ifdef CHANGE_NOSPAM_REGULARLY
4307 |
4308 | if ((uint32_t)(global_last_change_nospam_ts + CHANGE_NOSPAM_REGULAR_INTERVAL_SECS) < (uint32_t)get_unix_time())
4309 | {
4310 | change_nospam_to_new_random_value(tox);
4311 | }
4312 |
4313 | #endif
4314 |
4315 | if (global_want_restart == 1)
4316 | {
4317 | // need to restart me!
4318 | break;
4319 | }
4320 | else
4321 | {
4322 | check_online_status(tox);
4323 | check_dir(tox);
4324 | check_friends_dir(tox);
4325 | }
4326 | }
4327 |
4328 | kill_all_file_transfers(tox);
4329 | close_cam();
4330 | toxav_kill(mytox_av);
4331 | #ifdef TOX_HAVE_TOXUTIL
4332 | tox_utils_kill(tox);
4333 | #else
4334 | tox_kill(tox);
4335 | #endif
4336 |
4337 | if (logfile)
4338 | {
4339 | fclose(logfile);
4340 | logfile = NULL;
4341 | }
4342 |
4343 | return 0;
4344 | }
4345 |
4346 |
--------------------------------------------------------------------------------
/toxcam/update_from_ci.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | #####################################################
4 | # update toxcam binary from Circle CI (master branch)
5 | #####################################################
6 |
7 | cd $(dirname "$0")
8 |
9 | pkill toxcam_static # will stop toxcam
10 | cp -av toxcam_static toxcam_static__BACKUP
11 | wget -O toxcam_static 'https://circleci.com/api/v1/project/zoff99/ToxCam/latest/artifacts/0/$CIRCLE_ARTIFACTS/RASPI/toxcam_static?filter=successful&branch=master'
12 | chmod u+rwx toxcam_static
13 |
14 |
--------------------------------------------------------------------------------