diff --git a/CHANGES.md b/CHANGES.md index 2d517c9e..33164917 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -11,6 +11,16 @@ ## develop +## 18.12.0 + +- [ADD] ROS 対応 +- [CHANGE] ビルド時のターゲットと、パッケージのファイル名を変更する +- [CHANGE] p2p モードの切断後に自動的に window が閉じられないようにする +- [UPDATE] Boost 1.69.0 にアップデートする +- [UPDATE] CLI11 v1.6.2 にアップデートする +- [UPDATE] JSON v3.4.0 にアップデートする +- [CHANGE] x86_64, armv8 の場合は H264 を指定できないようにする + ## 18.10.2 - [ADD] 解像度を固定するオプションを追加する diff --git a/Makefile b/Makefile index bfd944a6..5d70f944 100644 --- a/Makefile +++ b/Makefile @@ -1,22 +1,29 @@ -ifndef ARCH - ARCH=arm +ifndef RTC_ROOT + RTC_ROOT = $(HOME) endif -ifndef OS - OS=raspbian +ifndef BOOST_PATH + BOOST_PATH = /root/boost-1.69.0 endif -ifndef RTC_ROOT - RTC_ROOT=$(HOME) +ifndef ROS_VERSION + USE_WEBRTC_LIBCXX = 1 endif UNAME := $(shell uname -s) TARGET = momo -RTC_LIB = libWebRTC_$(ARCH).a +RTC_LIB = libWebRTC_$(OUT_PATH).a + +RTC_LIB_PATH=$(RTC_ROOT)/src/out/$(OUT_PATH) + +CFLAGS += -Wno-macro-redefined -fno-lto -pthread -std=c++11 -DWEBRTC_POSIX -DOPENSSL_IS_BORINGSSL -Isrc/ + +ifdef USE_WEBRTC_LIBCXX + CFLAGS += -nostdinc++ -isystem$(RTC_ROOT)/src/buildtools/third_party/libc++/trunk/include +endif -CFLAGS += -fno-lto -pthread -std=gnu++11 -nostdinc++ -isystem$(RTC_ROOT)/src/buildtools/third_party/libc++/trunk/include -DWEBRTC_POSIX -DOPENSSL_IS_BORINGSSL -Isrc/ ifdef MOMO_VERSION CFLAGS += -DMOMO_VERSION='"$(MOMO_VERSION)"' endif @@ -24,44 +31,69 @@ endif # webrtc CFLAGS += -I$(RTC_ROOT)/src -I$(RTC_ROOT)/src/third_party/libyuv/include -I$(RTC_ROOT)/src/third_party/abseil-cpp +# H264 を使うかどうかの設定。 +# x86_64/armv8 の場合は H264 を使わない +ifeq ($(UNAME),Linux) + ifneq (,$(findstring arm64,$(OUT_PATH))) + CFLAGS += -DUSE_H264=0 + else + ifneq (,$(findstring x86_64,$(OUT_PATH))) + CFLAGS += -DUSE_H264=0 + else + CFLAGS += -DUSE_H264=1 + endif + endif +endif + ifeq ($(UNAME),Linux) - CC = $(RTC_ROOT)/src/third_party/llvm-build/Release+Asserts/bin/clang - CXX = $(RTC_ROOT)/src/third_party/llvm-build/Release+Asserts/bin/clang++ - AR = $(RTC_ROOT)/src/third_party/llvm-build/Release+Asserts/bin/llvm-ar CFLAGS += -fpic LDFLAGS += -lX11 -lXau -lXdmcp -lxcb -lplds4 -lXext -lexpat -ldl -lnss3 -lnssutil3 -lplc4 -lnspr4 -lrt - CFLAGS += -I/root/boost-1.68.0/include - LDFLAGS += -L/root/boost-1.68.0/lib - ifneq (,$(findstring arm,$(ARCH))) - ifneq (,$(findstring arm64,$(ARCH))) - CC += --sysroot=$(SYSROOT) --target=aarch64-linux-gnu - CXX += --sysroot=$(SYSROOT) --target=aarch64-linux-gnu - CFLAGS += -I$(SYSROOT)/usr/include/aarch64-linux-gnu - LDFLAGS += -L$(SYSROOT)/usr/lib/aarch64-linux-gnu + CFLAGS += -I$(BOOST_PATH)/include + LDFLAGS += -L$(BOOST_PATH)/lib + + ifneq (,$(findstring arm,$(OUT_PATH))) + SYSROOT = $(RTC_ROOT)/rootfs + ifneq (,$(findstring arm64,$(OUT_PATH))) + TARGET_ARCH = aarch64-linux-gnu else + TARGET_ARCH = arm-linux-gnueabihf + CFLAGS += -mfloat-abi=hard + ifneq (,$(findstring armv6,$(OUT_PATH))) + CFLAGS += -mcpu=arm1176jzf-s -mfpu=vfp + else + CFLAGS += -march=armv7-a -mtune=generic-armv7-a -mfpu=neon -mthumb + endif USE_IL_ENCODER ?= 1 - CC += --sysroot=$(SYSROOT) --target=arm-linux-gnueabihf - CXX += --sysroot=$(SYSROOT) --target=arm-linux-gnueabihf - CFLAGS += -I$(SYSROOT)/usr/include/arm-linux-gnueabihf - LDFLAGS += -L$(SYSROOT)/usr/lib/arm-linux-gnueabihf -B$(SYSROOT)/usr/lib/arm-linux-gnueabihf # ilclient ifneq ($(USE_IL_ENCODER),0) + ifneq (,$(findstring raspbian,$(OUT_PATH))) + VC_PATH = $(SYSROOT)/opt/vc + else + VC_PATH = $(SYSROOT)/usr + endif ILCLIENT_DIR = libs/ilclient IL_SOURCE = $(shell find $(ILCLIENT_DIR) -name '*.c') IL_OBJECT = $(IL_SOURCE:%.c=%.o) ILCLIENT_LIB = libilclient.a IL_CFLAGS = -DSTANDALONE -D__STDC_CONSTANT_MACROS -D__STDC_LIMIT_MACROS -DTARGET_POSIX -D_LINUX -fPIC -DPIC -D_REENTRANT -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -U_FORTIFY_SOURCE -g -DHAVE_LIBOPENMAX=2 -DOMX -DOMX_SKIP64BIT -ftree-vectorize -pipe -DUSE_EXTERNAL_OMX -DHAVE_LIBBCM_HOST -DUSE_EXTERNAL_LIBBCM_HOST -DUSE_VCHIQ_ARM - IL_INCLUDES = -I$(SYSROOT)/opt/vc/include/ -I$(SYSROOT)/opt/vc/include/interface/vcos/pthreads -I$(SYSROOT)/opt/vc/include/interface/vmcs_host/linux - CFLAGS += -DUSE_IL_ENCODER=1 $(IL_CFLAGS) -I$(SYSROOT)/opt/vc/include/ -I$(ILCLIENT_DIR)/ -I. - LDFLAGS += -mcpu=arm1176jzf-s -mfpu=vfp -mfloat-abi=hard -L$(SYSROOT)/opt/vc/lib/ -lbrcmGLESv2 -lbrcmEGL -lopenmaxil -lbcm_host -lvcos -lvchiq_arm -lm + IL_INCLUDES = -I$(VC_PATH)/include/ -I$(VC_PATH)/include/interface/vcos/pthreads -I$(VC_PATH)/include/interface/vmcs_host/linux + CFLAGS += -DUSE_IL_ENCODER=1 $(IL_CFLAGS) -I$(VC_PATH)/include/ -I$(ILCLIENT_DIR)/ -I. + LDFLAGS += -L$(VC_PATH)/lib/ -lbrcmGLESv2 -lbrcmEGL -lopenmaxil -lbcm_host -lvcos -lvchiq_arm -lm SOURCE += $(shell find $(CURDIR)/hwenc_il -maxdepth 1 -name '*.cpp') $(ILCLIENT_LIB) - else endif endif - SYSROOT = $(RTC_ROOT)/rootfs - RTC_LIB_PATH=$(RTC_ROOT)/src/out/$(ARCH)-$(OS) - else - RTC_LIB_PATH=$(RTC_ROOT)/src/out/$(ARCH) + endif + + CC = $(RTC_ROOT)/src/third_party/llvm-build/Release+Asserts/bin/clang + CXX = $(RTC_ROOT)/src/third_party/llvm-build/Release+Asserts/bin/clang++ + AR = $(RTC_ROOT)/src/third_party/llvm-build/Release+Asserts/bin/llvm-ar + ifdef TARGET_ARCH + CC += --sysroot=$(SYSROOT) --target=$(TARGET_ARCH) + CXX += --sysroot=$(SYSROOT) --target=$(TARGET_ARCH) + ifdef USE_WEBRTC_LIBCXX + CFLAGS += -I$(SYSROOT)/usr/include/$(TARGET_ARCH) + LDFLAGS += -L$(SYSROOT)/usr/lib/$(TARGET_ARCH) + endif endif endif @@ -69,10 +101,16 @@ ifeq ($(UNAME),Darwin) CFLAGS += -DWEBRTC_POSIX -DWEBRTC_MAC LDFLAGS += -F/System/Library/Frameworks -ldl -framework Foundation -framework AVFoundation -framework CoreServices -framework CoreFoundation -framework AudioUnit -framework AudioToolbox -framework CoreAudio -framework CoreGraphics -framework CoreMedia -framework CoreVideo LIBRTCCONDUCTOR = lib$(RTCCONDUCTOR)_mac.so - RTC_LIB_PATH=$(RTC_ROOT)/src/out/$(ARCH) endif -SOURCE += $(shell find $(CURDIR)/src -name '*.cpp') $(RTC_LIB) +ifdef ROS_VERSION + CFLAGS += -DHAVE_JPEG=1 -DUSE_ROS=1 -I$(SYSROOT)/opt/ros/$(ROS_VERSION)/include + LDFLAGS += -lpthread -L$(SYSROOT)/opt/ros/$(ROS_VERSION)/lib -lmessage_filters -lroscpp -lrosconsole -lroscpp_serialization -lrostime -lxmlrpcpp -lcpp_common -lrosconsole_log4cxx -lrosconsole_backend_interface + SOURCE += $(shell find $(CURDIR)/src -name '*.cpp') +else + SOURCE += $(shell find $(CURDIR)/src -type d -name 'ros' -prune -o -type f -name '*.cpp' -print) +endif +SOURCE += $(RTC_LIB) # boost CFLAGS += -I$(RTC_ROOT)/src/third_party/boringssl/src/include -DOPENSSL_IS_BORINGSSL diff --git a/README.md b/README.md index 53b98d99..8ceb8208 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,16 @@ # WebRTC Native Client Momo +[![GitHub tag (latest SemVer)](https://img.shields.io/github/tag/shiguredo/momo.svg)](https://github.com/shiguredo/momo) +[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) + ## WebRTC Native Client Momo について WebRTC Native Client Momo は libwebrtc を利用しブラウザなしで様々な環境で動作する WebRTC ネイティブクライアントです。 特に Raspberry Pi 環境では Raspberry Pi の GPU に積まれている H.264 ハードウェアエンコーダー機能を利用することが可能です。 +また [ROS](http://www.ros.org/) ノードとしても利用可能です。 + ## OpenMomo プロジェクトについて OpenMomo は WebRTC Native Client Momo をオープンソースとして公開し、継続的に開発を行うことで、ブラウザ以外での WebRTC 利用を推進していくプロジェクトです。 @@ -23,11 +28,17 @@ OpenMomo は WebRTC Native Client Momo をオープンソースとして公開 - Raspberry Pi 3 B/B+ で動作 - Raspbian Stretch ARMv6 - Raspberry Pi Zero W/WH で動作 +- Ubuntu 16.04 x86_64 ROS Kinetic で動作 + - http://wiki.ros.org/kinetic ## 使ってみる Momo を使ってみたい人は [USE.md](doc/USE.md) をお読みください。 +## ROS ノードとして使ってみる + +Momo を ROS ノードとして使ってみたい人は [USE_ROS.md](doc/USE_ROS.md) をお読みください。 + ## ビルドに挑戦する Momo のビルドに挑戦したい人は [BUILD.md](doc/BUILD.md) をお読みください。 @@ -69,3 +80,8 @@ https://discord.gg/gmEuZye ### 有料サポートについて WebRTC Native Client に対する有料でのサポート契約については WebRTC SFU Sora ライセンス契約をしているお客様が前提となります。 + +## H.264 のライセンス費用について + +- Raspberry Pi のハードウェアエンコーダのライセンス費用は Raspberry Pi の価格に含まれています + - https://www.raspberrypi.org/forums/viewtopic.php?t=200855 diff --git a/build/Makefile b/build/Makefile index 1a120348..7f1695de 100644 --- a/build/Makefile +++ b/build/Makefile @@ -1,14 +1,16 @@ BUILD_NUMBER=$(shell date +"%Y%m%d%H%M%S") WEBRTC_VERSION=71 -MOMO_VERSION=18.10.2 +MOMO_VERSION=18.12.0 + +RASPBIAN_VERSION=stretch TARGET=$@ .PHONY: all all: armv6 armv7 armv8 -.PHONY: armv6 armv7 armv8 -armv6 armv7 armv8: +.PHONY: armv6 armv7 armv8 armv7_ros +armv6 armv7 armv8 armv7_ros: # ARM 系ビルド全体で共通のビルド用イメージを作る docker image build --rm -t momo/webrtc-arm-buildbase arm --file arm/buildbase.Dockerfile @@ -35,6 +37,11 @@ armv8.rebuild: $(MAKE) -C arm/armv8 clean.image WEBRTC_VERSION=$(WEBRTC_VERSION) $(MAKE) -C arm/armv8 WEBRTC_VERSION=$(WEBRTC_VERSION) BUILD_NUMBER=$(BUILD_NUMBER) MOMO_VERSION=$(MOMO_VERSION) +.PHONY: armv7_ros.rebuild +armv7_ros.rebuild: + $(MAKE) -C arm/armv7_ros clean.image WEBRTC_VERSION=$(WEBRTC_VERSION) + $(MAKE) -C arm/armv7_ros WEBRTC_VERSION=$(WEBRTC_VERSION) BUILD_NUMBER=$(BUILD_NUMBER) MOMO_VERSION=$(MOMO_VERSION) + # 各プラットフォーム用イメージの掃除。これをすると全体的にビルドし直すことになる。 .PHONY: armv6.clean armv6.clean: @@ -48,13 +55,23 @@ armv7.clean: armv8.clean: $(MAKE) -C arm/armv8 clean.image.all WEBRTC_VERSION=$(WEBRTC_VERSION) -.PHONY: x86_64 -x86_64: +.PHONY: armv7_ros.clean +armv7_ros.clean: + $(MAKE) -C arm/armv7_ros clean.image.all WEBRTC_VERSION=$(WEBRTC_VERSION) + +.PHONY: ubuntu-1804_x86_64 +ubuntu-1804_x86_64: # x86_64 用ビルド - $(MAKE) -C $(TARGET) WEBRTC_VERSION=$(WEBRTC_VERSION) BUILD_NUMBER=$(BUILD_NUMBER) MOMO_VERSION=$(MOMO_VERSION) + $(MAKE) -C x86_64 WEBRTC_VERSION=$(WEBRTC_VERSION) BUILD_NUMBER=$(BUILD_NUMBER) MOMO_VERSION=$(MOMO_VERSION) # 生成されたバイナリをこのディレクトリに移動 - mv $(TARGET)/momo ./momo-$(TARGET)-m$(WEBRTC_VERSION)-$(BUILD_NUMBER) + mv x86_64/momo ./momo-ubuntu-18.04_x86_64-m$(WEBRTC_VERSION)-$(BUILD_NUMBER) + +.PHONY: ubuntu-1604_x86_64_ros +ubuntu-1604_x86_64_ros: + # x86_64_ros 用ビルド + $(MAKE) -C x86_64_ros WEBRTC_VERSION=$(WEBRTC_VERSION) BUILD_NUMBER=$(BUILD_NUMBER) MOMO_VERSION=$(MOMO_VERSION) + mv x86_64_ros/momo ./momo-ubuntu-16.04_x86_64_ros-m$(WEBRTC_VERSION)-$(BUILD_NUMBER) .PHONY: macos macos: @@ -73,35 +90,49 @@ define COPY endef -pkg: armv6.pkg armv7.pkg armv8.pkg x86_64.pkg +pkg: armv6.pkg armv7.pkg armv8.pkg ubuntu-1804_x86_64.pkg ubuntu-1804_x86_64_ros.pkg armv7_ros.pkg armv6.pkg: - mkdir momo-$(MOMO_VERSION)_raspbian_armv6 - $(foreach filename,$(FILENAMES),$(call COPY,../$(filename),momo-$(MOMO_VERSION)_raspbian_armv6/)) - cp $(lastword $(sort $(wildcard ./momo-armv6-*))) momo-$(MOMO_VERSION)_raspbian_armv6/momo - tar czf momo-$(MOMO_VERSION)_raspbian_armv6.tar.gz momo-$(MOMO_VERSION)_raspbian_armv6 - rm -rf momo-$(MOMO_VERSION)_raspbian_armv6 + mkdir momo-$(MOMO_VERSION)_raspbian-$(RASPBIAN_VERSION)_armv6 + $(foreach filename,$(FILENAMES),$(call COPY,../$(filename),momo-$(MOMO_VERSION)_raspbian-$(RASPBIAN_VERSION)_armv6/)) + cp $(lastword $(sort $(wildcard ./momo-armv6-*))) momo-$(MOMO_VERSION)_raspbian-$(RASPBIAN_VERSION)_armv6/momo + tar czf momo-$(MOMO_VERSION)_raspbian-$(RASPBIAN_VERSION)_armv6.tar.gz momo-$(MOMO_VERSION)_raspbian-$(RASPBIAN_VERSION)_armv6 + rm -rf momo-$(MOMO_VERSION)_raspbian-$(RASPBIAN_VERSION)_armv6 armv7.pkg: - mkdir momo-$(MOMO_VERSION)_raspbian_armv7 - $(foreach filename,$(FILENAMES),$(call COPY,../$(filename),momo-$(MOMO_VERSION)_raspbian_armv7/)) - cp $(lastword $(sort $(wildcard ./momo-armv7-*))) momo-$(MOMO_VERSION)_raspbian_armv7/momo - tar czf momo-$(MOMO_VERSION)_raspbian_armv7.tar.gz momo-$(MOMO_VERSION)_raspbian_armv7 - rm -rf momo-$(MOMO_VERSION)_raspbian_armv7 + mkdir momo-$(MOMO_VERSION)_raspbian-$(RASPBIAN_VERSION)_armv7 + $(foreach filename,$(FILENAMES),$(call COPY,../$(filename),momo-$(MOMO_VERSION)_raspbian-$(RASPBIAN_VERSION)_armv7/)) + cp $(lastword $(sort $(wildcard ./momo-armv7-*))) momo-$(MOMO_VERSION)_raspbian-$(RASPBIAN_VERSION)_armv7/momo + tar czf momo-$(MOMO_VERSION)_raspbian-$(RASPBIAN_VERSION)_armv7.tar.gz momo-$(MOMO_VERSION)_raspbian-$(RASPBIAN_VERSION)_armv7 + rm -rf momo-$(MOMO_VERSION)_raspbian-$(RASPBIAN_VERSION)_armv7 armv8.pkg: - mkdir momo-$(MOMO_VERSION)_ubuntu_armv8 - $(foreach filename,$(FILENAMES),$(call COPY,../$(filename),momo-$(MOMO_VERSION)_ubuntu_armv8/)) - cp $(lastword $(sort $(wildcard ./momo-armv8-*))) momo-$(MOMO_VERSION)_ubuntu_armv8/momo - tar czf momo-$(MOMO_VERSION)_ubuntu_armv8.tar.gz momo-$(MOMO_VERSION)_ubuntu_armv8 - rm -rf momo-$(MOMO_VERSION)_ubuntu_armv8 - -x86_64.pkg: - mkdir momo-$(MOMO_VERSION)_ubuntu_x86_64 - $(foreach filename,$(FILENAMES),$(call COPY,../$(filename),momo-$(MOMO_VERSION)_ubuntu_x86_64/)) - cp $(lastword $(sort $(wildcard ./momo-x86_64-*))) momo-$(MOMO_VERSION)_ubuntu_x86_64/momo - tar czf momo-$(MOMO_VERSION)_ubuntu_x86_64.tar.gz momo-$(MOMO_VERSION)_ubuntu_x86_64 - rm -rf momo-$(MOMO_VERSION)_ubuntu_x86_64 + mkdir momo-$(MOMO_VERSION)_ubuntu-16.04_armv8 + $(foreach filename,$(FILENAMES),$(call COPY,../$(filename),momo-$(MOMO_VERSION)_ubuntu-16.04_armv8/)) + cp $(lastword $(sort $(wildcard ./momo-armv8-*))) momo-$(MOMO_VERSION)_ubuntu-16.04_armv8/momo + tar czf momo-$(MOMO_VERSION)_ubuntu-16.04_armv8.tar.gz momo-$(MOMO_VERSION)_ubuntu-16.04_armv8 + rm -rf momo-$(MOMO_VERSION)_ubuntu-16.04_armv8 + +ubuntu-1804_x86_64.pkg: + mkdir momo-$(MOMO_VERSION)_ubuntu-18.04_x86_64 + $(foreach filename,$(FILENAMES),$(call COPY,../$(filename),momo-$(MOMO_VERSION)_ubuntu-18.04_x86_64/)) + cp $(lastword $(sort $(wildcard ./momo-ubuntu-18.04_x86_64-*))) momo-$(MOMO_VERSION)_ubuntu-18.04_x86_64/momo + tar czf momo-$(MOMO_VERSION)_ubuntu-18.04_x86_64.tar.gz momo-$(MOMO_VERSION)_ubuntu-18.04_x86_64 + rm -rf momo-$(MOMO_VERSION)_ubuntu-18.04_x86_64 + +ubuntu-1604_x86_64_ros.pkg: + mkdir momo-$(MOMO_VERSION)_ubuntu-16.04_x86_64_ros + $(foreach filename,$(FILENAMES),$(call COPY,../$(filename),momo-$(MOMO_VERSION)_ubuntu-16.04_x86_64_ros/)) + cp $(lastword $(sort $(wildcard ./momo-ubuntu-16.04_x86_64_ros-*))) momo-$(MOMO_VERSION)_ubuntu-16.04_x86_64_ros/momo + tar czf momo-$(MOMO_VERSION)_ubuntu-16.04_x86_64_ros.tar.gz momo-$(MOMO_VERSION)_ubuntu-16.04_x86_64_ros + rm -rf momo-$(MOMO_VERSION)_ubuntu-16.04_x86_64_ros + +armv7_ros.pkg: + mkdir momo-$(MOMO_VERSION)_ubuntu-16.04_armv7_ros + $(foreach filename,$(FILENAMES),$(call COPY,../$(filename),momo-$(MOMO_VERSION)_ubuntu-16.04_armv7_ros/)) + cp $(lastword $(sort $(wildcard ./momo-armv7_ros-*))) momo-$(MOMO_VERSION)_ubuntu-16.04_armv7_ros/momo + tar czf momo-$(MOMO_VERSION)_ubuntu-16.04_armv7_ros.tar.gz momo-$(MOMO_VERSION)_ubuntu-16.04_armv7_ros + rm -rf momo-$(MOMO_VERSION)_ubuntu-16.04_armv7_ros clean.pkg: rm -rf momo-$(MOMO_VERSION)_* diff --git a/build/arm/armv6/Dockerfile b/build/arm/armv6/Dockerfile index 0f027a0f..3ef99e00 100644 --- a/build/arm/armv6/Dockerfile +++ b/build/arm/armv6/Dockerfile @@ -16,10 +16,14 @@ RUN set -x \ COPY patch/4k.patch /root/ +# exit 0 は cipd ensure コマンドでのエラーの暫定対応 RUN set -x \ && cd /root/src \ && git checkout -b m$WEBRTC_VERSION remotes/branch-heads/$WEBRTC_VERSION \ - && gclient sync \ + && gclient sync; exit 0 + +RUN set -x \ + && cd /root/src \ && patch -p2 < ../4k.patch RUN set -x \ @@ -66,15 +70,15 @@ COPY patch/project-config-raspbian.jam /root/ RUN cd ~/ \ && set -ex \ - && curl -LO https://dl.bintray.com/boostorg/release/1.68.0/source/boost_1_68_0.tar.gz \ - && tar xf boost_1_68_0.tar.gz \ - && cd boost_1_68_0 \ + && curl -LO https://dl.bintray.com/boostorg/release/1.69.0/source/boost_1_69_0.tar.gz \ + && tar xf boost_1_69_0.tar.gz \ + && cd boost_1_69_0 \ && ./bootstrap.sh \ && cp ../project-config-raspbian.jam ./project-config.jam \ - && ./b2 target-os=linux architecture=arm address-model=32 link=static variant=release install -j`nproc` --prefix=/root/boost-1.68.0 --with-system --with-filesystem \ + && ./b2 target-os=linux architecture=arm address-model=32 link=static variant=release install -j`nproc` --prefix=/root/boost-1.69.0 --with-system --with-filesystem \ && cd ~/ \ - && rm boost_1_68_0.tar.gz \ - && rm -rf boost_1_68_0 + && rm boost_1_69_0.tar.gz \ + && rm -rf boost_1_69_0 # 必要なファイルだけ持ってくる FROM ubuntu:16.04 @@ -97,4 +101,4 @@ RUN set -x \ COPY --from=builder /root/rootfs/ /root/rootfs/ # Boost -COPY --from=builder /root/boost-1.68.0/ /root/boost-1.68.0/ +COPY --from=builder /root/boost-1.69.0/ /root/boost-1.69.0/ diff --git a/build/arm/armv6/Makefile b/build/arm/armv6/Makefile index 71044955..d3a365d1 100644 --- a/build/arm/armv6/Makefile +++ b/build/arm/armv6/Makefile @@ -19,7 +19,7 @@ all: clean docker container create -it --name momo momo/webrtc-armv6:m$(WEBRTC_VERSION) docker container start momo docker container cp momo.tar.gz momo:/root/ - docker container exec momo /bin/bash -c "cd /root && tar xf momo.tar.gz && cd momo && make USE_IL_ENCODER=$(USE_IL_ENCODER) ARCH=armv6 BUILD_MODE=$(BUILD_MODE) MOMO_VERSION=$(MOMO_VERSION)" + docker container exec momo /bin/bash -c "cd /root && tar xf momo.tar.gz && cd momo && make OUT_PATH=armv6-raspbian USE_IL_ENCODER=$(USE_IL_ENCODER) BUILD_MODE=$(BUILD_MODE) MOMO_VERSION=$(MOMO_VERSION)" docker container cp momo:/root/momo/momo . docker container stop momo docker container rm momo diff --git a/build/arm/armv7/Dockerfile b/build/arm/armv7/Dockerfile index fa83d759..0ce1b277 100644 --- a/build/arm/armv7/Dockerfile +++ b/build/arm/armv7/Dockerfile @@ -13,10 +13,14 @@ RUN set -x \ COPY patch/4k.patch /root/ +# exit 0 は cipd ensure コマンドでのエラーの暫定対応 RUN set -x \ && cd /root/src \ && git checkout -b m$WEBRTC_VERSION remotes/branch-heads/$WEBRTC_VERSION \ - && gclient sync \ + && gclient sync; exit 0 + +RUN set -x \ + && cd /root/src \ && patch -p2 < ../4k.patch RUN set -x \ @@ -61,15 +65,15 @@ COPY patch/project-config-raspbian.jam /root/ RUN cd ~/ \ && set -ex \ - && curl -LO https://dl.bintray.com/boostorg/release/1.68.0/source/boost_1_68_0.tar.gz \ - && tar xf boost_1_68_0.tar.gz \ - && cd boost_1_68_0 \ + && curl -LO https://dl.bintray.com/boostorg/release/1.69.0/source/boost_1_69_0.tar.gz \ + && tar xf boost_1_69_0.tar.gz \ + && cd boost_1_69_0 \ && ./bootstrap.sh \ && cp ../project-config-raspbian.jam ./project-config.jam \ - && ./b2 target-os=linux architecture=arm address-model=32 link=static variant=release install -j`nproc` --prefix=/root/boost-1.68.0 --with-system --with-filesystem \ + && ./b2 target-os=linux architecture=arm address-model=32 link=static variant=release install -j`nproc` --prefix=/root/boost-1.69.0 --with-system --with-filesystem \ && cd ~/ \ - && rm boost_1_68_0.tar.gz \ - && rm -rf boost_1_68_0 + && rm boost_1_69_0.tar.gz \ + && rm -rf boost_1_69_0 # 必要なファイルだけ持ってくる FROM ubuntu:16.04 @@ -92,4 +96,4 @@ RUN set -x \ COPY --from=builder /root/rootfs/ /root/rootfs/ # Boost -COPY --from=builder /root/boost-1.68.0/ /root/boost-1.68.0/ +COPY --from=builder /root/boost-1.69.0/ /root/boost-1.69.0/ diff --git a/build/arm/armv7/Makefile b/build/arm/armv7/Makefile index 3091eeb9..396fdc85 100644 --- a/build/arm/armv7/Makefile +++ b/build/arm/armv7/Makefile @@ -19,7 +19,7 @@ all: clean docker container create -it --name momo momo/webrtc-armv7:m$(WEBRTC_VERSION) docker container start momo docker container cp momo.tar.gz momo:/root/ - docker container exec momo /bin/bash -c "cd /root && tar xf momo.tar.gz && cd momo && make USE_IL_ENCODER=$(USE_IL_ENCODER) BUILD_MODE=$(BUILD_MODE) MOMO_VERSION=$(MOMO_VERSION)" + docker container exec momo /bin/bash -c "cd /root && tar xf momo.tar.gz && cd momo && make OUT_PATH=arm-raspbian USE_IL_ENCODER=$(USE_IL_ENCODER) BUILD_MODE=$(BUILD_MODE) MOMO_VERSION=$(MOMO_VERSION)" docker container cp momo:/root/momo/momo . docker container stop momo docker container rm momo diff --git a/build/arm/armv7_ros/Dockerfile b/build/arm/armv7_ros/Dockerfile new file mode 100644 index 00000000..bc141045 --- /dev/null +++ b/build/arm/armv7_ros/Dockerfile @@ -0,0 +1,99 @@ +FROM momo/webrtc-armv7-ros-buildbase as builder + +ARG WEBRTC_VERSION + +RUN set -x \ + && apt-get update \ + && cd /root \ + && fetch webrtc \ + && bash ./src/build/install-build-deps.sh \ + && gclient sync \ + && apt-get clean \ + && rm -rf /var/lib/apt/lists/* + +COPY patch/4k.patch /root/ + +# exit 0 は cipd ensure コマンドでのエラーの暫定対応 +RUN set -x \ + && cd /root/src \ + && git checkout -b m$WEBRTC_VERSION remotes/branch-heads/$WEBRTC_VERSION \ + && gclient sync; exit 0 + +RUN set -x \ + && cd /root/src \ + && patch -p2 < ../4k.patch + +RUN set -x \ + && cd /root/src \ + && rm -rf out/arm-xenial \ + && gn gen out/arm-xenial --args='target_os="linux" is_debug=false rtc_include_tests=false rtc_use_h264=true is_component_build=false use_rtti=true use_custom_libcxx=false use_custom_libcxx_for_host=false target_cpu="arm" target_sysroot="/root/rootfs"' \ + && ninja -C out/arm-xenial + +# ビルドに必要なファイルだけ /src に移動する +# このディレクトリをマルチステージビルド先から持ってくる +RUN set -x \ + && cd /root \ + # deps + && mkdir -p /src && cp -r src/build /src/build \ + # 生成されたライブラリ類 + && mkdir -p /src && cp -r src/out /src/out \ + # libwebrtc のヘッダ系 + && find src -maxdepth 1 -name '*.h' | while read line; do mkdir -p /`dirname $line`; mv $line /$line; done \ + && find src/api -name '*.h' | while read line; do mkdir -p /`dirname $line`; mv $line /$line; done \ + && find src/base -name '*.h' | while read line; do mkdir -p /`dirname $line`; mv $line /$line; done \ + && find src/call -name '*.h' | while read line; do mkdir -p /`dirname $line`; mv $line /$line; done \ + && find src/common_audio -name '*.h' | while read line; do mkdir -p /`dirname $line`; mv $line /$line; done \ + && find src/common_video -name '*.h' | while read line; do mkdir -p /`dirname $line`; mv $line /$line; done \ + && find src/logging -name '*.h' | while read line; do mkdir -p /`dirname $line`; mv $line /$line; done \ + && find src/media -name '*.h' | while read line; do mkdir -p /`dirname $line`; mv $line /$line; done \ + && find src/modules -name '*.h' | while read line; do mkdir -p /`dirname $line`; mv $line /$line; done \ + && find src/p2p -name '*.h' | while read line; do mkdir -p /`dirname $line`; mv $line /$line; done \ + && find src/pc -name '*.h' | while read line; do mkdir -p /`dirname $line`; mv $line /$line; done \ + && find src/rtc_base -name '*.h' | while read line; do mkdir -p /`dirname $line`; mv $line /$line; done \ + && find src/rtc_tools -name '*.h' | while read line; do mkdir -p /`dirname $line`; mv $line /$line; done \ + && find src/system_wrappers -name '*.h' | while read line; do mkdir -p /`dirname $line`; mv $line /$line; done \ + && find src/video -name '*.h' | while read line; do mkdir -p /`dirname $line`; mv $line /$line; done \ + # third_party 系 + && mkdir -p /src/third_party/llvm-build && cp -r src/third_party/llvm-build/Release+Asserts /src/third_party/llvm-build/Release+Asserts \ + && mkdir -p /src/buildtools/third_party && cp -r src/buildtools/third_party/libc++ /src/buildtools/third_party/libc++ \ + && mkdir -p /src/third_party && cp -r src/third_party/libyuv /src/third_party/libyuv \ + && mkdir -p /src/third_party && cp -r src/third_party/abseil-cpp /src/third_party/abseil-cpp \ + && mkdir -p /src/third_party/boringssl/src && cp -r src/third_party/boringssl/src/include /src/third_party/boringssl/src/include + +# Boost のビルド +COPY patch/project-config-arm_gcc.jam /root/ + +RUN cd ~/ \ + && set -ex \ + && curl -LO https://dl.bintray.com/boostorg/release/1.69.0/source/boost_1_69_0.tar.gz \ + && tar xf boost_1_69_0.tar.gz \ + && cd boost_1_69_0 \ + && ./bootstrap.sh \ + && cp ../project-config-arm_gcc.jam ./project-config.jam \ + && ./b2 target-os=linux architecture=arm address-model=32 link=static variant=release install -j`nproc` --prefix=/root/boost-1.69.0 --with-system --with-filesystem \ + && cd ~/ \ + && rm boost_1_69_0.tar.gz \ + && rm -rf boost_1_69_0 + +# 必要なファイルだけ持ってくる +FROM ubuntu:16.04 + +COPY --from=builder /src/ /root/src/ + +RUN set -x \ + && apt-get update \ + && apt-get -y upgrade \ + && apt-get -y install \ + build-essential \ + git \ + lsb-release \ + sudo \ + && bash /root/src/build/install-build-deps.sh --arm --no-nacl --no-chromeos-fonts \ + && apt-get clean \ + && rm -rf /var/lib/apt/lists/* + +# 構築した rootfs はそのままコピー +COPY --from=builder /root/rootfs/ /root/rootfs/ + +# Boost +COPY --from=builder /root/boost-1.69.0/ /root/boost-1.69.0/ diff --git a/build/arm/armv7_ros/Makefile b/build/arm/armv7_ros/Makefile new file mode 100644 index 00000000..8d224c4d --- /dev/null +++ b/build/arm/armv7_ros/Makefile @@ -0,0 +1,48 @@ +.PHONY: all +all: clean + cp -r ../../../patch patch + + # armv7_ros 全体で共通のビルド用イメージ + docker image build --rm -t momo/webrtc-armv7-ros-buildbase . --file buildbase.Dockerfile + + # armv7 用 momo を生成するために必要なデータだけ入ったイメージ + docker inspect momo/webrtc-armv7-ros:m$(WEBRTC_VERSION) > /dev/null 2>&1 || docker image build --rm -t momo/webrtc-armv7-ros:m$(WEBRTC_VERSION) --build-arg WEBRTC_VERSION=$(WEBRTC_VERSION) . + + rm -r patch/ + + git clone ../../.. momo + tar czf momo.tar.gz momo + rm -rf momo + + # ベースイメージから構築したコンテナに転送してビルドし、 + # ビルドが完了したら成果物の momo バイナリだけ取り出す + docker container create -it --name momo momo/webrtc-armv7-ros:m$(WEBRTC_VERSION) + docker container start momo + docker container cp momo.tar.gz momo:/root/ + docker container exec momo /bin/bash -c "cd /root && tar xf momo.tar.gz && cd momo && make OUT_PATH=arm-xenial USE_IL_ENCODER=$(USE_IL_ENCODER) ROS_VERSION=kinetic BUILD_MODE=$(BUILD_MODE) MOMO_VERSION=$(MOMO_VERSION)" + docker container cp momo:/root/momo/momo . + docker container stop momo + docker container rm momo + + rm momo.tar.gz + docker image prune -f + docker container prune -f + +.PHONY: clean +clean: + # ゴミ掃除する + -docker container stop momo > /dev/null 2>&1 + -docker container rm momo > /dev/null 2>&1 + -rm -rf momo/ > /dev/null 2>&1 + -rm momo > /dev/null 2>&1 + -rm momo.tar.gz > /dev/null 2>&1 + -rm -r patch/ > /dev/null 2>&1 + +.PHONY: clean.image +clean.image: clean + -docker image rm momo/webrtc-armv7-ros:m$(WEBRTC_VERSION) + +.PHONY: clean.image.all +clean.image.all: clean + -docker image rm momo/webrtc-armv7-ros-buildbase-ros + -docker image rm momo/webrtc-armv7-ros:m$(WEBRTC_VERSION) diff --git a/build/arm/armv7_ros/buildbase.Dockerfile b/build/arm/armv7_ros/buildbase.Dockerfile new file mode 100644 index 00000000..5c6e307f --- /dev/null +++ b/build/arm/armv7_ros/buildbase.Dockerfile @@ -0,0 +1,10 @@ +# armv7 用の WebRTC ビルド全体で必要なイメージ +FROM momo/webrtc-arm-buildbase + +COPY patch/rpi-xenial-ros.conf /root/ + +RUN set -x \ + && cd /root \ + && multistrap --no-auth -a armhf -d rootfs -f /root/rpi-xenial-ros.conf \ + && find rootfs/usr/lib/arm-linux-gnueabihf -lname '/*' -printf '%p %l\n' | while read link target; do ln -snfv "../../..${target}" "${link}"; done \ + && find rootfs/usr/lib/arm-linux-gnueabihf/pkgconfig -printf "%f\n" | while read target; do ln -snfv "../../lib/arm-linux-gnueabihf/pkgconfig/${target}" rootfs/usr/share/pkgconfig/${target}; done diff --git a/build/arm/armv8/Dockerfile b/build/arm/armv8/Dockerfile index 263732c2..814f206c 100644 --- a/build/arm/armv8/Dockerfile +++ b/build/arm/armv8/Dockerfile @@ -13,16 +13,20 @@ RUN set -x \ COPY patch/4k.patch /root/ +# exit 0 は cipd ensure コマンドでのエラーの暫定対応 RUN set -x \ && cd /root/src \ && git checkout -b m$WEBRTC_VERSION remotes/branch-heads/$WEBRTC_VERSION \ - && gclient sync \ + && gclient sync; exit 0 + +RUN set -x \ + && cd /root/src \ && patch -p2 < ../4k.patch RUN set -x \ && cd /root/src \ && rm -rf out/arm64-xenial \ - && gn gen out/arm64-xenial --args='target_os="linux" target_cpu="arm64" is_debug=false target_sysroot="/root/rootfs" rtc_use_h264=true rtc_include_tests=false use_rtti=true' \ + && gn gen out/arm64-xenial --args='target_os="linux" target_cpu="arm64" is_debug=false target_sysroot="/root/rootfs" rtc_use_h264=false rtc_include_tests=false use_rtti=true' \ && ninja -C out/arm64-xenial # ビルドに必要なファイルだけ /src に移動する @@ -61,15 +65,15 @@ COPY patch/project-config.jam /root/ RUN cd ~/ \ && set -ex \ - && curl -LO https://dl.bintray.com/boostorg/release/1.68.0/source/boost_1_68_0.tar.gz \ - && tar xf boost_1_68_0.tar.gz \ - && cd boost_1_68_0 \ + && curl -LO https://dl.bintray.com/boostorg/release/1.69.0/source/boost_1_69_0.tar.gz \ + && tar xf boost_1_69_0.tar.gz \ + && cd boost_1_69_0 \ && ./bootstrap.sh \ && cp ../project-config.jam ./ \ - && ./b2 target-os=linux architecture=arm address-model=64 link=static variant=release install -j`nproc` --prefix=/root/boost-1.68.0 --with-program_options --with-system --with-filesystem \ + && ./b2 target-os=linux architecture=arm address-model=64 link=static variant=release install -j`nproc` --prefix=/root/boost-1.69.0 --with-program_options --with-system --with-filesystem \ && cd ~/ \ - && rm boost_1_68_0.tar.gz \ - && rm -rf boost_1_68_0 + && rm boost_1_69_0.tar.gz \ + && rm -rf boost_1_69_0 # 必要なファイルだけ持ってくる FROM ubuntu:16.04 @@ -92,4 +96,4 @@ RUN set -x \ COPY --from=builder /root/rootfs/ /root/rootfs/ # Boost -COPY --from=builder /root/boost-1.68.0/ /root/boost-1.68.0/ +COPY --from=builder /root/boost-1.69.0/ /root/boost-1.69.0/ diff --git a/build/arm/armv8/Makefile b/build/arm/armv8/Makefile index 38b72708..175d8aab 100644 --- a/build/arm/armv8/Makefile +++ b/build/arm/armv8/Makefile @@ -19,7 +19,7 @@ all: clean docker container create -it --name momo momo/webrtc-armv8:m$(WEBRTC_VERSION) docker container start momo docker container cp momo.tar.gz momo:/root/ - docker container exec momo /bin/bash -c 'cd /root && tar xf momo.tar.gz && cd momo && make ARCH=arm64 OS=xenial RTC_ROOT=/root BUILD_MODE=$(BUILD_MODE) MOMO_VERSION=$(MOMO_VERSION)' + docker container exec momo /bin/bash -c 'cd /root && tar xf momo.tar.gz && cd momo && make OUT_PATH=arm64-xenial RTC_ROOT=/root BUILD_MODE=$(BUILD_MODE) MOMO_VERSION=$(MOMO_VERSION)' docker container cp momo:/root/momo/momo . docker container stop momo docker container rm momo diff --git a/build/macos/Makefile b/build/macos/Makefile index 22016e35..d92fee56 100644 --- a/build/macos/Makefile +++ b/build/macos/Makefile @@ -2,7 +2,7 @@ LIBWEBRTC = src/out/x86_64/obj/libwebrtc.a .PHONY: all all: $(LIBWEBRTC) - make -C ../../ ARCH=x86_64 RTC_ROOT=build/macos MOMO_VERSION=$(MOMO_VERSION) + make -C ../../ OUT_PATH=x86_64 RTC_ROOT=build/macos MOMO_VERSION=$(MOMO_VERSION) .PHONY: clean clean: @@ -22,4 +22,9 @@ $(LIBWEBRTC): gclient sync && \ gn gen out/x86_64 --args='target_os="mac" is_debug=false rtc_include_tests=false rtc_build_examples=false rtc_use_h264=true is_component_build=false use_rtti=true' && \ ninja -C out/x86_64 && \ - ninja -C out/x86_64 builtin_audio_decoder_factory + ninja -C out/x86_64 \ + builtin_audio_decoder_factory \ + builtin_video_decoder_factory \ + builtin_video_encoder_factory \ + peerconnection \ + create_pc_factory diff --git a/build/x86_64/Dockerfile b/build/x86_64/Dockerfile index e4dc8e14..b3413a5e 100644 --- a/build/x86_64/Dockerfile +++ b/build/x86_64/Dockerfile @@ -36,15 +36,19 @@ RUN set -x \ COPY patch/4k.patch /root/ +# exit 0 は cipd ensure コマンドでのエラーの暫定対応 RUN set -x \ && cd /root/src \ && git checkout -b m$WEBRTC_VERSION remotes/branch-heads/$WEBRTC_VERSION \ - && gclient sync \ + && gclient sync; exit 0 + +RUN set -x \ + && cd /root/src \ && patch -p2 < ../4k.patch RUN set -x \ && cd /root/src \ - && gn gen out/x86_64 --args='target_os="linux" is_debug=false rtc_include_tests=false rtc_use_h264=true is_component_build=false use_rtti=true' \ + && gn gen out/x86_64 --args='target_os="linux" is_debug=false rtc_include_tests=false rtc_use_h264=false is_component_build=false use_rtti=true' \ && ninja -C out/x86_64 # ビルドに必要なファイルだけ /src に移動する @@ -82,15 +86,15 @@ COPY patch/project-config-ubuntu-x86_64.jam /root/ RUN cd ~/ \ && set -ex \ - && curl -LO https://dl.bintray.com/boostorg/release/1.68.0/source/boost_1_68_0.tar.gz \ - && tar xf boost_1_68_0.tar.gz \ - && cd boost_1_68_0 \ + && curl -LO https://dl.bintray.com/boostorg/release/1.69.0/source/boost_1_69_0.tar.gz \ + && tar xf boost_1_69_0.tar.gz \ + && cd boost_1_69_0 \ && ./bootstrap.sh \ && cp ../project-config-ubuntu-x86_64.jam ./project-config.jam \ - && ./b2 target-os=linux architecture=arm address-model=32 link=static variant=release install -j`nproc` --prefix=/root/boost-1.68.0 --with-system --with-filesystem \ + && ./b2 target-os=linux architecture=arm address-model=32 link=static variant=release install -j`nproc` --prefix=/root/boost-1.69.0 --with-system --with-filesystem \ && cd ~/ \ - && rm boost_1_68_0.tar.gz \ - && rm -rf boost_1_68_0 + && rm boost_1_69_0.tar.gz \ + && rm -rf boost_1_69_0 # 必要なファイルだけ持ってくる FROM ubuntu:18.04 @@ -116,4 +120,4 @@ RUN set -x \ && rm -rf /var/lib/apt/lists/* # Boost -COPY --from=builder /root/boost-1.68.0/ /root/boost-1.68.0/ +COPY --from=builder /root/boost-1.69.0/ /root/boost-1.69.0/ diff --git a/build/x86_64/Makefile b/build/x86_64/Makefile index 53a99068..092b0b49 100644 --- a/build/x86_64/Makefile +++ b/build/x86_64/Makefile @@ -16,7 +16,7 @@ all: clean docker container create -it --name momo momo/webrtc-x86_64:m$(WEBRTC_VERSION) docker container start momo docker container cp momo.tar.gz momo:/root/ - docker container exec momo /bin/bash -c 'cd /root && tar xf momo.tar.gz && cd momo && make ARCH=x86_64 BUILD_MODE=$(BUILD_MODE) MOMO_VERSION=$(MOMO_VERSION)' + docker container exec momo /bin/bash -c 'cd /root && tar xf momo.tar.gz && cd momo && make OUT_PATH=x86_64 BUILD_MODE=$(BUILD_MODE) MOMO_VERSION=$(MOMO_VERSION)' docker container cp momo:/root/momo/momo . docker container stop momo docker container rm momo diff --git a/build/x86_64_ros/Dockerfile b/build/x86_64_ros/Dockerfile new file mode 100644 index 00000000..2e4e32ad --- /dev/null +++ b/build/x86_64_ros/Dockerfile @@ -0,0 +1,123 @@ +FROM ubuntu:18.04 as builder + +ARG WEBRTC_VERSION + +RUN apt-get update \ + && apt-get -y upgrade \ + && apt-get -y install \ + git \ + lsb-release \ + python \ + sudo \ + wget \ + && apt-get clean \ + && rm -rf /var/lib/apt/lists/* + +RUN set -x \ + && cd /root \ + && git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git ./depot_tools + +ENV PATH /root/depot_tools:$PATH +ENV DEBIAN_FRONTEND=noninteractive + +RUN set -x \ + && cd /root \ + && fetch webrtc + +RUN set -x \ + && apt-get update \ + && cd /root \ + && sed -i -e 's/sudo/sudo -E/g' ./src/build/install-build-deps.sh \ + && bash ./src/build/install-build-deps.sh --no-arm --no-chromeos-fonts \ + && cd src/build && git reset --hard && cd ../.. \ + && gclient sync \ + && apt-get clean \ + && rm -rf /var/lib/apt/lists/* + +COPY patch/4k.patch /root/ + +# exit 0 は cipd ensure コマンドでのエラーの暫定対応 +RUN set -x \ + && cd /root/src \ + && git checkout -b m$WEBRTC_VERSION remotes/branch-heads/$WEBRTC_VERSION \ + && gclient sync; exit 0 + +RUN set -x \ + && cd /root/src \ + && patch -p2 < ../4k.patch + +RUN set -x \ + && cd /root/src \ + && gn gen out/x86_64_ros --args='target_os="linux" is_debug=false rtc_include_tests=false rtc_use_h264=false is_component_build=false use_rtti=true use_custom_libcxx=false use_custom_libcxx_for_host=false' \ + && ninja -C out/x86_64_ros + +# ビルドに必要なファイルだけ /src に移動する +# このディレクトリをマルチステージビルド先から持ってくる +RUN set -x \ + && cd /root \ + # deps + && mkdir -p /src && cp -r src/build /src/build \ + # 生成されたライブラリ類 + && mkdir -p /src && cp -r src/out /src/out \ + # libwebrtc のヘッダ系 + && find src -maxdepth 1 -name '*.h' | while read line; do mkdir -p /`dirname $line`; mv $line /$line; done \ + && find src/api -name '*.h' | while read line; do mkdir -p /`dirname $line`; mv $line /$line; done \ + && find src/base -name '*.h' | while read line; do mkdir -p /`dirname $line`; mv $line /$line; done \ + && find src/call -name '*.h' | while read line; do mkdir -p /`dirname $line`; mv $line /$line; done \ + && find src/common_audio -name '*.h' | while read line; do mkdir -p /`dirname $line`; mv $line /$line; done \ + && find src/common_video -name '*.h' | while read line; do mkdir -p /`dirname $line`; mv $line /$line; done \ + && find src/logging -name '*.h' | while read line; do mkdir -p /`dirname $line`; mv $line /$line; done \ + && find src/media -name '*.h' | while read line; do mkdir -p /`dirname $line`; mv $line /$line; done \ + && find src/modules -name '*.h' | while read line; do mkdir -p /`dirname $line`; mv $line /$line; done \ + && find src/p2p -name '*.h' | while read line; do mkdir -p /`dirname $line`; mv $line /$line; done \ + && find src/pc -name '*.h' | while read line; do mkdir -p /`dirname $line`; mv $line /$line; done \ + && find src/rtc_base -name '*.h' | while read line; do mkdir -p /`dirname $line`; mv $line /$line; done \ + && find src/rtc_tools -name '*.h' | while read line; do mkdir -p /`dirname $line`; mv $line /$line; done \ + && find src/video -name '*.h' | while read line; do mkdir -p /`dirname $line`; mv $line /$line; done \ + # third_party 系 + && mkdir -p /src/third_party/llvm-build && cp -r src/third_party/llvm-build/Release+Asserts /src/third_party/llvm-build/Release+Asserts \ + && mkdir -p /src/buildtools/third_party && cp -r src/buildtools/third_party/libc++ /src/buildtools/third_party/libc++ \ + && mkdir -p /src/third_party && cp -r src/third_party/libyuv /src/third_party/libyuv \ + && mkdir -p /src/third_party && cp -r src/third_party/abseil-cpp /src/third_party/abseil-cpp \ + && mkdir -p /src/third_party/boringssl/src && cp -r src/third_party/boringssl/src/include /src/third_party/boringssl/src/include + +# Boost のビルド +COPY patch/project-config-ubuntu-x86_64_gcc.jam /root/ + +RUN cd ~/ \ + && set -ex \ + && curl -LO https://dl.bintray.com/boostorg/release/1.69.0/source/boost_1_69_0.tar.gz \ + && tar xf boost_1_69_0.tar.gz \ + && cd boost_1_69_0 \ + && ./bootstrap.sh \ + && cp ../project-config-ubuntu-x86_64_gcc.jam ./project-config.jam \ + && ./b2 target-os=linux link=static variant=release install -j`nproc` --prefix=/root/boost-1.69.0 --with-system \ + && cd ~/ \ + && rm boost_1_69_0.tar.gz \ + && rm -rf boost_1_69_0 + +# 必要なファイルだけ持ってくる +FROM ros:kinetic-ros-core-xenial + +COPY --from=builder /src/ /root/src/ + +ENV DEBIAN_FRONTEND=noninteractive + +RUN set -x \ + && apt-get update \ + && apt-get -y upgrade \ + && apt-get -y install \ + build-essential \ + git \ + lsb-release \ + sudo \ + && cd /root \ + && sed -i -e 's/sudo/sudo -E/g' ./src/build/install-build-deps.sh \ + && bash ./src/build/install-build-deps.sh --no-arm --no-chromeos-fonts \ + && cd src/build && git reset --hard && cd ../.. \ + && bash /root/src/build/install-build-deps.sh --no-arm --no-nacl --no-chromeos-fonts \ + && apt-get clean \ + && rm -rf /var/lib/apt/lists/* + +# Boost +COPY --from=builder /root/boost-1.69.0/ /root/boost-1.69.0/ diff --git a/build/x86_64_ros/Makefile b/build/x86_64_ros/Makefile new file mode 100644 index 00000000..d5078988 --- /dev/null +++ b/build/x86_64_ros/Makefile @@ -0,0 +1,44 @@ +.PHONY: all +all: clean + cp -r ../../patch patch + + # x86_64 用 momo を生成するために必要なデータだけ入ったイメージ + docker inspect momo/webrtc-x86_64_ros:m$(WEBRTC_VERSION) > /dev/null 2>&1 || docker image build --rm -t momo/webrtc-x86_64_ros:m$(WEBRTC_VERSION) --build-arg WEBRTC_VERSION=$(WEBRTC_VERSION) . + + rm -r patch/ + + git clone ../.. momo + tar czf momo.tar.gz momo + rm -rf momo + + # ベースイメージから構築したコンテナに転送してビルドし、 + # ビルドが完了したら成果物の momo バイナリだけ取り出す + docker container create -it --name momo momo/webrtc-x86_64_ros:m$(WEBRTC_VERSION) + docker container start momo + docker container cp momo.tar.gz momo:/root/ + docker container exec momo /bin/bash -c 'cd /root && tar xf momo.tar.gz && cd momo && make OUT_PATH=x86_64_ros ROS_VERSION=kinetic BUILD_MODE=$(BUILD_MODE) MOMO_VERSION=$(MOMO_VERSION)' + docker container cp momo:/root/momo/momo . + docker container stop momo + docker container rm momo + + rm momo.tar.gz + docker image prune -f + docker container prune -f + +.PHONY: clean +clean: + # ゴミ掃除する + -docker container stop momo > /dev/null 2>&1 + -docker container rm momo > /dev/null 2>&1 + -rm -rf momo/ > /dev/null 2>&1 + -rm momo > /dev/null 2>&1 + -rm momo.tar.gz > /dev/null 2>&1 + -rm -r patch/ > /dev/null 2>&1 + +.PHONY: clean.image +clean.image: + -docker image rm momo/webrtc-x86_64_ros:m$(WEBRTC_VERSION) + +.PHONY: clean.image.all +clean.image.all: + -docker image rm momo/webrtc-x86_64_ros:m$(WEBRTC_VERSION) diff --git a/doc/BUILD.md b/doc/BUILD.md index a647cdf8..955bd86a 100644 --- a/doc/BUILD.md +++ b/doc/BUILD.md @@ -45,10 +45,10 @@ $ make armv8 ## Ubuntu 18.04 (x86_64) 向けバイナリを作成する -build ディレクトリ以下で make x86_64 と打つことで Momo の Ubuntu 18.04 x86_64 向けバイナリが生成されます。 +build ディレクトリ以下で make ubuntu-1804_x86_64 と打つことで Momo の Ubuntu 18.04 x86_64 向けバイナリが生成されます。 ```shell -$ make x86_64 +$ make ubuntu-1804_x86_64 ``` ## macOS 10.14 または macOS 10.13 @@ -58,7 +58,3 @@ $ make x86_64 ## Windows 10 **現在準備中です** - -## ビルド時に Raspberry Pi の HWA を無効にする方法 - -- armv6, armv7 の場合、デフォルトで HWA を利用します。もし利用したくない場合は `make USE_IL_ENCODER=0 armv7` のように `USE_IL_ENCODER=0` を指定してください。 diff --git a/doc/DEV.md b/doc/DEV.md index b5b07e39..a3dcf3d1 100644 --- a/doc/DEV.md +++ b/doc/DEV.md @@ -23,6 +23,6 @@ $ make armv8 BUILD_MODE=pkg ``` $ git submodule status - da901cca542612a133efcb04e8e78080186991e4 libs/CLI11 (v1.6.1-8-gda901cc) - d2dd27dc3b8472dbaa7d66f83619b3ebcd9185fe libs/json (v3.1.2) + bd4dc911847d0cde7a6b41dfa626a85aab213baf libs/CLI11 (v1.6.2) + e3c28afb61227043dd7c0f9168b9394dfb016f87 libs/json (v3.4.0) ``` diff --git a/doc/USE.md b/doc/USE.md index fb14d52d..6340c537 100644 --- a/doc/USE.md +++ b/doc/USE.md @@ -83,13 +83,13 @@ Momo はモードを 2 つ持っています。一つが P2P モードで Momo ```shell $ momo --version -WebRTC Native Client Momo version 18.10.2 +WebRTC Native Client Momo version 18.12.0 ``` ### P2P で動作を確認する ```shell -$ momo --no-audio --video-codec H264 --video-bitrate 800 \ +$ momo --no-audio --video-codec VP8 --video-bitrate 800 \ p2p --port 8080 ``` @@ -108,7 +108,7 @@ $ momo --no-audio --video-codec VP8 --video-bitrate 500 \ ``` $ ./momo --version -WebRTC Native Client Momo 18.10.2 +WebRTC Native Client Momo 18.12.0 ``` ``` @@ -121,7 +121,7 @@ Options: --no-video ビデオを表示しない --no-audio オーディオを出さない --video-codec STR in [VP8,VP9,H264] - ビデオコーデック + ビデオコーデック --audio-codec STR in [OPUS,PCMU] オーディオコーデック --video-bitrate INT in [1 - 30000] @@ -157,7 +157,7 @@ Options: ``` -$ ./momo --no-audio --video-codec H264 --video-bitrate 1500 \ +$ ./momo --no-audio --video-codec VP8 --video-bitrate 1500 \ p2p --port 8080 ``` diff --git a/doc/USE_ROS.md b/doc/USE_ROS.md new file mode 100644 index 00000000..afc1642f --- /dev/null +++ b/doc/USE_ROS.md @@ -0,0 +1,108 @@ +# ROS 版 momo を使ってみる + +- OS: Ubuntu 16.04 + +## ROS 環境を用意する + +ROS 環境を用意しておきます。 + +- ROS Kinetic のインストール方法: http://wiki.ros.org/kinetic/Installation/Ubuntu + + +## momo の準備 + +### momo のダウンロード + +https://github.com/shiguredo/momo/releases にて ROS 版 momo のバイナリをダウンロードしてください。 + +必要なライブラリをインストールしてご利用ください。 + +#### 解凍後の構成 + +``` +$ tree +. +├── html +│   ├── p2p.html +│   └── webrtc.js +├── LICENSE +├── momo +└── NOTICE +``` + +#### ライブラリのインストール + +次のパッケージをイストールします。 + +``` +$ sudo apt -y install libnss3 +``` + + +## 実行する + +momo を実行する前に下記のように rosrun を使用して Web カメラを起動しておきます。 + +事前に、apt で ros-kinetic-usb-cam をインストールした上で実行します。 + +``` +$ rosrun usb_cam usb_cam_node _pixel_format:=mjpeg +``` + +### P2P で動作を確認する + +- 実行例 + +```shell +$ ./momo _use_p2p:=true \ + _compressed:=true \ + image:=/usb_cam/image_raw/compressed \ + _port:=8080 +``` + +http://[momo の IP アドレス]:8080/html/p2p.html にアクセスしてください。 + +image は Web カメラから送られてくる画像データの topic を指定してください。 + +- 変更可能なパラメータ + - image + - topic + - _port + - ポート番号 [0 - 65535] + - _log_level + - ログレベル [0 - 5] + + +### WebRTC SFU Sora で動作を確認する + +**この機能を利用する場合は WebRTC SFU Sora のライセンス契約が必要です** + +```shell +$ ./momo _use_sora:=true \ + _auto:=true \ + _compressed:=true \ + _port:=0 \ + _SIGNALING_URL:="wss://example.com/signaling" \ + _CHANNEL_ID:="sora" \ + _video_codec:=VP9 \ + _log_level:=5 \ + _video_bitrate:=300 \ + image:=/usb_cam/image_raw/compressed +``` + +image は Web カメラから送られてくる画像データの topic を指定してください。 + + +- 変更可能なパラメータ + - _SIGNALING_URL + - シグナリング URL + - _CHANNEL_ID + - チャネル ID + - image + - topic + - _video_codec + - ビデオコーデック [VP8,VP9] + - _video_bitrate + - ビデオビットレート [1 - 30000] + - _log_level + - ログレベル [0 - 5] diff --git a/html/webrtc.js b/html/webrtc.js index e8dbaccf..732d9b5c 100644 --- a/html/webrtc.js +++ b/html/webrtc.js @@ -37,7 +37,6 @@ ws.onmessage = function (evt) { } else if (message.type === 'close') { console.log('peer is closed ...'); - close(); } }; @@ -102,10 +101,6 @@ function prepareNewConnection() { switch (peer.iceConnectionState) { case 'closed': case 'failed': - if (peerConnection) { - close(); - } - break; case 'dissconnected': break; } diff --git a/libs/CLI11 b/libs/CLI11 index da901cca..bd4dc911 160000 --- a/libs/CLI11 +++ b/libs/CLI11 @@ -1 +1 @@ -Subproject commit da901cca542612a133efcb04e8e78080186991e4 +Subproject commit bd4dc911847d0cde7a6b41dfa626a85aab213baf diff --git a/libs/json b/libs/json index d2dd27dc..e3c28afb 160000 --- a/libs/json +++ b/libs/json @@ -1 +1 @@ -Subproject commit d2dd27dc3b8472dbaa7d66f83619b3ebcd9185fe +Subproject commit e3c28afb61227043dd7c0f9168b9394dfb016f87 diff --git a/patch/project-config-arm_gcc.jam b/patch/project-config-arm_gcc.jam new file mode 100644 index 00000000..2a00557a --- /dev/null +++ b/patch/project-config-arm_gcc.jam @@ -0,0 +1,25 @@ +import option ; +import feature ; + +using clang : + : /root/src/third_party/llvm-build/Release+Asserts/bin/clang++ + : --target=arm-linux-gnueabihf + --sysroot=/root/rootfs + -march=armv7-a + -mfloat-abi=hard + -mtune=generic-armv7-a + -mfpu=neon + -mthumb + ; + +project : default-build clang ; + +libraries = ; + +option.set prefix : /usr/local ; +option.set exec-prefix : /usr/local ; +option.set libdir : /usr/local/lib ; +option.set includedir : /usr/local/include ; + +# Stop on first error +option.set keep-going : false ; diff --git a/patch/project-config-rpi-xenial.jam b/patch/project-config-rpi-xenial.jam new file mode 100644 index 00000000..e65a443d --- /dev/null +++ b/patch/project-config-rpi-xenial.jam @@ -0,0 +1,25 @@ +import option ; +import feature ; + +using gcc : + : arm-linux-gnueabihf-g++ + : -std=gnu++11 + --sysroot=/root/rootfs + -march=armv7-a + -mfloat-abi=hard + -mtune=generic-armv7-a + -mfpu=neon + -mthumb + ; + +project : default-build gcc ; + +libraries = ; + +option.set prefix : /usr/local ; +option.set exec-prefix : /usr/local ; +option.set libdir : /usr/local/lib ; +option.set includedir : /usr/local/include ; + +# Stop on first error +option.set keep-going : false ; diff --git a/patch/project-config-ubuntu-x86_64_gcc.jam b/patch/project-config-ubuntu-x86_64_gcc.jam new file mode 100644 index 00000000..cc314143 --- /dev/null +++ b/patch/project-config-ubuntu-x86_64_gcc.jam @@ -0,0 +1,19 @@ + +import option ; +import feature ; + +using clang : + : /root/src/third_party/llvm-build/Release+Asserts/bin/clang++ + ; + +project : default-build clang ; + +libraries = ; + +option.set prefix : /usr/local ; +option.set exec-prefix : /usr/local ; +option.set libdir : /usr/local/lib ; +option.set includedir : /usr/local/include ; + +# Stop on first error +option.set keep-going : false ; \ No newline at end of file diff --git a/patch/rpi-xenial-ros.conf b/patch/rpi-xenial-ros.conf new file mode 100644 index 00000000..1025b3da --- /dev/null +++ b/patch/rpi-xenial-ros.conf @@ -0,0 +1,23 @@ +[General] +unpack=true +bootstrap=Ports Rasp ROS +aptsources=Ports Rasp ROS + +[Ports] +packages=g++ libasound2-dev libpulse-dev libudev-dev libexpat1-dev libnss3-dev python-dev libgtk-3-dev libconsole-bridge0.2v5 libboost-all-dev libconsole-bridge-dev +source=http://ports.ubuntu.com +keyring=ubuntu-keyring +suite=xenial +components=main universe + +[Rasp] +packages=libraspberrypi-bin libraspberrypi-bin-nonfree libraspberrypi-dev +source=http://ppa.launchpad.net/ubuntu-raspi2/ppa/ubuntu +keyring=ubuntu-keyring +suite=xenial + +[ROS] +packages=ros-kinetic-sensor-msgs ros-kinetic-message-filters ros-kinetic-roscpp ros-kinetic-rosconsole ros-kinetic-roscpp-serialization ros-kinetic-rostime ros-kinetic-xmlrpcpp ros-kinetic-cpp-common +source=http://packages.ros.org/ros/ubuntu +keyring=ubuntu-keyring +suite=xenial \ No newline at end of file diff --git a/src/connection_settings.h b/src/connection_settings.h index 701b0e32..e892d3b6 100644 --- a/src/connection_settings.h +++ b/src/connection_settings.h @@ -9,6 +9,11 @@ struct ConnectionSettings { + std::string camera_name = ""; +#if USE_ROS + bool image_compressed = false; +#endif + bool no_video = false; bool no_audio = false; std::string video_codec = "VP8"; @@ -19,13 +24,13 @@ struct ConnectionSettings int framerate = 0; bool fixed_resolution = false; std::string priority = "BALANCE"; + int port = 8080; std::string sora_signaling_host = "wss://example.com/signaling"; std::string sora_channel_id; bool sora_auto_connect = false; nlohmann::json sora_metadata; - int p2p_port = 8080; std::string p2p_document_root; int getWidth() { @@ -75,11 +80,11 @@ struct ConnectionSettings os << "framerate: " << cs.framerate << "\n"; os << "fixed_resolution: " << (cs.fixed_resolution ? "true" : "false") << "\n"; os << "priority: " << cs.priority << "\n"; + os << "port: " << cs.port << "\n"; os << "sora_signaling_host: " << cs.sora_signaling_host << "\n"; os << "sora_channel_id: " << cs.sora_channel_id << "\n"; os << "sora_auto_connect: " << (cs.sora_auto_connect ? "true" : "false") << "\n"; os << "sora_metadata: " << cs.sora_metadata << "\n"; - os << "p2p_port: " << cs.p2p_port << "\n"; os << "p2p_document_root: " << cs.p2p_document_root << "\n"; return os; } diff --git a/src/main.cpp b/src/main.cpp index d0f28483..3752c473 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -8,156 +8,33 @@ #include #include #include -#include -#include -#include -#include #include "rtc_base/logsinks.h" +#if USE_ROS +#include "ros/ros_log_sink.h" +#include "ros/ros_video_capture.h" +#include "signal_listener.h" +#endif + #include "connection_settings.h" +#include "util.h" #include "rtc/manager.h" #include "sora/sora_server.h" #include "p2p/p2p_server.h" -// バージョン情報 -// 通常は外から渡すが、渡されていなかった場合の対応 -#ifndef MOMO_VERSION -# define MOMO_VERSION "internal-build" -#endif - -// HWA を効かせる場合は 1 になる -#if USE_IL_ENCODER - #define MOMO_USE_IL_ENCODER 1 -#else - #define MOMO_USE_IL_ENCODER 0 -#endif - -using json = nlohmann::json; - const size_t kDefaultMaxLogFileSize = 10 * 1024 * 1024; -// 列挙した文字列のみを許可するバリデータ -struct Enum : public CLI::Validator { - Enum(std::vector xs) { - std::stringstream out; - - bool first = true; - for (auto x: xs) { - if (!first) { - out << ","; - } - first = false; - - out << x; - } - std::string name = out.str(); - - tname = "STR in [" + name + "]"; - func = [xs, name](std::string input) { - auto it = std::find(std::begin(xs), std::end(xs), input); - if (it == std::end(xs)) { - return "Value " + input + " not in range [" + name + "]"; - } - return std::string(); - }; - } -}; - -// JSON Value のみを許可するバリデータ -struct JsonValue : public CLI::Validator { - JsonValue() { - tname = "JSON Value"; - func = [](std::string input) { - try { - json::parse(input); - return std::string(); - } catch(json::parse_error& e) { - return "Value " + input + " is not JSON Value"; - } - }; - } -}; - -// ディレクトリが存在するか確認するバリデータ -struct DirectoryExists : public CLI::Validator { - DirectoryExists() { - tname = "Directory"; - func = [](std::string input) { - auto path = boost::filesystem::path(input); - auto st = boost::filesystem::status(path); - if (!boost::filesystem::exists(st)) { - return "Path " + input + " not exists"; - } - if (!boost::filesystem::is_directory(st)) { - return "Path " + input + " is not directory"; - } - - return std::string(); - }; - } -}; - int main(int argc, char* argv[]) { - CLI::App app("Momo - WebRTC ネイティブクライアント"); ConnectionSettings cs; bool is_daemon = false; - bool version = false; + bool use_p2p = false; + bool use_sora = false; int log_level = rtc::LS_NONE; - app.add_flag("--no-video", cs.no_video, "ビデオを表示しない"); - app.add_flag("--no-audio", cs.no_audio, "オーディオを出さない"); - app.add_option("--video-codec", cs.video_codec, "ビデオコーデック")->check(Enum({"VP8", "VP9", "H264"})); - app.add_option("--audio-codec", cs.audio_codec, "オーディオコーデック")->check(Enum({"OPUS", "PCMU"})); - app.add_option("--video-bitrate", cs.video_bitrate, "ビデオのビットレート")->check(CLI::Range(1, 30000)); - app.add_option("--audio-bitrate", cs.audio_bitrate, "オーディオのビットレート")->check(CLI::Range(6, 510)); - app.add_option("--resolution", cs.resolution, "解像度")->check(Enum({"QVGA", "VGA", "HD", "FHD", "4K"})); - app.add_option("--framerate", cs.framerate, "フレームレート")->check(CLI::Range(1, 60)); - app.add_flag("--fixed-resolution", cs.fixed_resolution, "固定解像度"); - app.add_option("--priority", cs.priority, "優先設定 (Experimental)")->check(Enum({"BALANCE", "FRAMERATE", "RESOLUTION"})); - app.add_flag("--daemon", is_daemon, "デーモン化する"); - app.add_flag("--version", version, "バージョン情報の表示"); - app.add_option("--log-level", log_level, "ログレベル")->check(CLI::Range(0, 5)); - - auto p2p_app = app.add_subcommand("p2p", "P2P"); - auto sora_app = app.add_subcommand("sora", "WebRTC SFU Sora"); - - p2p_app->add_option("--port", cs.p2p_port, "ポート番号")->check(CLI::Range(0, 65535)); - p2p_app->add_option("--document-root", cs.p2p_document_root, "配信ディレクトリ")->check(DirectoryExists()); - - sora_app->add_option("SIGNALING-URL", cs.sora_signaling_host, "シグナリングホスト")->required(); - sora_app->add_option("CHANNEL-ID", cs.sora_channel_id, "チャンネルID")->required(); - sora_app->add_flag("--auto", cs.sora_auto_connect, "自動接続する"); - // 隠しオプション - std::string sora_metadata; - sora_app->add_option("--metadata", sora_metadata, "メタデータ")->group("")->check(JsonValue()); - - try { - app.parse(argc, argv); - } catch (const CLI::ParseError &e) { - return app.exit(e); - } - - // メタデータのパース - if (!sora_metadata.empty()) { - cs.sora_metadata = json::parse(sora_metadata); - } - - if (cs.p2p_document_root.empty()) { - cs.p2p_document_root = boost::filesystem::current_path().string(); - } - - if (version) { - std::cout << "WebRTC Native Client Momo version " MOMO_VERSION " USE_IL_ENCODER=" BOOST_PP_STRINGIZE(MOMO_USE_IL_ENCODER) << std::endl; - return 0; - } - - if (!p2p_app->parsed() && !sora_app->parsed()) { - std::cout << app.help() << std::endl; - return 1; - } + Util::parseArgs(argc, argv, is_daemon, use_p2p, use_sora, log_level, cs); #ifndef _MSC_VER if (is_daemon) @@ -170,6 +47,22 @@ int main(int argc, char* argv[]) } #endif + + rtc::LogMessage::LogToDebug((rtc::LoggingSeverity)log_level); + rtc::LogMessage::LogTimestamps(); + rtc::LogMessage::LogThreads(); + +#if USE_ROS + std::unique_ptr log_sink(new ROSLogSink()); + rtc::LogMessage::AddLogToStream(log_sink.get(), rtc::LS_INFO); + std::unique_ptr capturer(new ROSVideoCapture(cs)); + SignalManager::init(); + if (!capturer->Init()) + { + RTC_LOG(LS_ERROR) << __FUNCTION__ << "Failed to start ROSVideoCapture"; + return 0; + } +#else std::unique_ptr log_sink( new rtc::FileRotatingLogSink("./", "webrtc_logs", kDefaultMaxLogFileSize, 10)); if (!log_sink->Init()) @@ -178,13 +71,14 @@ int main(int argc, char* argv[]) log_sink.reset(); return 1; } - - rtc::LogMessage::LogToDebug((rtc::LoggingSeverity)log_level); - rtc::LogMessage::LogTimestamps(); - rtc::LogMessage::LogThreads(); rtc::LogMessage::AddLogToStream(log_sink.get(), rtc::LS_INFO); + // この時点では RTCManager の準備ができていないので RTCManager::createVideoCapture() を呼んでも動作しない。 + // なので capturer が nullptr だったら RTCManager 側で作るようにする。 + // std::unique_ptr capturer = RTCManager::createVideoCapture(); + std::unique_ptr capturer; +#endif - std::unique_ptr rtc_manager(new RTCManager(cs)); + std::unique_ptr rtc_manager(new RTCManager(cs, std::move(capturer))); { boost::asio::io_context ioc{1}; @@ -194,13 +88,13 @@ int main(int argc, char* argv[]) ioc.stop(); }); - if (sora_app->parsed()) { - const boost::asio::ip::tcp::endpoint endpoint{boost::asio::ip::make_address("127.0.0.1"), 8080}; + if (use_sora) { + const boost::asio::ip::tcp::endpoint endpoint{boost::asio::ip::make_address("127.0.0.1"), static_cast(cs.port)}; std::make_shared(ioc, endpoint, rtc_manager.get(), cs)->run(); } - if (p2p_app->parsed()) { - const boost::asio::ip::tcp::endpoint endpoint{boost::asio::ip::make_address("0.0.0.0"), static_cast(cs.p2p_port)}; + if (use_p2p) { + const boost::asio::ip::tcp::endpoint endpoint{boost::asio::ip::make_address("0.0.0.0"), static_cast(cs.port)}; std::make_shared(ioc, endpoint, std::make_shared(cs.p2p_document_root), rtc_manager.get(), cs)->run(); } diff --git a/src/p2p/p2p_connection.cpp b/src/p2p/p2p_connection.cpp index 7aec84ff..d7b50e33 100644 --- a/src/p2p/p2p_connection.cpp +++ b/src/p2p/p2p_connection.cpp @@ -54,3 +54,10 @@ void P2PConnection::onCreateDescription(webrtc::SdpType type, const std::string std::string str_desc = json_desc.dump(); _send(std::move(str_desc)); } + +void P2PConnection::onSetDescription(webrtc::SdpType type) { + RTC_LOG(LS_INFO) << __FUNCTION__ << " SdpType: " << webrtc::SdpTypeToString(type); + if (type == webrtc::SdpType::kOffer) { + _connection->createAnswer(); + } +} diff --git a/src/p2p/p2p_connection.h b/src/p2p/p2p_connection.h index 32579fd5..d980f559 100644 --- a/src/p2p/p2p_connection.h +++ b/src/p2p/p2p_connection.h @@ -21,7 +21,7 @@ class P2PConnection : public RTCMessageSender void onIceCandidate( const std::string sdp_mid, const int sdp_mlineindex, const std::string sdp) override; void onCreateDescription(webrtc::SdpType type, const std::string sdp) override; - void onSetDescription(webrtc::SdpType type) override {}; + void onSetDescription(webrtc::SdpType type) override; private: std::shared_ptr _connection; diff --git a/src/p2p/p2p_websocket_session.cpp b/src/p2p/p2p_websocket_session.cpp index cdca9cad..2502c523 100644 --- a/src/p2p/p2p_websocket_session.cpp +++ b/src/p2p/p2p_websocket_session.cpp @@ -5,20 +5,6 @@ using json = nlohmann::json; -// RAII を使ってエラーの時に ws_ と connection_ を reset する。 -// ws_, connection_ と this で循環参照させてるので、処理を継続しない場合には ws_ と connection_ を reset しておかないとリークしてしまう。 -struct P2PWebsocketSession::SafeWS { - P2PWebsocketSession* p; - SafeWS(P2PWebsocketSession* p) : p(p) {} - ~SafeWS() { - if (p != nullptr) { - p->ws_.reset(); - p->connection_.reset(); - } - } - void ok() { p = nullptr; } -}; - P2PWebsocketSession::P2PWebsocketSession(RTCManager* rtc_manager, ConnectionSettings conn_settings) : rtc_manager_(rtc_manager) , conn_settings_(conn_settings) @@ -33,18 +19,7 @@ P2PWebsocketSession::~P2PWebsocketSession() std::shared_ptr P2PWebsocketSession::make_shared(boost::asio::ip::tcp::socket socket, RTCManager* rtc_manager, ConnectionSettings conn_settings) { auto p = std::make_shared(rtc_manager, conn_settings); - p->ws_ = std::make_shared(std::move(socket), - std::bind( - &P2PWebsocketSession::onRead, - p->shared_from_this(), - std::placeholders::_1, - std::placeholders::_2, - std::placeholders::_3), - std::bind( - &P2PWebsocketSession::onWrite, - p->shared_from_this(), - std::placeholders::_1, - std::placeholders::_2)); + p->ws_ = std::unique_ptr(new Websocket(std::move(socket))); return p; } @@ -72,15 +47,16 @@ void P2PWebsocketSession::onAccept(boost::system::error_code ec) { RTC_LOG(LS_INFO) << __FUNCTION__ << ": " << ec; - SafeWS sws(this); - if (ec) return MOMO_BOOST_ERROR(ec, "Accept"); // WebSocket での読み込みを開始 - ws_->startToRead(); - - sws.ok(); + ws_->startToRead(std::bind( + &P2PWebsocketSession::onRead, + shared_from_this(), + std::placeholders::_1, + std::placeholders::_2, + std::placeholders::_3)); } void P2PWebsocketSession::onRead(boost::system::error_code ec, std::size_t bytes_transferred, std::string recv_string) @@ -89,8 +65,6 @@ void P2PWebsocketSession::onRead(boost::system::error_code ec, std::size_t bytes boost::ignore_unused(bytes_transferred); - SafeWS sws(this); - if (ec == boost::beast::websocket::error::closed) return; @@ -133,10 +107,10 @@ void P2PWebsocketSession::onRead(boost::system::error_code ec, std::size_t bytes } auto send = std::bind( - [](std::shared_ptr session, std::string str) { + [](P2PWebsocketSession* session, std::string str) { session->ws_->sendText(str); }, - shared_from_this(), + this, std::placeholders::_1); connection_ = std::make_shared(rtc_manager_, send); std::shared_ptr rtc_conn = connection_->getRTCConnection(); @@ -192,21 +166,4 @@ void P2PWebsocketSession::onRead(boost::system::error_code ec, std::size_t bytes { return; } - - sws.ok(); -} - -void P2PWebsocketSession::onWrite(boost::system::error_code ec, std::size_t bytes_transferred) -{ - RTC_LOG(LS_INFO) << __FUNCTION__ << ": " << ec; - - SafeWS sws(this); - - if (ec == boost::asio::error::operation_aborted) - return; - - if (ec) - return MOMO_BOOST_ERROR(ec, "Write"); - - sws.ok(); } diff --git a/src/p2p/p2p_websocket_session.h b/src/p2p/p2p_websocket_session.h index 424740c0..a5e0223d 100644 --- a/src/p2p/p2p_websocket_session.h +++ b/src/p2p/p2p_websocket_session.h @@ -17,15 +17,13 @@ class P2PWebsocketSession : public std::enable_shared_from_this { - std::shared_ptr ws_; + std::unique_ptr ws_; boost::beast::multi_buffer sending_buffer_; RTCManager* rtc_manager_; ConnectionSettings conn_settings_; std::shared_ptr connection_; - struct SafeWS; - public: P2PWebsocketSession(RTCManager* rtc_manager, ConnectionSettings conn_settings); ~P2PWebsocketSession(); @@ -37,7 +35,6 @@ class P2PWebsocketSession : public std::enable_shared_from_this + +#include "rtc_base/logging.h" +#include "rtc_base/logsinks.h" + +class ROSLogSink : public rtc::LogSink +{ +public: + void OnLogMessage(const std::string &message) override { + ROS_INFO_STREAM(message); + } + + void OnLogMessage(const std::string &message, + rtc::LoggingSeverity severity, + const char *tag) override + { + switch (severity) + { + case rtc::LS_SENSITIVE: + case rtc::LS_VERBOSE: + case rtc::LS_NONE: + ROS_DEBUG_STREAM(message); + break; + case rtc::LS_INFO: + ROS_INFO_STREAM(message); + break; + case rtc::LS_WARNING: + ROS_WARN_STREAM(message); + break; + case rtc::LS_ERROR: + ROS_ERROR_STREAM(message); + break; + } + } +}; + +#endif \ No newline at end of file diff --git a/src/ros/ros_video_capture.cpp b/src/ros/ros_video_capture.cpp new file mode 100644 index 00000000..23e03244 --- /dev/null +++ b/src/ros/ros_video_capture.cpp @@ -0,0 +1,174 @@ +#include "ros_video_capture.h" + +#include +#include + +#include "api/video/i420_buffer.h" +#include "rtc_base/logsinks.h" +#include "third_party/libyuv/include/libyuv.h" +#include "sensor_msgs/image_encodings.h" + +ROSVideoCapture::ROSVideoCapture(ConnectionSettings conn_settings) + : running_(false), last_time_ns_(0), width_(0), height_(0), interval_(0) +{ + ros::NodeHandle nh; + if (conn_settings.image_compressed) + { + sub_ = nh.subscribe(conn_settings.camera_name, 1, boost::bind(&ROSVideoCapture::ROSCallbackCompressed, this, _1)); + } + else + { + sub_ = nh.subscribe(conn_settings.camera_name, 1, boost::bind(&ROSVideoCapture::ROSCallbackRaw, this, _1)); + } + + spinner_ = new ros::AsyncSpinner(1); + spinner_->start(); +} + +ROSVideoCapture::~ROSVideoCapture() +{ + spinner_->stop(); +} + +uint32_t ROSVideoCapture::ConvertEncodingType(const std::string encoding) +{ + if (encoding == sensor_msgs::image_encodings::RGB8) + { + return libyuv::FOURCC_RAW; + } + else if (encoding == sensor_msgs::image_encodings::BGR8) + { + return libyuv::FOURCC_24BG; + } + else if (encoding == sensor_msgs::image_encodings::RGBA8) + { + return libyuv::FOURCC_BGRA; + } + else if (encoding == sensor_msgs::image_encodings::BGRA8) + { + return libyuv::FOURCC_RGBA; + } + return libyuv::FOURCC_ANY; +} + +void ROSVideoCapture::ROSCallbackRaw(const sensor_msgs::ImageConstPtr &image) +{ + ROSCallback(image->header.stamp, image->data.data(), image->data.size(), image->width, image->height, ConvertEncodingType(image->encoding)); +} + +void ROSVideoCapture::ROSCallbackCompressed(const sensor_msgs::CompressedImageConstPtr &image) +{ + int width, height; + if (libyuv::MJPGSize(image->data.data(), image->data.size(), &width, &height) < 0) + { + RTC_LOG(LS_ERROR) << "MJPGSize Failed"; + return; + } + ROSCallback(image->header.stamp, image->data.data(), image->data.size(), width, height, libyuv::FOURCC_MJPG); +} + +void ROSVideoCapture::ROSCallback(ros::Time ros_time, const uint8_t *sample, size_t sample_size, int src_width, int src_height, uint32_t fourcc) +{ + rtc::scoped_refptr dst_buffer(webrtc::I420Buffer::Create(src_width, src_height)); + dst_buffer->InitializeData(); + + if (libyuv::ConvertToI420(sample, sample_size, + dst_buffer.get()->MutableDataY(), dst_buffer.get()->StrideY(), + dst_buffer.get()->MutableDataU(), dst_buffer.get()->StrideU(), + dst_buffer.get()->MutableDataV(), dst_buffer.get()->StrideV(), + 0, 0, src_width, src_height, src_width, src_height, + libyuv::kRotate0, fourcc) < 0) + { + RTC_LOG(LS_ERROR) << "ConvertToI420 Failed"; + return; + } + + webrtc::VideoFrame captureFrame(dst_buffer, 0, rtc::TimeMillis(), webrtc::kVideoRotation_0); + uint64_t ros_time_ns = ros_time.toNSec(); + if (last_time_ns_ != 0) { + interval_ = ros_time_ns - last_time_ns_; + } + last_time_ns_ = ros_time_ns; + width_ = src_width; + height_ = src_height; + captureFrame.set_ntp_time_ms((int64_t)(ros_time_ns / 1000000)); + std::unique_lock lk(mtx_); + if (!running_) { + if (interval_ != 0) { + condition_.notify_all(); + } + return; + } + OnFrame(captureFrame, src_width, src_height); +} + +bool ROSVideoCapture::Init() +{ + std::unique_lock lk(mtx_); + // 確実にラムダ式の条件が満たされるまで待つ(既に満たされていたらそもそも wait しない) + condition_.wait(lk, [this]() { return signal_received_ || interval_ != 0; }); + if (signal_received_) { + return false; + } + // 必ず interval_ != 0 になっているので処理を続行 + + std::vector formats; + formats.push_back(cricket::VideoFormat(width_, height_, interval_, cricket::FOURCC_I420)); + SetSupportedFormats(formats); + return true; +} + +void ROSVideoCapture::OnSignal(int signum) +{ + std::unique_lock lk(mtx_); + // 単純に notify_all するだけだと spurious wakeup との区別が付かないのでメンバ変数を用意する + signal_received_ = true; + condition_.notify_all(); +} + +cricket::CaptureState ROSVideoCapture::Start( + const cricket::VideoFormat &capture_format) +{ + std::unique_lock lk(mtx_); + running_ = true; + SetCaptureState(cricket::CS_RUNNING); + return cricket::CS_RUNNING; +} + +void ROSVideoCapture::Stop() +{ + std::unique_lock lk(mtx_); + running_ = false; + SetCaptureState(cricket::CS_STOPPED); +} + +bool ROSVideoCapture::IsRunning() +{ + return running_; +} + +bool ROSVideoCapture::GetPreferredFourccs( + std::vector *fourccs) +{ + if (!fourccs) + return false; + fourccs->push_back(cricket::FOURCC_I420); + return true; +} + +bool ROSVideoCapture::GetBestCaptureFormat(const cricket::VideoFormat &desired, + cricket::VideoFormat *best_format) +{ + if (!best_format) + return false; + best_format->width = width_; + best_format->height = height_; + best_format->fourcc = cricket::FOURCC_I420; + best_format->interval = desired.interval; + return true; +} + +bool ROSVideoCapture::IsScreencast() const +{ + return false; +} \ No newline at end of file diff --git a/src/ros/ros_video_capture.h b/src/ros/ros_video_capture.h new file mode 100644 index 00000000..1af1c66a --- /dev/null +++ b/src/ros/ros_video_capture.h @@ -0,0 +1,58 @@ +#ifndef ROS_VIDEO_CAPTURE_H_ +#define ROS_VIDEO_CAPTURE_H_ + +#include "ros/ros.h" + +#include "sensor_msgs/Image.h" +#include "sensor_msgs/CompressedImage.h" +#include "media/base/videocapturer.h" + +#include +#include +#include + +#include "connection_settings.h" +#include "signal_listener.h" + +class ROSVideoCapture : public cricket::VideoCapturer, public SignalListener +{ +public: + explicit ROSVideoCapture(ConnectionSettings conn_settings); + ~ROSVideoCapture() override; + + bool Init(); + + void OnSignal(int signum) override; + + // cricket::VideoCapturer interface. + cricket::CaptureState Start( + const cricket::VideoFormat &capture_format) override; + void Stop() override; + + bool IsRunning() override; + bool GetPreferredFourccs(std::vector *fourccs) override; + + bool GetBestCaptureFormat(const cricket::VideoFormat &desired, + cricket::VideoFormat *best_format) override; + bool IsScreencast() const override; + + void ROSCallbackRaw(const sensor_msgs::ImageConstPtr &image); + void ROSCallbackCompressed(const sensor_msgs::CompressedImageConstPtr &image); + +private: + static uint32_t ConvertEncodingType(const std::string encoding); + void ROSCallback(ros::Time ros_time, const uint8_t* sample, size_t sample_size, int src_width, int src_height, uint32_t fourcc); + + ros::AsyncSpinner* spinner_; + ros::Subscriber sub_; + std::mutex mtx_; + std::condition_variable condition_; + bool running_; + uint64_t last_time_ns_; + int width_; + int height_; + int64_t interval_; + bool signal_received_ = false; +}; + +#endif \ No newline at end of file diff --git a/src/rtc/connection.cpp b/src/rtc/connection.cpp index 7d39c325..fb4e45a8 100644 --- a/src/rtc/connection.cpp +++ b/src/rtc/connection.cpp @@ -32,6 +32,10 @@ void RTCConnection::setOffer(const std::string sdp) SetSessionDescriptionObserver::Create( session_description->GetType(), _sender), session_description.release()); +} + +void RTCConnection::createAnswer() +{ _connection->CreateAnswer( CreateSessionDescriptionObserver::Create(_sender, _connection), webrtc::PeerConnectionInterface::RTCOfferAnswerOptions()); @@ -154,4 +158,4 @@ bool RTCConnection::isMediaEnabled( return track->enabled(); } return false; -} \ No newline at end of file +} diff --git a/src/rtc/connection.h b/src/rtc/connection.h index ae6088b5..c1739b78 100644 --- a/src/rtc/connection.h +++ b/src/rtc/connection.h @@ -13,6 +13,7 @@ class RTCConnection ~RTCConnection(); void createOffer(); void setOffer(const std::string sdp); + void createAnswer(); void setAnswer(const std::string sdp); void addIceCandidate(const std::string sdp_mid, const int sdp_mlineindex, const std::string sdp); @@ -34,4 +35,4 @@ class RTCConnection RTCMessageSender *_sender; rtc::scoped_refptr _connection; }; -#endif \ No newline at end of file +#endif diff --git a/src/rtc/manager.cpp b/src/rtc/manager.cpp index 1b79fc34..bb456af2 100644 --- a/src/rtc/manager.cpp +++ b/src/rtc/manager.cpp @@ -23,7 +23,7 @@ #include "absl/memory/memory.h" #endif -RTCManager::RTCManager(ConnectionSettings conn_settings) : _conn_settings(conn_settings) +RTCManager::RTCManager(ConnectionSettings conn_settings, std::unique_ptr capturer) : _conn_settings(conn_settings) { rtc::InitializeSSL(); @@ -68,7 +68,24 @@ RTCManager::RTCManager(ConnectionSettings conn_settings) : _conn_settings(conn_s if (!_conn_settings.no_video) { - createVideoSource(); +#if USE_ROS + _video_source = _factory->CreateVideoSource(std::move(capturer)); +#else + + capturer = createVideoCapturer(); + + webrtc::FakeConstraints constraints; + constraints.AddMandatory(webrtc::MediaConstraintsInterface::kMaxWidth, _conn_settings.getWidth()); + constraints.AddMandatory(webrtc::MediaConstraintsInterface::kMaxHeight, _conn_settings.getHeight()); + constraints.AddOptional(webrtc::MediaConstraintsInterface::kMinWidth, _conn_settings.getWidth()); + constraints.AddOptional(webrtc::MediaConstraintsInterface::kMinHeight, _conn_settings.getHeight()); + constraints.AddOptional(webrtc::MediaConstraintsInterface::kMinWidth, _conn_settings.getWidth()); + constraints.AddOptional(webrtc::MediaConstraintsInterface::kMinHeight, _conn_settings.getHeight()); + if (_conn_settings.framerate != 0) { + constraints.AddMandatory(webrtc::MediaConstraintsInterface::kMaxFrameRate, _conn_settings.framerate); + } + _video_source = _factory->CreateVideoSource(std::move(capturer), &constraints); +#endif } } @@ -83,14 +100,14 @@ RTCManager::~RTCManager() rtc::CleanupSSL(); } -void RTCManager::createVideoSource() { +std::unique_ptr RTCManager::createVideoCapturer() { std::unique_ptr capturer = nullptr; std::vector device_names; std::unique_ptr info( webrtc::VideoCaptureFactory::CreateDeviceInfo()); if (!info) { RTC_LOG(LS_WARNING) << __FUNCTION__ << "CreateDeviceInfo failed"; - return; + return nullptr; } int num_devices = info->NumberOfDevices(); for (int i = 0; i < num_devices; ++i) { @@ -106,23 +123,7 @@ void RTCManager::createVideoSource() { for (const auto& name : device_names) { capturer = factory.Create(cricket::Device(name, 0)); } - if (capturer) { - webrtc::FakeConstraints constraints; - constraints.AddMandatory(webrtc::MediaConstraintsInterface::kMaxWidth, _conn_settings.getWidth()); - constraints.AddMandatory(webrtc::MediaConstraintsInterface::kMaxHeight, _conn_settings.getHeight()); - constraints.AddOptional(webrtc::MediaConstraintsInterface::kMinWidth, _conn_settings.getWidth()); - constraints.AddOptional(webrtc::MediaConstraintsInterface::kMinHeight, _conn_settings.getHeight()); - constraints.AddOptional(webrtc::MediaConstraintsInterface::kMinWidth, _conn_settings.getWidth()); - constraints.AddOptional(webrtc::MediaConstraintsInterface::kMinHeight, _conn_settings.getHeight()); - if (_conn_settings.framerate != 0) { - constraints.AddMandatory(webrtc::MediaConstraintsInterface::kMaxFrameRate, _conn_settings.framerate); - } - _video_source = _factory->CreateVideoSource(std::move(capturer), &constraints); - } - else - { - RTC_LOG(LS_WARNING) << __FUNCTION__ << "CreateVideoCapturer failed"; - } + return capturer; } std::shared_ptr RTCManager::createConnection( diff --git a/src/rtc/manager.h b/src/rtc/manager.h index ba06e4c2..00f6c5fd 100644 --- a/src/rtc/manager.h +++ b/src/rtc/manager.h @@ -8,15 +8,14 @@ class RTCManager { public: - RTCManager(ConnectionSettings conn_settings); + RTCManager(ConnectionSettings conn_settings, std::unique_ptr capturer); ~RTCManager(); + static std::unique_ptr createVideoCapturer(); std::shared_ptr createConnection( webrtc::PeerConnectionInterface::RTCConfiguration rtc_config, RTCMessageSender *sender); private: - void createVideoSource(); - rtc::scoped_refptr _factory; rtc::scoped_refptr _video_source; std::unique_ptr _networkThread; @@ -24,4 +23,4 @@ class RTCManager std::unique_ptr _signalingThread; ConnectionSettings _conn_settings; }; -#endif \ No newline at end of file +#endif diff --git a/src/signal_listener.cpp b/src/signal_listener.cpp new file mode 100644 index 00000000..fb987ca1 --- /dev/null +++ b/src/signal_listener.cpp @@ -0,0 +1,41 @@ +#include "signal_listener.h" + +#include +#include + +SignalListener::SignalListener() +{ + SignalManager::add(this); +} + +SignalListener::~SignalListener() +{ + SignalManager::remove(this); +} + +std::vector SignalManager::_listeners; + +void SignalManager::sigintHandler(int signum) +{ + for (SignalListener *listener : _listeners) + { + listener->OnSignal(signum); + } +} + +void SignalManager::init() +{ + signal(SIGINT, SignalManager::sigintHandler); +} + +void SignalManager::add(SignalListener *listener) +{ + _listeners.push_back(listener); +} + +void SignalManager::remove(SignalListener *listener) +{ + _listeners.erase( + std::remove(_listeners.begin(), _listeners.end(), listener), + _listeners.end()); +} \ No newline at end of file diff --git a/src/signal_listener.h b/src/signal_listener.h new file mode 100644 index 00000000..406cd2ba --- /dev/null +++ b/src/signal_listener.h @@ -0,0 +1,29 @@ +#ifndef SIGNAL_LISTENER_H_ +#define SIGNAL_LISTENER_H_ + +#include + +class SignalManager; + +class SignalListener +{ +public: + SignalListener(); + ~SignalListener(); + + virtual void OnSignal(int signum) = 0; +}; + +class SignalManager +{ +public: + static void init(); + static void add(SignalListener *listener); + static void remove(SignalListener *listener); + +private: + static void sigintHandler(int signum); + + static std::vector _listeners; +}; +#endif \ No newline at end of file diff --git a/src/sora/sora_websocket_client.cpp b/src/sora/sora_websocket_client.cpp index b56a760c..6e16ac7e 100644 --- a/src/sora/sora_websocket_client.cpp +++ b/src/sora/sora_websocket_client.cpp @@ -61,18 +61,7 @@ void SoraWebsocketClient::reset() { if (parseURL(parts_)) { auto ssl_ctx = createSSLContext(); boost::beast::websocket::stream> wss(ioc_, ssl_ctx); - ws_ = std::make_shared(ioc_, std::move(ssl_ctx), - std::bind( - &SoraWebsocketClient::onRead, - this, - std::placeholders::_1, - std::placeholders::_2, - std::placeholders::_3), - std::bind( - &SoraWebsocketClient::onWrite, - this, - std::placeholders::_1, - std::placeholders::_2)); + ws_.reset(new Websocket(ioc_, std::move(ssl_ctx))); // SNI の設定を行う if (!SSL_set_tlsext_host_name(ws_->nativeSecureSocket().next_layer().native_handle(), parts_.host.c_str())) { @@ -81,18 +70,7 @@ void SoraWebsocketClient::reset() { } } else { boost::beast::websocket::stream ws(ioc_); - ws_ = std::make_shared(ioc_, - std::bind( - &SoraWebsocketClient::onRead, - this, - std::placeholders::_1, - std::placeholders::_2, - std::placeholders::_3), - std::bind( - &SoraWebsocketClient::onWrite, - this, - std::placeholders::_1, - std::placeholders::_2)); + ws_.reset(new Websocket(ioc_)); } } @@ -100,7 +78,6 @@ void SoraWebsocketClient::release() { connection_ = nullptr; } - bool SoraWebsocketClient::connect() { RTC_LOG(LS_INFO) << __FUNCTION__; @@ -240,7 +217,12 @@ void SoraWebsocketClient::onHandshake(boost::system::error_code ec) connected_ = true; - ws_->startToRead(); + ws_->startToRead(std::bind( + &SoraWebsocketClient::onRead, + this, + std::placeholders::_1, + std::placeholders::_2, + std::placeholders::_3)); doSendConnect(); } @@ -361,14 +343,6 @@ void SoraWebsocketClient::onRead(boost::system::error_code ec, std::size_t bytes } } -void SoraWebsocketClient::onWrite(boost::system::error_code ec, std::size_t bytes_transferred) -{ - boost::ignore_unused(bytes_transferred); - - if (ec) - return MOMO_BOOST_ERROR(ec, "Write"); -} - // WebRTC からのコールバック // これらは別スレッドからやってくるので取り扱い注意 void SoraWebsocketClient::onIceConnectionStateChange(webrtc::PeerConnectionInterface::IceConnectionState new_state) { @@ -394,7 +368,12 @@ void SoraWebsocketClient::onCreateDescription(webrtc::SdpType type, const std::s }; ws_->sendText(json_message.dump()); } -void SoraWebsocketClient::onSetDescription(webrtc::SdpType type) {} +void SoraWebsocketClient::onSetDescription(webrtc::SdpType type) { + RTC_LOG(LS_INFO) << __FUNCTION__ << " SdpType: " << webrtc::SdpTypeToString(type); + if (type == webrtc::SdpType::kOffer) { + connection_->createAnswer(); + } +} void SoraWebsocketClient::doIceConnectionStateChange(webrtc::PeerConnectionInterface::IceConnectionState new_state) { RTC_LOG(LS_INFO) << __FUNCTION__ << ": newState=" << Util::iceConnectionStateToString(new_state); diff --git a/src/sora/sora_websocket_client.h b/src/sora/sora_websocket_client.h index aa622c29..dbceeef8 100644 --- a/src/sora/sora_websocket_client.h +++ b/src/sora/sora_websocket_client.h @@ -25,7 +25,7 @@ class SoraWebsocketClient : public std::enable_shared_from_this ws_; + std::unique_ptr ws_; URLParts parts_; @@ -83,7 +83,6 @@ class SoraWebsocketClient : public std::enable_shared_from_this +#include +#include +#include +#if USE_ROS +#include "ros/ros.h" +#endif + +// バージョン情報 +// 通常は外から渡すが、渡されていなかった場合の対応 +#ifndef MOMO_VERSION +#define MOMO_VERSION "internal-build" +#endif + +// HWA を効かせる場合は 1 になる +#if USE_IL_ENCODER + #define MOMO_USE_IL_ENCODER 1 +#else + #define MOMO_USE_IL_ENCODER 0 +#endif + +// H264 を有効にする場合は 1 になる +#if USE_H264 + #define MOMO_USE_H264 1 +#else + #define MOMO_USE_H264 0 +#endif + +using json = nlohmann::json; + +// 列挙した文字列のみを許可するバリデータ +struct Enum : public CLI::Validator +{ + Enum(std::vector xs) + { + std::stringstream out; + + bool first = true; + for (auto x : xs) + { + if (!first) + { + out << ","; + } + first = false; + + out << x; + } + std::string name = out.str(); + + tname = "STR in [" + name + "]"; + func = [xs, name](std::string input) { + auto it = std::find(std::begin(xs), std::end(xs), input); + if (it == std::end(xs)) + { + return "Value " + input + " not in range [" + name + "]"; + } + return std::string(); + }; + } +}; + +// JSON Value のみを許可するバリデータ +struct JsonValue : public CLI::Validator +{ + JsonValue() + { + tname = "JSON Value"; + func = [](std::string input) { + try + { + json::parse(input); + return std::string(); + } + catch (json::parse_error &e) + { + return "Value " + input + " is not JSON Value"; + } + }; + } +}; + +// ディレクトリが存在するか確認するバリデータ +struct DirectoryExists : public CLI::Validator { + DirectoryExists() { + tname = "Directory"; + func = [](std::string input) { + auto path = boost::filesystem::path(input); + auto st = boost::filesystem::status(path); + if (!boost::filesystem::exists(st)) { + return "Path " + input + " not exists"; + } + if (!boost::filesystem::is_directory(st)) { + return "Path " + input + " is not directory"; + } + + return std::string(); + }; + } +}; + +#if USE_ROS + +void Util::parseArgs(int argc, char *argv[], bool &is_daemon, + bool &use_p2p, bool &use_sora, + int &log_level, ConnectionSettings &cs) +{ + ros::init(argc, argv, "momo", ros::init_options::AnonymousName); + + ros::NodeHandle nh; + cs.camera_name = nh.resolveName("image"); + + ros::NodeHandle local_nh("~"); + local_nh.param("compressed", cs.image_compressed, cs.image_compressed); + + local_nh.param("use_p2p", use_p2p, use_p2p); + local_nh.param("use_sora", use_sora, use_sora); + + local_nh.param("no_video", cs.no_video, cs.no_video); + local_nh.param("no_audio", cs.no_audio, cs.no_audio); + local_nh.param("video_codec", cs.video_codec, cs.video_codec); + local_nh.param("audio_codec", cs.audio_codec, cs.audio_codec); + local_nh.param("video_bitrate", cs.video_bitrate, cs.video_bitrate); + local_nh.param("audio_bitrate", cs.audio_bitrate, cs.audio_bitrate); + local_nh.param("resolution", cs.resolution, cs.resolution); + local_nh.param("framerate", cs.framerate, cs.framerate); + local_nh.param("priority", cs.priority, cs.priority); + local_nh.param("port", cs.port, cs.port); + local_nh.param("log_level", log_level, log_level); + + if (use_sora && local_nh.hasParam("SIGNALING_URL") && local_nh.hasParam("CHANNEL_ID")) { + local_nh.getParam("SIGNALING_URL", cs.sora_signaling_host); + local_nh.getParam("CHANNEL_ID", cs.sora_channel_id); + local_nh.param("auto", cs.sora_auto_connect, cs.sora_auto_connect); + + // 隠しオプション + std::string sora_metadata; + local_nh.param("metadata", sora_metadata, ""); + + // メタデータのパース + if (!sora_metadata.empty()) + { + cs.sora_metadata = json::parse(sora_metadata); + } + } else if (use_p2p) { + local_nh.param("document_root", cs.p2p_document_root, get_current_dir_name()); + } else { + exit(1); + } +} + +#else + +void Util::parseArgs(int argc, char *argv[], bool &is_daemon, + bool &use_p2p, bool &use_sora, + int &log_level, ConnectionSettings &cs) +{ + CLI::App app("Momo - WebRTC ネイティブクライアント"); + + bool version = false; + + app.add_flag("--no-video", cs.no_video, "ビデオを表示しない"); + app.add_flag("--no-audio", cs.no_audio, "オーディオを出さない"); +#if MOMO_USE_H264 + app.add_option("--video-codec", cs.video_codec, "ビデオコーデック")->check(Enum({"VP8", "VP9", "H264"})); +#else + app.add_option("--video-codec", cs.video_codec, "ビデオコーデック")->check(Enum({"VP8", "VP9"})); +#endif + app.add_option("--audio-codec", cs.audio_codec, "オーディオコーデック")->check(Enum({"OPUS", "PCMU"})); + app.add_option("--video-bitrate", cs.video_bitrate, "ビデオのビットレート")->check(CLI::Range(1, 30000)); + app.add_option("--audio-bitrate", cs.audio_bitrate, "オーディオのビットレート")->check(CLI::Range(6, 510)); + app.add_option("--resolution", cs.resolution, "解像度")->check(Enum({"QVGA", "VGA", "HD", "FHD", "4K"})); + app.add_option("--framerate", cs.framerate, "フレームレート")->check(CLI::Range(1, 60)); + app.add_flag("--fixed-resolution", cs.fixed_resolution, "固定解像度"); + app.add_option("--priority", cs.priority, "優先設定 (Experimental)")->check(Enum({"BALANCE", "FRAMERATE", "RESOLUTION"})); + app.add_option("--port", cs.port, "ポート番号")->check(CLI::Range(0, 65535)); + app.add_flag("--daemon", is_daemon, "デーモン化する"); + app.add_flag("--version", version, "バージョン情報の表示"); + app.add_option("--log-level", log_level, "ログレベル")->check(CLI::Range(0, 5)); + + auto p2p_app = app.add_subcommand("p2p", "P2P"); + auto sora_app = app.add_subcommand("sora", "WebRTC SFU Sora"); + + p2p_app->add_option("--document-root", cs.p2p_document_root, "配信ディレクトリ")->check(DirectoryExists()); + + sora_app->add_option("SIGNALING-URL", cs.sora_signaling_host, "シグナリングホスト")->required(); + sora_app->add_option("CHANNEL-ID", cs.sora_channel_id, "チャンネルID")->required(); + sora_app->add_flag("--auto", cs.sora_auto_connect, "自動接続する"); + + // 隠しオプション + std::string sora_metadata; + sora_app->add_option("--metadata", sora_metadata, "メタデータ")->group("")->check(JsonValue()); + + try + { + app.parse(argc, argv); + } + catch (const CLI::ParseError &e) + { + exit(app.exit(e)); + } + + // メタデータのパース + if (!sora_metadata.empty()) { + cs.sora_metadata = json::parse(sora_metadata); + } + + if (cs.p2p_document_root.empty()) { + cs.p2p_document_root = boost::filesystem::current_path().string(); + } + + if (version) + { + std::cout << "WebRTC Native Client Momo version " MOMO_VERSION " USE_IL_ENCODER=" BOOST_PP_STRINGIZE(MOMO_USE_IL_ENCODER) << std::endl; + exit(0); + } + + if (!p2p_app->parsed() && !sora_app->parsed()) + { + std::cout << app.help() << std::endl; + exit(1); + } + + if (sora_app->parsed()) { + use_sora = true; + } + + if (p2p_app->parsed()) { + use_p2p = true; + } +} + +#endif std::string Util::generateRundomChars() { diff --git a/src/util.h b/src/util.h index 53eca147..7629cf07 100644 --- a/src/util.h +++ b/src/util.h @@ -3,10 +3,14 @@ #include #include "api/peerconnectioninterface.h" +#include "connection_settings.h" class Util { -public: + public: + static void parseArgs(int argc, char *argv[], bool &is_daemon, + bool &use_p2p, bool &use_sora, + int &log_level, ConnectionSettings &cs); static std::string generateRundomChars(); static std::string generateRundomChars(size_t length); static std::string iceConnectionStateToString( diff --git a/src/ws/websocket.cpp b/src/ws/websocket.cpp index f5cd9faa..4232759d 100644 --- a/src/ws/websocket.cpp +++ b/src/ws/websocket.cpp @@ -3,21 +3,25 @@ #include -Websocket::Websocket(boost::asio::io_context& ioc, read_callback_t on_read, write_callback_t on_write) +Websocket::Websocket(boost::asio::io_context& ioc) : ws_(new websocket_t(ioc)) - , on_read_(on_read) - , on_write_(on_write) - , strand_(ws_->get_executor()) { } -Websocket::Websocket(boost::asio::io_context& ioc, boost::asio::ssl::context ssl_ctx, read_callback_t on_read, write_callback_t on_write) + , strand_(ws_->get_executor()) { + ws_->write_buffer_size(8192); +} +Websocket::Websocket(boost::asio::io_context& ioc, boost::asio::ssl::context ssl_ctx) : wss_(new ssl_websocket_t(ioc, ssl_ctx)) - , on_read_(on_read) - , on_write_(on_write) - , strand_(wss_->get_executor()) { } -Websocket::Websocket(boost::asio::ip::tcp::socket socket, read_callback_t on_read, write_callback_t on_write) + , strand_(wss_->get_executor()) { + wss_->write_buffer_size(8192); +} +Websocket::Websocket(boost::asio::ip::tcp::socket socket) : ws_(new websocket_t(std::move(socket))) - , on_read_(on_read) - , on_write_(on_write) - , strand_(ws_->get_executor()) { } + , strand_(ws_->get_executor()) { + ws_->write_buffer_size(8192); +} + +Websocket::~Websocket() { + RTC_LOG(LS_INFO) << __FUNCTION__; +} bool Websocket::isSSL() const { return wss_ != nullptr; } Websocket::websocket_t& Websocket::nativeSocket() { return *ws_; } @@ -25,15 +29,16 @@ Websocket::ssl_websocket_t& Websocket::nativeSecureSocket() { return *wss_; } boost::asio::strand& Websocket::strand() { return strand_; } -void Websocket::startToRead() { +void Websocket::startToRead(read_callback_t on_read) { boost::asio::post( strand_, std::bind( &Websocket::doRead, - shared_from_this())); + this, + on_read)); } -void Websocket::doRead() { +void Websocket::doRead(read_callback_t on_read) { RTC_LOG(LS_INFO) << __FUNCTION__; if (isSSL()) { @@ -43,7 +48,8 @@ void Websocket::doRead() { strand_, std::bind( &Websocket::onRead, - shared_from_this(), + this, + on_read, std::placeholders::_1, std::placeholders::_2))); } else { @@ -53,21 +59,22 @@ void Websocket::doRead() { strand_, std::bind( &Websocket::onRead, - shared_from_this(), + this, + on_read, std::placeholders::_1, std::placeholders::_2))); } } -void Websocket::onRead(boost::system::error_code ec, std::size_t bytes_transferred) { +void Websocket::onRead(read_callback_t on_read, boost::system::error_code ec, std::size_t bytes_transferred) { RTC_LOG(LS_INFO) << __FUNCTION__ << ": " << ec.message(); - // エラーだろうが何だろうが on_read_ コールバック関数は必ず呼ぶ + // エラーだろうが何だろうが on_read コールバック関数は必ず呼ぶ const auto text = boost::beast::buffers_to_string(read_buffer_.data()); read_buffer_.consume(read_buffer_.size()); - on_read_(ec, bytes_transferred, std::move(text)); + on_read(ec, bytes_transferred, std::move(text)); if (ec == boost::asio::error::operation_aborted) return; @@ -75,7 +82,7 @@ void Websocket::onRead(boost::system::error_code ec, std::size_t bytes_transferr if (ec) return MOMO_BOOST_ERROR(ec, "onRead"); - doRead(); + doRead(on_read); } void Websocket::sendText(std::string text) { @@ -84,7 +91,7 @@ void Websocket::sendText(std::string text) { strand_, std::bind( &Websocket::doSendText, - shared_from_this(), + this, std::move(text))); } @@ -95,8 +102,14 @@ void Websocket::doSendText(std::string text) { boost::beast::flat_buffer buffer; const auto n = boost::asio::buffer_copy(buffer.prepare(text.size()), boost::asio::buffer(text)); + RTC_LOG(LS_VERBOSE) << __FUNCTION__ << ": n=" << n; buffer.commit(n); + { + std::string tmp = boost::beast::buffers_to_string(buffer.data()); + RTC_LOG(LS_VERBOSE) << __FUNCTION__ << ": size=" << tmp.size() << " text=" << tmp; + } + write_buffer_.push_back(std::move(buffer)); if (empty) { @@ -107,6 +120,14 @@ void Websocket::doWrite() { RTC_LOG(LS_INFO) << __FUNCTION__; auto& buffer = write_buffer_.front(); + + RTC_LOG(LS_VERBOSE) << __FUNCTION__ << ": " << boost::beast::buffers_to_string(buffer.data()); + + { + std::string tmp = boost::beast::buffers_to_string(buffer.data()); + RTC_LOG(LS_VERBOSE) << __FUNCTION__ << ": size=" << tmp.size() << " text=" << tmp; + } + if (isSSL()) { wss_->text(true); wss_->async_write( @@ -115,7 +136,7 @@ void Websocket::doWrite() { strand_, std::bind( &Websocket::onWrite, - shared_from_this(), + this, std::placeholders::_1, std::placeholders::_2))); } else { @@ -126,7 +147,7 @@ void Websocket::doWrite() { strand_, std::bind( &Websocket::onWrite, - shared_from_this(), + this, std::placeholders::_1, std::placeholders::_2))); } @@ -137,7 +158,7 @@ void Websocket::onWrite(boost::system::error_code ec, std::size_t bytes_transfer RTC_LOG(LS_INFO) << __FUNCTION__ << ": " << ec.message(); // エラーだろうが何だろうが on_write_ コールバック関数は必ず呼ぶ - on_write_(ec, bytes_transferred); + // on_write(ec, bytes_transferred); if (ec == boost::asio::error::operation_aborted) return; @@ -145,6 +166,11 @@ void Websocket::onWrite(boost::system::error_code ec, std::size_t bytes_transfer if (ec) return MOMO_BOOST_ERROR(ec, "onWrite"); + { + std::string tmp = boost::beast::buffers_to_string(write_buffer_.front().data()); + RTC_LOG(LS_VERBOSE) << __FUNCTION__ << ": bytes_transferred=" << bytes_transferred << " size=" << tmp.size() << " text=" << tmp; + } + write_buffer_.erase(write_buffer_.begin()); if (!write_buffer_.empty()) diff --git a/src/ws/websocket.h b/src/ws/websocket.h index 7bb26728..89692bdc 100644 --- a/src/ws/websocket.h +++ b/src/ws/websocket.h @@ -13,21 +13,17 @@ // 任意のスレッドから sendText を呼ぶことで書き込みができる。 // // 接続の確立に関しては、nativeSocket() および nativeSecureSocket() 関数を使って自前で行うこと。 -class Websocket : public std::enable_shared_from_this +class Websocket { public: typedef boost::beast::websocket::stream websocket_t; typedef boost::beast::websocket::stream> ssl_websocket_t; typedef std::function read_callback_t; - typedef std::function write_callback_t; private: std::unique_ptr ws_; std::unique_ptr wss_; - read_callback_t on_read_; - write_callback_t on_write_; - boost::asio::strand strand_; boost::beast::multi_buffer read_buffer_; @@ -35,11 +31,12 @@ class Websocket : public std::enable_shared_from_this public: // 非SSL - Websocket(boost::asio::io_context& ioc, read_callback_t on_read, write_callback_t on_write); + Websocket(boost::asio::io_context& ioc); // SSL - Websocket(boost::asio::io_context& ioc, boost::asio::ssl::context ssl_ctx, read_callback_t on_read, write_callback_t on_write); + Websocket(boost::asio::io_context& ioc, boost::asio::ssl::context ssl_ctx); // 非SSL + ソケット直接 - Websocket(boost::asio::ip::tcp::socket socket, read_callback_t on_read, write_callback_t on_write); + Websocket(boost::asio::ip::tcp::socket socket); + ~Websocket(); bool isSSL() const; @@ -50,13 +47,11 @@ class Websocket : public std::enable_shared_from_this public: // Websocket からの読み込みを開始する。 - // これを呼ばなくても、最初の書き込みを行ったら勝手に読み込みも始まるが、 - // 最初の読み込みを明示的に行いたい場合に呼ぶ。 - void startToRead(); + void startToRead(read_callback_t on_read); private: - void doRead(); - void onRead(boost::system::error_code ec, std::size_t bytes_transferred); + void doRead(read_callback_t on_read); + void onRead(read_callback_t on_read, boost::system::error_code ec, std::size_t bytes_transferred); public: void sendText(std::string text); @@ -64,7 +59,6 @@ class Websocket : public std::enable_shared_from_this private: void doSendText(std::string text); void doWrite(); - void onWrite(boost::system::error_code ec, std::size_t bytes_transferred); };