diff --git a/common/cpp/include/flutter_media_stream.h b/common/cpp/include/flutter_media_stream.h index 49f0fa8c20..17da12e346 100644 --- a/common/cpp/include/flutter_media_stream.h +++ b/common/cpp/include/flutter_media_stream.h @@ -44,6 +44,9 @@ class FlutterMediaStream { void MediaStreamTrackDispose(const std::string& track_id, std::unique_ptr result); + void MediaStreamTrackClone(const std::string& track_id, + std::unique_ptr result); + void CreateLocalMediaStream(std::unique_ptr result); void OnDeviceChange(); diff --git a/common/cpp/include/flutter_webrtc_base.h b/common/cpp/include/flutter_webrtc_base.h index f0dd23b5a2..a6fb2ccfbe 100644 --- a/common/cpp/include/flutter_webrtc_base.h +++ b/common/cpp/include/flutter_webrtc_base.h @@ -119,6 +119,8 @@ class FlutterWebRTCBase { data_channel_observers_; std::map> peerconnection_observers_; + std::map> video_sources_; + std::map> audio_sources_; mutable std::mutex mutex_; void lock() { mutex_.lock(); } diff --git a/common/cpp/src/flutter_media_stream.cc b/common/cpp/src/flutter_media_stream.cc index 627c2e5151..606ba66633 100644 --- a/common/cpp/src/flutter_media_stream.cc +++ b/common/cpp/src/flutter_media_stream.cc @@ -181,6 +181,7 @@ void FlutterMediaStream::GetUserAudio(const EncodableMap& constraints, params[EncodableValue("audioTracks")] = EncodableValue(audioTracks); stream->AddTrack(track); + base_->audio_sources_[track->id().std_string()] = source; base_->local_tracks_[track->id().std_string()] = track; } } @@ -319,6 +320,7 @@ void FlutterMediaStream::GetUserVideo(const EncodableMap& constraints, stream->AddTrack(track); + base_->video_sources_[track->id().std_string()] = source; base_->local_tracks_[track->id().std_string()] = track; base_->video_capturers_[track->id().std_string()] = video_capturer; } @@ -483,12 +485,14 @@ void FlutterMediaStream::MediaStreamDispose( for (auto track : audio_tracks.std_vector()) { stream->RemoveTrack(track); base_->local_tracks_.erase(track->id().std_string()); + base_->audio_sources_.erase(track->id().std_string()); } vector> video_tracks = stream->video_tracks(); for (auto track : video_tracks.std_vector()) { stream->RemoveTrack(track); base_->local_tracks_.erase(track->id().std_string()); + base_->video_sources_.erase(track->id().std_string()); if (base_->video_capturers_.find(track->id().std_string()) != base_->video_capturers_.end()) { auto video_capture = base_->video_capturers_[track->id().std_string()]; @@ -558,4 +562,55 @@ void FlutterMediaStream::MediaStreamTrackDispose( base_->RemoveMediaTrackForId(track_id); result->Success(); } + +void FlutterMediaStream::MediaStreamTrackClone( + const std::string& track_id, + std::unique_ptr result) { + + std::string new_track_id = base_->GenerateUUID(); + + EncodableMap track_params; + + for (auto it : base_->local_streams_) { + auto stream = it.second; + auto audio_tracks = stream->audio_tracks(); + for (auto original_audio_track : audio_tracks.std_vector()) { + if (original_audio_track->id().std_string() == track_id) { + // clone audio track + auto audio_source = base_->audio_sources_[track_id]; + scoped_refptr track = + base_->factory_->CreateAudioTrack(audio_source, new_track_id); + base_->audio_sources_[track->id().std_string()] = audio_source; + + track_params[EncodableValue("readyState")] = "live"; + track_params[EncodableValue("kind")] = + EncodableValue(track->kind().std_string()); + track_params[EncodableValue("enabled")] = + EncodableValue(track->enabled()); + } + } + auto video_tracks = stream->video_tracks(); + for (auto original_video_track : video_tracks.std_vector()) { + if (original_video_track->id().std_string() == track_id) { + // clone video track + auto video_source = base_->video_sources_[track_id]; + //TODO copy surface texture + scoped_refptr track = + base_->factory_->CreateVideoTrack(video_source, new_track_id); + base_->video_sources_[track->id().std_string()] = video_source; + + track_params[EncodableValue("readyState")] = "live"; + track_params[EncodableValue("kind")] = + EncodableValue(track->kind().std_string()); + track_params[EncodableValue("enabled")] = + EncodableValue(track->enabled()); + } + } + } + track_params[EncodableValue("id")] = EncodableValue(new_track_id); + track_params[EncodableValue("label")] = EncodableValue(new_track_id); + track_params[EncodableValue("remote")] = EncodableValue(false); + + result->Success(EncodableValue(track_params)); + } } // namespace stream_webrtc_flutter_plugin diff --git a/common/cpp/src/flutter_webrtc.cc b/common/cpp/src/flutter_webrtc.cc index 6b47b3fc71..015d485d74 100644 --- a/common/cpp/src/flutter_webrtc.cc +++ b/common/cpp/src/flutter_webrtc.cc @@ -432,6 +432,15 @@ void FlutterWebRTC::HandleMethodCall( GetValue(*method_call.arguments()); const std::string track_id = findString(params, "trackId"); MediaStreamTrackDispose(track_id, std::move(result)); + } else if (method_call.method_name().compare("trackClone") == 0) { + if (!method_call.arguments()) { + result->Error("Bad Arguments", "Null constraints arguments received"); + return; + } + const EncodableMap params = + GetValue(*method_call.arguments()); + const std::string track_id = findString(params, "trackId"); + MediaStreamTrackClone(track_id, std::move(result)); } else if (method_call.method_name().compare("restartIce") == 0) { if (!method_call.arguments()) { result->Error("Bad Arguments", "Null constraints arguments received"); diff --git a/windows/CMakeLists.txt b/windows/CMakeLists.txt index a3b9280ae5..a17637b286 100644 --- a/windows/CMakeLists.txt +++ b/windows/CMakeLists.txt @@ -47,7 +47,7 @@ target_link_libraries(${PLUGIN_NAME} PRIVATE ) # List of absolute paths to libraries that should be bundled with the plugin -set(flutter_webrtc_bundled_libraries +set(stream_webrtc_flutter_bundled_libraries "${CMAKE_CURRENT_SOURCE_DIR}/../third_party/libwebrtc/lib/win64/libwebrtc.dll" PARENT_SCOPE )