diff --git a/src/sora.cpp b/src/sora.cpp index d14ca65..8f5518b 100644 --- a/src/sora.cpp +++ b/src/sora.cpp @@ -541,11 +541,10 @@ void Sora::Disconnect() { void Sora::SwitchCamera(const sora_conf::internal::CameraConfig& cc) { RTC_LOG(LS_INFO) << "SwitchCamera: " << jsonif::to_json(cc); - boost::asio::post(*ioc_, [self = shared_from_this(), cc = cc]() { - self->DoSwitchCamera(cc); - }); -} -void Sora::DoSwitchCamera(const sora_conf::internal::CameraConfig& cc) { + + // このあたりのキャプチャラ作成は、IO スレッドではなく Unity スレッドで行う。 + // (DoConnect で作成したキャプチャラは Unity スレッド上で実行されてるので、 + // 全て同じスレッドでやる必要がある) std::function on_frame; if (on_capturer_frame_) { on_frame = [on_frame = @@ -582,10 +581,40 @@ void Sora::DoSwitchCamera(const sora_conf::internal::CameraConfig& cc) { std::string video_track_id = rtc::CreateRandomString(16); auto video_track = factory_->CreateVideoTrack(video_track_id, capturer.get()); - renderer_->ReplaceTrack(video_track_.get(), video_track.get()); - video_sender_->SetTrack(video_track.get()); + + // video_track_ をこのスレッド(Unity スレッド)で設定したいので、 + // IO スレッドの実行完了を待つ + std::promise p; + std::future f = p.get_future(); + boost::asio::post(*ioc_, + [self = shared_from_this(), cc = cc, video_track, &p]() { + self->DoSwitchCamera(cc, video_track); + p.set_value(); + }); + f.wait(); + video_track_ = video_track; } +void Sora::DoSwitchCamera( + const sora_conf::internal::CameraConfig& cc, + rtc::scoped_refptr video_track) { + if (video_track_ == nullptr) { + webrtc::RTCErrorOr> + video_result = signaling_->GetPeerConnection()->AddTrack(video_track, + {stream_id_}); + video_sender_ = video_result.value(); + + auto track_id = renderer_->AddTrack(video_track.get()); + PushEvent([this, track_id]() { + if (on_add_track_) { + on_add_track_(track_id, ""); + } + }); + } else { + renderer_->ReplaceTrack(video_track_.get(), video_track.get()); + } + video_sender_->SetTrack(video_track.get()); +} void Sora::RenderCallbackStatic(int event_id) { auto sora = (Sora*)IdPointer::Instance().Lookup(event_id); @@ -838,16 +867,16 @@ void Sora::OnSetOffer(std::string offer) { on_set_offer_(offer); } }); - std::string stream_id = rtc::CreateRandomString(16); + stream_id_ = rtc::CreateRandomString(16); if (audio_track_ != nullptr) { webrtc::RTCErrorOr> audio_result = signaling_->GetPeerConnection()->AddTrack(audio_track_, - {stream_id}); + {stream_id_}); } if (video_track_ != nullptr) { webrtc::RTCErrorOr> video_result = signaling_->GetPeerConnection()->AddTrack(video_track_, - {stream_id}); + {stream_id_}); video_sender_ = video_result.value(); } diff --git a/src/sora.h b/src/sora.h index 3b6d485..7a72db8 100644 --- a/src/sora.h +++ b/src/sora.h @@ -92,7 +92,9 @@ class Sora : public std::enable_shared_from_this, private: void DoConnect(const sora_conf::internal::ConnectConfig& config, std::function on_disconnect); - void DoSwitchCamera(const sora_conf::internal::CameraConfig& cc); + void DoSwitchCamera( + const sora_conf::internal::CameraConfig& cc, + rtc::scoped_refptr video_track); static rtc::scoped_refptr CreateADM( webrtc::TaskQueueFactory* task_queue_factory, @@ -168,6 +170,8 @@ class Sora : public std::enable_shared_from_this, std::map connection_ids_; + std::string stream_id_; + rtc::scoped_refptr capturer_; int capturer_type_ = 0; std::shared_ptr capturer_sink_;