diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 597f4c6..f21d7bd 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -4,9 +4,7 @@ on: push: paths-ignore: - 'doc/**' - - 'README.md' - schedule: - - cron: "0 0 * * *" + - '**/*.md' jobs: build-windows: diff --git a/CHANGES.md b/CHANGES.md index 1b7026a..a933352 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -11,6 +11,21 @@ ## develop +## 2020.3 + +- [UPDATE] Boost のバージョンを 1.73.0 に上げる + - @voluntas +- [UPDATE] WebRTC のバージョンを M83 (4103@{#12}) に上げる + - @melpon +- [CHANGE] Sora.Role.Upstream, Sora.Role.Downstream を削除 + - @melpon +- [FIX] 接続確立中に Sora.Dispose するとエラーになることがあったのを修正 + - @melpon +- [FIX] 接続が確立する前に ping を受け取ると通信が切断されてしまっていたのを修正 + - @melpon +- [FIX] Windows 版の H.264 デコードでリサイズが発生した際にエラーになるのを修正 + - @melpon + ## 2020.2 - [UPDATE] WebRTC のバージョンを M81 (4044@{#12}) に上げる diff --git a/README.md b/README.md index b80dcf2..66d9913 100644 --- a/README.md +++ b/README.md @@ -50,8 +50,6 @@ Sora Unity SDK ではソフトウェアでの H.264 エンコード/デコード そのため Windows では NVIDIA VIDEO CODEC SDK 、macOS では VideoToolbox を利用し、H.264 のエンコード/デコードを実現しています。 -**NVIDIA VIDEO CODEC SDK を利用した H.264 はデコードは現時点では非対応です** - 詳細は H.264 を [USE_H264.md](doc/USE_H264.md) をお読みください ## 対応機能 @@ -84,6 +82,7 @@ Sora Unity SDK ではソフトウェアでの H.264 エンコード/デコード - NVIDIA VIDEO CODEC SDK - Windows 版 - H.264 のハードウェアエンコードへの対応 + - H.264 のハードウェアデコードへの対応 ## 非対応 @@ -104,26 +103,6 @@ Sora Unity SDK ではソフトウェアでの H.264 エンコード/デコード - Windows 10 1809 x86_64 以降 - macOS 10.15 x86_64 以降 -## ライセンス - -Apache License 2.0 - -``` -Copyright 2019-2020, Wandbox LLC (Original Author) -Copyright 2019-2020, Shiguredo Inc - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -``` ## 有償での優先実装 @@ -131,6 +110,8 @@ limitations under the License. - [スロースネットワークス株式会社](http://www.sloth-networks.co.jp) 様 - WebRTC's Statistics 対応 - 企業名非公開 +- Windows 版 NVIDIA VIDEO CODEC SDK による H.264 デコーダ対応 + - [スロースネットワークス株式会社](http://www.sloth-networks.co.jp) 様 ## 有償での優先実装が可能な機能一覧 @@ -170,3 +151,24 @@ iOS 10.0 以上への対応 ### Android 対応 Android 5.0 以上への対応 + +## ライセンス + +Apache License 2.0 + +``` +Copyright 2019-2020, Wandbox LLC (Original Author) +Copyright 2019-2020, Shiguredo Inc + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +``` diff --git a/Sora/Sora.cs b/Sora/Sora.cs index a679b35..1dde842 100644 --- a/Sora/Sora.cs +++ b/Sora/Sora.cs @@ -5,8 +5,6 @@ public class Sora : IDisposable { public enum Role { - Upstream, - Downstream, Sendonly, Recvonly, Sendrecv, @@ -29,7 +27,7 @@ public class Config public string SignalingUrl = ""; public string ChannelId = ""; public string Metadata = ""; - public Role Role = Sora.Role.Upstream; + public Role Role = Sora.Role.Sendonly; public bool Multistream = false; public CapturerType CapturerType = Sora.CapturerType.DeviceCamera; public UnityEngine.Camera UnityCamera = null; @@ -104,8 +102,6 @@ public bool Connect(Config config) } var role = - config.Role == Role.Upstream ? "upstream" : - config.Role == Role.Downstream ? "downstream" : config.Role == Role.Sendonly ? "sendonly" : config.Role == Role.Recvonly ? "recvonly" : "sendrecv"; return sora_connect( diff --git a/VERSIONS b/VERSIONS index 2092ba6..e983e7d 100644 --- a/VERSIONS +++ b/VERSIONS @@ -1,5 +1,5 @@ -SORA_UNITY_SDK_VERSION=2020.2 -BOOST_VERSION=1.72.0 +SORA_UNITY_SDK_VERSION=2020.3 +BOOST_VERSION=1.73.0 JSON_VERSION=3.6.1 -WEBRTC_BUILD_VERSION=81.4044.13.2 +WEBRTC_BUILD_VERSION=83.4103.12.2 CUDA_VERSION=10.2 diff --git a/doc/QA.md b/doc/QA.md new file mode 100644 index 0000000..dc25b50 --- /dev/null +++ b/doc/QA.md @@ -0,0 +1,4 @@ +# 質問と答え +### 解像度を変更したい +- 解像度を変更したい場合はこちらの[SET_VIDEO_SIZE.md](https://github.com/shiguredo/sora-unity-sdk/blob/develop/doc/SET_VIDEO_SIZE.md)をお読みください + diff --git a/doc/SET_VIDEO_SIZE.md b/doc/SET_VIDEO_SIZE.md new file mode 100644 index 0000000..e63a9d7 --- /dev/null +++ b/doc/SET_VIDEO_SIZE.md @@ -0,0 +1,51 @@ +## 解像度の変更方法 +### 概要 +解像度の変更には「送信する映像のサイズ」、「受信するテクスチャのサイズ」、「Unityの表示上のサイズ」の3つを変える必要があります。 +ここでの変更方法は[sora-unity-sdk-samples](https://github.com/shiguredo/sora-unity-sdk-samples)を参考例として記載しています。 + +### 変更対象 +- SoraSample.cs +- RawImage(pub/sub/multi_pubシーンのみ) + +### 変更方法 +#### 送信する映像のサイズの変更 +--------------------------------------- +##### SoraSample.cs +`VideoWidth`と`VideoHeight`パラメータを追加してください。 +[![Image from Gyazo](https://i.gyazo.com/36bad2d5d625a7e63107a9a2a5db7984.png)](https://gyazo.com/36bad2d5d625a7e63107a9a2a5db7984) + +#### 受信するテクスチャのサイズの変更 +--------------------------------------- +##### SoraSample.cs +テクスチャを生成するパラメータを変更してください。 +参考:[UnityDocument:Texture2D.Texture2D](https://docs.unity3d.com/jp/460/ScriptReference/Texture2D-ctor.html) + +- pub/subの場合 +[![Image from Gyazo](https://i.gyazo.com/47ae4e50834e793a7d5e84d0a68788a2.png)](https://gyazo.com/47ae4e50834e793a7d5e84d0a68788a2) +- multi_pub_sub/multi_subの場合 +[![Image from Gyazo](https://i.gyazo.com/50d3e2699d008e59d2649733aae6b7ea.png)](https://gyazo.com/50d3e2699d008e59d2649733aae6b7ea) + +#### Unityの表示上のサイズの変更 +##### RawImage(pub/sub/multi_pubシーンのみ) +--------------------------------------- +HierarchyからRawImageを選択し、Inspectorから`Width`と`Height`の値を変更してください。 +`Width`と`Height`を変更すると設定した値によっては「開始」と「終了」ボタンが隠れてしまうため、 +Hierarchyから「ButtonStart」と「ButtonEnd」を選択して少し上に動かしてください。 + +[![Image from Gyazo](https://i.gyazo.com/9ba94ab0b13edc2d4d4bf0d529e3ed14.png)](https://gyazo.com/9ba94ab0b13edc2d4d4bf0d529e3ed14) + +参考:`Width`と`Height`を変更するとGameビューでは以下のように変化します。 +[![Image from Gyazo](https://i.gyazo.com/791329a7ea7d5524cb781027ef918446.png)](https://gyazo.com/791329a7ea7d5524cb781027ef918446) + +###### multi_pubsubシーンを変更したい場合 +multi_pubsubシーンは動的に必要なイメージ数が変わるため、あらかじめ設定するRawImageはありません。 +その場合はHierarchyのCanvas/BaseTrackの変更とCanvas/Scroll Viewのサイズ変更をしてください。 +[![Image from Gyazo](https://i.gyazo.com/e025bc6392b4424e1b25d0b6f95b2589.png)](https://gyazo.com/e025bc6392b4424e1b25d0b6f95b2589) + +#### 変更結果 +- Unityでの表示 +[![Image from Gyazo](https://i.gyazo.com/1b5cbd74888c36e3923ec99910db5955.png)](https://gyazo.com/1b5cbd74888c36e3923ec99910db5955) + +- Unityから送信した映像の表示 +設定した1280x720になっています。 +[![Image from Gyazo](https://i.gyazo.com/3e7b05d4a2467dcd211b95660a764910.png)](https://gyazo.com/3e7b05d4a2467dcd211b95660a764910) diff --git a/doc/USE_H264.md b/doc/USE_H264.md index 17f18f6..027f630 100644 --- a/doc/USE_H264.md +++ b/doc/USE_H264.md @@ -5,8 +5,6 @@ Sora Unity SDK では、ソフトウェアでの H.264 エンコード/デコー ただし、ハードウェアで H.264 エンコーダ/デコーダが使える場合は、それを積極的に利用します。 - Windows 版では [NVIDIA VIDEO CODEC SDK](https://developer.nvidia.com/nvidia-video-codec-sdk) がインストールされていれば、これを利用します。 - - もしこれが利用可能な場合 **H.264 エンコードのみ可能** です。H.264 のデコードはできません。 - - つまりシングルストリームの場合は `Sora.Role.Upstream` または `Sora.Role.Sendonly` のみ、マルチストリームの場合は `Sora.Role.Sendonly` でしか動作しません。 - macOS 版では [VideoToolbox](https://developer.apple.com/documentation/videotoolbox) を利用します。 - VideoToolbox によって H.264 エンコード/デコードが可能です。 diff --git a/src/hwenc_nvcodec/nvcodec_video_decoder.cpp b/src/hwenc_nvcodec/nvcodec_video_decoder.cpp index c687a24..5d29375 100644 --- a/src/hwenc_nvcodec/nvcodec_video_decoder.cpp +++ b/src/hwenc_nvcodec/nvcodec_video_decoder.cpp @@ -17,8 +17,18 @@ NvCodecVideoDecoder::~NvCodecVideoDecoder() { Release(); } +void NvCodecVideoDecoder::Log(NvCodecVideoDecoderCuda::LogType type, const std::string& log) { + if (type == NvCodecVideoDecoderCuda::LogType::LOG_INFO) { + RTC_LOG(LS_INFO) << log; + } else if (type == NvCodecVideoDecoderCuda::LogType::LOG_WARNING) { + RTC_LOG(LS_WARNING) << log; + } else { + RTC_LOG(LS_ERROR) << log; + } +} + bool NvCodecVideoDecoder::IsSupported(cudaVideoCodec codec_id) { - auto decoder = NvCodecVideoDecoderCuda::Create(codec_id); + auto decoder = NvCodecVideoDecoderCuda::Create(codec_id, &NvCodecVideoDecoder::Log); return decoder != nullptr; } @@ -101,7 +111,7 @@ const char* NvCodecVideoDecoder::ImplementationName() const { } int32_t NvCodecVideoDecoder::InitNvCodec() { - decoder_ = NvCodecVideoDecoderCuda::Create(codec_id_); + decoder_ = NvCodecVideoDecoderCuda::Create(codec_id_, &NvCodecVideoDecoder::Log); output_info_ = false; return WEBRTC_VIDEO_CODEC_OK; } diff --git a/src/hwenc_nvcodec/nvcodec_video_decoder.h b/src/hwenc_nvcodec/nvcodec_video_decoder.h index 3d8b03b..d19609c 100644 --- a/src/hwenc_nvcodec/nvcodec_video_decoder.h +++ b/src/hwenc_nvcodec/nvcodec_video_decoder.h @@ -38,6 +38,8 @@ class NvCodecVideoDecoder : public webrtc::VideoDecoder { const char* ImplementationName() const override; private: + static void NvCodecVideoDecoder::Log(NvCodecVideoDecoderCuda::LogType type, const std::string& log); + int32_t InitNvCodec(); void ReleaseNvCodec(); diff --git a/src/hwenc_nvcodec/nvcodec_video_decoder_cuda.cpp b/src/hwenc_nvcodec/nvcodec_video_decoder_cuda.cpp index 41e81c9..8c1fb21 100644 --- a/src/hwenc_nvcodec/nvcodec_video_decoder_cuda.cpp +++ b/src/hwenc_nvcodec/nvcodec_video_decoder_cuda.cpp @@ -1,12 +1,19 @@ #include "nvcodec_video_decoder_cuda.h" +#include +#include + +typedef std::function LogFunc; + #ifdef __cuda_cuda_h__ -inline bool check(CUresult e, int iLine, const char* szFile) { +inline bool check(const LogFunc& f, CUresult e, int iLine, const char* szFile) { if (e != CUDA_SUCCESS) { const char* szErrName = NULL; cuGetErrorName(e, &szErrName); - std::cerr << "CUDA driver API error " << szErrName << " at line " << iLine - << " in file " << szFile << std::endl; + std::stringstream ss; + ss << "CUDA driver API error " << szErrName << " at line " << iLine + << " in file " << szFile; + f(NvCodecVideoDecoderCuda::LogType::LOG_ERROR, ss.str()); return false; } return true; @@ -14,10 +21,12 @@ inline bool check(CUresult e, int iLine, const char* szFile) { #endif #ifdef __CUDA_RUNTIME_H__ -inline bool check(cudaError_t e, int iLine, const char* szFile) { +inline bool check(const LogFunc& f, cudaError_t e, int iLine, const char* szFile) { if (e != cudaSuccess) { - std::cerr << "CUDA runtime API error " << cudaGetErrorName(e) << " at line " - << iLine << " in file " << szFile << std::endl; + std::stringstream ss; + ss << "CUDA runtime API error " << cudaGetErrorName(e) << " at line " + << iLine << " in file " << szFile; + f(NvCodecVideoDecoderCuda::LogType::LOG_ERROR, ss.str()); return false; } return true; @@ -25,7 +34,7 @@ inline bool check(cudaError_t e, int iLine, const char* szFile) { #endif #ifdef _NV_ENCODEAPI_H_ -inline bool check(NVENCSTATUS e, int iLine, const char* szFile) { +inline bool check(const LogFunc& f, NVENCSTATUS e, int iLine, const char* szFile) { const char* aszErrName[] = { "NV_ENC_SUCCESS", "NV_ENC_ERR_NO_ENCODE_DEVICE", @@ -55,8 +64,10 @@ inline bool check(NVENCSTATUS e, int iLine, const char* szFile) { "NV_ENC_ERR_RESOURCE_NOT_MAPPED", }; if (e != NV_ENC_SUCCESS) { - std::cerr << "NVENC error " << aszErrName[e] << " at line " << iLine - << " in file " << szFile << std::endl; + std::stringstream ss; + ss << "NVENC error " << aszErrName[e] << " at line " << iLine + << " in file " << szFile; + f(NvCodecVideoDecoderCuda::LogType::LOG_ERROR, ss.str()); return false; } return true; @@ -64,10 +75,12 @@ inline bool check(NVENCSTATUS e, int iLine, const char* szFile) { #endif #ifdef _WINERROR_ -inline bool check(HRESULT e, int iLine, const char* szFile) { +inline bool check(const LogFunc& f, HRESULT e, int iLine, const char* szFile) { if (e != S_OK) { - std::cerr << "HRESULT error 0x" << (void*)e << " at line " << iLine - << " in file " << szFile << std::endl; + std::stringstream ss; + ss << "HRESULT error 0x" << (void*)e << " at line " << iLine + << " in file " << szFile; + f(NvCodecVideoDecoderCuda::LogType::LOG_ERROR, ss.str()); return false; } return true; @@ -75,30 +88,34 @@ inline bool check(HRESULT e, int iLine, const char* szFile) { #endif #if defined(__gl_h_) || defined(__GL_H__) -inline bool check(GLenum e, int iLine, const char* szFile) { +inline bool check(const LogFunc& f, GLenum e, int iLine, const char* szFile) { if (e != 0) { - std::cerr << "GLenum error " << e << " at line " << iLine << " in file " - << szFile << std::endl; + std::stringstream ss; + ss << "GLenum error " << e << " at line " << iLine << " in file " + << szFile; + f(NvCodecVideoDecoderCuda::LogType::LOG_ERROR, ss.str()); return false; } return true; } #endif -inline bool check(int e, int iLine, const char* szFile) { +inline bool check(const LogFunc& f, int e, int iLine, const char* szFile) { if (e < 0) { - std::cerr << "General error " << e << " at line " << iLine << " in file " - << szFile << std::endl; + std::stringstream ss; + ss << "General error " << e << " at line " << iLine << " in file " + << szFile; + f(NvCodecVideoDecoderCuda::LogType::LOG_ERROR, ss.str()); return false; } return true; } -#define ck(call) check(call, __LINE__, __FILE__) +#define ck(f, call) check(f, call, __LINE__, __FILE__) -std::unique_ptr NvCodecVideoDecoderCuda::Create(cudaVideoCodec codec_id) { +std::unique_ptr NvCodecVideoDecoderCuda::Create(cudaVideoCodec codec_id, std::function f) { auto p = std::unique_ptr(new NvCodecVideoDecoderCuda()); - if (p->Init(codec_id) != 0) { + if (p->Init(codec_id, f) != 0) { return nullptr; } return p; @@ -108,27 +125,28 @@ NvCodecVideoDecoderCuda::~NvCodecVideoDecoderCuda() { Release(); } -int32_t NvCodecVideoDecoderCuda::Init(cudaVideoCodec codec_id) { - if (!ck(cuInit(0))) { +int32_t NvCodecVideoDecoderCuda::Init(cudaVideoCodec codec_id, const std::function& f) { + if (!ck(f, cuInit(0))) { return -1; } int gpu_num = 0; - if (!ck(cuDeviceGetCount(&gpu_num))) { + if (!ck(f, cuDeviceGetCount(&gpu_num))) { return -2; } if (gpu_num == 0) { return -3; } - if (!ck(cuDeviceGet(&cu_device_, 0))) { + if (!ck(f, cuDeviceGet(&cu_device_, 0))) { return -4; } - if (!ck(cuCtxCreate(&cu_context_, 0, cu_device_))) { + if (!ck(f, cuCtxCreate(&cu_context_, 0, cu_device_))) { return -5; } try { - decoder_.reset(new NvDecoder(cu_context_, false, codec_id)); + decoder_.reset(new NvDecoder(cu_context_, false, codec_id, nullptr, false, false, nullptr, nullptr, 3840, 2160)); } catch (NVDECException& e) { + f(NvCodecVideoDecoderCuda::LogType::LOG_ERROR, e.what()); return -4; } diff --git a/src/hwenc_nvcodec/nvcodec_video_decoder_cuda.h b/src/hwenc_nvcodec/nvcodec_video_decoder_cuda.h index a56e87d..fbfda4f 100644 --- a/src/hwenc_nvcodec/nvcodec_video_decoder_cuda.h +++ b/src/hwenc_nvcodec/nvcodec_video_decoder_cuda.h @@ -2,6 +2,8 @@ #define NVCODEC_VIDEO_DECODER_CUDA_H_ #include +#include +#include // NvCodec #include @@ -11,17 +13,22 @@ class NvCodecVideoDecoderCuda { public: + enum class LogType { + LOG_INFO, + LOG_WARNING, + LOG_ERROR, + }; // cudaVideoCodec_H264 // cudaVideoCodec_VP8 // cudaVideoCodec_VP9 - static std::unique_ptr Create(cudaVideoCodec codec_id); + static std::unique_ptr Create(cudaVideoCodec codec_id, std::function f); NvDecoder* GetNvDecoder() { return decoder_.get(); } void Decode(const uint8_t* ptr, int size, uint8_t**& frames, int& frame_count); ~NvCodecVideoDecoderCuda(); private: - int32_t Init(cudaVideoCodec codec_id); + int32_t Init(cudaVideoCodec codec_id, const std::function& f); void Release(); private: diff --git a/src/sora.cpp b/src/sora.cpp index 219690c..f639a28 100644 --- a/src/sora.cpp +++ b/src/sora.cpp @@ -5,7 +5,7 @@ namespace sora { -Sora::Sora(UnityContext* context) : ioc_(1), context_(context) { +Sora::Sora(UnityContext* context) : context_(context) { ptrid_ = IdPointer::Instance().Register(this); } @@ -14,16 +14,20 @@ Sora::~Sora() { IdPointer::Instance().Unregister(ptrid_); + unity_adm_ = nullptr; + + ioc_->stop(); + if (thread_) { + thread_->Stop(); + thread_.reset(); + } if (signaling_) { signaling_->release(); } signaling_.reset(); + ioc_.reset(); rtc_manager_.reset(); renderer_.reset(); - ioc_.stop(); - if (thread_) { - thread_->Stop(); - } RTC_LOG(LS_INFO) << "Sora object destroy finished"; } void Sora::SetOnAddTrack(std::function on_add_track) { @@ -84,8 +88,7 @@ bool Sora::Connect(std::string unity_version, << " audio_recording_device=" << audio_recording_device << " audio_playout_device=" << audio_playout_device; - if (role != "upstream" && role != "downstream" && role != "sendonly" && - role != "recvonly" && role != "sendrecv") { + if (role != "sendonly" && role != "recvonly" && role != "sendrecv") { RTC_LOG(LS_ERROR) << "Invalid role: " << role; return false; } @@ -122,7 +125,7 @@ bool Sora::Connect(std::string unity_version, config.audio_recording_device = audio_recording_device; config.audio_playout_device = audio_playout_device; - if (role == "upstream" || role == "sendonly" || role == "sendrecv") { + if (role == "sendonly" || role == "sendrecv") { // 送信側は capturer を設定する。送信のみの場合は playout の設定はしない rtc::scoped_refptr capturer = CreateVideoCapturer( capturer_type, unity_camera_texture, video_capturer_device, video_width, @@ -131,7 +134,7 @@ bool Sora::Connect(std::string unity_version, return false; } - config.no_playout = role == "upstream" || role == "sendonly"; + config.no_playout = role == "sendonly"; rtc_manager_ = RTCManager::Create(config, std::move(capturer), renderer_.get(), unity_adm_, std::move(task_queue_factory)); @@ -150,15 +153,9 @@ bool Sora::Connect(std::string unity_version, << " channel_id=" << channel_id_; SoraSignalingConfig config; config.unity_version = unity_version; - config.role = role == "upstream" - ? SoraSignalingConfig::Role::Upstream - : role == "downstream" - ? SoraSignalingConfig::Role::Downstream - : role == "sendonly" - ? SoraSignalingConfig::Role::Sendonly - : role == "recvonly" - ? SoraSignalingConfig::Role::Recvonly - : SoraSignalingConfig::Role::Sendrecv; + config.role = role == "sendonly" ? SoraSignalingConfig::Role::Sendonly : + role == "recvonly" ? SoraSignalingConfig::Role::Recvonly : + SoraSignalingConfig::Role::Sendrecv; config.multistream = multistream; config.signaling_url = signaling_url_; config.channel_id = channel_id_; @@ -175,8 +172,9 @@ bool Sora::Connect(std::string unity_version, } } + ioc_.reset(new boost::asio::io_context(1)); signaling_ = SoraSignaling::Create( - ioc_, rtc_manager_.get(), config, [this](std::string json) { + *ioc_, rtc_manager_.get(), config, [this](std::string json) { std::lock_guard guard(event_mutex_); event_queue_.push_back([this, json = std::move(json)]() { // ここは Unity スレッドから呼ばれる @@ -204,7 +202,7 @@ bool Sora::Connect(std::string unity_version, } thread_->PostTask(RTC_FROM_HERE, [this]() { RTC_LOG(LS_INFO) << "io_context started"; - ioc_.run(); + ioc_->run(); RTC_LOG(LS_INFO) << "io_context finished"; }); diff --git a/src/sora.h b/src/sora.h index fd971c3..57068ee 100644 --- a/src/sora.h +++ b/src/sora.h @@ -31,30 +31,8 @@ namespace sora { -struct SoraConfig { - std::string signaling_url; - std::string channel_id; - std::string metadata; - bool downstream = false; - bool multistream = false; - int capturer_type = 0; - std::string video_capturer_device; - void* unity_camera_texture = nullptr; - int video_width = 640; - int video_height = 480; - bool unity_audio_input = false; - std::string audio_recording_device = ""; - std::string audio_playout_device = ""; - - bool disable_echo_cancellation = false; - bool disable_auto_gain_control = false; - bool disable_noise_suppression = false; - bool disable_highpass_filter = false; - bool disable_typing_detection = false; -}; - class Sora { - boost::asio::io_context ioc_; + std::unique_ptr ioc_; UnityContext* context_; std::string signaling_url_; std::string channel_id_; diff --git a/src/sora_signaling.cpp b/src/sora_signaling.cpp index 0729ea7..ba4a146 100644 --- a/src/sora_signaling.cpp +++ b/src/sora_signaling.cpp @@ -110,7 +110,10 @@ bool SoraSignaling::Init() { } void SoraSignaling::release() { - connection_ = nullptr; + // connection_ を nullptr にした上で解放する + // デストラクタ中にコールバックが呼ばれて解放中の connection_ にアクセスしてしまうことがあるため + auto connection = std::move(connection_); + connection = nullptr; } bool SoraSignaling::connect() { @@ -206,8 +209,6 @@ void SoraSignaling::onHandshake(boost::system::error_code ec) { void SoraSignaling::doSendConnect() { std::string role = - config_.role == SoraSignalingConfig::Role::Upstream ? "upstream" : - config_.role == SoraSignalingConfig::Role::Downstream ? "downstream" : config_.role == SoraSignalingConfig::Role::Sendonly ? "sendonly" : config_.role == SoraSignalingConfig::Role::Recvonly ? "recvonly" : "sendrecv"; @@ -326,6 +327,7 @@ void SoraSignaling::onRead(boost::system::error_code ec, } else if (type == "ping") { if (rtc_state_ != webrtc::PeerConnectionInterface::IceConnectionState:: kIceConnectionConnected) { + doRead(); return; } bool stats = json_message.value("stats", false); @@ -428,7 +430,7 @@ void SoraSignaling::onCreateDescription(webrtc::SdpType type, void SoraSignaling::onSetDescription(webrtc::SdpType type) { RTC_LOG(LS_INFO) << __FUNCTION__ << " SdpType: " << webrtc::SdpTypeToString(type); - if (type == webrtc::SdpType::kOffer) { + if (connection_ && type == webrtc::SdpType::kOffer) { connection_->createAnswer(); } } diff --git a/src/sora_signaling.h b/src/sora_signaling.h index a654ab6..bbbd0bd 100644 --- a/src/sora_signaling.h +++ b/src/sora_signaling.h @@ -36,8 +36,8 @@ struct SoraSignalingConfig { std::string audio_codec = "OPUS"; int audio_bitrate = 0; - enum class Role { Upstream, Downstream, Sendonly, Recvonly, Sendrecv }; - Role role = Role::Upstream; + enum class Role { Sendonly, Recvonly, Sendrecv }; + Role role = Role::Sendonly; bool multistream = false; };