diff --git a/INSTALL b/INSTALL index 007e9396d0a2492cd2d6e17d42f359655dfe0b5e..2099840756e6302d837dcd51b5dcd6262f7adb16 100644 --- a/INSTALL +++ b/INSTALL @@ -12,8 +12,8 @@ without warranty of any kind. Basic Installation ================== - Briefly, the shell commands `./configure; make; make install' should -configure, build, and install this package. The following + Briefly, the shell command `./configure && make && make install' +should configure, build, and install this package. The following more-detailed instructions are generic; see the `README' file for instructions specific to this package. Some packages provide this `INSTALL' file but do not implement all of the features documented diff --git a/Makefile.am b/Makefile.am index 939db31e1d55e167a55d70579608444b376f082a..aed0bdd4a39d037f25d9e4987b9243750c9a425e 100644 --- a/Makefile.am +++ b/Makefile.am @@ -20,13 +20,7 @@ endif ACLOCAL_AMFLAGS = -I m4 - -#FIXME: this will change when libring is fixed -if HAVE_WIN32 -SUBDIRS = bin -else SUBDIRS = src ringtones man $(TESTS_DIR) doc bin -endif EXTRA_DIST = m4/libtool.m4 \ m4/lt~obsolete.m4 \ diff --git a/bin/Makefile.am b/bin/Makefile.am index 96b12d76efd87a6c1e2930889a545f335815f35c..1d30d435c42108ab2659df9fcd547fa393a1f779 100644 --- a/bin/Makefile.am +++ b/bin/Makefile.am @@ -1,8 +1,10 @@ if HAVE_WIN32 libexec_PROGRAMS = ringcli ringcli_SOURCES = winmain.cpp -#FIXME This is temporary -ringcli_LDADD = $(SPEEX_LIBS) +ringcli_CXXFLAGS = -I$(top_srcdir)/src \ + -I$(top_srcdir)/src/dring \ + -DTOP_BUILDDIR=\"$$(cd "$(top_builddir)"; pwd)\" +ringcli_LDADD = $(top_builddir)/src/libring.la endif if HAVE_OSX diff --git a/bin/winmain.cpp b/bin/winmain.cpp index 6addb4b3854f7103417e33fc4dcff7507589d278..992a7c92a116533e8becbb9f23bec0fba63b399a 100644 --- a/bin/winmain.cpp +++ b/bin/winmain.cpp @@ -1,10 +1,231 @@ -#include <speex/speex.h> -#include <cstdio> -#include <cmath> +/* + * Copyright (C) 2004-2015 Savoir-Faire Linux Inc. + * Author: Edric Milaret <edric.ladent-milaret@savoirfairelinux.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Additional permission under GNU GPL version 3 section 7: + * + * If you modify this program, or any covered work, by linking or + * combining it with the OpenSSL project's OpenSSL library (or a + * modified version of that library), containing parts covered by the + * terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc. + * grants you additional permission to convey the resulting work. + * Corresponding Source for a non-source form of such a combination + * shall include the source code for the parts of OpenSSL used as well + * as that of the covered work. + */ -int main() +#include <iostream> +#include <thread> +#include <cstring> +#include <signal.h> +#include <getopt.h> +#include <string> + +#include "dring.h" +#include "callmanager_interface.h" +#include "configurationmanager_interface.h" +#include "presencemanager_interface.h" +#ifdef RING_VIDEO +#include "videomanager_interface.h" +#endif +#include "fileutils.h" + +#include <windows.h> + +using namespace std::placeholders; + +bool isActive = false; +static int ringFlags = 0; +bool loop = true; + +static void +print_title() +{ + std::cout + << "Ring Daemon " << DRing::version() + << ", by Savoir-Faire Linux 2004-2015" << std::endl + << "http://www.ring.cx/" << std::endl; +} + +static void +print_usage() +{ + std::cout << std::endl << + "-c, --console \t- Log in console (instead of syslog)" << std::endl << + "-d, --debug \t- Debug mode (more verbose)" << std::endl << + "-p, --persistent \t- Stay alive after client quits" << std::endl << + "-h, --help \t- Print help" << std::endl; +} + +// Parse command line arguments, setting debug options or printing a help +// message accordingly. +// returns true if we should quit (i.e. help was printed), false otherwise +static bool +parse_args(int argc, char *argv[], bool& persistent) +{ + static const struct option long_options[] = { + /* These options set a flag. */ + {"debug", no_argument, NULL, 'd'}, + {"console", no_argument, NULL, 'c'}, + {"persistent", no_argument, NULL, 'p'}, + {"help", no_argument, NULL, 'h'}, + {"version", no_argument, NULL, 'v'}, + {0, 0, 0, 0} /* Sentinel */ + }; + + int consoleFlag = false; + int debugFlag = false; + int helpFlag = false; + int versionFlag = false; + + while (true) { + /* getopt_long stores the option index here. */ + int option_index = 0; + + auto c = getopt_long(argc, argv, "dcphv", long_options, &option_index); + + // end of the options + if (c == -1) + break; + + switch (c) { + case 'd': + debugFlag = true; + break; + + case 'c': + consoleFlag = true; + break; + + case 'p': + persistent = true; + break; + + case 'h': + case '?': + helpFlag = true; + break; + + case 'v': + versionFlag = true; + break; + + default: + break; + } + } + + if (helpFlag) { + print_usage(); + return true; + } + + if (versionFlag) { + // We've always print the title/version, so we can just exit + return true; + } + + if (consoleFlag) + ringFlags |= DRing::DRING_FLAG_CONSOLE_LOG; + + if (debugFlag) + ringFlags |= DRing::DRING_FLAG_DEBUG; + + return false; +} + +void +IncomingCall(const std::string& accountId, + const std::string& callId, const std::string& message) +{ + if (not isActive) { + DRing::accept(callId); + isActive = true; + } else + DRing::refuse(callId); +} + +static int +run() +{ + using SharedCallback = std::shared_ptr<DRing::CallbackWrapperBase>; + + DRing::init(static_cast<DRing::InitFlag>(ringFlags)); + + std::map<std::string, SharedCallback> callHandlers; + callHandlers.insert(DRing::exportable_callback<DRing::CallSignal::IncomingCall> + (std::bind(&IncomingCall, _1, _2, _3))); + + registerCallHandlers(callHandlers); + + if (!DRing::start()) + return -1; + + while (loop) { + DRing::pollEvents(); + Sleep(1000); // milliseconds + } + + DRing::fini(); +} + +static void +interrupt() { - const SpeexMode *mode = speex_lib_get_mode(SPEEX_MODEID_NB); - printf("Hello %s %f\n", mode->modeName, M_PI); - return 0; + loop = false; +} + +static void +signal_handler(int code) +{ + std::cerr << "Caught signal " << code + << ", terminating..." << std::endl; + // Unset signal handlers + signal(SIGINT, SIG_DFL); + signal(SIGTERM, SIG_DFL); + + interrupt(); +} + +int +main(int argc, char *argv []) +{ + // make a copy as we don't want to modify argv[0], copy it to a vector to + // guarantee that memory is correctly managed/exception safe + std::string programName {argv[0]}; + std::vector<char> writable(programName.size() + 1); + std::copy(std::begin(programName), std::end(programName),std::begin(writable)); + + ring::fileutils::set_program_dir(writable.data()); + + print_title(); + + bool persistent = false; + if (parse_args(argc, argv, persistent)) + return 0; + + // TODO: Block signals for all threads but the main thread, decide how/if we should + // handle other signals + signal(SIGINT, signal_handler); + signal(SIGTERM, signal_handler); + +#ifdef RING_VIDEO + std::cerr << "Warning: built with video support" << std::endl; +#endif + + return run(); } diff --git a/configure.ac b/configure.ac index d8371dbae0474491c96c69df7fde4f7068c80713..4ec4867309cf9cdcb91029ca66f456184182d4ec 100644 --- a/configure.ac +++ b/configure.ac @@ -63,10 +63,6 @@ case "${host_os}" in SYS=mingw32 AC_CHECK_TOOL(WINDRES, windres, :) AC_CHECK_TOOL(OBJCOPY, objcopy, :) - AH_TOP([#if defined(_WIN32) && !defined(_WIN32_WINNT)]) - AH_TOP([# define _WIN32_WINNT 0x0502 /* Windows XP SP2 */]) - AH_TOP([#endif]) - AC_DEFINE([_WIN32_IE], 0x0600, [Define to '0x0600' for IE 6.0 (and shell) APIs.]) AC_DEFINE([_UNICODE], [1], [Define to 1 for Unicode (Wide Chars) APIs.]) AC_DEFINE([UNICODE], [1], [Define to 1 for Unicode (Wide Chars) APIs.]) AC_DEFINE([_ISOC99_SOURCE], [1], [Extensions to ISO C89 from ISO C99.]) @@ -77,8 +73,8 @@ case "${host_os}" in AC_DEFINE([_XOPEN_SOURCE_EXTENDED], [1], [XPG things and X/Open Unix extensions.]) AC_DEFINE([_BSD_SOURCE], [1], [ISO C, POSIX, and 4.3BSD things.]) AC_DEFINE([_SVID_SOURCE], [1], [ISO C, POSIX, and SVID things.]) - - LDFLAGS="${LDFLAGS} -Wl,--nxcompat -Wl,--no-seh -Wl,--dynamicbase" + CPPFLAGS+="-D_WIN32_WINNT=0x0601 -DWINVER=0x0601" + LDFLAGS+="-no-undefined -avoid-version -Wl,--nxcompat -Wl,--dynamicbase" ac_default_prefix="`pwd`/_win32" DESTDIR="`pwd`/_win32/" AC_SUBST(WINDOWS_ARCH) @@ -218,6 +214,11 @@ AS_IF([test -n "${CONTRIB_DIR}"], [ CFLAGS="${CFLAGS} -I${CONTRIB_DIR}/include" CXXFLAGS="${CXXFLAGS} -I${CONTRIB_DIR}/include" OBJCFLAGS="${OBJCFLAGS} -I${CONTRIB_DIR}/include" + AS_IF([test "${SYS}" = "mingw32"],[ + PKG_CONFIG_PATH_CUSTOM="${CONTRIB_DIR}/lib/pkgconfig:${CONTRIB_DIR}/lib64/pkgconfig" + AC_SUBST(PKG_CONFIG_PATH_CUSTOM) + export PKG_CONFIG_PATH_CUSTOM + ]) export PKG_CONFIG_PATH="${CONTRIB_DIR}/lib/pkgconfig:${CONTRIB_DIR}/lib64/pkgconfig:$PKG_CONFIG_PATH" LDFLAGS="${LDFLAGS} -L${CONTRIB_DIR}/lib" @@ -301,6 +302,22 @@ AS_IF([test "x$have_jack" = "xyes"],, ]) ]) +dnl check for libportaudio +AS_IF([test "${SYS}" = "mingw32"],[ +AC_ARG_WITH([portaudio], [AS_HELP_STRING([--without-portaudio], + [disable support for portaudio])], [], [with_portaudio=yes]) + +AS_IF([test "x$with_portaudio" = "xyes"], + [PKG_CHECK_MODULES(PORTAUDIO, [portaudio-2.0], + [AC_DEFINE([HAVE_PORTAUDIO], 1, [Define if you have portaudio])], + [AC_MSG_WARN([Missing libportaudio development files]) + AC_DEFINE([HAVE_PORTAUDIO], 0, [Define if you have portaudio]) + ]) + ]) +]) +AM_CONDITIONAL(BUILD_PORTAUDIO, test "x$with_portaudio" = "xyes") +AM_CONDITIONAL(HAVE_PORTAUDIO, test "x$with_portaudio" = "xyes") + AC_DEFINE_UNQUOTED([HAVE_JACK], `if test "x$have_jack" = "xyes"; then echo 1; else echo 0; fi`, [Define if you have jack]) AM_CONDITIONAL(BUILD_JACK, test "x$have_jack" = "xyes") @@ -572,7 +589,7 @@ dnl debug mode is default-disabled AC_ARG_ENABLE([debug], AS_HELP_STRING([--enable-debug], [Build in debug mode, adds stricter warnings, disables optimization])) AS_IF([test "x$enable_debug" = "xyes"], - [CXXFLAGS="${CXXFLAGS} -g -Wall -Wextra -Wnon-virtual-dtor -O0"]) + [CXXFLAGS="${CXXFLAGS} -g -fno-omit-frame-pointer -Wall -Wextra -Wnon-virtual-dtor -O0"]) dnl What Makefiles to generate @@ -591,6 +608,7 @@ AC_CONFIG_FILES([Makefile \ src/media/audio/opensl/Makefile \ src/media/audio/jack/Makefile \ src/media/audio/coreaudio/Makefile \ + src/media/audio/portaudio/Makefile \ src/media/audio/sound/Makefile \ src/config/Makefile \ src/client/Makefile \ @@ -598,6 +616,7 @@ AC_CONFIG_FILES([Makefile \ src/media/video/Makefile \ src/media/video/v4l2/Makefile \ src/media/video/osxvideo/Makefile \ + src/media/video/winvideo/Makefile \ src/media/video/test/Makefile \ src/upnp/Makefile \ test/Makefile \ diff --git a/contrib/src/ffmpeg/rules.mak b/contrib/src/ffmpeg/rules.mak new file mode 100644 index 0000000000000000000000000000000000000000..7196653acc1617a04e1dcc4eddf0fe4f79fc4f85 --- /dev/null +++ b/contrib/src/ffmpeg/rules.mak @@ -0,0 +1,119 @@ +FFMPEG_HASH := f90c9bbbca32620a9cb78898a2b1b7d2cce9ad0f +FFMPEG_GITURL := https://github.com/FFmpeg/FFmpeg.git + +ifdef HAVE_WIN32 +PKGS += ffmpeg +endif + +FFMPEGCONF = \ + --cc="$(CC)" \ + --pkg-config="$(PKG_CONFIG)" + +#disable everything +FFMPEGCONF += \ + --disable-everything \ + --enable-zlib \ + --enable-gpl \ + --enable-swscale \ + --enable-protocols \ + --disable-programs \ + --disable-sdl + + +#enable muxers/demuxers +FFMPEGCONF += \ + --enable-demuxers \ + --enable-muxers + +#enable parsers +FFMPEGCONF += \ + --enable-parser=h263 \ + --enable-parser=h264 \ + --enable-parser=mpeg4video \ + --enable-parser=vp8 + +#librairies +FFMPEGCONF += \ + --enable-libx264 \ + --enable-libvpx + +#encoders/decoders +FFMPEGCONF += \ + --enable-encoder=adpcm_g722 \ + --enable-decoder=adpcm_g722 \ + --enable-encoder=rawvideo \ + --enable-decoder=rawvideo \ + --enable-encoder=libx264 \ + --enable-decoder=h264 \ + --enable-encoder=pcm_alaw \ + --enable-decoder=pcm_alaw \ + --enable-encoder=pcm_mulaw \ + --enable-decoder=pcm_mulaw \ + --enable-encoder=mpeg4 \ + --enable-decoder=mpeg4 \ + --enable-encoder=libvpx_vp8 \ + --enable-decoder=vp8 \ + --enable-encoder=h263 \ + --enable-decoder=h263 \ + --enable-encoder=mjpeg \ + --enable-decoder=mjpeg \ + --enable-decoder=mjpegb \ + +FFMPEGCONF += \ + --enable-indev=dshow \ + --enable-dxva2 + +# There is an unresolved symbol for speex when linking statically +ifndef HAVE_WIN32 +FFMPEGCONF += \ + --enable-libspeex \ + --enable-libopus \ + --enable-encoder=libspeex \ + --enable-decoder=libspeex +endif + +DEPS_ffmpeg = iconv zlib x264 vpx opus speex $(DEPS_vpx) + +ifdef HAVE_CROSS_COMPILE +FFMPEGCONF += --cross-prefix=$(HOST)- +endif + +# x86 stuff +ifeq ($(ARCH),i386) +FFMPEGCONF += --arch=x86 +endif + +ifeq ($(ARCH),x86_64) +FFMPEGCONF += --arch=x86_64 +endif + +# Windows +ifdef HAVE_WIN32 +FFMPEGCONF += --target-os=mingw32 --enable-memalign-hack +FFMPEGCONF += --enable-w32threads --disable-decoder=dca +endif + +ifeq ($(call need_pkg,"ffmpeg >= 2.6.1"),) +PKGS_FOUND += ffmepg +endif + +$(TARBALLS)/ffmpeg-$(FFMPEG_HASH).tar.xz: + $(call download_git,$(FFMPEG_GITURL),release/2.6, $(FFMPEG_HASH)) + +.sum-ffmpeg: ffmpeg-$(FFMPEG_HASH).tar.xz + $(warning Not implemented.) + touch $@ + +ffmpeg: ffmpeg-$(FFMPEG_HASH).tar.xz .sum-ffmpeg + rm -Rf $@ $@-$(FFMPEG_HASH) + mkdir -p $@-$(FFMPEG_HASH) + (cd $@-$(FFMPEG_HASH) && tar xv --strip-components=1 -f ../$<) + $(UPDATE_AUTOCONFIG) + $(MOVE) + +.ffmpeg: ffmpeg + cd $< && $(HOSTVARS) ./configure \ + --extra-ldflags="$(LDFLAGS)" $(FFMPEGCONF) \ + --prefix="$(PREFIX)" --enable-static --disable-shared + cd $< && $(MAKE) install-libs install-headers + touch $@ diff --git a/contrib/src/main.mak b/contrib/src/main.mak index 046be757a40aa8cac23fdf20377ba41f1b50038a..b16b6fac0ffdf22b8e479fc63519686bbd4876a3 100644 --- a/contrib/src/main.mak +++ b/contrib/src/main.mak @@ -41,12 +41,22 @@ ifeq ($(ARCH)-$(HAVE_WIN32),x86_64-1) HAVE_WIN64 := 1 endif +ifdef HAVE_CROSS_COMPILE +PKG_CONFIG ?= $(HOST)-pkg-config --static +PKG_CONFIG_PATH_CUSTOM = $(PREFIX)/lib/pkgconfig +export PKG_CONFIG_PATH_CUSTOM +else +PKG_CONFIG ?= pkg-config +endif + +PKG_CONFIG_PATH := $(PKG_CONFIG_PATH):$(PREFIX)/lib/pkgconfig +export PKG_CONFIG_PATH + ifdef HAVE_CROSS_COMPILE need_pkg = 1 else need_pkg = $(shell $(PKG_CONFIG) $(1) || echo 1) endif - # # Default values for tools # @@ -147,6 +157,7 @@ ifdef HAVE_WIN32 ifneq ($(shell $(CC) $(CFLAGS) -E -dM -include _mingw.h - < /dev/null | grep -E __MINGW64_VERSION_MAJOR),) HAVE_MINGW_W64 := 1 endif +EXTRA_CXXFLAGS += -std=c++11 endif ifdef HAVE_SOLARIS @@ -186,16 +197,7 @@ endif ACLOCAL_AMFLAGS += -I$(PREFIX)/share/aclocal export ACLOCAL_AMFLAGS -PKG_CONFIG ?= pkg-config -ifdef HAVE_CROSS_COMPILE -# This inhibits .pc file from within the cross-compilation toolchain sysroot. -# Hopefully, nobody ever needs that. -PKG_CONFIG_PATH := /usr/share/pkgconfig -PKG_CONFIG_LIBDIR := /usr/$(HOST)/lib/pkgconfig -export PKG_CONFIG_LIBDIR -endif -PKG_CONFIG_PATH := $(PKG_CONFIG_PATH):$(PREFIX)/lib/pkgconfig -export PKG_CONFIG_PATH + ifndef GIT ifeq ($(shell git --version >/dev/null 2>&1 || echo FAIL),) @@ -268,7 +270,7 @@ HOSTCONF += --enable-static --disable-shared endif ifdef HAVE_WIN32 -HOSTCONF += --without-pic +HOSTCONF += --enable-static --disable-shared --without-pic PIC := else HOSTCONF += --with-pic diff --git a/contrib/src/pjproject/errno.patch b/contrib/src/pjproject/errno.patch new file mode 100644 index 0000000000000000000000000000000000000000..357fb19c9417e7c5c0c3dfbd6ca808c039abb7b9 --- /dev/null +++ b/contrib/src/pjproject/errno.patch @@ -0,0 +1,13 @@ +--- pjproject/pjlib/include/pj/errno.h 2013-04-04 23:02:19.000000000 -0400 ++++ pjproject/pjlib/include/pj/errno.h 2015-02-27 12:21:24.171567801 -0500 +@@ -432,6 +432,11 @@ + * Socket is stopped + */ + #define PJ_ESOCKETSTOP (PJ_ERRNO_START_STATUS + 24)/* 70024 */ ++/** ++ * @hideinitializer ++ * There is no data available right now, try again later. ++ */ ++#define PJ_EAGAIN (PJ_ERRNO_START_STATUS + 25)/* 70025 */ + + /** @} */ /* pj_errnum */ diff --git a/contrib/src/pjproject/gnutls.patch b/contrib/src/pjproject/gnutls.patch index 2b2903fd6e5fbaa837960b6d0c6c8d1538a30b92..6330d077c9a8df73585d766dfbd7669adec48ecd 100644 --- a/contrib/src/pjproject/gnutls.patch +++ b/contrib/src/pjproject/gnutls.patch @@ -83,7 +83,7 @@ index a296266..03f727f 100755 +$as_echo "Using SSL prefix... $with_ssl" >&6; } + fi + if test "x$ssl_backend" = "xgnutls"; then -+ for ac_prog in pkg-config "python pkgconfig.py" ++ for ac_prog in ${host}-pkg-config pkg-config "python pkgconfig.py" +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 @@ -330,7 +330,7 @@ index cd71a7a..465285e 100644 + fi + if test "x$ssl_backend" = "xgnutls"; then + AC_CHECK_PROGS(PKG_CONFIG, -+ pkg-config "python pkgconfig.py", ++ $host-pkg-config pkg-config "python pkgconfig.py", + none) + AC_MSG_RESULT([checking for GnuTLS installations..]) + AC_SUBST(gnutls_h_present) @@ -1062,7 +1062,7 @@ index 0000000..7b4b941 + if (circ_write(&ssock->circ_buf_output, data, len) != PJ_SUCCESS) { + pj_lock_release(ssock->circ_buf_output_mutex); + -+ errno = ENOMEM; ++ errno = PJ_ENOMEM; + return -1; + } + @@ -1085,7 +1085,7 @@ index 0000000..7b4b941 + pj_lock_release(ssock->circ_buf_input_mutex); + + /* Data buffers not yet filled */ -+ errno = EAGAIN; ++ errno = PJ_EAGAIN; + return -1; + } + diff --git a/contrib/src/pjproject/rules.mak b/contrib/src/pjproject/rules.mak index e9bf51c0ca8c6d90cc91e4abe3a9e3ca63f4e811..a401cee89835ddd9aae46df767e49c72db25f43e 100644 --- a/contrib/src/pjproject/rules.mak +++ b/contrib/src/pjproject/rules.mak @@ -23,6 +23,9 @@ PJPROJECT_OPTIONS := --disable-oss \ ifdef HAVE_ANDROID PJPROJECT_OPTIONS += --with-ssl=$(PREFIX) endif +ifdef HAVE_WIN32 +PJPROJECT_OPTIONS += --with-ssl=$(PREFIX) +endif PJPROJECT_EXTRA_CFLAGS = -DPJ_ICE_MAX_CAND=32 -DPJ_ICE_MAX_CHECKS=150 -DPJ_ICE_COMP_BITS=2 @@ -50,6 +53,7 @@ ifdef HAVE_WIN32 $(APPLY) $(SRC)/pjproject/intptr_t.patch $(APPLY) $(SRC)/pjproject/pj_win.patch endif + $(APPLY) $(SRC)/pjproject/errno.patch $(APPLY) $(SRC)/pjproject/aconfigureupdate.patch $(APPLY) $(SRC)/pjproject/endianness.patch $(APPLY) $(SRC)/pjproject/unknowncipher.patch diff --git a/contrib/src/portaudio/SHA512SUMS b/contrib/src/portaudio/SHA512SUMS new file mode 100644 index 0000000000000000000000000000000000000000..4f6479a77579eaae6259b7457e5222ce57d44ae0 --- /dev/null +++ b/contrib/src/portaudio/SHA512SUMS @@ -0,0 +1 @@ +078adfdc2cec7fbd4019837eee65f8411b873b51064dfd7334e1c55118c26ea1fb68cb22e46ee69adb69c78d026b00a7ed973c40632e7d79703e12669a62ee3e portaudio-v19_20140130.tgz \ No newline at end of file diff --git a/contrib/src/portaudio/rules.mak b/contrib/src/portaudio/rules.mak new file mode 100644 index 0000000000000000000000000000000000000000..c0db18a8b5b429e65e051e79bc96e7993bc3e775 --- /dev/null +++ b/contrib/src/portaudio/rules.mak @@ -0,0 +1,26 @@ +# PortAudio + +PORTAUDIO_VERSION := v19_20140130 +PORTAUDIO_URL := http://www.portaudio.com/archives/pa_stable_$(PORTAUDIO_VERSION).tgz + +ifdef HAVE_WIN32 +PKGS += portaudio +endif + +ifeq ($(call need_pkg,"portaudio >= 2.0"),) +PKGS_FOUND += portaudio +endif + + +$(TARBALLS)/portaudio-$(PORTAUDIO_VERSION).tgz: + $(call download,$(PORTAUDIO_URL)) + +.sum-portaudio: portaudio-$(PORTAUDIO_VERSION).tgz + +portaudio: portaudio-$(PORTAUDIO_VERSION).tgz .sum-portaudio + $(UNPACK) + +.portaudio: portaudio + cd $< && $(HOSTVARS) ./configure $(HOSTCONF) + cd $< && $(MAKE) install + touch $@ diff --git a/src/Makefile.am b/src/Makefile.am index 539e128e6e5af688d8ae90b2734ceb1ee186f375..fb02b72c8e3f68ce7e389b446a190513eec68f45 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -12,6 +12,10 @@ if HAVE_OSX RING_VIDEO_LIBS+= \ ./media/video/osxvideo/libosxvideo.la endif +if HAVE_WIN32 +RING_VIDEO_LIBS+= \ + ./media/video/winvideo/libwinvideo.la +endif endif if BUILD_INSTANT_MESSAGING @@ -66,6 +70,7 @@ libring_la_LDFLAGS = \ @YAMLCPP_LIBS@ \ @SPEEXDSP_LIBS@ \ @LIBUPNP_LIBS@ \ + @PORTAUDIO_LIBS@ \ $(TLS_LIB) \ $(IAX_LIB) \ $(IM_LIB) \ @@ -88,6 +93,7 @@ libring_la_CFLAGS = \ @LIBUPNP_CFLAGS@ \ @SPEEXDSP_CFLAGS@ \ @LIBUPNP_CFLAGS@ \ + @PORTAUDIO_CFLAGS@ \ $(TLS_CFLAGS) if USE_DHT @@ -143,6 +149,12 @@ libring_la_SOURCES = conference.cpp \ gnutls_support.h \ rational.h +if HAVE_WIN32 +libring_la_SOURCES += \ + dlfcn.c \ + winsyslog.c +endif + nobase_include_HEADERS= dring/dring.h \ dring/security_const.h \ dring/callmanager_interface.h \ diff --git a/src/dlfcn.c b/src/dlfcn.c new file mode 100644 index 0000000000000000000000000000000000000000..3ade181716ff77c5c7273132f0bb4532c44a9f58 --- /dev/null +++ b/src/dlfcn.c @@ -0,0 +1,246 @@ +/* +* dlfcn-win32 +* Copyright (c) 2007 Ramiro Polla +* +* dlfcn-win32 is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 2.1 of the License, or (at your option) any later version. +* +* dlfcn-win32 is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with dlfcn-win32; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ +#include <windows.h> +#include <stdio.h> +#include "dlfcn.h" +/* Note: +* MSDN says these functions are not thread-safe. We make no efforts to have +* any kind of thread safety. +*/ +typedef struct global_object { + HMODULE hModule; + struct global_object *previous; + struct global_object *next; +} global_object; +static global_object first_object; +/* These functions implement a double linked list for the global objects. */ +static global_object *global_search( HMODULE hModule ) +{ + global_object *pobject; + if( hModule == NULL ) + return NULL; + for( pobject = &first_object; pobject ; pobject = pobject->next ) + if( pobject->hModule == hModule ) + return pobject; + return NULL; + } + static void global_add( HMODULE hModule ) + { + global_object *pobject; + global_object *nobject; + if( hModule == NULL ) + return; + pobject = global_search( hModule ); +/* Do not add object again if it's already on the list */ + if( pobject ) + return; + for( pobject = &first_object; pobject->next ; pobject = pobject->next ); + nobject = malloc( sizeof(global_object) ); +/* Should this be enough to fail global_add, and therefore also fail +* dlopen? +*/ +if( !nobject ) + return; +pobject->next = nobject; +nobject->next = NULL; +nobject->previous = pobject; +nobject->hModule = hModule; +} +static void global_rem( HMODULE hModule ) +{ + global_object *pobject; + if( hModule == NULL ) + return; + pobject = global_search( hModule ); + if( !pobject ) + return; + if( pobject->next ) + pobject->next->previous = pobject->previous; + if( pobject->previous ) + pobject->previous->next = pobject->next; + free( pobject ); +} +/* POSIX says dlerror( ) doesn't have to be thread-safe, so we use one +* static buffer. +* MSDN says the buffer cannot be larger than 64K bytes, so we set it to +* the limit. +*/ +static char error_buffer[65535]; +static char *current_error; +static int copy_string( char *dest, int dest_size, const char *src ) +{ + int i = 0; +/* gcc should optimize this out */ + if( !src || !dest ) + return 0; + for( i = 0 ; i < dest_size-1 ; i++ ) + { + if( !src[i] ) + break; + else + dest[i] = src[i]; + } + dest[i] = '\0'; + return i; +} +static void save_err_str( const char *str ) +{ + DWORD dwMessageId; + DWORD pos; + dwMessageId = GetLastError( ); + if( dwMessageId == 0 ) + return; +/* Format error message to: +* "<argument to function that failed>": <Windows localized error message> +*/ +pos = copy_string( error_buffer, sizeof(error_buffer), "\"" ); +pos += copy_string( error_buffer+pos, sizeof(error_buffer)-pos, str ); +pos += copy_string( error_buffer+pos, sizeof(error_buffer)-pos, "\": " ); +pos += FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwMessageId, + MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ), + error_buffer+pos, sizeof(error_buffer)-pos, NULL ); +if( pos > 1 ) +{ +/* POSIX says the string must not have trailing <newline> */ + if( error_buffer[pos-2] == '\r' && error_buffer[pos-1] == '\n' ) + error_buffer[pos-2] = '\0'; +} +current_error = error_buffer; +} +static void save_err_ptr_str( const void *ptr ) +{ +char ptr_buf[19]; /* 0x<pointer> up to 64 bits. */ + sprintf( ptr_buf, "0x%p", ptr ); + save_err_str( ptr_buf ); +} +void *dlopen( const char *file, int mode ) +{ + HMODULE hModule; + UINT uMode; + current_error = NULL; +/* Do not let Windows display the critical-error-handler message box */ + uMode = SetErrorMode( SEM_FAILCRITICALERRORS ); + if( file == 0 ) + { +/* POSIX says that if the value of file is 0, a handle on a global +* symbol object must be provided. That object must be able to access +* all symbols from the original program file, and any objects loaded +* with the RTLD_GLOBAL flag. +* The return value from GetModuleHandle( ) allows us to retrieve +* symbols only from the original program file. For objects loaded with +* the RTLD_GLOBAL flag, we create our own list later on. +*/ +hModule = GetModuleHandle( NULL ); +if( !hModule ) + save_err_ptr_str( file ); +} +else +{ + char lpFileName[MAX_PATH]; + int i; +/* MSDN says backslashes *must* be used instead of forward slashes. */ + for( i = 0 ; i < sizeof(lpFileName)-1 ; i++ ) + { + if( !file[i] ) + break; + else if( file[i] == '/' ) + lpFileName[i] = '\\'; + else + lpFileName[i] = file[i]; + } + lpFileName[i] = '\0'; +/* POSIX says the search path is implementation-defined. +* LOAD_WITH_ALTERED_SEARCH_PATH is used to make it behave more closely +* to UNIX's search paths (start with system folders instead of current +* folder). +*/ +hModule = LoadLibraryEx( (LPSTR) lpFileName, NULL, + LOAD_WITH_ALTERED_SEARCH_PATH ); +/* If the object was loaded with RTLD_GLOBAL, add it to list of global +* objects, so that its symbols may be retrieved even if the handle for +* the original program file is passed. POSIX says that if the same +* file is specified in multiple invocations, and any of them are +* RTLD_GLOBAL, even if any further invocations use RTLD_LOCAL, the +* symbols will remain global. +*/ +if( !hModule ) + save_err_str( lpFileName ); +else if( (mode & RTLD_GLOBAL) ) + global_add( hModule ); +} +/* Return to previous state of the error-mode bit flags. */ +SetErrorMode( uMode ); +return (void *) hModule; +} +int dlclose( void *handle ) +{ + HMODULE hModule = (HMODULE) handle; + BOOL ret; + current_error = NULL; + ret = FreeLibrary( hModule ); +/* If the object was loaded with RTLD_GLOBAL, remove it from list of global +* objects. +*/ +if( ret ) + global_rem( hModule ); +else + save_err_ptr_str( handle ); +/* dlclose's return value in inverted in relation to FreeLibrary's. */ +ret = !ret; +return (int) ret; +} +void *dlsym( void *handle, const char *name ) +{ + FARPROC symbol; + current_error = NULL; + symbol = GetProcAddress( handle, name ); + if( symbol == NULL ) + { + HMODULE hModule; +/* If the handle for the original program file is passed, also search +* in all globally loaded objects. +*/ +hModule = GetModuleHandle( NULL ); +if( hModule == handle ) +{ + global_object *pobject; + for( pobject = &first_object; pobject ; pobject = pobject->next ) + { + if( pobject->hModule ) + { + symbol = GetProcAddress( pobject->hModule, name ); + if( symbol != NULL ) + break; + } + } +} +} +if( symbol == NULL ) + save_err_str( name ); +return (void*) symbol; +} +char *dlerror( void ) +{ + char *error_pointer = current_error; +/* POSIX says that invoking dlerror( ) a second time, immediately following +* a prior invocation, shall result in NULL being returned. +*/ +current_error = NULL; +return error_pointer; +} \ No newline at end of file diff --git a/src/dlfcn.h b/src/dlfcn.h new file mode 100644 index 0000000000000000000000000000000000000000..42ed6c6aba12d61586ccc346456f6d0f4e79543d --- /dev/null +++ b/src/dlfcn.h @@ -0,0 +1,43 @@ +/* +* dlfcn-win32 +* Copyright (c) 2007 Ramiro Polla +* +* dlfcn-win32 is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 2.1 of the License, or (at your option) any later version. +* +* dlfcn-win32 is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with dlfcn-win32; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ +#ifndef DLFCN_H +#define DLFCN_H +#ifdef __cplusplus +extern "C" { +#endif +/* POSIX says these are implementation-defined. +* To simplify use with Windows API, we treat them the same way. +*/ +#define RTLD_LAZY 0 +#define RTLD_NOW 0 +#define RTLD_GLOBAL (1 << 1) +#define RTLD_LOCAL (1 << 2) +/* These two were added in The Open Group Base Specifications Issue 6. +* Note: All other RTLD_* flags in any dlfcn.h are not standard compliant. +*/ +#define RTLD_DEFAULT 0 +#define RTLD_NEXT 0 +void *dlopen ( const char *file, int mode ); +int dlclose( void *handle ); +void *dlsym ( void *handle, const char *name ); +char *dlerror( void ); +#ifdef __cplusplus +} +#endif +#endif /* DLFCN_H */ \ No newline at end of file diff --git a/src/dring/account_const.h b/src/dring/account_const.h index 7b6543c844182ecc28301c4ec80522f16818ab92..0ceb5a2da6a274318c028b92fe60adb0266903c0 100644 --- a/src/dring/account_const.h +++ b/src/dring/account_const.h @@ -31,6 +31,11 @@ #ifndef DRING_ACCOUNT_H #define DRING_ACCOUNT_H +//Defined in windows.h +#ifdef ERROR +#undef ERROR +#endif + namespace DRing { namespace Account { diff --git a/src/fileutils.cpp b/src/fileutils.cpp index b96bb745d4bfd6ad6ce8ab4c39589747847c4b3b..1b66b332ca4cd53cd203c88bf495137cb74dd5d0 100644 --- a/src/fileutils.cpp +++ b/src/fileutils.cpp @@ -47,8 +47,13 @@ #include <signal.h> #include <unistd.h> #include <fcntl.h> -#include <pwd.h> -#ifndef __ANDROID__ +#ifndef _WIN32 + #include <pwd.h> +#else + #include <shlobj.h> + #define NAME_MAX 255 +#endif +#if !defined __ANDROID__ && !defined _WIN32 # include <wordexp.h> #endif @@ -71,7 +76,11 @@ bool check_dir(const char *path) DIR *dir = opendir(path); if (!dir) { // doesn't exist +#ifndef _WIN32 if (mkdir(path, 0755) != 0) { // couldn't create the dir +#else + if (recursive_mkdir(path) != true) { +#endif perror(path); return false; } @@ -97,6 +106,7 @@ const char *get_program_dir() return program_dir; } +#ifndef _WIN32 /* Lock a file region */ static int lockReg(int fd, int cmd, int type, int whence, int start, off_t len) @@ -159,11 +169,12 @@ create_pidfile() return f; } +#endif // !_WIN32 std::string expand_path(const std::string &path) { -#ifdef __ANDROID__ +#if defined __ANDROID__ || defined WIN32 RING_ERR("Path expansion not implemented, returning original"); return path; #else @@ -276,7 +287,11 @@ readDirectory(const std::string& dir) dirent* entry; std::vector<std::string> files; +#ifndef _WIN32 while (!readdir_r(dp, reinterpret_cast<dirent*>(buf.data()), &entry) && entry) { +#else + while ((entry = readdir(dp)) != nullptr) { +#endif const std::string fname {entry->d_name}; if (fname == "." || fname == "..") continue; @@ -323,7 +338,16 @@ get_cache_dir() std::string get_home_dir() { -#ifdef __ANDROID__ +#if defined __ANDROID__ + return get_program_dir(); +#elif defined _WIN32 + WCHAR path[MAX_PATH]; + if (SUCCEEDED(SHGetFolderPathW(nullptr, CSIDL_PROFILE, nullptr, 0, path))) { + char tmp[MAX_PATH]; + char DefChar = ' '; + WideCharToMultiByte(CP_ACP, 0, path, -1, tmp, MAX_PATH, &DefChar, nullptr); + return std::string(tmp); + } return get_program_dir(); #else @@ -365,4 +389,22 @@ get_data_dir() #endif } +#ifdef _WIN32 +bool +recursive_mkdir(const std::string& path) +{ + if (mkdir(path.data()) != 0) { + if (errno == ENOENT) { + recursive_mkdir(path.substr(0, path.find_last_of(DIR_SEPARATOR_STR))); + } else if (errno != EEXIST) { + if (mkdir(path.data()) != 0) { + RING_ERR("Could not create directory."); + return false; + } + } + } + return true; +} +#endif // !_WIN32 + }} // namespace ring::fileutils diff --git a/src/fileutils.h b/src/fileutils.h index b1558e6f21caed7590ca41ea54dffd613e835aad..192fba01223acec7e42e54ae82fae53cca660bdb 100644 --- a/src/fileutils.h +++ b/src/fileutils.h @@ -44,8 +44,13 @@ #define PIDFILE ".ring.pid" +#ifndef _WIN32 #define DIR_SEPARATOR_STR "/" // Directory separator char #define DIR_SEPARATOR_CH '/' // Directory separator string +#else +#define DIR_SEPARATOR_STR "\\" // Directory separator char +#define DIR_SEPARATOR_CH '\\' // Directory separator string +#endif namespace ring { namespace fileutils { @@ -58,6 +63,10 @@ namespace ring { namespace fileutils { std::string expand_path(const std::string &path); bool isDirectoryWritable(const std::string &directory); +#ifdef _WIN32 + bool recursive_mkdir(const std::string& path); +#endif + /** * Read content of the directory. * The result is a list of full paths of files in the directory, diff --git a/src/ip_utils.cpp b/src/ip_utils.cpp index 422f67a457b3246032e60c83b4b22d472eb05475..dfd6ad600d69b156328eeb95125bbd2b7677fa79 100644 --- a/src/ip_utils.cpp +++ b/src/ip_utils.cpp @@ -34,16 +34,14 @@ #include "sip/sip_utils.h" -#include <arpa/inet.h> -#include <arpa/nameser.h> -#include <resolv.h> - -#include <netdb.h> -#include <net/if.h> #include <sys/types.h> -#include <sys/ioctl.h> #include <unistd.h> +#ifdef _WIN32 +#define InetPtonA inet_pton +WINSOCK_API_LINKAGE INT WSAAPI InetPtonA(INT Family, LPCSTR pStringBuf, PVOID pAddr); +#endif + namespace ring { std::vector<IpAddr> @@ -141,6 +139,7 @@ ip_utils::getInterfaceAddr(const std::string &interface, pj_uint16_t family) const auto unix_family = family == pj_AF_INET() ? AF_INET : AF_INET6; IpAddr addr = {}; +#ifndef _WIN32 int fd = socket(unix_family, SOCK_DGRAM, 0); if (fd < 0) { RING_ERR("Could not open socket: %m"); @@ -170,6 +169,35 @@ ip_utils::getInterfaceAddr(const std::string &interface, pj_uint16_t family) addr = ifr.ifr_addr; if (addr.isUnspecified()) return getLocalAddr(addr.getFamily()); +#else // _WIN32 + struct addrinfo hints; + struct addrinfo *result = NULL; + struct sockaddr_in *sockaddr_ipv4; + struct sockaddr_in6 *sockaddr_ipv6; + + ZeroMemory(&hints, sizeof(hints)); + + DWORD dwRetval = getaddrinfo(interface.c_str(), "0", &hints, &result); + if (dwRetval != 0) { + RING_ERR("getaddrinfo failed with error: %d", dwRetval); + return addr; + } + + switch (result->ai_family) { + sockaddr_ipv4 = (struct sockaddr_in *) result->ai_addr; + addr = sockaddr_ipv4->sin_addr; + break; + case AF_INET6: + sockaddr_ipv6 = (struct sockaddr_in6 *) result->ai_addr; + addr = sockaddr_ipv6->sin6_addr; + break; + default: + break; + } + + if (addr.isUnspecified()) + return getLocalAddr(addr.getFamily()); +#endif // !_WIN32 return addr; } @@ -177,11 +205,11 @@ ip_utils::getInterfaceAddr(const std::string &interface, pj_uint16_t family) std::vector<std::string> ip_utils::getAllIpInterfaceByName() { - static ifreq ifreqs[20]; - ifconf ifconf; - std::vector<std::string> ifaceList; ifaceList.push_back("default"); +#ifndef _WIN32 + static ifreq ifreqs[20]; + ifconf ifconf; ifconf.ifc_buf = (char*) (ifreqs); ifconf.ifc_len = sizeof(ifreqs); @@ -196,6 +224,9 @@ ip_utils::getAllIpInterfaceByName() close(sock); } +#else + RING_ERR("Not implemented yet. (iphlpapi.h problem)"); +#endif return ifaceList; } @@ -222,7 +253,7 @@ std::vector<IpAddr> ip_utils::getLocalNameservers() { std::vector<IpAddr> res; -#ifdef __ANDROID__ +#if defined __ANDROID__ || defined _WIN32 #warning "Not implemented" #else if (not (_res.options & RES_INIT)) diff --git a/src/ip_utils.h b/src/ip_utils.h index ee23b5c36237b337e85b09053daa50a4405a910f..4adaba22f1a3a2bbfa60602c33ae3c8a41b7521f 100644 --- a/src/ip_utils.h +++ b/src/ip_utils.h @@ -34,7 +34,28 @@ #include <pjlib.h> -#include <netinet/ip.h> +#ifdef _WIN32 + #include <ws2tcpip.h> + #include <config.h> + #include <winsock2.h> + + //define in mingw + #ifdef interface + #undef interface + #endif + #ifdef s_addr + #undef s_addr + #endif +#else + #include <arpa/inet.h> + #include <netinet/in.h> + #include <arpa/nameser.h> + #include <resolv.h> + #include <netdb.h> + #include <netinet/ip.h> + #include <net/if.h> + #include <sys/ioctl.h> +#endif #include <string> #include <vector> diff --git a/src/logger.c b/src/logger.c index 9dd07e0cb45a3c755e84b4f2146cfaf5b6ec6f5e..9200c49d34d3476482785095fbe38168dbba1e78 100644 --- a/src/logger.c +++ b/src/logger.c @@ -38,6 +38,10 @@ static int consoleLog; static int debugMode; +#ifdef WIN32 +#include "winsyslog.h" +#endif + void logger(const int level, const char* format, ...) { if (!debugMode && level == LOG_DEBUG) @@ -51,11 +55,21 @@ void logger(const int level, const char* format, ...) void vlogger(const int level, const char *format, va_list ap) { +#ifdef WIN32 + HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE); + CONSOLE_SCREEN_BUFFER_INFO consoleInfo; + WORD saved_attributes; +#endif + if (!debugMode && level == LOG_DEBUG) return; if (consoleLog) { +#ifndef _WIN32 const char *color_prefix = ""; +#else + WORD color_prefix = FOREGROUND_GREEN; +#endif switch (level) { case LOG_ERR: @@ -66,9 +80,23 @@ void vlogger(const int level, const char *format, va_list ap) break; } +#ifndef _WIN32 fputs(color_prefix, stderr); +#else + GetConsoleScreenBufferInfo(hConsole, &consoleInfo); + saved_attributes = consoleInfo.wAttributes; + SetConsoleTextAttribute(hConsole, color_prefix); +#endif + vfprintf(stderr, format, ap); + +#ifndef _WIN32 fputs(END_COLOR"\n", stderr); +#else + fputs("\n", stderr); + SetConsoleTextAttribute(hConsole, saved_attributes); +#endif + } else { vsyslog(level, format, ap); } diff --git a/src/logger.h b/src/logger.h index 379d9d7a1156ef34028fab1934fc9275940949d6..2658d3cadf0522d13547021845454ee29e171df5 100644 --- a/src/logger.h +++ b/src/logger.h @@ -73,8 +73,8 @@ void strErr(); ##__VA_ARGS__ #else -#define LOG_FORMAT(M, ...) "%s:%d: " M, FILE_NAME, __LINE__, \ - ##__VA_ARGS__ +#define LOG_FORMAT(M, ...) "%s:%d: " M, FILE_NAME , __LINE__, \ + ##__VA_ARGS__ #endif #ifdef __ANDROID__ @@ -98,14 +98,18 @@ void strErr(); #define LOGGER(M, LEVEL, ...) __android_log_print(LEVEL, APP_NAME, \ LOG_FORMAT(M, ##__VA_ARGS__)) -/* TODO: WINDOWS, Actually implement logging system. */ -#elif defined _WIN32 -#define LOG_ERR 0 -#define LOG_WARNING 1 -#define LOG_INFO 2 -#define LOG_DEBUG 3 +#elif _WIN32 + +#include "winsyslog.h" -#define LOGGER(M, LEVEL, ...) printf(M, ##__VA_ARGS__) +#define LOG_ERR EVENTLOG_ERROR_TYPE +#define LOG_WARNING EVENTLOG_WARNING_TYPE +#define LOG_INFO EVENTLOG_INFORMATION_TYPE +#define LOG_DEBUG EVENTLOG_SUCCESS + +#define FILE_NAME __FILE__ + +#define LOGGER(M, LEVEL, ...) logger(LEVEL, LOG_FORMAT(M, ##__VA_ARGS__)) #else @@ -122,9 +126,7 @@ void strErr(); #define RING_INFO(M, ...) LOGGER(M, LOG_INFO, ##__VA_ARGS__) #define RING_DBG(M, ...) LOGGER(M, LOG_DEBUG, ##__VA_ARGS__) - #define BLACK "\033[22;30m" -#define RED "\033[22;31m" #define GREEN "\033[22;32m" #define BROWN "\033[22;33m" #define BLUE "\033[22;34m" @@ -134,13 +136,20 @@ void strErr(); #define DARK_GREY "\033[01;30m" #define LIGHT_RED "\033[01;31m" #define LIGHT_SCREEN "\033[01;32m" -#define YELLOW "\033[01;33m" #define LIGHT_BLUE "\033[01;34m" #define LIGHT_MAGENTA "\033[01;35m" #define LIGHT_CYAN "\033[01;36m" #define WHITE "\033[01;37m" #define END_COLOR "\033[0m" +#ifndef _WIN32 +#define RED "\033[22;31m" +#define YELLOW "\033[01;33m" +#else +#define RED FOREGROUND_RED +#define YELLOW FOREGROUND_RED + FOREGROUND_GREEN +#endif + #ifdef __cplusplus } #endif diff --git a/src/managerimpl.cpp b/src/managerimpl.cpp index f217e59546c38923dfc78449bdeee57d07795734..e3a9a07c45e1f4e91972e99573c467bb4e300d00 100644 --- a/src/managerimpl.cpp +++ b/src/managerimpl.cpp @@ -2000,7 +2000,11 @@ ManagerImpl::retrieveConfigPath() const if (not xdg_env.empty()) configdir = xdg_env + DIR_SEPARATOR_STR + PACKAGE; +#ifndef _WIN32 if (mkdir(configdir.data(), 0700) != 0) { +#else + if (fileutils::recursive_mkdir(configdir.data()) != true) { +#endif // If directory creation failed if (errno != EEXIST) RING_DBG("Cannot create directory: %s!", configdir.c_str()); diff --git a/src/media/Makefile.am b/src/media/Makefile.am index ec6072a4fc88b0b2d0b4a0fb1c1307703b5d1d2f..730b78c04ff3f6de564a3dade1b9ff61d02d7203 100644 --- a/src/media/Makefile.am +++ b/src/media/Makefile.am @@ -43,6 +43,10 @@ endif libmedia_la_LDFLAGS = @LIBAVCODEC_LIBS@ @LIBAVFORMAT_LIBS@ @LIBAVDEVICE_LIBS@ @LIBSWSCALE_LIBS@ @LIBAVUTIL_LIBS@ +if HAVE_WIN32 +libmedia_la_LDFLAGS += -lws2_32 -lwsock32 +endif + AM_CFLAGS=@LIBAVCODEC_CFLAGS@ @LIBAVFORMAT_CFLAGS@ @LIBAVDEVICE_CFLAGS@ @LIBSWSCALE_CFLAGS@ AM_CXXFLAGS=@LIBAVCODEC_CFLAGS@ @LIBAVFORMAT_CFLAGS@ @LIBAVDEVICE_CFLAGS@ @LIBSWSCALE_CFLAGS@ diff --git a/src/media/audio/Makefile.am b/src/media/audio/Makefile.am index d39e5851b2e1025f296acff9bc4c5d189e5ff922..85e2686cfbf3abd50a9583e3cb46c78bd064e749 100644 --- a/src/media/audio/Makefile.am +++ b/src/media/audio/Makefile.am @@ -24,6 +24,10 @@ if HAVE_OSX SUBDIRS += coreaudio endif +if HAVE_PORTAUDIO +SUBDIRS += portaudio +endif + if BUILD_SPEEXDSP RING_SPEEXDSP_SRC=dsp.cpp RING_SPEEXDSP_HEAD=dsp.h @@ -89,3 +93,8 @@ if BUILD_OPENSL libaudio_la_LIBADD += ./opensl/libopensl.la libaudio_la_LDFLAGS += -lOpenSLES endif + +if BUILD_PORTAUDIO +libaudio_la_LIBADD += ./portaudio/libportaudiolayer.la +libaudio_la_LDFLAGS += @PORTAUDIO_LIBS@ +endif diff --git a/src/media/audio/audiolayer.h b/src/media/audio/audiolayer.h index 78fad4f1d386cd351517bf5502a47b4dbb0a2d47..97ba7297916abc7bfbba4ccdd8ff2684a6a88cb2 100644 --- a/src/media/audio/audiolayer.h +++ b/src/media/audio/audiolayer.h @@ -53,6 +53,7 @@ #define ALSA_API_STR "alsa" #define JACK_API_STR "jack" #define COREAUDIO_API_STR "coreaudio" +#define PORTAUDIO_API_STR "portaudio" #define PCM_DEFAULT "default" // Default ALSA plugin #define PCM_DSNOOP "plug:dsnoop" // Alsa plugin for microphone sharing diff --git a/src/media/audio/portaudio/Makefile.am b/src/media/audio/portaudio/Makefile.am new file mode 100644 index 0000000000000000000000000000000000000000..a8fed9adfea088cb002dde553e556c62cd4b3997 --- /dev/null +++ b/src/media/audio/portaudio/Makefile.am @@ -0,0 +1,14 @@ +include $(top_srcdir)/globals.mak + +if BUILD_PORTAUDIO + +noinst_LTLIBRARIES = libportaudiolayer.la + +libportaudiolayer_la_SOURCES = \ + portaudiolayer.cpp + + +noinst_HEADERS = \ + portaudiolayer.h + +endif diff --git a/src/media/audio/portaudio/portaudiolayer.cpp b/src/media/audio/portaudio/portaudiolayer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0795a2d2dec2891e040ec24fa6f14e79b0966f17 --- /dev/null +++ b/src/media/audio/portaudio/portaudiolayer.cpp @@ -0,0 +1,446 @@ +/* + * Copyright (C) 2004-2015 Savoir-Faire Linux Inc. + * Author: Edric Ladent-Milaret <edric.ladent-milaret@savoirfairelinux.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Additional permission under GNU GPL version 3 section 7: + * + * If you modify this program, or any covered work, by linking or + * combining it with the OpenSSL project's OpenSSL library (or a + * modified version of that library), containing parts covered by the + * terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc. + * grants you additional permission to convey the resulting work. + * Corresponding Source for a non-source form of such a combination + * shall include the source code for the parts of OpenSSL used as well + * as that of the covered work. + */ + +#include "portaudiolayer.h" +#include "manager.h" +#include "noncopyable.h" +#include "audio/resampler.h" +#include "audio/ringbufferpool.h" +#include "audio/ringbuffer.h" + +namespace ring { +//FIXME: We should use WASAPi or DirectSound +PortAudioLayer::PortAudioLayer(const AudioPreference &pref) + : AudioLayer(pref) + , indexIn_(pref.getAlsaCardin()) + , indexOut_(pref.getAlsaCardout()) + , indexRing_(pref.getAlsaCardring()) + , playbackBuff_(0, audioFormat_) + , mainRingBuffer_(Manager::instance().getRingBufferPool().getRingBuffer(RingBufferPool::DEFAULT_ID)) +{ + isStarted_ = false; + this->init(); +} + +PortAudioLayer::~PortAudioLayer() +{ + this->terminate(); +} + +std::vector<std::string> +PortAudioLayer::getCaptureDeviceList() const +{ + return this->getDeviceByType(false); +} + +std::vector<std::string> +PortAudioLayer::getPlaybackDeviceList() const +{ + return this->getDeviceByType(true); +} + +int +PortAudioLayer::getAudioDeviceIndex(const std::string& name, + DeviceType type) const +{ + + int numDevices = 0; + (void) type; + + numDevices = Pa_GetDeviceCount(); + if (numDevices < 0) + this->handleError(numDevices); + else { + const PaDeviceInfo *deviceInfo; + for (int i = 0; i < numDevices; i++) { + deviceInfo = Pa_GetDeviceInfo(i); + if (deviceInfo->name == name) + return i; + } + } + return -1; +} + +std::string +PortAudioLayer::getAudioDeviceName(int index, DeviceType type) const +{ + (void) type; + const PaDeviceInfo *deviceInfo; + deviceInfo = Pa_GetDeviceInfo(index); + return deviceInfo->name; +} + +int +PortAudioLayer::getIndexCapture() const +{ + return this->indexIn_; +} + +int +PortAudioLayer::getIndexPlayback() const +{ + return this->indexOut_; +} + +int +PortAudioLayer::getIndexRingtone() const +{ + return this->indexRing_; +} + +void +PortAudioLayer::startStream() +{ + if (isRunning_) + return; + this->initStream(); + isRunning_ = isStarted_ = true; +} + +void +PortAudioLayer::stopStream() +{ + + if (!isRunning_) + return; + + RING_DBG("Stop PortAudio Streams"); + + //FIX ME : Abort or Stop ?? + for (int i = 0; i < Direction::End; i++) { + auto err = Pa_AbortStream(streams[i]); + if(err != paNoError) + this->handleError(err); + + err = Pa_CloseStream(streams[i]); + if (err != paNoError) + this->handleError(err); + } + + isRunning_ = isStarted_ = false; + + /* Flush the ring buffers */ + flushUrgent(); + flushMain(); +} + +void +PortAudioLayer::updatePreference(AudioPreference &preference, + int index, DeviceType type) +{ + switch (type) { + case DeviceType::PLAYBACK: + preference.setAlsaCardout(index); + break; + + case DeviceType::CAPTURE: + preference.setAlsaCardin(index); + break; + + case DeviceType::RINGTONE: + preference.setAlsaCardring(index); + break; + + default: + break; + } +} + +std::vector<std::string> +PortAudioLayer::getDeviceByType(const bool& playback) const +{ + std::vector<std::string> ret; + int numDevices = 0; + + numDevices = Pa_GetDeviceCount(); + if (numDevices < 0) + this->handleError(numDevices); + else { + for (int i = 0; i < numDevices; i++) { + const auto deviceInfo = Pa_GetDeviceInfo(i); + if (playback) { + if (deviceInfo->maxOutputChannels > 0) + ret.push_back(deviceInfo->name); + } else { + if (deviceInfo->maxInputChannels > 0) + ret.push_back(deviceInfo->name); + } + } + } + return ret; +} + +int +PortAudioLayer::paOutputCallback(const void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + const PaStreamCallbackTimeInfo* timeInfo, + PaStreamCallbackFlags statusFlags, + void *userData) +{ + + (void) inputBuffer; + (void) timeInfo; + (void) statusFlags; + + auto ref = (PortAudioLayer*)userData; + auto out = (AudioSample*)outputBuffer; + + AudioFormat mainBufferAudioFormat = + Manager::instance().getRingBufferPool().getInternalAudioFormat(); + bool resample = + ref->audioFormat_.sample_rate != mainBufferAudioFormat.sample_rate; + auto urgentFramesToGet = + ref->urgentRingBuffer_.availableForGet(RingBufferPool::DEFAULT_ID); + + if (urgentFramesToGet > 0) { + RING_WARN("Getting urgent frames."); + size_t totSample = std::min(framesPerBuffer, + (unsigned long)urgentFramesToGet); + + ref->playbackBuff_.setFormat(ref->audioFormat_); + ref->playbackBuff_.resize(totSample); + ref->urgentRingBuffer_.get(ref->playbackBuff_, RingBufferPool::DEFAULT_ID); + + ref->playbackBuff_.applyGain(ref->isPlaybackMuted_ ? 0.0 : ref->playbackGain_); + + ref->playbackBuff_.interleave(out); + + Manager::instance().getRingBufferPool().discard(totSample, + RingBufferPool::DEFAULT_ID); + } + + unsigned normalFramesToGet = + Manager::instance().getRingBufferPool().availableForGet(RingBufferPool::DEFAULT_ID); + if (normalFramesToGet > 0) { + double resampleFactor = 1.0; + unsigned readableSamples = framesPerBuffer; + + if (resample) { + resampleFactor = + static_cast<double>(ref->audioFormat_.sample_rate) + / mainBufferAudioFormat.sample_rate; + readableSamples = std::ceil(framesPerBuffer / resampleFactor); + } + + readableSamples = std::min(readableSamples, normalFramesToGet); + + ref->playbackBuff_.setFormat(ref->audioFormat_); + ref->playbackBuff_.resize(readableSamples); + Manager::instance().getRingBufferPool().getData(ref->playbackBuff_, + RingBufferPool::DEFAULT_ID); + ref->playbackBuff_.applyGain(ref->isPlaybackMuted_ ? 0.0 : ref->playbackGain_); + + if (resample) { + AudioBuffer resampledOutput(readableSamples, ref->audioFormat_); + ref->resampler_->resample(ref->playbackBuff_, resampledOutput); + + resampledOutput.interleave(out); + } else { + ref->playbackBuff_.interleave(out); + } + } + if (normalFramesToGet <= 0) { + auto tone = Manager::instance().getTelephoneTone(); + auto file_tone = Manager::instance().getTelephoneFile(); + + ref->playbackBuff_.setFormat(ref->audioFormat_); + ref->playbackBuff_.resize(framesPerBuffer); + + if (tone) { + tone->getNext(ref->playbackBuff_, ref->playbackGain_); + } else if (file_tone) { + file_tone->getNext(ref->playbackBuff_, ref->playbackGain_); + } else { + //RING_WARN("No tone or file_tone!"); + ref->playbackBuff_.reset(); + } + ref->playbackBuff_.interleave(out); + } + return paContinue; +} + +int +PortAudioLayer::paInputCallback(const void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + const PaStreamCallbackTimeInfo* timeInfo, + PaStreamCallbackFlags statusFlags, + void *userData) +{ + + (void) outputBuffer; + (void) timeInfo; + (void) statusFlags; + + auto ref = (PortAudioLayer*)userData; + auto in = (AudioSample*)inputBuffer; + + if (framesPerBuffer == 0) { + RING_WARN("No frames for input."); + return paContinue; + } + + const auto mainBufferFormat = + Manager::instance().getRingBufferPool().getInternalAudioFormat(); + bool resample = + ref->audioInputFormat_.sample_rate != mainBufferFormat.sample_rate; + + AudioBuffer inBuff(framesPerBuffer, ref->audioInputFormat_); + + inBuff.deinterleave(in, framesPerBuffer, ref->audioInputFormat_.nb_channels); + + inBuff.applyGain(ref->isCaptureMuted_ ? 0.0 : ref->captureGain_); + + if (resample) { + auto outSamples = + framesPerBuffer + / (static_cast<double>(ref->audioInputFormat_.sample_rate) + / mainBufferFormat.sample_rate); + AudioBuffer out(outSamples, mainBufferFormat); + ref->inputResampler_->resample(inBuff, out); + ref->dcblocker_.process(out); + ref->mainRingBuffer_->put(out); + } else { + ref->dcblocker_.process(inBuff); + ref->mainRingBuffer_->put(inBuff); + } + return paContinue; +} + +// PRIVATE METHOD +void +PortAudioLayer::handleError(const PaError& err) const +{ + RING_ERR("PortAudioLayer error : %s", Pa_GetErrorText(err)); +} + +void +PortAudioLayer::init() +{ + RING_DBG("Init PortAudioLayer"); + const auto err = Pa_Initialize(); + if (err != paNoError) { + this->handleError(err); + this->terminate(); + } + //FIXME: Maybe find a better way + const PaDeviceInfo *outputDeviceInfo = Pa_GetDeviceInfo(indexOut_); + audioFormat_.nb_channels = outputDeviceInfo->maxOutputChannels; + audioFormat_.sample_rate = 48000; + hardwareFormatAvailable(audioFormat_); +} + +void +PortAudioLayer::terminate() const +{ + RING_DBG("PortAudioLayer terminate."); + const auto err = Pa_Terminate(); + if (err != paNoError) + this->handleError(err); +} + +void +PortAudioLayer::initStream() +{ + dcblocker_.reset(); + + RING_DBG("Open PortAudio Output Stream"); + PaStreamParameters outputParameters; + outputParameters.device = indexOut_; + RING_DBG("Index Device: %d", indexOut_); + if (outputParameters.device == paNoDevice) { + //TODO Should we fallback to default output device ? + RING_ERR("Error: No valid output device. There will be no sound."); + } + const auto outputDeviceInfo = + Pa_GetDeviceInfo(outputParameters.device); + RING_DBG("Default Sample Rate : %d", outputDeviceInfo->defaultSampleRate); + outputParameters.channelCount = + audioFormat_.nb_channels = outputDeviceInfo->maxOutputChannels; + //FIX ME : Default is 0.... + audioFormat_.sample_rate = 48000; + + outputParameters.sampleFormat = paInt16; + outputParameters.suggestedLatency = outputDeviceInfo->defaultLowOutputLatency; + outputParameters.hostApiSpecificStreamInfo = NULL; + + PaError err = Pa_OpenStream( + &streams[Direction::Output], + NULL, + &outputParameters, + audioFormat_.sample_rate, + paFramesPerBufferUnspecified, + paNoFlag, + &PortAudioLayer::paOutputCallback, + this); + if(err != paNoError) + this->handleError(err); + + RING_DBG("Open PortAudio Input Stream"); + PaStreamParameters inputParameters; + inputParameters.device = indexIn_; + if (inputParameters.device == paNoDevice) { + //TODO Should we fallback to default output device ? + RING_ERR("Error: No valid input device. There will be no mic."); + } + + const auto inputDeviceInfo = + Pa_GetDeviceInfo(inputParameters.device); + //FIX ME : Default is 0.... + audioInputFormat_.sample_rate = 48000; + inputParameters.channelCount = + audioInputFormat_.nb_channels = inputDeviceInfo->maxInputChannels; + inputParameters.sampleFormat = paInt16; + inputParameters.suggestedLatency = inputDeviceInfo->defaultLowInputLatency; + inputParameters.hostApiSpecificStreamInfo = NULL; + + err = Pa_OpenStream( + &streams[Direction::Input], + &inputParameters, + NULL, + audioInputFormat_.sample_rate, + paFramesPerBufferUnspecified, + paNoFlag, + &PortAudioLayer::paInputCallback, + this); + + RING_DBG("Start PortAudio Streams"); + for (int i = 0; i < Direction::End; i++) { + err = Pa_StartStream(streams[i]); + if (err != paNoError) + this->handleError(err); + } + + hardwareFormatAvailable(audioFormat_); + hardwareInputFormatAvailable(audioInputFormat_); + + flushUrgent(); + flushMain(); +} +} // namespace ring diff --git a/src/media/audio/portaudio/portaudiolayer.h b/src/media/audio/portaudio/portaudiolayer.h new file mode 100644 index 0000000000000000000000000000000000000000..a982c378eee96cb1dd1b3cf328797dd762787fe3 --- /dev/null +++ b/src/media/audio/portaudio/portaudiolayer.h @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2004-2015 Savoir-Faire Linux Inc. + * Author: Edric Ladent-Milaret <edric.ladent-milaret@savoirfairelinux.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Additional permission under GNU GPL version 3 section 7: + * + * If you modify this program, or any covered work, by linking or + * combining it with the OpenSSL project's OpenSSL library (or a + * modified version of that library), containing parts covered by the + * terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc. + * grants you additional permission to convey the resulting work. + * Corresponding Source for a non-source form of such a combination + * shall include the source code for the parts of OpenSSL used as well + * as that of the covered work. + */ + +#ifndef PORTAUDIO_LAYER_H +#define PORTAUDIO_LAYER_H + +#include <portaudio.h> + +#include "audio/audiolayer.h" +#include "noncopyable.h" + +namespace ring { + +class PortAudioLayer : public AudioLayer { + +public: + PortAudioLayer(const AudioPreference &pref); + ~PortAudioLayer(); + + virtual std::vector<std::string> getCaptureDeviceList() const; + virtual std::vector<std::string> getPlaybackDeviceList() const; + + virtual int getAudioDeviceIndex(const std::string& name, DeviceType type) const; + virtual std::string getAudioDeviceName(int index, DeviceType type) const; + virtual int getIndexCapture() const; + virtual int getIndexPlayback() const; + virtual int getIndexRingtone() const; + + /** + * Start the capture stream and prepare the playback stream. + * The playback starts accordingly to its threshold + */ + virtual void startStream(); + + /** + * Stop the playback and capture streams. + * Drops the pending frames and put the capture and playback handles to PREPARED state + */ + virtual void stopStream(); + + virtual void updatePreference(AudioPreference &pref, int index, DeviceType type); + + private: + NON_COPYABLE(PortAudioLayer); + + void handleError(const PaError& err) const; + void init(void); + void terminate(void) const; + void initStream(void); + std::vector<std::string> getDeviceByType(const bool& playback) const; + + PaDeviceIndex indexIn_; + PaDeviceIndex indexOut_; + PaDeviceIndex indexRing_; + + AudioBuffer playbackBuff_; + + std::shared_ptr<RingBuffer> mainRingBuffer_; + + bool isRunning_; + + enum Direction {Input=0, Output=1, End=2}; + PaStream* streams[(int)Direction::End]; + + static int paOutputCallback(const void *inputBuffer, void* outputBuffer, + unsigned long framesPerBuffer, + const PaStreamCallbackTimeInfo* timeInfo, + PaStreamCallbackFlags statusFlags, + void *userData); + + static int paInputCallback(const void *inputBuffer, void* outputBuffer, + unsigned long framesPerBuffer, + const PaStreamCallbackTimeInfo* timeInfo, + PaStreamCallbackFlags statusFlags, + void *userData); + }; + } + +#endif \ No newline at end of file diff --git a/src/media/audio/sound/audiofile.cpp b/src/media/audio/sound/audiofile.cpp index 113237d5293b252facb12494fc29536c26144252..5cc2dde353e7d9ac13b53d1d6cc4ac92e4ccd561 100644 --- a/src/media/audio/sound/audiofile.cpp +++ b/src/media/audio/sound/audiofile.cpp @@ -97,7 +97,7 @@ AudioFile::AudioFile(const std::string &fileName, unsigned int sampleRate) : if (!fileHandle) throw AudioFileException("File handle " + fileName + " could not be created"); if (fileHandle.error()) { - RING_ERR("%s", fileHandle.strError()); + RING_ERR("Error fileHandle: %s", fileHandle.strError()); throw AudioFileException("File " + fileName + " doesn't exist"); } diff --git a/src/media/media_codec.h b/src/media/media_codec.h index 181d0bf2bda7adcc5049f30604fc25bacdab44ca..e4ff91b39c1a99aa502b453d9a32c8d6d8150bde 100644 --- a/src/media/media_codec.h +++ b/src/media/media_codec.h @@ -33,6 +33,10 @@ #ifndef __MEDIA_CODEC_H__ #define __MEDIA_CODEC_H__ +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + #include "audio/audiobuffer.h" // for AudioFormat #include "ip_utils.h" diff --git a/src/media/media_decoder.cpp b/src/media/media_decoder.cpp index 6f9f2252aa79c5634b7e739fda1d35c6f1524658..f62c6111fc90b73fcd19952652b1bd70ad23f5c8 100644 --- a/src/media/media_decoder.cpp +++ b/src/media/media_decoder.cpp @@ -223,7 +223,6 @@ int MediaDecoder::setupFromVideoData() #else ret = avformat_find_stream_info(inputCtx_, NULL); #endif - if (ret < 0) { // workaround for this bug: // http://patches.libav.org/patch/22541/ @@ -284,7 +283,6 @@ int MediaDecoder::setupFromVideoData() RING_ERR("Could not open codec"); return -1; } - return 0; } diff --git a/src/media/socket_pair.cpp b/src/media/socket_pair.cpp index b7f0ab1379f4345f55d22f01215258c196bd6fd9..4011f4bde7caa6aa5274054d846aab1af9f4cede 100644 --- a/src/media/socket_pair.cpp +++ b/src/media/socket_pair.cpp @@ -43,10 +43,12 @@ extern "C" { #include <cstring> #include <stdexcept> #include <unistd.h> -#include <poll.h> #include <sys/types.h> -#include <sys/socket.h> -#include <netdb.h> + +#ifdef _WIN32 +#define SOCK_NONBLOCK FIONBIO +#define poll WSAPoll +#endif #ifdef __ANDROID__ #include <asm-generic/fcntl.h> @@ -308,7 +310,7 @@ SocketPair::readRtpData(void *buf, int buf_size) socklen_t from_len = sizeof(from); start: - int result = recvfrom(rtpHandle_, buf, buf_size, 0, + int result = recvfrom(rtpHandle_, (char*)buf, buf_size, 0, (struct sockaddr *)&from, &from_len); if (result > 0 and srtpContext_ and srtpContext_->srtp_in.aes) if (ff_srtp_decrypt(&srtpContext_->srtp_in, data, &result) < 0) @@ -341,7 +343,7 @@ SocketPair::readRtcpData(void *buf, int buf_size) // work with system socket struct sockaddr_storage from; socklen_t from_len = sizeof(from); - return recvfrom(rtcpHandle_, buf, buf_size, 0, + return recvfrom(rtcpHandle_,(char*) buf, buf_size, 0, (struct sockaddr *)&from, &from_len); } @@ -375,11 +377,11 @@ SocketPair::writeRtpData(void* buf, int buf_size) if (buf_size < 0) return buf_size; - return sendto(rtpHandle_, srtpContext_->encryptbuf, buf_size, 0, + return sendto(rtpHandle_, (char*)srtpContext_->encryptbuf, buf_size, 0, (sockaddr*) &rtpDestAddr_, rtpDestAddrLen_); } - return sendto(rtpHandle_, buf, buf_size, 0, + return sendto(rtpHandle_, (char*)buf, buf_size, 0, (sockaddr*) &rtpDestAddr_, rtpDestAddrLen_); } @@ -406,7 +408,7 @@ SocketPair::writeRtcpData(void *buf, int buf_size) auto ret = ff_network_wait_fd(rtcpHandle_); if (ret < 0) return ret; - return sendto(rtcpHandle_, buf, buf_size, 0, + return sendto(rtcpHandle_,(char*) buf, buf_size, 0, (sockaddr*) &rtcpDestAddr_, rtcpDestAddrLen_); } diff --git a/src/media/socket_pair.h b/src/media/socket_pair.h index b1df9343eae7ef2455b76ff4c3cd0a086fdb5d16..7c6bc07ca6468b757169ab38138bcab804fd84d9 100644 --- a/src/media/socket_pair.h +++ b/src/media/socket_pair.h @@ -32,9 +32,22 @@ #ifndef SOCKET_PAIR_H_ #define SOCKET_PAIR_H_ +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + #include "media_io_handle.h" +#ifndef _WIN32 #include <sys/socket.h> +#include <netdb.h> +#include <poll.h> +#else +#include <winsock2.h> +#include <ws2tcpip.h> +using socklen_t = int; +#endif + #include <mutex> #include <memory> #include <atomic> diff --git a/src/media/video/Makefile.am b/src/media/video/Makefile.am index 73876d36a360e237d24726100402578d6f631920..7aebbe40d122e01032ca62c9bd331b0bc18c4992 100644 --- a/src/media/video/Makefile.am +++ b/src/media/video/Makefile.am @@ -12,6 +12,11 @@ SUBDIRS+= \ osxvideo endif +if HAVE_WIN32 +SUBDIRS+= \ + winvideo +endif + noinst_LTLIBRARIES = libvideo.la libvideo_la_SOURCES = \ video_device.h \ diff --git a/src/media/video/sinkclient.cpp b/src/media/video/sinkclient.cpp index 910cce4b76b462d387e2ea45491dc9e8517c33e8..8e83deb7276381de2775fc0b67336c45fdb09b47 100644 --- a/src/media/video/sinkclient.cpp +++ b/src/media/video/sinkclient.cpp @@ -51,7 +51,9 @@ #include "client/ring_signal.h" #include "dring/videomanager_interface.h" +#ifndef _WIN32 #include <sys/mman.h> +#endif #include <fcntl.h> #include <cstdio> #include <sstream> diff --git a/src/media/video/winvideo/Makefile.am b/src/media/video/winvideo/Makefile.am new file mode 100644 index 0000000000000000000000000000000000000000..835c37398d517af18aa50828c9e17e147827e243 --- /dev/null +++ b/src/media/video/winvideo/Makefile.am @@ -0,0 +1,11 @@ +include $(top_srcdir)/globals.mak + +noinst_LTLIBRARIES = libwinvideo.la + +libwinvideo_la_SOURCES = \ + video_device_impl.cpp \ + video_device_monitor_impl.cpp + +AM_OBJCXXFLAGS = -std=c++11 + +libwinvideo_la_LIBADD = -ldxguid -lole32 -luuid -lstrmiids -loleaut32 \ No newline at end of file diff --git a/src/media/video/winvideo/capture_graph_interfaces.h b/src/media/video/winvideo/capture_graph_interfaces.h new file mode 100644 index 0000000000000000000000000000000000000000..fe74f8c3dcb06a31d906e1fee4dedd4855ea6232 --- /dev/null +++ b/src/media/video/winvideo/capture_graph_interfaces.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2015 Savoir-Faire Linux Inc. + * Author: Edric Milaret <edric.ladent-milaret@savoirfairelinux.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Additional permission under GNU GPL version 3 section 7: + * + * If you modify this program, or any covered work, by linking or + * combining it with the OpenSSL project's OpenSSL library (or a + * modified version of that library), containing parts covered by the + * terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc. + * grants you additional permission to convey the resulting work. + * Corresponding Source for a non-source form of such a combination + * shall include the source code for the parts of OpenSSL used as well + * as that of the covered work. + */ + +#ifndef CAPTURE_GRAPH_INTERFACES +#define CAPTURE_GRAPH_INTERFACES + +#include <dshow.h> + +namespace ring { namespace video { + +class CaptureGraphInterfaces { +public: + CaptureGraphInterfaces() + : captureGraph_(nullptr) + , graph_(nullptr) + , videoInputFilter_(nullptr) + , streamConf_(nullptr) + {} + + ICaptureGraphBuilder2* captureGraph_; + IGraphBuilder* graph_; + IBaseFilter* videoInputFilter_; + IAMStreamConfig* streamConf_; +}; + +}} // namespace ring::video + +#endif \ No newline at end of file diff --git a/src/media/video/winvideo/video_device_impl.cpp b/src/media/video/winvideo/video_device_impl.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f6cbf60f186d46d75afb9e33c2c2c2bbcad936ef --- /dev/null +++ b/src/media/video/winvideo/video_device_impl.cpp @@ -0,0 +1,356 @@ +/* + * Copyright (C) 2015 Savoir-Faire Linux Inc. + * Author: Edric Milaret <edric.ladent-milaret@savoirfairelinux.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Additional permission under GNU GPL version 3 section 7: + * + * If you modify this program, or any covered work, by linking or + * combining it with the OpenSSL project's OpenSSL library (or a + * modified version of that library), containing parts covered by the + * terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc. + * grants you additional permission to convey the resulting work. + * Corresponding Source for a non-source form of such a combination + * shall include the source code for the parts of OpenSSL used as well + * as that of the covered work. + */ + +#include <algorithm> +#include <cassert> +#include <climits> +#include <map> +#include <string> +#include <sstream> +#include <stdexcept> +#include <string> +#include <vector> + +#include "logger.h" +#include "../video_device.h" +#include "capture_graph_interfaces.h" + +#include <dshow.h> + +namespace ring { namespace video { + +class VideoDeviceImpl { + public: + /** + * @throw std::runtime_error + */ + VideoDeviceImpl(const std::string& path); + std::string device; + std::string name; + unsigned int id; + + std::vector<std::string> getChannelList() const; + std::vector<std::string> getSizeList(const std::string& channel) const; + std::vector<std::string> getSizeList() const; + std::vector<std::string> getRateList(const std::string& channel, + const std::string& size) const; + float getRate(unsigned rate) const; + + VideoSettings getSettings() const; + void applySettings(VideoSettings settings); + + DeviceParams getDeviceParams() const; + + private: + std::unique_ptr<CaptureGraphInterfaces> cInterface; + + void setup(); + std::vector<std::string> sizeList_; + std::map<std::string, std::vector<std::string> > rateList_; + std::map<std::string, AM_MEDIA_TYPE*> capMap_; +}; + +VideoDeviceImpl::VideoDeviceImpl(const std::string& id) + : id(atoi(id.c_str())) + , cInterface(new CaptureGraphInterfaces()) +{ + setup(); + + applySettings(VideoSettings()); +} + +void +VideoDeviceImpl::setup() +{ + HRESULT hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED); + if (FAILED(hr)) + return RING_ERR("Could not initialize video device."); + + hr = CoCreateInstance( + CLSID_CaptureGraphBuilder2, + nullptr, + CLSCTX_INPROC_SERVER, + IID_ICaptureGraphBuilder2, + (void**) &cInterface->captureGraph_); + if (FAILED(hr)) + return RING_ERR("Could not create the Filter Graph Manager"); + + hr = CoCreateInstance(CLSID_FilterGraph, + nullptr, + CLSCTX_INPROC_SERVER,IID_IGraphBuilder, + (void**) &cInterface->graph_); + if (FAILED(hr)) + return RING_ERR("Could not add the graph builder!"); + + hr = cInterface->captureGraph_->SetFiltergraph(cInterface->graph_); + if (FAILED(hr)) + return RING_ERR("Could not set filtergraph."); + + ICreateDevEnum *pSysDevEnum = nullptr; + hr = CoCreateInstance(CLSID_SystemDeviceEnum, + nullptr, + CLSCTX_INPROC_SERVER, + IID_ICreateDevEnum, + (void **)&pSysDevEnum); + if (FAILED(hr)) + return RING_ERR("Could not create the enumerator!"); + + IEnumMoniker *pEnumCat = nullptr; + hr = pSysDevEnum->CreateClassEnumerator( + CLSID_VideoInputDeviceCategory, + &pEnumCat, + 0); + if (SUCCEEDED(hr)) { + IMoniker *pMoniker = nullptr; + ULONG cFetched; + unsigned int deviceCounter = 0; + bool done = false; + while ((pEnumCat->Next(1, &pMoniker, &cFetched) == S_OK) && (not done)) + { + if (deviceCounter == this->id) { + IPropertyBag *pPropBag; + hr = pMoniker->BindToStorage( + 0, + 0, + IID_IPropertyBag, + (void **)&pPropBag); + if (SUCCEEDED(hr)) { + VARIANT varName; + VariantInit(&varName); + hr = pPropBag->Read(L"FriendlyName", &varName, 0); + if (SUCCEEDED(hr)) { + int l = WideCharToMultiByte( + CP_UTF8, + 0, + varName.bstrVal, + -1, + 0, 0, 0, 0); + auto tmp = new char[l]; + WideCharToMultiByte( + CP_UTF8, + 0, + varName.bstrVal, + -1, + tmp, + l, + 0, 0); + this->name = std::string(tmp); + this->device = std::string("video=") + this->name; + hr = pMoniker->BindToObject( + nullptr, nullptr, + IID_IBaseFilter, + (void**)&cInterface->videoInputFilter_); + if (SUCCEEDED(hr)) + hr = cInterface->graph_->AddFilter( + cInterface->videoInputFilter_, + varName.bstrVal); + else { + RING_ERR("Could not add filter to device."); + break; + } + hr = cInterface->captureGraph_->FindInterface( + &PIN_CATEGORY_PREVIEW, + &MEDIATYPE_Video, + cInterface->videoInputFilter_, + IID_IAMStreamConfig, + (void **)&cInterface->streamConf_); + if(FAILED(hr)) { + hr = cInterface->captureGraph_->FindInterface( + &PIN_CATEGORY_CAPTURE, + &MEDIATYPE_Video, + cInterface->videoInputFilter_, + IID_IAMStreamConfig, + (void **)&cInterface->streamConf_); + if (FAILED(hr)) { + RING_ERR("Couldn't config the stream!"); + break; + } + } + done = true; + } + VariantClear(&varName); + pPropBag->Release(); + pPropBag = nullptr; + pMoniker->Release(); + pMoniker = nullptr; + } + } + deviceCounter++; + } + pEnumCat->Release(); + pEnumCat = nullptr; + if (done && SUCCEEDED(hr)) { + int piCount; + int piSize; + cInterface->streamConf_->GetNumberOfCapabilities(&piCount, &piSize); + AM_MEDIA_TYPE *pmt; + VIDEO_STREAM_CONFIG_CAPS pSCC; + for (int i = 0; i < piCount; i++) { + cInterface->streamConf_->GetStreamCaps(i, &pmt, (BYTE*)&pSCC); + if (pmt->formattype == FORMAT_VideoInfo) { + auto videoInfo = (VIDEOINFOHEADER*) pmt->pbFormat; + sizeList_.push_back( + std::to_string(videoInfo->bmiHeader.biWidth) + "x" + + std::to_string(videoInfo->bmiHeader.biHeight)); + rateList_[sizeList_.back()].push_back( + std::to_string(1e7 / pSCC.MinFrameInterval)); + rateList_[sizeList_.back()].push_back( + std::to_string(1e7 / pSCC.MaxFrameInterval)); + capMap_[sizeList_.back()] = pmt; + } + } + } + } + pSysDevEnum->Release(); + pSysDevEnum = NULL; +} + +void +VideoDeviceImpl::applySettings(VideoSettings settings) +{ + if (!settings.video_size.empty()) { + auto pmt = capMap_[settings.video_size]; + ((VIDEOINFOHEADER*) pmt->pbFormat)->AvgTimePerFrame = settings.framerate; + if (FAILED(cInterface->streamConf_->SetFormat(capMap_[settings.video_size]))) { + RING_ERR("Could not set settings."); + } + } +} + +DeviceParams +VideoDeviceImpl::getDeviceParams() const +{ + DeviceParams params; + + params.input = device; + params.format = "dshow"; + + AM_MEDIA_TYPE *pmt; + HRESULT hr = cInterface->streamConf_->GetFormat(&pmt); + if (SUCCEEDED(hr)) { + if (pmt->formattype == FORMAT_VideoInfo) { + auto videoInfo = (VIDEOINFOHEADER*) pmt->pbFormat; + params.width = videoInfo->bmiHeader.biWidth; + params.height = videoInfo->bmiHeader.biHeight; + params.framerate = 1e7 / videoInfo->AvgTimePerFrame; + } + } + return params; +} + +VideoSettings +VideoDeviceImpl::getSettings() const +{ + VideoSettings settings; + + settings.name = name; + + AM_MEDIA_TYPE *pmt; + HRESULT hr = cInterface->streamConf_->GetFormat(&pmt); + if (SUCCEEDED(hr)) { + if (pmt->formattype == FORMAT_VideoInfo) { + auto videoInfo = (VIDEOINFOHEADER*) pmt->pbFormat; + settings.video_size = std::to_string(videoInfo->bmiHeader.biWidth) + + "x" + std::to_string(videoInfo->bmiHeader.biHeight); + settings.framerate = 1e7 / videoInfo->AvgTimePerFrame; + } + } + return settings; +} + +VideoDevice::VideoDevice(const std::string& path) + : deviceImpl_(new VideoDeviceImpl(path)) +{ + node_ = path; + name = deviceImpl_->name; +} + +DeviceParams +VideoDevice::getDeviceParams() const +{ + return deviceImpl_->getDeviceParams(); +} + +void +VideoDevice::applySettings(VideoSettings settings) +{ + deviceImpl_->applySettings(settings); +} + +VideoSettings +VideoDevice::getSettings() const +{ + return deviceImpl_->getSettings(); +} + +std::vector<std::string> +VideoDeviceImpl::getSizeList() const +{ + return sizeList_; +} + +std::vector<std::string> +VideoDeviceImpl::getRateList(const std::string& channel, + const std::string& size) const +{ + (void) channel; + return rateList_.at(size); +} + +std::vector<std::string> +VideoDeviceImpl::getSizeList(const std::string& channel) const +{ + (void) channel; + return sizeList_; +} + +std::vector<std::string> +VideoDeviceImpl::getChannelList() const +{ + return {"default"}; +} + +DRing::VideoCapabilities +VideoDevice::getCapabilities() const +{ + DRing::VideoCapabilities cap; + + for (const auto& chan : deviceImpl_->getChannelList()) { + for (const auto& size : deviceImpl_->getSizeList(chan)) { + cap[chan][size] = deviceImpl_->getRateList(chan, size); + } + } + return cap; +} + +VideoDevice::~VideoDevice() +{} + +}} // namespace ring::video \ No newline at end of file diff --git a/src/media/video/winvideo/video_device_monitor_impl.cpp b/src/media/video/winvideo/video_device_monitor_impl.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e66624e29bf70f90afeac4f8a857812bc8f5d78b --- /dev/null +++ b/src/media/video/winvideo/video_device_monitor_impl.cpp @@ -0,0 +1,169 @@ +/* + * Copyright (C) 2015 Savoir-Faire Linux Inc. + * Author: Edric Milaret <edric.ladent-milaret@savoirfairelinux.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Additional permission under GNU GPL version 3 section 7: + * + * If you modify this program, or any covered work, by linking or + * combining it with the OpenSSL project's OpenSSL library (or a + * modified version of that library), containing parts covered by the + * terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc. + * grants you additional permission to convey the resulting work. + * Corresponding Source for a non-source form of such a combination + * shall include the source code for the parts of OpenSSL used as well + * as that of the covered work. + */ + +#include <algorithm> +#include <cerrno> +#include <cstdio> +#include <mutex> +#include <sstream> +#include <stdexcept> // for std::runtime_error +#include <string> +#include <thread> +#include <unistd.h> +#include <vector> + +#include "../video_device_monitor.h" +#include "logger.h" +#include "noncopyable.h" + +#include <dshow.h> +#include <dbt.h> + +namespace ring { namespace video { + +class VideoDeviceMonitorImpl { + public: + /* + * This is the only restriction to the pImpl design: + * as the Linux implementation has a thread, it needs a way to notify + * devices addition and deletion. + * + * This class should maybe inherit from VideoDeviceMonitor instead of + * being its pImpl. + */ + VideoDeviceMonitorImpl(VideoDeviceMonitor* monitor); + ~VideoDeviceMonitorImpl(); + + void start(); + + private: + NON_COPYABLE(VideoDeviceMonitorImpl); + + VideoDeviceMonitor* monitor_; + + void run(); + + mutable std::mutex mutex_; + bool probing_; + std::thread thread_; +}; + +VideoDeviceMonitorImpl::VideoDeviceMonitorImpl(VideoDeviceMonitor* monitor) + : monitor_(monitor) + , mutex_() + , thread_() +{} + +void +VideoDeviceMonitorImpl::start() +{ + probing_ = true; + thread_ = std::thread(&VideoDeviceMonitorImpl::run, this); +} + +VideoDeviceMonitorImpl::~VideoDeviceMonitorImpl() +{ + probing_ = false; + if (thread_.joinable()) + thread_.join(); +} + +void +VideoDeviceMonitorImpl::run() +{ + //FIX ME : That's one shot + std::list<std::string> deviceList; + HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED); + ICreateDevEnum *pDevEnum; + hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, + CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pDevEnum)); + + IEnumMoniker *pEnum; + if (SUCCEEDED(hr)) { + hr = pDevEnum->CreateClassEnumerator( + CLSID_VideoInputDeviceCategory, + &pEnum, 0); + if (FAILED(hr)) { + RING_ERR("No webcam found."); + hr = VFW_E_NOT_FOUND; + } + pDevEnum->Release(); + if (hr != VFW_E_NOT_FOUND) { + IMoniker *pMoniker = NULL; + unsigned deviceID = 0; + while (pEnum->Next(1, &pMoniker, NULL) == S_OK) + { + IPropertyBag *pPropBag; + HRESULT hr = pMoniker->BindToStorage( + 0, + 0, + IID_PPV_ARGS(&pPropBag)); + if (FAILED(hr)) { + pMoniker->Release(); + continue; + } + + VARIANT var; + VariantInit(&var); + hr = pPropBag->Read(L"Description", &var, 0); + if (FAILED(hr)) { + hr = pPropBag->Read(L"FriendlyName", &var, 0); + } + if (SUCCEEDED(hr)) { + deviceList.push_back(std::to_string(deviceID)); + VariantClear(&var); + } + + hr = pPropBag->Write(L"FriendlyName", &var); + pPropBag->Release(); + pMoniker->Release(); + deviceID++; + } + pEnum->Release(); + for (auto device : deviceList) { + //FIXME: Custom id is a weak way to do that + monitor_->addDevice(device); + } + } + } +} + +VideoDeviceMonitor::VideoDeviceMonitor() + : preferences_() + , devices_() + , monitorImpl_(new VideoDeviceMonitorImpl(this)) +{ + monitorImpl_->start(); +} + +VideoDeviceMonitor::~VideoDeviceMonitor() +{} + +}} // namespace ring::video diff --git a/src/preferences.cpp b/src/preferences.cpp index 473b252dcc9aeb3a538a66af63215462f6f1ebfc..ef1b16508b9efd36f452208e519af2a660dfa6e1 100644 --- a/src/preferences.cpp +++ b/src/preferences.cpp @@ -50,6 +50,9 @@ #if HAVE_COREAUDIO #include "audio/coreaudio/corelayer.h" #endif +#if HAVE_PORTAUDIO +#include "audio/portaudio/portaudiolayer.h" +#endif #endif /* HAVE_OPENSL */ #include <yaml-cpp/yaml.h> @@ -58,6 +61,7 @@ #include "sip/sip_utils.h" #include <sstream> #include <algorithm> +#include <stdexcept> #include "fileutils.h" namespace ring { @@ -356,6 +360,8 @@ AudioLayer* AudioPreference::createAudioLayer() audioApi_ = ALSA_API_STR; #elif HAVE_COREAUDIO audioApi_ = COREAUDIO_API_STR; +#elif HAVE_PORTAUDIO + audioApi_ = PORTAUDIO_API_STR; #else throw; #endif @@ -396,6 +402,15 @@ AudioLayer* AudioPreference::createAudioLayer() return NULL; #endif +#if HAVE_PORTAUDIO + audioApi_ = PORTAUDIO_API_STR; + try { + return new PortAudioLayer(*this); + } catch (const std::runtime_error &e) { + RING_WARN("Could not create PortAudio layer. There will be no sound."); + } + return nullptr; +#endif #endif // __ANDROID__ } diff --git a/src/registration_states.h b/src/registration_states.h index 5b72325b44287fe0701cb04f00767d5633dea0c7..e523b93cdbee7e6f1c25f11218352fb544634f83 100644 --- a/src/registration_states.h +++ b/src/registration_states.h @@ -32,6 +32,10 @@ #ifndef REGISTRATION_STATES_H_ #define REGISTRATION_STATES_H_ +#ifdef REGISTERED +#undef REGISTERED +#endif + namespace ring { /** Contains all the Registration states for an account can be in */ diff --git a/src/ringdht/ringaccount.cpp b/src/ringdht/ringaccount.cpp index 8d7987a8c2f1d674cf229932164073c5d27579a2..299a1f6ad466f1e6aab548b2b8e223878f38342f 100644 --- a/src/ringdht/ringaccount.cpp +++ b/src/ringdht/ringaccount.cpp @@ -690,7 +690,7 @@ void RingAccount::doRegister_() #if 0 // enable if dht_ logging is needed dht_.setLoggers( - [](char const* m, va_list args){ vlogger(LOG_ERR, m, args); }, + [](char const* m, va_list args){ vlogger(LOG_ERR, m, args); } [](char const* m, va_list args){ vlogger(LOG_WARNING, m, args); }, [](char const* m, va_list args){ vlogger(LOG_DEBUG, m, args); } ); diff --git a/src/ringdht/sips_transport_ice.cpp b/src/ringdht/sips_transport_ice.cpp index 9a0bc223713dd361b3cd2866bc6cf99c8f92504d..cbbf482071daaa15f5c852590228c3c5a4567744 100644 --- a/src/ringdht/sips_transport_ice.cpp +++ b/src/ringdht/sips_transport_ice.cpp @@ -401,7 +401,7 @@ SipsIceTransport::certGetInfo(pj_pool_t* pool, pj_ssl_cert_info* ci, std::memset(ci, 0, sizeof(pj_ssl_cert_info)); /* Full raw certificate */ - const pj_str_t raw_crt_pjstr {(char*)crt_raw.data, crt_raw.size}; + const pj_str_t raw_crt_pjstr {(char*)crt_raw.data, (long int) crt_raw.size}; pj_strdup(pool, &ci->cert_raw, &raw_crt_pjstr); /* Version */ diff --git a/src/sip/sip_utils.cpp b/src/sip/sip_utils.cpp index 0df195756ab3b4b6bf782edd7899a29b51aba0d8..6b1510c7e7b650e2c8bed984c179b84858638354 100644 --- a/src/sip/sip_utils.cpp +++ b/src/sip/sip_utils.cpp @@ -43,10 +43,12 @@ #include <pjsip/sip_uri.h> #include <pj/list.h> +#ifndef _WIN32 #include <netdb.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> +#endif #include <vector> #include <algorithm> diff --git a/src/sip/sipaccount.cpp b/src/sip/sipaccount.cpp index ad35de41578f29e2174664b8f73440b1abef21b7..b6a698e34fdb824f2a7abc51a555f1e987943e2c 100644 --- a/src/sip/sipaccount.cpp +++ b/src/sip/sipaccount.cpp @@ -68,7 +68,7 @@ #include "string_utils.h" #include <unistd.h> -#include <pwd.h> + #include <algorithm> #include <array> @@ -76,6 +76,15 @@ #include <sstream> #include <cstdlib> +#include "upnp/upnp_control.h" +#include "ip_utils.h" + +#ifdef _WIN32 +#include <lmcons.h> +#else +#include <pwd.h> +#endif + namespace ring { using yaml_utils::parseValue; @@ -1332,10 +1341,18 @@ bool SIPAccount::proxyMatch(const std::string& hostname, pjsip_endpoint * /*endp std::string SIPAccount::getLoginName() { +#ifndef _WIN32 struct passwd * user_info = getpwuid(getuid()); return user_info ? user_info->pw_name : ""; +#else + LPWSTR username[UNLEN+1]; + DWORD username_len = UNLEN+1; + return GetUserName(*username, &username_len) ? std::string((char*)*username) : ""; +#endif } + + std::string SIPAccount::getFromUri() const { std::string scheme; diff --git a/src/sip/sipaccountbase.h b/src/sip/sipaccountbase.h index 1cef21d25a3876bf764e726f58c1235952ae65d5..d1c764722b00c176cccf67f1d8be7a58479039a5 100644 --- a/src/sip/sipaccountbase.h +++ b/src/sip/sipaccountbase.h @@ -43,6 +43,7 @@ #include "noncopyable.h" #include <pjsip/sip_types.h> +#include <opendht/value.h> #include <array> #include <vector> diff --git a/src/sip/tlsvalidator.cpp b/src/sip/tlsvalidator.cpp index 2837bf2dc1290218dd449ee765e68fc27dba36c0..14790f9a37e6f15e8503c55d447522de0c79d82c 100644 --- a/src/sip/tlsvalidator.cpp +++ b/src/sip/tlsvalidator.cpp @@ -54,10 +54,12 @@ #include <sys/types.h> #include <sys/stat.h> +#ifndef _WIN32 #include <sys/socket.h> #include <netinet/tcp.h> #include <netinet/in.h> #include <netdb.h> +#endif #include <unistd.h> #include <fcntl.h> diff --git a/src/sip/tlsvalidator.h b/src/sip/tlsvalidator.h index 563164364b359d684a3177d1351b5fa171a9eed3..e68319d1a69fe225ab805072421d7df76d90b205 100644 --- a/src/sip/tlsvalidator.h +++ b/src/sip/tlsvalidator.h @@ -35,6 +35,32 @@ namespace ring { namespace tls { class GnuTlsGlobalInit; }} // namespace ring::tls +#if !defined (S_IRWXG) +#define S_IRWXG 00070 +#endif /* S_IRWXG */ +#if !defined (S_IRGRP) +#define S_IRGRP 00040 +#endif /* S_IRGRP */ +#if !defined (S_IWGRP) +#define S_IWGRP 00020 +#endif /* S_IWGRP */ +#if !defined (S_IXGRP) +#define S_IXGRP 00010 +#endif /* S_IXGRP */ +#if !defined (S_IRWXO) +#define S_IRWXO 00007 +#endif /* S_IRWXO */ +#if !defined (S_IROTH) +#define S_IROTH 00004 +#endif /* S_IROTH */ +#if !defined (S_IWOTH) +#define S_IWOTH 00002 +#endif /* S_IWOTH */ +#if !defined (S_IXOTH) +#define S_IXOTH 00001 +#endif /* S_IXOTH */ + + namespace ring { class TlsValidatorException : public std::runtime_error { diff --git a/src/winsyslog.c b/src/winsyslog.c new file mode 100644 index 0000000000000000000000000000000000000000..69f311b449a868e2abec67134b0dc87b4b80b330 --- /dev/null +++ b/src/winsyslog.c @@ -0,0 +1,108 @@ +/* + * This header borrowed from Cygnus GNUwin32 project + * + * Modified for use with functions to map syslog + * calls to EventLog calls on the windows platform + * + * much of this is not used, but here for the sake of + * error free compilation. EventLogs will most likely + * not behave as syslog does, but may be useful anyway. + * much of what syslog does can be emulated here, but + * that will have to be done later. + */ + +#include "winsyslog.h" +#include <stdio.h> +#include <fcntl.h> +#include <process.h> +#include <stdlib.h> + +#ifndef THREAD_SAFE +static char *loghdr; /* log file header string */ +static HANDLE loghdl = NULL; /* handle of event source */ +#endif + +static CHAR * // return error message +getLastErrorText( // converts "Lasr Error" code into text + CHAR *pBuf, // message buffer + ULONG bufSize) // buffer size +{ + DWORD retSize; + LPTSTR pTemp=NULL; + + if (bufSize < 16) { + if (bufSize > 0) { + pBuf[0]='\0'; + } + return(pBuf); + } + retSize=FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER| + FORMAT_MESSAGE_FROM_SYSTEM| + FORMAT_MESSAGE_ARGUMENT_ARRAY, + NULL, + GetLastError(), + LANG_NEUTRAL, + (LPTSTR)&pTemp, + 0, + NULL); + if (!retSize || pTemp == NULL) { + pBuf[0]='\0'; + } + else { + pTemp[strlen(pTemp)-2]='\0'; //remove cr and newline character + sprintf(pBuf,"%0.*s (0x%x)",bufSize-16,pTemp,GetLastError()); + LocalFree((HLOCAL)pTemp); + } + return(pBuf); +} + +void closelog(void) +{ + DeregisterEventSource(loghdl); + free(loghdr); +} + +/* Emulator for GNU vsyslog() routine + * Accepts: priority + * format + * arglist + */ +// TODO: use a real EventIdentifier with a Message Text file ? +// https://msdn.microsoft.com/en-us/library/windows/desktop/aa363679%28v=vs.85%29.aspx + void vsyslog(int level, const char* format, va_list arglist) + { + CONST CHAR *arr[1]; + char tmp[1024]; + + if (!loghdl) + openlog(LOGFILE, WINLOG_PID, WINLOG_MAIL); + + vsprintf(tmp, format, arglist); + + arr[0] = tmp; + BOOL err = ReportEvent(loghdl, (unsigned short) level, (unsigned short)level, + level, NULL, 1, 0, arr, NULL); + + if (err == 0) + { + CHAR errText[1024]; + puts(getLastErrorText(errText, 1024)); + } +} + +/* Emulator for BSD openlog() routine + * Accepts: identity + * options + * facility + */ + void openlog(const char *ident, int logopt, int facility) + { + char tmp[1024]; + + if (loghdl) { + closelog(); + } + loghdl = RegisterEventSource(NULL, ident); + sprintf(tmp, (logopt & WINLOG_PID) ? "%s[%d]" : "%s", ident, getpid()); + loghdr = _strdup(tmp); /* save header for later */ +} \ No newline at end of file diff --git a/src/winsyslog.h b/src/winsyslog.h new file mode 100644 index 0000000000000000000000000000000000000000..628573206354bba26e481fc3edd8190632c7b1c2 --- /dev/null +++ b/src/winsyslog.h @@ -0,0 +1,64 @@ +/* + * This header borrowed from Cygnus GNUwin32 project + * + * Modified for use with functions to map syslog + * calls to EventLog calls on the windows platform + * + * much of this is not used, but here for the sake of + * error free compilation. EventLogs will most likely + * not behave as syslog does, but may be useful anyway. + * much of what syslog does can be emulated here, but + * that will have to be done later. + */ + +#ifndef WINSYSLOG_H +#define WINSYSLOG_H +#define WIN32_LEAN_AND_MEAN +#include <windows.h> + +#define WINLOG_PRIMASK 0x07 + +#define WINLOG_PRI(p) ((p) & WINLOG_PRIMASK) +#define WINLOG_MAKEPRI(fac, pri) (((fac) << 3) | (pri)) + +#define WINLOG_KERN (0<<3) +#define WINLOG_USER (1<<3) +#define WINLOG_MAIL (2<<3) +#define WINLOG_DAEMON (3<<3) +#define WINLOG_AUTH (4<<3) +#define WINLOG_SYSLOG (5<<3) +#define WINLOG_LPR (6<<3) +#define WINLOG_NEWS (7<<3) +#define WINLOG_UUCP (8<<3) +#define WINLOG_CRON (9<<3) +#define WINLOG_AUTHPRIV (10<<3) + +#define WINLOG_NFACILITIES 10 +#define WINLOG_FACMASK 0x03f8 +#define WINLOG_FAC(p) (((p) & WINLOG_FACMASK) >> 3) + +#define WINLOG_MASK(pri) (1 << (pri)) +#define WINLOG_UPTO(pri) ((1 << ((pri)+1)) - 1) + +#define LOGFILE "ringcli" + +/* + * Option flags for openlog. + * + * WINLOG_ODELAY no longer does anything. + * WINLOG_NDELAY is the inverse of what it used to be. + */ +#define WINLOG_PID 0x01 /* log the pid with each message */ +#define WINLOG_CONS 0x02 /* log on the console if errors in sending */ +#define WINLOG_ODELAY 0x04 /* delay open until first syslog() (default) */ +#define WINLOG_NDELAY 0x08 /* don't delay open */ +#define WINLOG_NOWAIT 0x10 /* don't wait for console forks: DEPRECATED */ +#define WINLOG_PERROR 0x20 /* log to stderr as well */ + +#define strerror_r(errno,buf,len) strerror_s(buf,len,errno) + +extern void closelog(void); +extern void openlog(const char *, int, int); +extern void vsyslog(int, const char *, va_list); + +#endif \ No newline at end of file