diff --git a/patches/DirectXShaderCompiler/.patches b/patches/DirectXShaderCompiler/.patches new file mode 100644 index 0000000000000..d75547d9cdf4e --- /dev/null +++ b/patches/DirectXShaderCompiler/.patches @@ -0,0 +1,2 @@ +fix_hlmatrixlowerpass_leaving_call_to_dangling_functionval.patch +cherry-pick-a65e511a14b4.patch diff --git a/patches/DirectXShaderCompiler/cherry-pick-a65e511a14b4.patch b/patches/DirectXShaderCompiler/cherry-pick-a65e511a14b4.patch new file mode 100644 index 0000000000000..232ecbc60f30d --- /dev/null +++ b/patches/DirectXShaderCompiler/cherry-pick-a65e511a14b4.patch @@ -0,0 +1,66 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Antonio Maiorano +Date: Wed, 3 Apr 2024 15:58:51 -0400 +Subject: Fix ASAN use-after-free on unreferenced self-assignment of struct + instance (#6466) + +When deleting an unused memcpy, ScalarReplAggregatesHLSL was attempting +to delete both the target and the source of the memcpy without first +checking if they were both same, resulting in a double-delete. + +Bug: chromium:331123811 +Change-Id: Idaef95a06b10a7fb6f0ca2e662972a44ec662fbc +Reviewed-on: https://chromium-review.googlesource.com/c/external/github.com/microsoft/DirectXShaderCompiler/+/5419225 +Reviewed-by: David Neto +Reviewed-by: dan sinclair +Reviewed-by: Ben Clayton + +diff --git a/lib/Transforms/Scalar/ScalarReplAggregatesHLSL.cpp b/lib/Transforms/Scalar/ScalarReplAggregatesHLSL.cpp +index b3589884aa3b690e1aad5ca7a19218a222591d39..8e2eff7f69ec378393c7a9afc4040cd9e921c42d 100644 +--- a/lib/Transforms/Scalar/ScalarReplAggregatesHLSL.cpp ++++ b/lib/Transforms/Scalar/ScalarReplAggregatesHLSL.cpp +@@ -989,9 +989,11 @@ void DeleteMemcpy(MemCpyInst *MI) { + if (op0->user_empty()) + op0->eraseFromParent(); + } +- if (Instruction *op1 = dyn_cast(Op1)) { +- if (op1->user_empty()) +- op1->eraseFromParent(); ++ if (Op0 != Op1) { ++ if (Instruction *op1 = dyn_cast(Op1)) { ++ if (op1->user_empty()) ++ op1->eraseFromParent(); ++ } + } + } + +diff --git a/tools/clang/test/DXC/unreferenced_struct_selft_assignment_crash.hlsl b/tools/clang/test/DXC/unreferenced_struct_selft_assignment_crash.hlsl +new file mode 100644 +index 0000000000000000000000000000000000000000..81adf71867c9868992372e12dc1ba81aebb48344 +--- /dev/null ++++ b/tools/clang/test/DXC/unreferenced_struct_selft_assignment_crash.hlsl +@@ -0,0 +1,24 @@ ++// RUN: %dxc -T cs_6_0 %s | FileCheck %s ++ ++// Validate that self-assignment of a static struct instance that is not ++// referenced does not crash the compiler. This was resulting in an ASAN ++// use-after-free in ScalarReplAggregatesHLSL because DeleteMemcpy would ++// attempt to delete both source and target, even if both were the same. ++// CHECK: define void @main() { ++// CHECK-NEXT: ret void ++// CHECK-NEXT: } ++ ++struct MyStruct { ++ int m0; ++}; ++ ++static MyStruct s; ++ ++void foo() { ++ s = s; ++} ++ ++[numthreads(1, 1, 1)] ++void main() { ++ foo(); ++} diff --git a/patches/dxc/fix_hlmatrixlowerpass_leaving_call_to_dangling_functionval.patch b/patches/DirectXShaderCompiler/fix_hlmatrixlowerpass_leaving_call_to_dangling_functionval.patch similarity index 100% rename from patches/dxc/fix_hlmatrixlowerpass_leaving_call_to_dangling_functionval.patch rename to patches/DirectXShaderCompiler/fix_hlmatrixlowerpass_leaving_call_to_dangling_functionval.patch diff --git a/patches/angle/.patches b/patches/angle/.patches index 9b0cc39feb206..18d747a9ead9f 100644 --- a/patches/angle/.patches +++ b/patches/angle/.patches @@ -3,3 +3,6 @@ m120_translator_fail_compilation_if_too_many_struct_fields.patch m120_translator_limit_private_variable_size_to_64kb.patch m120_vulkan_don_t_crash_when_glcopyteximage2d_redefines_itself.patch m123_vulkan_fix_access_to_inactive_attributes.patch +cherry-pick-f6672dbbe223.patch +m119_move_invalid_uniform_protection_to_the_frontend.patch +m120_fix_off-by-one_bounds_check_on_uniform_location.patch diff --git a/patches/angle/cherry-pick-f6672dbbe223.patch b/patches/angle/cherry-pick-f6672dbbe223.patch new file mode 100644 index 0000000000000..6b8212f330fdf --- /dev/null +++ b/patches/angle/cherry-pick-f6672dbbe223.patch @@ -0,0 +1,267 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Shahbaz Youssefi +Date: Mon, 25 Mar 2024 14:46:56 -0400 +Subject: M123: Translator: Disallow samplers in structs in interface blocks + +As disallowed by the spec: + +> Types and declarators are the same as for other uniform variable +> declarations outside blocks, with these exceptions: +> +> * opaque types are not allowed + +Bug: chromium:328859176 +Change-Id: Ib94977860102329e520e635c3757827c93ca2163 +Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/5391986 +Auto-Submit: Shahbaz Youssefi +Reviewed-by: Geoff Lang +Commit-Queue: Shahbaz Youssefi +(cherry picked from commit a0fa06f6d79ced897c0fe2795551268199d29806) +Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/5435737 +Reviewed-by: Yuly Novikov + +diff --git a/src/compiler/translator/ParseContext.cpp b/src/compiler/translator/ParseContext.cpp +index e174725beb764407185e471a9916ffd164493cd8..cb9eb3a4a566348f11aa5962037164147bc65684 100644 +--- a/src/compiler/translator/ParseContext.cpp ++++ b/src/compiler/translator/ParseContext.cpp +@@ -34,27 +34,39 @@ namespace + + const int kWebGLMaxStructNesting = 4; + +-bool ContainsSampler(const TStructure *structType); ++struct IsSamplerFunc ++{ ++ bool operator()(TBasicType type) { return IsSampler(type); } ++}; ++struct IsOpaqueFunc ++{ ++ bool operator()(TBasicType type) { return IsOpaqueType(type); } ++}; ++ ++template ++bool ContainsOpaque(const TStructure *structType); + +-bool ContainsSampler(const TType &type) ++template ++bool ContainsOpaque(const TType &type) + { +- if (IsSampler(type.getBasicType())) ++ if (OpaqueFunc{}(type.getBasicType())) + { + return true; + } + if (type.getBasicType() == EbtStruct) + { +- return ContainsSampler(type.getStruct()); ++ return ContainsOpaque(type.getStruct()); + } + + return false; + } + +-bool ContainsSampler(const TStructure *structType) ++template ++bool ContainsOpaque(const TStructure *structType) + { + for (const auto &field : structType->fields()) + { +- if (ContainsSampler(*field->type())) ++ if (ContainsOpaque(*field->type())) + return true; + } + return false; +@@ -1057,7 +1069,7 @@ bool TParseContext::checkIsNotOpaqueType(const TSourceLoc &line, + { + if (pType.type == EbtStruct) + { +- if (ContainsSampler(pType.userDef)) ++ if (ContainsOpaque(pType.userDef)) + { + std::stringstream reasonStream = sh::InitializeStream(); + reasonStream << reason << " (structure contains a sampler)"; +@@ -4923,12 +4935,9 @@ TIntermDeclaration *TParseContext::addInterfaceBlock( + { + TField *field = (*fieldList)[memberIndex]; + TType *fieldType = field->type(); +- if (IsOpaqueType(fieldType->getBasicType())) ++ if (ContainsOpaque(*fieldType)) + { +- std::string reason("unsupported type - "); +- reason += fieldType->getBasicString(); +- reason += " types are not allowed in interface blocks"; +- error(field->line(), reason.c_str(), fieldType->getBasicString()); ++ error(field->line(), "Opaque types are not allowed in interface blocks", blockName); + } + + const TQualifier qualifier = fieldType->getQualifier(); +diff --git a/src/tests/gl_tests/GLSLTest.cpp b/src/tests/gl_tests/GLSLTest.cpp +index f4b7ce6222ff4a29cb20b75bc102e2c8ae478189..8ac5b758b128ded933d727f7dccb0ce8f8eb338b 100644 +--- a/src/tests/gl_tests/GLSLTest.cpp ++++ b/src/tests/gl_tests/GLSLTest.cpp +@@ -6716,7 +6716,34 @@ void main() + gl_FragColor = vec4(f(us), 0, 0, 1); + })"; + +- CompileShader(GL_FRAGMENT_SHADER, kFS); ++ GLuint fs = CompileShader(GL_FRAGMENT_SHADER, kFS); ++ EXPECT_NE(fs, 0u); ++ ASSERT_GL_NO_ERROR(); ++} ++ ++// Test that structs with samplers are not allowed in interface blocks. This is forbidden per ++// GLES3: ++// ++// > Types and declarators are the same as for other uniform variable declarations outside blocks, ++// > with these exceptions: ++// > * opaque types are not allowed ++TEST_P(GLSLTest_ES3, StructWithSamplersDisallowedInInterfaceBlock) ++{ ++ const char kFS[] = R"(#version 300 es ++precision mediump float; ++struct S { sampler2D samp; bool b; }; ++ ++layout(std140) uniform Buffer { S s; } buffer; ++ ++out vec4 color; ++ ++void main() ++{ ++ color = texture(buffer.s.samp, vec2(0)); ++})"; ++ ++ GLuint fs = CompileShader(GL_FRAGMENT_SHADER, kFS); ++ EXPECT_EQ(fs, 0u); + ASSERT_GL_NO_ERROR(); + } + +@@ -18195,6 +18222,116 @@ void main() { + EXPECT_EQ(0u, shader); + } + ++// Same as TooManyFieldsInStruct, but with samplers in the struct. ++TEST_P(GLSLTest_ES3, TooManySamplerFieldsInStruct) ++{ ++ std::ostringstream fs; ++ fs << R"(#version 300 es ++precision highp float; ++struct TooManyFields ++{ ++)"; ++ for (uint32_t i = 0; i < (1 << 16); ++i) ++ { ++ fs << " sampler2D field" << i << ";\n"; ++ } ++ fs << R"(}; ++uniform TooManyFields s; ++out vec4 color; ++void main() { ++ color = texture(s.field0, vec2(0)); ++})"; ++ ++ GLuint shader = CompileShader(GL_FRAGMENT_SHADER, fs.str().c_str()); ++ EXPECT_EQ(0u, shader); ++} ++ ++// More complex variation of ManySamplerFieldsInStruct. This one compiles fine. ++TEST_P(GLSLTest_ES3, ManySamplerFieldsInStructComplex) ++{ ++ // D3D and OpenGL may be more restrictive about this many samplers. ++ ANGLE_SKIP_TEST_IF(IsD3D() || IsOpenGL()); ++ ++ std::ostringstream fs; ++ fs << R"(#version 300 es ++precision highp float; ++ ++struct X { ++ mediump sampler2D a[0xf00]; ++ mediump sampler2D b[0xf00]; ++ mediump sampler2D c[0xf000]; ++ mediump sampler2D d[0xf00]; ++}; ++ ++struct Y { ++ X s1; ++ mediump sampler2D a[0xf00]; ++ mediump sampler2D b[0xf000]; ++ mediump sampler2D c[0x14000]; ++}; ++ ++struct S { ++ Y s1; ++}; ++ ++struct structBuffer { S s; }; ++ ++uniform structBuffer b; ++ ++out vec4 color; ++void main() ++{ ++ color = texture(b.s.s1.s1.c[0], vec2(0)); ++})"; ++ ++ GLuint shader = CompileShader(GL_FRAGMENT_SHADER, fs.str().c_str()); ++ EXPECT_NE(0u, shader); ++} ++ ++// Make sure a large array of samplers works. ++TEST_P(GLSLTest, ManySamplers) ++{ ++ // D3D and OpenGL may be more restrictive about this many samplers. ++ ANGLE_SKIP_TEST_IF(IsD3D() || IsOpenGL()); ++ ++ std::ostringstream fs; ++ fs << R"(precision highp float; ++ ++uniform mediump sampler2D c[0x12000]; ++ ++void main() ++{ ++ gl_FragColor = texture2D(c[0], vec2(0)); ++})"; ++ ++ GLuint shader = CompileShader(GL_FRAGMENT_SHADER, fs.str().c_str()); ++ EXPECT_NE(0u, shader); ++} ++ ++// Make sure a large array of samplers works when declared in a struct. ++TEST_P(GLSLTest, ManySamplersInStruct) ++{ ++ // D3D and OpenGL may be more restrictive about this many samplers. ++ ANGLE_SKIP_TEST_IF(IsD3D() || IsOpenGL()); ++ ++ std::ostringstream fs; ++ fs << R"(precision highp float; ++ ++struct X { ++ mediump sampler2D c[0x12000]; ++}; ++ ++uniform X x; ++ ++void main() ++{ ++ gl_FragColor = texture2D(x.c[0], vec2(0)); ++})"; ++ ++ GLuint shader = CompileShader(GL_FRAGMENT_SHADER, fs.str().c_str()); ++ EXPECT_NE(0u, shader); ++} ++ + // Test that passing large arrays to functions are compiled correctly. Regression test for the + // SPIR-V generator that made a copy of the array to pass to the function, by decomposing and + // reconstructing it (in the absence of OpCopyLogical), but the reconstruction instruction has a +diff --git a/src/tests/gl_tests/PixelLocalStorageTest.cpp b/src/tests/gl_tests/PixelLocalStorageTest.cpp +index c49ba5741ad565ad9637fb2188a472ccbebc6284..126936271eb25eec601349a560fabc6f0f7d4b75 100644 +--- a/src/tests/gl_tests/PixelLocalStorageTest.cpp ++++ b/src/tests/gl_tests/PixelLocalStorageTest.cpp +@@ -5573,8 +5573,7 @@ TEST_P(PixelLocalStorageCompilerTest, Declarations) + EXPECT_FALSE(log.compileFragmentShader(kPLSInStruct)); + EXPECT_TRUE(log.has("ERROR: 0:5: 'pixelLocalANGLE' : disallowed type in struct")); + EXPECT_TRUE( +- log.has("ERROR: 0:10: 'pixelLocalANGLE' : unsupported type - pixelLocalANGLE types are not " +- "allowed in interface blocks")); ++ log.has("ERROR: 0:10: 'PLSBlock' : Opaque types are not allowed in interface blocks")); + + ASSERT_GL_NO_ERROR(); + } diff --git a/patches/angle/m119_move_invalid_uniform_protection_to_the_frontend.patch b/patches/angle/m119_move_invalid_uniform_protection_to_the_frontend.patch new file mode 100644 index 0000000000000..390084d7e036e --- /dev/null +++ b/patches/angle/m119_move_invalid_uniform_protection_to_the_frontend.patch @@ -0,0 +1,60 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Geoff Lang +Date: Tue, 17 Oct 2023 11:39:10 -0400 +Subject: M119: Move invalid uniform protection to the frontend. + +The frontend potentialy indexes into mUniformLocations with invalid +uniform locations while validation is disabled too. Move the validation +from the Metal backend to the frontend. + +Bug: chromium:1484878 +Change-Id: I92bc43aa28cfa26d601bb28f318860375f618608 +Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/4947652 +Reviewed-by: Shahbaz Youssefi +Commit-Queue: Shahbaz Youssefi +(cherry picked from commit e076d6cfd0e1d6948623bb344c5a38753b0c2b2e) +Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/4969232 +Reviewed-by: Kenneth Russell + +diff --git a/src/libANGLE/Program.cpp b/src/libANGLE/Program.cpp +index 5caab257c909d81ea40c8bdad6bca8ce5e9c72c7..5dc66027831b0d1ac1915faf0d32223d6a71cd1c 100644 +--- a/src/libANGLE/Program.cpp ++++ b/src/libANGLE/Program.cpp +@@ -2192,7 +2192,7 @@ GLuint Program::getUniformIndex(const std::string &name) const + + bool Program::shouldIgnoreUniform(UniformLocation location) const + { +- if (location.value == -1) ++ if (location.value < 0 || static_cast(location.value) >= mUniformLocations.size()) + { + return true; + } +diff --git a/src/libANGLE/renderer/metal/ProgramMtl.mm b/src/libANGLE/renderer/metal/ProgramMtl.mm +index 5b86c4a8e0fa00012460d2e14101494c1dc4fa82..c7b98020e47c2f881815685e122ecaa57dbc1ad9 100644 +--- a/src/libANGLE/renderer/metal/ProgramMtl.mm ++++ b/src/libANGLE/renderer/metal/ProgramMtl.mm +@@ -766,22 +766,10 @@ void operator()() override + ProgramExecutableMtl *executableMtl = getExecutable(); + + const std::vector &uniformLocations = mState.getUniformLocations(); +- if (location < 0 || static_cast(location) >= uniformLocations.size()) +- { +- ERR() << "Invalid uniform location " << location << ", expected [0, " +- << uniformLocations.size() << ")"; +- return; +- } +- const gl::VariableLocation &locationInfo = uniformLocations[location]; ++ const gl::VariableLocation &locationInfo = uniformLocations[location]; + + const std::vector &linkedUniforms = mState.getUniforms(); +- if (locationInfo.index >= linkedUniforms.size()) +- { +- ERR() << "Invalid uniform location index " << locationInfo.index << ", expected [0, " +- << linkedUniforms.size() << ")"; +- return; +- } +- const gl::LinkedUniform &linkedUniform = linkedUniforms[locationInfo.index]; ++ const gl::LinkedUniform &linkedUniform = linkedUniforms[locationInfo.index]; + + if (linkedUniform.isSampler()) + { diff --git a/patches/angle/m120_fix_off-by-one_bounds_check_on_uniform_location.patch b/patches/angle/m120_fix_off-by-one_bounds_check_on_uniform_location.patch new file mode 100644 index 0000000000000..148a7cb088a28 --- /dev/null +++ b/patches/angle/m120_fix_off-by-one_bounds_check_on_uniform_location.patch @@ -0,0 +1,39 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Geoff Lang +Date: Wed, 22 Nov 2023 12:01:31 -0500 +Subject: M120: Fix off-by-one bounds check on uniform location. + +Log an error when the user provides an invalid uniform location. + +Bug: chromium:1504162 +Bug: chromium:1484878 +Change-Id: Ieb7eb964d508954ac8dfa8e4d9bd941778185223 +Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/5054238 +Commit-Queue: Geoff Lang +Reviewed-by: James Godfrey-Kittle +(cherry picked from commit fba482b7107ccf3e178f6bf56b6b0285407ace3a) +Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/5080772 +Reviewed-by: Shahbaz Youssefi + +diff --git a/src/libANGLE/Program.cpp b/src/libANGLE/Program.cpp +index 5dc66027831b0d1ac1915faf0d32223d6a71cd1c..d9e9582679b1e16e122c7e7b0a699e23cf45ae46 100644 +--- a/src/libANGLE/Program.cpp ++++ b/src/libANGLE/Program.cpp +@@ -2192,13 +2192,15 @@ GLuint Program::getUniformIndex(const std::string &name) const + + bool Program::shouldIgnoreUniform(UniformLocation location) const + { +- if (location.value < 0 || static_cast(location.value) >= mUniformLocations.size()) ++ if (location.value < 0) + { + return true; + } + +- if (mState.mExecutable->mUniformLocations[static_cast(location.value)].ignored) ++ if (static_cast(location.value) >= mState.mExecutable->mUniformLocations.size()) + { ++ ERR() << "Invalid uniform location " << location.value << ", expected [0, " ++ << mState.mExecutable->mUniformLocations.size() << ")"; + return true; + } + diff --git a/patches/chromium/.patches b/patches/chromium/.patches index 8819b8c350eb0..c1a02ad349c71 100644 --- a/patches/chromium/.patches +++ b/patches/chromium/.patches @@ -163,3 +163,4 @@ update_crashpad_to_37afd37401253ebcebcf6e07ce15c8cfecb1a1cc.patch m122_webcodecs_disable_async_videoframe_readback_to_mitigate_a.patch fix_paintimage_deserialization_arbitrary-read_issue.patch reland_sensors_winrt_call_onreadingchangedcallback_via.patch +cherry-pick-1b1f34234346.patch diff --git a/patches/chromium/cherry-pick-1b1f34234346.patch b/patches/chromium/cherry-pick-1b1f34234346.patch new file mode 100644 index 0000000000000..74866f77cf5c7 --- /dev/null +++ b/patches/chromium/cherry-pick-1b1f34234346.patch @@ -0,0 +1,42 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: kylechar +Date: Tue, 9 Apr 2024 17:14:26 +0000 +Subject: Validate buffer length + +The BitmapInSharedMemory mojo traits were only validating row length and +not total buffer length. + +(cherry picked from commit 1a19ff70bd54847d818566bd7a1e7c384c419746) + +(cherry picked from commit f15315f1cb7897e208947a40d538aac693283d7f) + +Bug: 331237485 +Change-Id: Ia2318899c44e9e7ac72fc7183954e6ce2c702179 +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5396796 +Commit-Queue: Kyle Charbonneau +Cr-Original-Original-Commit-Position: refs/heads/main@{#1278417} +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5420432 +Commit-Queue: danakj +Cr-Original-Commit-Position: refs/branch-heads/6312@{#786} +Cr-Original-Branched-From: 6711dcdae48edaf98cbc6964f90fac85b7d9986e-refs/heads/main@{#1262506} +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5433678 +Reviewed-by: danakj +Reviewed-by: Kyle Charbonneau +Cr-Commit-Position: refs/branch-heads/6099@{#2003} +Cr-Branched-From: e6ee4500f7d6549a9ac1354f8d056da49ef406be-refs/heads/main@{#1217362} + +diff --git a/services/viz/public/cpp/compositing/bitmap_in_shared_memory_mojom_traits.cc b/services/viz/public/cpp/compositing/bitmap_in_shared_memory_mojom_traits.cc +index a6e5f45d9e72b9ac48e536c3a7756966b3c263cf..519d554055e5182cdcbae44fafdac339a64a923b 100644 +--- a/services/viz/public/cpp/compositing/bitmap_in_shared_memory_mojom_traits.cc ++++ b/services/viz/public/cpp/compositing/bitmap_in_shared_memory_mojom_traits.cc +@@ -76,6 +76,10 @@ bool StructTraits::Read( + if (!mapping_ptr->IsValid()) + return false; + ++ if (mapping_ptr->size() < image_info.computeByteSize(data.row_bytes())) { ++ return false; ++ } ++ + if (!sk_bitmap->installPixels(image_info, mapping_ptr->memory(), + data.row_bytes(), &DeleteSharedMemoryMapping, + mapping_ptr.get())) { diff --git a/patches/config.json b/patches/config.json index 7cfbe4b81c96b..a75f71d0a467c 100644 --- a/patches/config.json +++ b/patches/config.json @@ -15,5 +15,5 @@ { "patch_dir": "src/electron/patches/angle", "repo": "src/third_party/angle" }, { "patch_dir": "src/electron/patches/sqlite", "repo": "src/third_party/sqlite/src" }, { "patch_dir": "src/electron/patches/libvpx", "repo": "src/third_party/libvpx/source/libvpx" }, - { "patch_dir": "src/electron/patches/dxc", "repo": "src/third_party/dawn/third_party/dxc" } + { "patch_dir": "src/electron/patches/DirectXShaderCompiler", "repo": "src/third_party/dawn/third_party/dxc" } ] diff --git a/patches/v8/.patches b/patches/v8/.patches index 53858dc1dd124..b79c396eac4bc 100644 --- a/patches/v8/.patches +++ b/patches/v8/.patches @@ -11,3 +11,4 @@ merged_wasm_add_bounds_check_in_tier-up_of_wasm-to-js_wrapper.patch merged_parser_fix_home_object_proxy_to_work_off-thread.patch merged_wasm_check_for_type-definition_count_limit.patch merged_runtime_recreate_enum_cache_on_map_update_if_any_previous.patch +merged_wasm_check_the_cached_memory_for_growability.patch diff --git a/patches/v8/merged_wasm_check_the_cached_memory_for_growability.patch b/patches/v8/merged_wasm_check_the_cached_memory_for_growability.patch new file mode 100644 index 0000000000000..67cb1b3b7cf59 --- /dev/null +++ b/patches/v8/merged_wasm_check_the_cached_memory_for_growability.patch @@ -0,0 +1,49 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Clemens Backes +Date: Wed, 17 Jan 2024 09:41:46 +0000 +Subject: Merged: [wasm] Check the cached memory for growability + +Instead of always checking memory 0, do check if the actually cached +memory is growable. + +R=jkummerow@chromium.org + +(cherry picked from commit 1285ee44a9e5207a8c1302bfaa745ca06f0a90a8) +Bug: chromium:1518257 + +Change-Id: Ic415e281d85bb979f1fd27aa5e14a5fcc52ffbf1 +Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/5232161 +Reviewed-by: Jakob Kummerow +Commit-Queue: Clemens Backes +Cr-Commit-Position: refs/branch-heads/12.0@{#36} +Cr-Branched-From: ed7b4caf1fb8184ad9e24346c84424055d4d430a-refs/heads/12.0.267@{#1} +Cr-Branched-From: 210e75b19db4352c9b78dce0bae11c2dc3077df4-refs/heads/main@{#90651} + +diff --git a/src/wasm/graph-builder-interface.cc b/src/wasm/graph-builder-interface.cc +index 4cbd8a9032622382c15321c82409db6e3da3a511..2ed779148501c45db238e805eb3c4a8c7009bdc9 100644 +--- a/src/wasm/graph-builder-interface.cc ++++ b/src/wasm/graph-builder-interface.cc +@@ -265,17 +265,18 @@ class WasmGraphBuildingInterface { + } + } + +- // Load the instance cache entries into the Ssa Environment. ++ // Load the instance cache entries into the SSA Environment. + void LoadInstanceCacheIntoSsa(SsaEnv* ssa_env) { + builder_->InitInstanceCache(&ssa_env->instance_cache); + } + +- // Reload the instance cache entries into the Ssa Environment, if memory can ++ // Reload the instance cache entries into the SSA Environment, if memory can + // actually grow. + void ReloadInstanceCacheIntoSsa(SsaEnv* ssa_env, const WasmModule* module) { +- if (module->memories.empty()) return; +- const WasmMemory* memory0 = &module->memories[0]; +- if (memory0->initial_pages == memory0->maximum_pages) return; ++ if (!builder_->has_cached_memory()) return; ++ const WasmMemory* cached_memory = ++ &module->memories[builder_->cached_memory_index()]; ++ if (cached_memory->initial_pages == cached_memory->maximum_pages) return; + LoadInstanceCacheIntoSsa(ssa_env); + } + diff --git a/patches/webrtc/.patches b/patches/webrtc/.patches index e7b348709c85f..01784b3e9b323 100644 --- a/patches/webrtc/.patches +++ b/patches/webrtc/.patches @@ -3,3 +3,5 @@ fix_mark_pipewire_capturer_as_failed_after_session_is_closed.patch fix_check_pipewire_init_before_creating_generic_capturer.patch pipewire_capturer_make_restore_tokens_re-usable_more_than_one_time.patch tighten_som_dchecks_to_checks_in_vp9_packetization.patch +m122_merge_limit_max_frame_size_in_dav1d_decoder.patch +revert_2_m120_jseptransportcontroller_remove_raw_pointers_to.patch diff --git a/patches/webrtc/m122_merge_limit_max_frame_size_in_dav1d_decoder.patch b/patches/webrtc/m122_merge_limit_max_frame_size_in_dav1d_decoder.patch new file mode 100644 index 0000000000000..4e7c3d4596325 --- /dev/null +++ b/patches/webrtc/m122_merge_limit_max_frame_size_in_dav1d_decoder.patch @@ -0,0 +1,35 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Sergey Silkin +Date: Wed, 21 Feb 2024 10:35:54 +0100 +Subject: Limit max frame size in DAV1D decoder +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +(cherry picked from commit 74a4038eaddcac773b9fc172ad446df6eb704b11) + +Bug: chromium:325284120 +Change-Id: Iea0aea0a17bb0b1f73b3c1cbd408b7a6cd2b216e +Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/340180 +Commit-Queue: Sergey Silkin +Reviewed-by: Erik Språng +Cr-Original-Commit-Position: refs/heads/main@{#41776} +Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/340580 +Reviewed-by: Philip Eliasson +Commit-Queue: Erik Språng +Cr-Commit-Position: refs/branch-heads/6261@{#1} +Cr-Branched-From: be2786cd2383b7ec5d158add166275d19e246763-refs/heads/main@{#41596} + +diff --git a/modules/video_coding/codecs/av1/dav1d_decoder.cc b/modules/video_coding/codecs/av1/dav1d_decoder.cc +index 3100c0d41bf429fa55984e07f137983d24ef58f8..77c360b9449ff784a15f0ba6e132fe8511d537ae 100644 +--- a/modules/video_coding/codecs/av1/dav1d_decoder.cc ++++ b/modules/video_coding/codecs/av1/dav1d_decoder.cc +@@ -87,6 +87,8 @@ bool Dav1dDecoder::Configure(const Settings& settings) { + s.n_threads = std::max(2, settings.number_of_cores()); + s.max_frame_delay = 1; // For low latency decoding. + s.all_layers = 0; // Don't output a frame for every spatial layer. ++ // Limit max frame size to avoid OOM'ing fuzzers. crbug.com/325284120. ++ s.frame_size_limit = 16384 * 16384; + s.operating_point = 31; // Decode all operating points. + + return dav1d_open(&context_, &s) == 0; diff --git a/patches/webrtc/revert_2_m120_jseptransportcontroller_remove_raw_pointers_to.patch b/patches/webrtc/revert_2_m120_jseptransportcontroller_remove_raw_pointers_to.patch new file mode 100644 index 0000000000000..39c5f866c6d5c --- /dev/null +++ b/patches/webrtc/revert_2_m120_jseptransportcontroller_remove_raw_pointers_to.patch @@ -0,0 +1,1580 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Tomas Gunnarsson +Date: Fri, 26 Jan 2024 12:01:53 +0000 +Subject: Revert^2 "[M120] JsepTransportController: Remove raw pointers to + description objects" + +This reverts commit bf2e30678e0e5b21f2a2d49180a13225fdcfaa1a. + +Reason for revert: Time to reland the fix for M120 now. + +Original change's description: +> Revert "[M120] JsepTransportController: Remove raw pointers to description objects" +> +> This reverts commit e79a99060f70a356b131d9f2f7497914984944d1. +> +> Reason for revert: Merged too early. Will re-land for the next spin. +> +> Original change's description: +> > [M120] JsepTransportController: Remove raw pointers to description objects +> > +> > Remove member variables that point to objects owned externally (in practice by SdpOfferAnswerHandler). The objects also live on the +> > signaling thread whereas JsepTransportController performs +> > operations on the network thread. Removing the raw pointers avoids +> > the risk of referencing the description objects after they've been +> > deleted or if the state is inconsistent across threads. +> > +> > (cherry picked from commit c56052001dd747ae37c0cf7bab604791fe7912b0) +> > +> > Bug: webrtc:1515832 +> > No-Try: true +> > Change-Id: I852b2a3993964be817f93c46b5bc4b03121cde86 +> > Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/334061 +> > Commit-Queue: Tomas Gunnarsson +> > Reviewed-by: Harald Alvestrand +> > Cr-Original-Commit-Position: refs/heads/main@{#41505} +> > Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/335180 +> > Reviewed-by: Mirko Bonadei +> > Cr-Commit-Position: refs/branch-heads/6099@{#2} +> > Cr-Branched-From: 507f1cc3270d0577f79882acbd78e63e66008f3d-refs/heads/main@{#41042} +> +> Change-Id: Id4bd21fbc8b7306de1aba0854815ada5c9333468 +> No-Try: true +> Bug: chromium:1515832 +> Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/335620 +> Bot-Commit: rubber-stamper@appspot.gserviceaccount.com +> Commit-Queue: Tomas Gunnarsson +> Reviewed-by: Mirko Bonadei +> Cr-Commit-Position: refs/branch-heads/6099@{#3} +> Cr-Branched-From: 507f1cc3270d0577f79882acbd78e63e66008f3d-refs/heads/main@{#41042} + +No-Try: true +Bug: chromium:1515832 +Change-Id: I13a24182908d7a616234d9c701bf7000a162df8e +Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/336282 +Commit-Queue: Tomas Gunnarsson +Bot-Commit: rubber-stamper@appspot.gserviceaccount.com +Reviewed-by: Mirko Bonadei +Cr-Commit-Position: refs/branch-heads/6099@{#4} +Cr-Branched-From: 507f1cc3270d0577f79882acbd78e63e66008f3d-refs/heads/main@{#41042} + +diff --git a/pc/jsep_transport_controller.cc b/pc/jsep_transport_controller.cc +index 792365b521c3a6bb40ff23be3dce0ec3db24dccb..251e28c4c0ab6055495fb76fd64f38677b94ec5a 100644 +--- a/pc/jsep_transport_controller.cc ++++ b/pc/jsep_transport_controller.cc +@@ -76,14 +76,18 @@ JsepTransportController::~JsepTransportController() { + + RTCError JsepTransportController::SetLocalDescription( + SdpType type, +- const cricket::SessionDescription* description) { ++ const cricket::SessionDescription* local_desc, ++ const cricket::SessionDescription* remote_desc) { ++ RTC_DCHECK(local_desc); + TRACE_EVENT0("webrtc", "JsepTransportController::SetLocalDescription"); ++ + if (!network_thread_->IsCurrent()) { + return network_thread_->BlockingCall( +- [=] { return SetLocalDescription(type, description); }); ++ [=] { return SetLocalDescription(type, local_desc, remote_desc); }); + } + + RTC_DCHECK_RUN_ON(network_thread_); ++ + if (!initial_offerer_.has_value()) { + initial_offerer_.emplace(type == SdpType::kOffer); + if (*initial_offerer_) { +@@ -92,20 +96,22 @@ RTCError JsepTransportController::SetLocalDescription( + SetIceRole_n(cricket::ICEROLE_CONTROLLED); + } + } +- return ApplyDescription_n(/*local=*/true, type, description); ++ return ApplyDescription_n(/*local=*/true, type, local_desc, remote_desc); + } + + RTCError JsepTransportController::SetRemoteDescription( + SdpType type, +- const cricket::SessionDescription* description) { ++ const cricket::SessionDescription* local_desc, ++ const cricket::SessionDescription* remote_desc) { ++ RTC_DCHECK(remote_desc); + TRACE_EVENT0("webrtc", "JsepTransportController::SetRemoteDescription"); + if (!network_thread_->IsCurrent()) { + return network_thread_->BlockingCall( +- [=] { return SetRemoteDescription(type, description); }); ++ [=] { return SetRemoteDescription(type, local_desc, remote_desc); }); + } + + RTC_DCHECK_RUN_ON(network_thread_); +- return ApplyDescription_n(/*local=*/false, type, description); ++ return ApplyDescription_n(/*local=*/false, type, local_desc, remote_desc); + } + + RtpTransportInternal* JsepTransportController::GetRtpTransport( +@@ -555,18 +561,20 @@ JsepTransportController::GetActiveDtlsTransports() { + RTCError JsepTransportController::ApplyDescription_n( + bool local, + SdpType type, +- const cricket::SessionDescription* description) { ++ const cricket::SessionDescription* local_desc, ++ const cricket::SessionDescription* remote_desc) { + TRACE_EVENT0("webrtc", "JsepTransportController::ApplyDescription_n"); +- RTC_DCHECK(description); + +- if (local) { +- local_desc_ = description; +- } else { +- remote_desc_ = description; +- } ++ // Stash away the description object that we'll be applying (since this ++ // function is used for both local and remote). ++ const cricket::SessionDescription* description = ++ local ? local_desc : remote_desc; ++ ++ RTC_DCHECK(description); + + RTCError error; +- error = ValidateAndMaybeUpdateBundleGroups(local, type, description); ++ error = ++ ValidateAndMaybeUpdateBundleGroups(local, type, local_desc, remote_desc); + if (!error.ok()) { + return error; + } +@@ -673,7 +681,11 @@ RTCError JsepTransportController::ApplyDescription_n( + RTCError JsepTransportController::ValidateAndMaybeUpdateBundleGroups( + bool local, + SdpType type, +- const cricket::SessionDescription* description) { ++ const cricket::SessionDescription* local_desc, ++ const cricket::SessionDescription* remote_desc) { ++ const cricket::SessionDescription* description = ++ local ? local_desc : remote_desc; ++ + RTC_DCHECK(description); + + std::vector new_bundle_groups = +@@ -739,72 +751,74 @@ RTCError JsepTransportController::ValidateAndMaybeUpdateBundleGroups( + } + } + } else if (type == SdpType::kAnswer) { +- std::vector offered_bundle_groups = +- local ? remote_desc_->GetGroupsByName(cricket::GROUP_TYPE_BUNDLE) +- : local_desc_->GetGroupsByName(cricket::GROUP_TYPE_BUNDLE); +- +- std::map +- offered_bundle_groups_by_mid; +- for (const cricket::ContentGroup* offered_bundle_group : +- offered_bundle_groups) { +- for (const std::string& content_name : +- offered_bundle_group->content_names()) { +- offered_bundle_groups_by_mid[content_name] = offered_bundle_group; ++ if ((local && remote_desc) || (!local && local_desc)) { ++ std::vector offered_bundle_groups = ++ local ? remote_desc->GetGroupsByName(cricket::GROUP_TYPE_BUNDLE) ++ : local_desc->GetGroupsByName(cricket::GROUP_TYPE_BUNDLE); ++ ++ std::map ++ offered_bundle_groups_by_mid; ++ for (const cricket::ContentGroup* offered_bundle_group : ++ offered_bundle_groups) { ++ for (const std::string& content_name : ++ offered_bundle_group->content_names()) { ++ offered_bundle_groups_by_mid[content_name] = offered_bundle_group; ++ } + } +- } + +- std::map +- new_bundle_groups_by_offered_bundle_groups; +- for (const cricket::ContentGroup* new_bundle_group : new_bundle_groups) { +- if (!new_bundle_group->FirstContentName()) { +- // Empty groups could be a subset of any group. +- continue; +- } +- // The group in the answer (new_bundle_group) must have a corresponding +- // group in the offer (original_group), because the answer groups may only +- // be subsets of the offer groups. +- auto it = offered_bundle_groups_by_mid.find( +- *new_bundle_group->FirstContentName()); +- if (it == offered_bundle_groups_by_mid.end()) { +- return RTCError(RTCErrorType::INVALID_PARAMETER, +- "A BUNDLE group was added in the answer that did not " +- "exist in the offer."); +- } +- const cricket::ContentGroup* offered_bundle_group = it->second; +- if (new_bundle_groups_by_offered_bundle_groups.find( +- offered_bundle_group) != +- new_bundle_groups_by_offered_bundle_groups.end()) { +- return RTCError(RTCErrorType::INVALID_PARAMETER, +- "A MID in the answer has changed group."); +- } +- new_bundle_groups_by_offered_bundle_groups.insert( +- std::make_pair(offered_bundle_group, new_bundle_group)); +- for (const std::string& content_name : +- new_bundle_group->content_names()) { +- it = offered_bundle_groups_by_mid.find(content_name); +- // The BUNDLE group in answer should be a subset of offered group. +- if (it == offered_bundle_groups_by_mid.end() || +- it->second != offered_bundle_group) { ++ std::map ++ new_bundle_groups_by_offered_bundle_groups; ++ for (const cricket::ContentGroup* new_bundle_group : new_bundle_groups) { ++ if (!new_bundle_group->FirstContentName()) { ++ // Empty groups could be a subset of any group. ++ continue; ++ } ++ // The group in the answer (new_bundle_group) must have a corresponding ++ // group in the offer (original_group), because the answer groups may ++ // only be subsets of the offer groups. ++ auto it = offered_bundle_groups_by_mid.find( ++ *new_bundle_group->FirstContentName()); ++ if (it == offered_bundle_groups_by_mid.end()) { + return RTCError(RTCErrorType::INVALID_PARAMETER, +- "A BUNDLE group in answer contains a MID='" + +- content_name + +- "' that was not in the offered group."); ++ "A BUNDLE group was added in the answer that did not " ++ "exist in the offer."); + } +- } +- } +- +- for (const auto& bundle_group : bundles_.bundle_groups()) { +- for (const std::string& content_name : bundle_group->content_names()) { +- // An answer that removes m= sections from pre-negotiated BUNDLE group +- // without rejecting it, is invalid. +- auto it = new_bundle_groups_by_mid.find(content_name); +- if (it == new_bundle_groups_by_mid.end()) { +- auto* content_info = description->GetContentByName(content_name); +- if (!content_info || !content_info->rejected) { ++ const cricket::ContentGroup* offered_bundle_group = it->second; ++ if (new_bundle_groups_by_offered_bundle_groups.find( ++ offered_bundle_group) != ++ new_bundle_groups_by_offered_bundle_groups.end()) { ++ return RTCError(RTCErrorType::INVALID_PARAMETER, ++ "A MID in the answer has changed group."); ++ } ++ new_bundle_groups_by_offered_bundle_groups.insert( ++ std::make_pair(offered_bundle_group, new_bundle_group)); ++ for (const std::string& content_name : ++ new_bundle_group->content_names()) { ++ it = offered_bundle_groups_by_mid.find(content_name); ++ // The BUNDLE group in answer should be a subset of offered group. ++ if (it == offered_bundle_groups_by_mid.end() || ++ it->second != offered_bundle_group) { + return RTCError(RTCErrorType::INVALID_PARAMETER, +- "Answer cannot remove m= section with mid='" + ++ "A BUNDLE group in answer contains a MID='" + + content_name + +- "' from already-established BUNDLE group."); ++ "' that was not in the offered group."); ++ } ++ } ++ } ++ ++ for (const auto& bundle_group : bundles_.bundle_groups()) { ++ for (const std::string& content_name : bundle_group->content_names()) { ++ // An answer that removes m= sections from pre-negotiated BUNDLE group ++ // without rejecting it, is invalid. ++ auto it = new_bundle_groups_by_mid.find(content_name); ++ if (it == new_bundle_groups_by_mid.end()) { ++ auto* content_info = description->GetContentByName(content_name); ++ if (!content_info || !content_info->rejected) { ++ return RTCError(RTCErrorType::INVALID_PARAMETER, ++ "Answer cannot remove m= section with mid='" + ++ content_name + ++ "' from already-established BUNDLE group."); ++ } + } + } + } +diff --git a/pc/jsep_transport_controller.h b/pc/jsep_transport_controller.h +index 5880e346cdd4a2d0290ea68bb63ba0caa51b949a..8eae3a020346d84e7ab48d7e6226e07872ba79a1 100644 +--- a/pc/jsep_transport_controller.h ++++ b/pc/jsep_transport_controller.h +@@ -161,11 +161,24 @@ class JsepTransportController : public sigslot::has_slots<> { + // level, creating/destroying transport objects as needed and updating their + // properties. This includes RTP, DTLS, and ICE (but not SCTP). At least not + // yet? May make sense to in the future. ++ // ++ // `local_desc` must always be valid. If a remote description has previously ++ // been set via a call to `SetRemoteDescription()` then `remote_desc` should ++ // point to that description object in order to keep the current local and ++ // remote session descriptions in sync. + RTCError SetLocalDescription(SdpType type, +- const cricket::SessionDescription* description); +- ++ const cricket::SessionDescription* local_desc, ++ const cricket::SessionDescription* remote_desc); ++ ++ // Call to apply a remote description (See `SetLocalDescription()` for local). ++ // ++ // `remote_desc` must always be valid. If a local description has previously ++ // been set via a call to `SetLocalDescription()` then `local_desc` should ++ // point to that description object in order to keep the current local and ++ // remote session descriptions in sync. + RTCError SetRemoteDescription(SdpType type, +- const cricket::SessionDescription* description); ++ const cricket::SessionDescription* local_desc, ++ const cricket::SessionDescription* remote_desc); + + // Get transports to be used for the provided `mid`. If bundling is enabled, + // calling GetRtpTransport for multiple MIDs may yield the same object. +@@ -325,14 +338,23 @@ class JsepTransportController : public sigslot::has_slots<> { + CallbackList + signal_ice_candidate_pair_changed_ RTC_GUARDED_BY(network_thread_); + ++ // Called from SetLocalDescription and SetRemoteDescription. ++ // When `local` is true, local_desc must be valid. Similarly when ++ // `local` is false, remote_desc must be valid. The description counterpart ++ // to the one that's being applied, may be nullptr but when it's supplied ++ // the counterpart description's content groups will be kept up to date for ++ // `type == SdpType::kAnswer`. + RTCError ApplyDescription_n(bool local, + SdpType type, +- const cricket::SessionDescription* description) ++ const cricket::SessionDescription* local_desc, ++ const cricket::SessionDescription* remote_desc) + RTC_RUN_ON(network_thread_); + RTCError ValidateAndMaybeUpdateBundleGroups( + bool local, + SdpType type, +- const cricket::SessionDescription* description); ++ const cricket::SessionDescription* local_desc, ++ const cricket::SessionDescription* remote_desc) ++ RTC_RUN_ON(network_thread_); + RTCError ValidateContent(const cricket::ContentInfo& content_info); + + void HandleRejectedContent(const cricket::ContentInfo& content_info) +@@ -481,8 +503,6 @@ class JsepTransportController : public sigslot::has_slots<> { + const Config config_; + bool active_reset_srtp_params_ RTC_GUARDED_BY(network_thread_); + +- const cricket::SessionDescription* local_desc_ = nullptr; +- const cricket::SessionDescription* remote_desc_ = nullptr; + absl::optional initial_offerer_; + + cricket::IceConfig ice_config_; +diff --git a/pc/jsep_transport_controller_unittest.cc b/pc/jsep_transport_controller_unittest.cc +index faa8842e35f427a65632347ae42505fd49d87351..2a4e7875ee91e784fd7ab8f4d1aadd46975b3ec0 100644 +--- a/pc/jsep_transport_controller_unittest.cc ++++ b/pc/jsep_transport_controller_unittest.cc +@@ -265,9 +265,10 @@ class JsepTransportControllerTest : public JsepTransportController::Observer, + } + + auto description = CreateSessionDescriptionWithBundleGroup(); +- EXPECT_TRUE(transport_controller_ +- ->SetLocalDescription(SdpType::kOffer, description.get()) +- .ok()); ++ EXPECT_TRUE( ++ transport_controller_ ++ ->SetLocalDescription(SdpType::kOffer, description.get(), nullptr) ++ .ok()); + + transport_controller_->MaybeStartGathering(); + auto fake_audio_dtls = static_cast( +@@ -385,9 +386,10 @@ class JsepTransportControllerTest : public JsepTransportController::Observer, + TEST_F(JsepTransportControllerTest, GetRtpTransport) { + CreateJsepTransportController(JsepTransportController::Config()); + auto description = CreateSessionDescriptionWithoutBundle(); +- EXPECT_TRUE(transport_controller_ +- ->SetLocalDescription(SdpType::kOffer, description.get()) +- .ok()); ++ EXPECT_TRUE( ++ transport_controller_ ++ ->SetLocalDescription(SdpType::kOffer, description.get(), nullptr) ++ .ok()); + auto audio_rtp_transport = transport_controller_->GetRtpTransport(kAudioMid1); + auto video_rtp_transport = transport_controller_->GetRtpTransport(kVideoMid1); + EXPECT_NE(nullptr, audio_rtp_transport); +@@ -402,9 +404,10 @@ TEST_F(JsepTransportControllerTest, GetDtlsTransport) { + config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyNegotiate; + CreateJsepTransportController(std::move(config)); + auto description = CreateSessionDescriptionWithoutBundle(); +- EXPECT_TRUE(transport_controller_ +- ->SetLocalDescription(SdpType::kOffer, description.get()) +- .ok()); ++ EXPECT_TRUE( ++ transport_controller_ ++ ->SetLocalDescription(SdpType::kOffer, description.get(), nullptr) ++ .ok()); + EXPECT_NE(nullptr, transport_controller_->GetDtlsTransport(kAudioMid1)); + EXPECT_NE(nullptr, transport_controller_->GetRtcpDtlsTransport(kAudioMid1)); + EXPECT_NE(nullptr, +@@ -437,9 +440,10 @@ TEST_F(JsepTransportControllerTest, GetDtlsTransportWithRtcpMux) { + config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire; + CreateJsepTransportController(std::move(config)); + auto description = CreateSessionDescriptionWithoutBundle(); +- EXPECT_TRUE(transport_controller_ +- ->SetLocalDescription(SdpType::kOffer, description.get()) +- .ok()); ++ EXPECT_TRUE( ++ transport_controller_ ++ ->SetLocalDescription(SdpType::kOffer, description.get(), nullptr) ++ .ok()); + EXPECT_NE(nullptr, transport_controller_->GetDtlsTransport(kAudioMid1)); + EXPECT_EQ(nullptr, transport_controller_->GetRtcpDtlsTransport(kAudioMid1)); + EXPECT_NE(nullptr, transport_controller_->GetDtlsTransport(kVideoMid1)); +@@ -449,9 +453,10 @@ TEST_F(JsepTransportControllerTest, GetDtlsTransportWithRtcpMux) { + TEST_F(JsepTransportControllerTest, SetIceConfig) { + CreateJsepTransportController(JsepTransportController::Config()); + auto description = CreateSessionDescriptionWithoutBundle(); +- EXPECT_TRUE(transport_controller_ +- ->SetLocalDescription(SdpType::kOffer, description.get()) +- .ok()); ++ EXPECT_TRUE( ++ transport_controller_ ++ ->SetLocalDescription(SdpType::kOffer, description.get(), nullptr) ++ .ok()); + + transport_controller_->SetIceConfig( + CreateIceConfig(kTimeout, cricket::GATHER_CONTINUALLY)); +@@ -467,9 +472,10 @@ TEST_F(JsepTransportControllerTest, SetIceConfig) { + cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS, + nullptr); + +- EXPECT_TRUE(transport_controller_ +- ->SetLocalDescription(SdpType::kOffer, description.get()) +- .ok()); ++ EXPECT_TRUE( ++ transport_controller_ ++ ->SetLocalDescription(SdpType::kOffer, description.get(), nullptr) ++ .ok()); + fake_audio_dtls = static_cast( + transport_controller_->GetDtlsTransport(kAudioMid2)); + ASSERT_NE(nullptr, fake_audio_dtls); +@@ -482,11 +488,14 @@ TEST_F(JsepTransportControllerTest, SetIceConfig) { + TEST_F(JsepTransportControllerTest, NeedIceRestart) { + CreateJsepTransportController(JsepTransportController::Config()); + auto description = CreateSessionDescriptionWithoutBundle(); ++ EXPECT_TRUE( ++ transport_controller_ ++ ->SetLocalDescription(SdpType::kOffer, description.get(), nullptr) ++ .ok()); ++ // TODO(tommi): Note that _now_ we set `remote`. (was not set before). + EXPECT_TRUE(transport_controller_ +- ->SetLocalDescription(SdpType::kOffer, description.get()) +- .ok()); +- EXPECT_TRUE(transport_controller_ +- ->SetRemoteDescription(SdpType::kAnswer, description.get()) ++ ->SetRemoteDescription(SdpType::kAnswer, description.get(), ++ description.get()) + .ok()); + + // Initially NeedsIceRestart should return false. +@@ -505,7 +514,8 @@ TEST_F(JsepTransportControllerTest, NeedIceRestart) { + audio_transport_info->description.ice_ufrag = kIceUfrag2; + audio_transport_info->description.ice_pwd = kIcePwd2; + EXPECT_TRUE(transport_controller_ +- ->SetLocalDescription(SdpType::kOffer, description.get()) ++ ->SetLocalDescription(SdpType::kOffer, description.get(), ++ description.get()) + .ok()); + // Because the ICE is only restarted for audio, NeedsIceRestart is expected to + // return false for audio and true for video. +@@ -516,9 +526,10 @@ TEST_F(JsepTransportControllerTest, NeedIceRestart) { + TEST_F(JsepTransportControllerTest, MaybeStartGathering) { + CreateJsepTransportController(JsepTransportController::Config()); + auto description = CreateSessionDescriptionWithBundleGroup(); +- EXPECT_TRUE(transport_controller_ +- ->SetLocalDescription(SdpType::kOffer, description.get()) +- .ok()); ++ EXPECT_TRUE( ++ transport_controller_ ++ ->SetLocalDescription(SdpType::kOffer, description.get(), nullptr) ++ .ok()); + // After setting the local description, we should be able to start gathering + // candidates. + transport_controller_->MaybeStartGathering(); +@@ -529,10 +540,10 @@ TEST_F(JsepTransportControllerTest, MaybeStartGathering) { + TEST_F(JsepTransportControllerTest, AddRemoveRemoteCandidates) { + CreateJsepTransportController(JsepTransportController::Config()); + auto description = CreateSessionDescriptionWithoutBundle(); +- transport_controller_->SetLocalDescription(SdpType::kOffer, +- description.get()); +- transport_controller_->SetRemoteDescription(SdpType::kAnswer, +- description.get()); ++ transport_controller_->SetLocalDescription(SdpType::kOffer, description.get(), ++ nullptr); ++ transport_controller_->SetRemoteDescription( ++ SdpType::kAnswer, description.get(), description.get()); + auto fake_audio_dtls = static_cast( + transport_controller_->GetDtlsTransport(kAudioMid1)); + ASSERT_NE(nullptr, fake_audio_dtls); +@@ -565,9 +576,10 @@ TEST_F(JsepTransportControllerTest, SetAndGetLocalCertificate) { + // Apply the local certificate. + EXPECT_TRUE(transport_controller_->SetLocalCertificate(certificate1)); + // Apply the local description. +- EXPECT_TRUE(transport_controller_ +- ->SetLocalDescription(SdpType::kOffer, description.get()) +- .ok()); ++ EXPECT_TRUE( ++ transport_controller_ ++ ->SetLocalDescription(SdpType::kOffer, description.get(), nullptr) ++ .ok()); + returned_certificate = transport_controller_->GetLocalCertificate(kAudioMid1); + EXPECT_TRUE(returned_certificate); + EXPECT_EQ(certificate1->identity()->certificate().ToPEMString(), +@@ -586,9 +598,10 @@ TEST_F(JsepTransportControllerTest, SetAndGetLocalCertificate) { + TEST_F(JsepTransportControllerTest, GetRemoteSSLCertChain) { + CreateJsepTransportController(JsepTransportController::Config()); + auto description = CreateSessionDescriptionWithBundleGroup(); +- EXPECT_TRUE(transport_controller_ +- ->SetLocalDescription(SdpType::kOffer, description.get()) +- .ok()); ++ EXPECT_TRUE( ++ transport_controller_ ++ ->SetLocalDescription(SdpType::kOffer, description.get(), nullptr) ++ .ok()); + rtc::FakeSSLCertificate fake_certificate("fake_data"); + + auto fake_audio_dtls = static_cast( +@@ -622,16 +635,18 @@ TEST_F(JsepTransportControllerTest, GetDtlsRole) { + cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE, + answer_certificate); + +- EXPECT_TRUE(transport_controller_ +- ->SetLocalDescription(SdpType::kOffer, offer_desc.get()) +- .ok()); ++ EXPECT_TRUE( ++ transport_controller_ ++ ->SetLocalDescription(SdpType::kOffer, offer_desc.get(), nullptr) ++ .ok()); + + absl::optional role = + transport_controller_->GetDtlsRole(kAudioMid1); + // The DTLS role is not decided yet. + EXPECT_FALSE(role); + EXPECT_TRUE(transport_controller_ +- ->SetRemoteDescription(SdpType::kAnswer, answer_desc.get()) ++ ->SetRemoteDescription(SdpType::kAnswer, offer_desc.get(), ++ answer_desc.get()) + .ok()); + role = transport_controller_->GetDtlsRole(kAudioMid1); + +@@ -642,9 +657,10 @@ TEST_F(JsepTransportControllerTest, GetDtlsRole) { + TEST_F(JsepTransportControllerTest, GetStats) { + CreateJsepTransportController(JsepTransportController::Config()); + auto description = CreateSessionDescriptionWithBundleGroup(); +- EXPECT_TRUE(transport_controller_ +- ->SetLocalDescription(SdpType::kOffer, description.get()) +- .ok()); ++ EXPECT_TRUE( ++ transport_controller_ ++ ->SetLocalDescription(SdpType::kOffer, description.get(), nullptr) ++ .ok()); + + cricket::TransportStats stats; + EXPECT_TRUE(transport_controller_->GetStats(kAudioMid1, &stats)); +@@ -657,9 +673,10 @@ TEST_F(JsepTransportControllerTest, GetStats) { + TEST_F(JsepTransportControllerTest, SignalConnectionStateFailed) { + CreateJsepTransportController(JsepTransportController::Config()); + auto description = CreateSessionDescriptionWithoutBundle(); +- EXPECT_TRUE(transport_controller_ +- ->SetLocalDescription(SdpType::kOffer, description.get()) +- .ok()); ++ EXPECT_TRUE( ++ transport_controller_ ++ ->SetLocalDescription(SdpType::kOffer, description.get(), nullptr) ++ .ok()); + + auto fake_ice = static_cast( + transport_controller_->GetDtlsTransport(kAudioMid1)->ice_transport()); +@@ -681,9 +698,10 @@ TEST_F(JsepTransportControllerTest, + SignalConnectionStateConnectedNoMediaTransport) { + CreateJsepTransportController(JsepTransportController::Config()); + auto description = CreateSessionDescriptionWithoutBundle(); +- EXPECT_TRUE(transport_controller_ +- ->SetLocalDescription(SdpType::kOffer, description.get()) +- .ok()); ++ EXPECT_TRUE( ++ transport_controller_ ++ ->SetLocalDescription(SdpType::kOffer, description.get(), nullptr) ++ .ok()); + + auto fake_audio_dtls = static_cast( + transport_controller_->GetDtlsTransport(kAudioMid1)); +@@ -729,9 +747,10 @@ TEST_F(JsepTransportControllerTest, + TEST_F(JsepTransportControllerTest, SignalConnectionStateComplete) { + CreateJsepTransportController(JsepTransportController::Config()); + auto description = CreateSessionDescriptionWithoutBundle(); +- EXPECT_TRUE(transport_controller_ +- ->SetLocalDescription(SdpType::kOffer, description.get()) +- .ok()); ++ EXPECT_TRUE( ++ transport_controller_ ++ ->SetLocalDescription(SdpType::kOffer, description.get(), nullptr) ++ .ok()); + + auto fake_audio_dtls = static_cast( + transport_controller_->GetDtlsTransport(kAudioMid1)); +@@ -788,9 +807,10 @@ TEST_F(JsepTransportControllerTest, SignalConnectionStateComplete) { + TEST_F(JsepTransportControllerTest, SignalIceGatheringStateGathering) { + CreateJsepTransportController(JsepTransportController::Config()); + auto description = CreateSessionDescriptionWithoutBundle(); +- EXPECT_TRUE(transport_controller_ +- ->SetLocalDescription(SdpType::kOffer, description.get()) +- .ok()); ++ EXPECT_TRUE( ++ transport_controller_ ++ ->SetLocalDescription(SdpType::kOffer, description.get(), nullptr) ++ .ok()); + + auto fake_audio_dtls = static_cast( + transport_controller_->GetDtlsTransport(kAudioMid1)); +@@ -803,9 +823,10 @@ TEST_F(JsepTransportControllerTest, SignalIceGatheringStateGathering) { + TEST_F(JsepTransportControllerTest, SignalIceGatheringStateComplete) { + CreateJsepTransportController(JsepTransportController::Config()); + auto description = CreateSessionDescriptionWithoutBundle(); +- EXPECT_TRUE(transport_controller_ +- ->SetLocalDescription(SdpType::kOffer, description.get()) +- .ok()); ++ EXPECT_TRUE( ++ transport_controller_ ++ ->SetLocalDescription(SdpType::kOffer, description.get(), nullptr) ++ .ok()); + + auto fake_audio_dtls = static_cast( + transport_controller_->GetDtlsTransport(kAudioMid1)); +@@ -838,9 +859,10 @@ TEST_F(JsepTransportControllerTest, + SignalingWhenLastIncompleteTransportDestroyed) { + CreateJsepTransportController(JsepTransportController::Config()); + auto description = CreateSessionDescriptionWithBundleGroup(); +- EXPECT_TRUE(transport_controller_ +- ->SetLocalDescription(SdpType::kOffer, description.get()) +- .ok()); ++ EXPECT_TRUE( ++ transport_controller_ ++ ->SetLocalDescription(SdpType::kOffer, description.get(), nullptr) ++ .ok()); + + auto fake_audio_dtls = static_cast( + transport_controller_->GetDtlsTransport(kAudioMid1)); +@@ -861,7 +883,8 @@ TEST_F(JsepTransportControllerTest, + + // Set the remote description and enable the bundle. + EXPECT_TRUE(transport_controller_ +- ->SetRemoteDescription(SdpType::kAnswer, description.get()) ++ ->SetRemoteDescription(SdpType::kAnswer, description.get(), ++ description.get()) + .ok()); + // The BUNDLE should be enabled, the incomplete video transport should be + // deleted and the states should be updated. +@@ -887,11 +910,13 @@ TEST_F(JsepTransportControllerTest, + AddAudioSection(description.get(), kAudioMid1, kIceUfrag1, kIcePwd1, + cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS, + nullptr); ++ EXPECT_TRUE( ++ transport_controller_ ++ ->SetLocalDescription(SdpType::kOffer, description.get(), nullptr) ++ .ok()); + EXPECT_TRUE(transport_controller_ +- ->SetLocalDescription(SdpType::kOffer, description.get()) +- .ok()); +- EXPECT_TRUE(transport_controller_ +- ->SetRemoteDescription(SdpType::kAnswer, description.get()) ++ ->SetRemoteDescription(SdpType::kAnswer, description.get(), ++ description.get()) + .ok()); + + // Trigger and verify initial non-new states. +@@ -914,7 +939,8 @@ TEST_F(JsepTransportControllerTest, + // to "new". + description->contents()[0].rejected = true; + EXPECT_TRUE(transport_controller_ +- ->SetRemoteDescription(SdpType::kOffer, description.get()) ++ ->SetRemoteDescription(SdpType::kOffer, description.get(), ++ description.get()) + .ok()); + EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionNew, + ice_connection_state_, kTimeout); +@@ -941,9 +967,10 @@ TEST_F(JsepTransportControllerTest, + TEST_F(JsepTransportControllerTest, SignalCandidatesGathered) { + CreateJsepTransportController(JsepTransportController::Config()); + auto description = CreateSessionDescriptionWithBundleGroup(); +- EXPECT_TRUE(transport_controller_ +- ->SetLocalDescription(SdpType::kOffer, description.get()) +- .ok()); ++ EXPECT_TRUE( ++ transport_controller_ ++ ->SetLocalDescription(SdpType::kOffer, description.get(), nullptr) ++ .ok()); + transport_controller_->MaybeStartGathering(); + + auto fake_audio_dtls = static_cast( +@@ -998,11 +1025,13 @@ TEST_F(JsepTransportControllerTest, IceRoleNotRedetermined) { + cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE, + nullptr); + ++ EXPECT_TRUE( ++ transport_controller_ ++ ->SetRemoteDescription(SdpType::kOffer, nullptr, remote_offer.get()) ++ .ok()); + EXPECT_TRUE(transport_controller_ +- ->SetRemoteDescription(SdpType::kOffer, remote_offer.get()) +- .ok()); +- EXPECT_TRUE(transport_controller_ +- ->SetLocalDescription(SdpType::kAnswer, local_answer.get()) ++ ->SetLocalDescription(SdpType::kAnswer, local_answer.get(), ++ remote_offer.get()) + .ok()); + + auto fake_dtls = static_cast( +@@ -1015,10 +1044,11 @@ TEST_F(JsepTransportControllerTest, IceRoleNotRedetermined) { + AddAudioSection(restart_local_offer.get(), kAudioMid1, kIceUfrag3, kIcePwd3, + cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS, + nullptr); +- EXPECT_TRUE( +- transport_controller_ +- ->SetLocalDescription(SdpType::kOffer, restart_local_offer.get()) +- .ok()); ++ EXPECT_TRUE(transport_controller_ ++ ->SetLocalDescription(SdpType::kOffer, ++ restart_local_offer.get(), ++ remote_offer.get()) ++ .ok()); + EXPECT_EQ(cricket::ICEROLE_CONTROLLED, + fake_dtls->fake_ice_transport()->GetIceRole()); + } +@@ -1030,9 +1060,10 @@ TEST_F(JsepTransportControllerTest, SetIceRoleWhenIceLiteInRemoteAnswer) { + AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1, + cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS, + nullptr); +- EXPECT_TRUE(transport_controller_ +- ->SetLocalDescription(SdpType::kOffer, local_offer.get()) +- .ok()); ++ EXPECT_TRUE( ++ transport_controller_ ++ ->SetLocalDescription(SdpType::kOffer, local_offer.get(), nullptr) ++ .ok()); + auto fake_dtls = static_cast( + transport_controller_->GetDtlsTransport(kAudioMid1)); + EXPECT_EQ(cricket::ICEROLE_CONTROLLING, +@@ -1045,7 +1076,8 @@ TEST_F(JsepTransportControllerTest, SetIceRoleWhenIceLiteInRemoteAnswer) { + cricket::ICEMODE_LITE, cricket::CONNECTIONROLE_PASSIVE, + nullptr); + EXPECT_TRUE(transport_controller_ +- ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get()) ++ ->SetRemoteDescription(SdpType::kAnswer, local_offer.get(), ++ remote_answer.get()) + .ok()); + EXPECT_EQ(cricket::ICEROLE_CONTROLLING, + fake_dtls->fake_ice_transport()->GetIceRole()); +@@ -1069,11 +1101,13 @@ TEST_F(JsepTransportControllerTest, + nullptr); + // Initial Offer/Answer exchange. If the remote offerer is ICE-Lite, then the + // local side is the controlling. ++ EXPECT_TRUE( ++ transport_controller_ ++ ->SetRemoteDescription(SdpType::kOffer, nullptr, remote_offer.get()) ++ .ok()); + EXPECT_TRUE(transport_controller_ +- ->SetRemoteDescription(SdpType::kOffer, remote_offer.get()) +- .ok()); +- EXPECT_TRUE(transport_controller_ +- ->SetLocalDescription(SdpType::kAnswer, local_answer.get()) ++ ->SetLocalDescription(SdpType::kAnswer, local_answer.get(), ++ remote_offer.get()) + .ok()); + auto fake_dtls = static_cast( + transport_controller_->GetDtlsTransport(kAudioMid1)); +@@ -1085,15 +1119,17 @@ TEST_F(JsepTransportControllerTest, + AddAudioSection(remote_offer2.get(), kAudioMid1, kIceUfrag2, kIcePwd2, + cricket::ICEMODE_LITE, cricket::CONNECTIONROLE_ACTPASS, + nullptr); ++ EXPECT_TRUE(transport_controller_ ++ ->SetRemoteDescription(SdpType::kOffer, local_answer.get(), ++ remote_offer2.get()) ++ .ok()); + auto local_answer2 = std::make_unique(); + AddAudioSection(local_answer2.get(), kAudioMid1, kIceUfrag2, kIcePwd2, + cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE, + nullptr); + EXPECT_TRUE(transport_controller_ +- ->SetRemoteDescription(SdpType::kOffer, remote_offer2.get()) +- .ok()); +- EXPECT_TRUE(transport_controller_ +- ->SetLocalDescription(SdpType::kAnswer, local_answer2.get()) ++ ->SetLocalDescription(SdpType::kAnswer, local_answer2.get(), ++ remote_offer2.get()) + .ok()); + fake_dtls = static_cast( + transport_controller_->GetDtlsTransport(kAudioMid1)); +@@ -1145,11 +1181,13 @@ TEST_F(JsepTransportControllerTest, MultipleMediaSectionsOfSameTypeWithBundle) { + local_offer->AddGroup(bundle_group); + remote_answer->AddGroup(bundle_group); + ++ EXPECT_TRUE( ++ transport_controller_ ++ ->SetLocalDescription(SdpType::kOffer, local_offer.get(), nullptr) ++ .ok()); + EXPECT_TRUE(transport_controller_ +- ->SetLocalDescription(SdpType::kOffer, local_offer.get()) +- .ok()); +- EXPECT_TRUE(transport_controller_ +- ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get()) ++ ->SetRemoteDescription(SdpType::kAnswer, local_offer.get(), ++ remote_answer.get()) + .ok()); + // Verify that all the sections are bundled on kAudio1. + auto transport1 = transport_controller_->GetRtpTransport(kAudioMid1); +@@ -1224,11 +1262,13 @@ TEST_F(JsepTransportControllerTest, MultipleBundleGroups) { + remote_answer->AddGroup(bundle_group1); + remote_answer->AddGroup(bundle_group2); + ++ EXPECT_TRUE( ++ transport_controller_ ++ ->SetLocalDescription(SdpType::kOffer, local_offer.get(), nullptr) ++ .ok()); + EXPECT_TRUE(transport_controller_ +- ->SetLocalDescription(SdpType::kOffer, local_offer.get()) +- .ok()); +- EXPECT_TRUE(transport_controller_ +- ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get()) ++ ->SetRemoteDescription(SdpType::kAnswer, local_offer.get(), ++ remote_answer.get()) + .ok()); + + // Verify that (kMid1Audio,kMid2Video) and (kMid3Audio,kMid4Video) form two +@@ -1307,11 +1347,13 @@ TEST_F(JsepTransportControllerTest, + // endpoint that does not have support for multiple BUNDLE groups. + remote_answer->AddGroup(bundle_group1); + ++ EXPECT_TRUE( ++ transport_controller_ ++ ->SetLocalDescription(SdpType::kOffer, local_offer.get(), nullptr) ++ .ok()); + EXPECT_TRUE(transport_controller_ +- ->SetLocalDescription(SdpType::kOffer, local_offer.get()) +- .ok()); +- EXPECT_TRUE(transport_controller_ +- ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get()) ++ ->SetRemoteDescription(SdpType::kAnswer, local_offer.get(), ++ remote_answer.get()) + .ok()); + + // Verify that (kMid1Audio,kMid2Video) form a bundle group, but that +@@ -1382,12 +1424,14 @@ TEST_F(JsepTransportControllerTest, MultipleBundleGroupsIllegallyChangeGroup) { + remote_answer->AddGroup(answer_bundle_group2); + + // Accept offer. +- EXPECT_TRUE(transport_controller_ +- ->SetLocalDescription(SdpType::kOffer, local_offer.get()) +- .ok()); ++ EXPECT_TRUE( ++ transport_controller_ ++ ->SetLocalDescription(SdpType::kOffer, local_offer.get(), nullptr) ++ .ok()); + // Reject answer! + EXPECT_FALSE(transport_controller_ +- ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get()) ++ ->SetRemoteDescription(SdpType::kAnswer, local_offer.get(), ++ remote_answer.get()) + .ok()); + } + +@@ -1445,12 +1489,14 @@ TEST_F(JsepTransportControllerTest, MultipleBundleGroupsInvalidSubsets) { + remote_answer->AddGroup(answer_bundle_group2); + + // Accept offer. +- EXPECT_TRUE(transport_controller_ +- ->SetLocalDescription(SdpType::kOffer, local_offer.get()) +- .ok()); ++ EXPECT_TRUE( ++ transport_controller_ ++ ->SetLocalDescription(SdpType::kOffer, local_offer.get(), nullptr) ++ .ok()); + // Reject answer! + EXPECT_FALSE(transport_controller_ +- ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get()) ++ ->SetRemoteDescription(SdpType::kAnswer, local_offer.get(), ++ remote_answer.get()) + .ok()); + } + +@@ -1483,11 +1529,12 @@ TEST_F(JsepTransportControllerTest, MultipleBundleGroupsInvalidOverlap) { + offer->AddGroup(offer_bundle_group2); + + // Reject offer, both if set as local or remote. ++ EXPECT_FALSE(transport_controller_ ++ ->SetLocalDescription(SdpType::kOffer, offer.get(), nullptr) ++ .ok()); + EXPECT_FALSE( +- transport_controller_->SetLocalDescription(SdpType::kOffer, offer.get()) +- .ok()); +- EXPECT_FALSE( +- transport_controller_->SetRemoteDescription(SdpType::kOffer, offer.get()) ++ transport_controller_ ++ ->SetRemoteDescription(SdpType::kOffer, offer.get(), offer.get()) + .ok()); + } + +@@ -1563,11 +1610,13 @@ TEST_F(JsepTransportControllerTest, MultipleBundleGroupsUnbundleFirstMid) { + remote_answer->AddGroup(answer_bundle_group1); + remote_answer->AddGroup(answer_bundle_group2); + ++ EXPECT_TRUE( ++ transport_controller_ ++ ->SetLocalDescription(SdpType::kOffer, local_offer.get(), nullptr) ++ .ok()); + EXPECT_TRUE(transport_controller_ +- ->SetLocalDescription(SdpType::kOffer, local_offer.get()) +- .ok()); +- EXPECT_TRUE(transport_controller_ +- ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get()) ++ ->SetRemoteDescription(SdpType::kAnswer, local_offer.get(), ++ remote_answer.get()) + .ok()); + + auto mid1_transport = transport_controller_->GetRtpTransport(kMid1Audio); +@@ -1659,9 +1708,10 @@ TEST_F(JsepTransportControllerTest, MultipleBundleGroupsChangeFirstMid) { + remote_answer->AddGroup(answer_bundle_group1); + remote_answer->AddGroup(answer_bundle_group2); + +- EXPECT_TRUE(transport_controller_ +- ->SetLocalDescription(SdpType::kOffer, local_offer.get()) +- .ok()); ++ EXPECT_TRUE( ++ transport_controller_ ++ ->SetLocalDescription(SdpType::kOffer, local_offer.get(), nullptr) ++ .ok()); + + // The fact that we accept this answer is actually a bug. If we accept the + // first MID to be in the group, we should also accept that it is the tagged +@@ -1669,7 +1719,8 @@ TEST_F(JsepTransportControllerTest, MultipleBundleGroupsChangeFirstMid) { + // TODO(https://crbug.com/webrtc/12699): When this issue is fixed, change this + // to EXPECT_FALSE and remove the below expectations about transports. + EXPECT_TRUE(transport_controller_ +- ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get()) ++ ->SetRemoteDescription(SdpType::kAnswer, local_offer.get(), ++ remote_answer.get()) + .ok()); + auto mid1_transport = transport_controller_->GetRtpTransport(kMid1Audio); + auto mid2_transport = transport_controller_->GetRtpTransport(kMid2Audio); +@@ -1734,11 +1785,13 @@ TEST_F(JsepTransportControllerTest, + remote_answer->AddGroup(bundle_group1); + remote_answer->AddGroup(bundle_group2); + ++ EXPECT_TRUE( ++ transport_controller_ ++ ->SetLocalDescription(SdpType::kOffer, local_offer.get(), nullptr) ++ .ok()); + EXPECT_TRUE(transport_controller_ +- ->SetLocalDescription(SdpType::kOffer, local_offer.get()) +- .ok()); +- EXPECT_TRUE(transport_controller_ +- ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get()) ++ ->SetRemoteDescription(SdpType::kAnswer, local_offer.get(), ++ remote_answer.get()) + .ok()); + + // Add kMid3Audio and kMid6Video to the respective audio/video bundle groups. +@@ -1769,7 +1822,8 @@ TEST_F(JsepTransportControllerTest, + subsequent_offer->AddGroup(bundle_group1); + subsequent_offer->AddGroup(bundle_group2); + EXPECT_TRUE(transport_controller_ +- ->SetLocalDescription(SdpType::kOffer, subsequent_offer.get()) ++ ->SetLocalDescription(SdpType::kOffer, subsequent_offer.get(), ++ remote_answer.get()) + .ok()); + auto mid1_transport = transport_controller_->GetRtpTransport(kMid1Audio); + auto mid2_transport = transport_controller_->GetRtpTransport(kMid2Audio); +@@ -1832,11 +1886,13 @@ TEST_F(JsepTransportControllerTest, + remote_answer->AddGroup(bundle_group1); + remote_answer->AddGroup(bundle_group2); + ++ EXPECT_TRUE( ++ transport_controller_ ++ ->SetLocalDescription(SdpType::kOffer, local_offer.get(), nullptr) ++ .ok()); + EXPECT_TRUE(transport_controller_ +- ->SetLocalDescription(SdpType::kOffer, local_offer.get()) +- .ok()); +- EXPECT_TRUE(transport_controller_ +- ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get()) ++ ->SetRemoteDescription(SdpType::kAnswer, local_offer.get(), ++ remote_answer.get()) + .ok()); + + // Switch to grouping (kMid1Audio,kMid2Audio,kMid3Video,kMid4Video). +@@ -1861,10 +1917,11 @@ TEST_F(JsepTransportControllerTest, + cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS, + nullptr); + subsequent_offer->AddGroup(new_bundle_group); +- EXPECT_FALSE( +- transport_controller_ +- ->SetLocalDescription(SdpType::kOffer, subsequent_offer.get()) +- .ok()); ++ EXPECT_FALSE(transport_controller_ ++ ->SetLocalDescription(SdpType::kOffer, ++ subsequent_offer.get(), ++ remote_answer.get()) ++ .ok()); + } + + TEST_F(JsepTransportControllerTest, +@@ -1912,11 +1969,13 @@ TEST_F(JsepTransportControllerTest, + nullptr); + remote_answer->AddGroup(bundle_group); + ++ EXPECT_TRUE( ++ transport_controller_ ++ ->SetLocalDescription(SdpType::kOffer, local_offer.get(), nullptr) ++ .ok()); + EXPECT_TRUE(transport_controller_ +- ->SetLocalDescription(SdpType::kOffer, local_offer.get()) +- .ok()); +- EXPECT_TRUE(transport_controller_ +- ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get()) ++ ->SetRemoteDescription(SdpType::kAnswer, local_offer.get(), ++ remote_answer.get()) + .ok()); + + // Switch to grouping (kMid1Audio,kMid2Audio) and (kMid3Video,kMid4Video). +@@ -1943,10 +2002,11 @@ TEST_F(JsepTransportControllerTest, + nullptr); + subsequent_offer->AddGroup(new_bundle_group1); + subsequent_offer->AddGroup(new_bundle_group2); +- EXPECT_FALSE( +- transport_controller_ +- ->SetLocalDescription(SdpType::kOffer, subsequent_offer.get()) +- .ok()); ++ EXPECT_FALSE(transport_controller_ ++ ->SetLocalDescription(SdpType::kOffer, ++ subsequent_offer.get(), ++ remote_answer.get()) ++ .ok()); + } + + TEST_F(JsepTransportControllerTest, +@@ -1997,11 +2057,13 @@ TEST_F(JsepTransportControllerTest, + remote_answer->AddGroup(bundle_group1); + remote_answer->AddGroup(bundle_group2); + ++ EXPECT_TRUE( ++ transport_controller_ ++ ->SetLocalDescription(SdpType::kOffer, local_offer.get(), nullptr) ++ .ok()); + EXPECT_TRUE(transport_controller_ +- ->SetLocalDescription(SdpType::kOffer, local_offer.get()) +- .ok()); +- EXPECT_TRUE(transport_controller_ +- ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get()) ++ ->SetRemoteDescription(SdpType::kAnswer, local_offer.get(), ++ remote_answer.get()) + .ok()); + + // Switch to grouping (kMid1Audio,kMid3Video) and (kMid2Audio,kMid3Video). +@@ -2028,10 +2090,11 @@ TEST_F(JsepTransportControllerTest, + nullptr); + subsequent_offer->AddGroup(new_bundle_group1); + subsequent_offer->AddGroup(new_bundle_group2); +- EXPECT_FALSE( +- transport_controller_ +- ->SetLocalDescription(SdpType::kOffer, subsequent_offer.get()) +- .ok()); ++ EXPECT_FALSE(transport_controller_ ++ ->SetLocalDescription(SdpType::kOffer, ++ subsequent_offer.get(), ++ remote_answer.get()) ++ .ok()); + } + + // Tests that only a subset of all the m= sections are bundled. +@@ -2065,11 +2128,13 @@ TEST_F(JsepTransportControllerTest, BundleSubsetOfMediaSections) { + + local_offer->AddGroup(bundle_group); + remote_answer->AddGroup(bundle_group); ++ EXPECT_TRUE( ++ transport_controller_ ++ ->SetLocalDescription(SdpType::kOffer, local_offer.get(), nullptr) ++ .ok()); + EXPECT_TRUE(transport_controller_ +- ->SetLocalDescription(SdpType::kOffer, local_offer.get()) +- .ok()); +- EXPECT_TRUE(transport_controller_ +- ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get()) ++ ->SetRemoteDescription(SdpType::kAnswer, local_offer.get(), ++ remote_answer.get()) + .ok()); + + // Verifiy that only `kAudio1` and `kVideo1` are bundled. +@@ -2106,11 +2171,13 @@ TEST_F(JsepTransportControllerTest, BundleOnDataSectionInSubsequentOffer) { + local_offer->AddGroup(bundle_group); + remote_answer->AddGroup(bundle_group); + ++ EXPECT_TRUE( ++ transport_controller_ ++ ->SetLocalDescription(SdpType::kOffer, local_offer.get(), nullptr) ++ .ok()); + EXPECT_TRUE(transport_controller_ +- ->SetLocalDescription(SdpType::kOffer, local_offer.get()) +- .ok()); +- EXPECT_TRUE(transport_controller_ +- ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get()) ++ ->SetRemoteDescription(SdpType::kAnswer, local_offer.get(), ++ remote_answer.get()) + .ok()); + auto data_transport = transport_controller_->GetRtpTransport(kDataMid1); + +@@ -2132,15 +2199,17 @@ TEST_F(JsepTransportControllerTest, BundleOnDataSectionInSubsequentOffer) { + bundle_group.AddContentName(kAudioMid1); + bundle_group.AddContentName(kVideoMid1); + local_offer->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE); +- remote_answer->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE); + local_offer->AddGroup(bundle_group); +- remote_answer->AddGroup(bundle_group); + + EXPECT_TRUE(transport_controller_ +- ->SetLocalDescription(SdpType::kOffer, local_offer.get()) ++ ->SetLocalDescription(SdpType::kOffer, local_offer.get(), ++ remote_answer.get()) + .ok()); ++ remote_answer->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE); ++ remote_answer->AddGroup(bundle_group); + EXPECT_TRUE(transport_controller_ +- ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get()) ++ ->SetRemoteDescription(SdpType::kAnswer, local_offer.get(), ++ remote_answer.get()) + .ok()); + + auto audio_transport = transport_controller_->GetRtpTransport(kAudioMid1); +@@ -2186,11 +2255,13 @@ TEST_F(JsepTransportControllerTest, VideoDataRejectedInAnswer) { + local_offer->AddGroup(bundle_group); + remote_answer->AddGroup(bundle_group); + ++ EXPECT_TRUE( ++ transport_controller_ ++ ->SetLocalDescription(SdpType::kOffer, local_offer.get(), nullptr) ++ .ok()); + EXPECT_TRUE(transport_controller_ +- ->SetLocalDescription(SdpType::kOffer, local_offer.get()) +- .ok()); +- EXPECT_TRUE(transport_controller_ +- ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get()) ++ ->SetRemoteDescription(SdpType::kAnswer, local_offer.get(), ++ remote_answer.get()) + .ok()); + + // Verify the RtpTransport/DtlsTransport is destroyed correctly. +@@ -2233,11 +2304,13 @@ TEST_F(JsepTransportControllerTest, ChangeBundledMidNotSupported) { + + local_offer->AddGroup(bundle_group); + remote_answer->AddGroup(bundle_group); ++ EXPECT_TRUE( ++ transport_controller_ ++ ->SetLocalDescription(SdpType::kOffer, local_offer.get(), nullptr) ++ .ok()); + EXPECT_TRUE(transport_controller_ +- ->SetLocalDescription(SdpType::kOffer, local_offer.get()) +- .ok()); +- EXPECT_TRUE(transport_controller_ +- ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get()) ++ ->SetRemoteDescription(SdpType::kAnswer, local_offer.get(), ++ remote_answer.get()) + .ok()); + EXPECT_EQ(transport_controller_->GetRtpTransport(kAudioMid1), + transport_controller_->GetRtpTransport(kVideoMid1)); +@@ -2245,15 +2318,17 @@ TEST_F(JsepTransportControllerTest, ChangeBundledMidNotSupported) { + // Reorder the bundle group. + EXPECT_TRUE(bundle_group.RemoveContentName(kAudioMid1)); + bundle_group.AddContentName(kAudioMid1); ++ EXPECT_TRUE(transport_controller_ ++ ->SetLocalDescription(SdpType::kOffer, local_offer.get(), ++ remote_answer.get()) ++ .ok()); + // The answerer uses the new bundle group and now the bundle mid is changed to + // `kVideo1`. + remote_answer->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE); + remote_answer->AddGroup(bundle_group); +- EXPECT_TRUE(transport_controller_ +- ->SetLocalDescription(SdpType::kOffer, local_offer.get()) +- .ok()); + EXPECT_FALSE(transport_controller_ +- ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get()) ++ ->SetRemoteDescription(SdpType::kAnswer, local_offer.get(), ++ remote_answer.get()) + .ok()); + } + // Test that rejecting only the first m= section of a BUNDLE group is treated as +@@ -2294,18 +2369,21 @@ TEST_F(JsepTransportControllerTest, RejectFirstContentInBundleGroup) { + local_offer->AddGroup(bundle_group); + remote_answer->AddGroup(bundle_group); + +- EXPECT_TRUE(transport_controller_ +- ->SetLocalDescription(SdpType::kOffer, local_offer.get()) +- .ok()); ++ EXPECT_TRUE( ++ transport_controller_ ++ ->SetLocalDescription(SdpType::kOffer, local_offer.get(), nullptr) ++ .ok()); + EXPECT_FALSE(transport_controller_ +- ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get()) ++ ->SetRemoteDescription(SdpType::kAnswer, local_offer.get(), ++ remote_answer.get()) + .ok()); + + // Reject all the contents. + remote_answer->contents()[1].rejected = true; + remote_answer->contents()[2].rejected = true; + EXPECT_TRUE(transport_controller_ +- ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get()) ++ ->SetRemoteDescription(SdpType::kAnswer, local_offer.get(), ++ remote_answer.get()) + .ok()); + EXPECT_EQ(nullptr, transport_controller_->GetRtpTransport(kAudioMid1)); + EXPECT_EQ(nullptr, transport_controller_->GetRtpTransport(kVideoMid1)); +@@ -2325,9 +2403,10 @@ TEST_F(JsepTransportControllerTest, ApplyNonRtcpMuxOfferWhenMuxingRequired) { + + local_offer->contents()[0].media_description()->set_rtcp_mux(false); + // Applying a non-RTCP-mux offer is expected to fail. +- EXPECT_FALSE(transport_controller_ +- ->SetLocalDescription(SdpType::kOffer, local_offer.get()) +- .ok()); ++ EXPECT_FALSE( ++ transport_controller_ ++ ->SetLocalDescription(SdpType::kOffer, local_offer.get(), nullptr) ++ .ok()); + } + + // Tests that applying non-RTCP-mux answer would fail when kRtcpMuxPolicyRequire +@@ -2340,9 +2419,10 @@ TEST_F(JsepTransportControllerTest, ApplyNonRtcpMuxAnswerWhenMuxingRequired) { + AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1, + cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS, + nullptr); +- EXPECT_TRUE(transport_controller_ +- ->SetLocalDescription(SdpType::kOffer, local_offer.get()) +- .ok()); ++ EXPECT_TRUE( ++ transport_controller_ ++ ->SetLocalDescription(SdpType::kOffer, local_offer.get(), nullptr) ++ .ok()); + + auto remote_answer = std::make_unique(); + AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1, +@@ -2351,7 +2431,8 @@ TEST_F(JsepTransportControllerTest, ApplyNonRtcpMuxAnswerWhenMuxingRequired) { + // Applying a non-RTCP-mux answer is expected to fail. + remote_answer->contents()[0].media_description()->set_rtcp_mux(false); + EXPECT_FALSE(transport_controller_ +- ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get()) ++ ->SetRemoteDescription(SdpType::kAnswer, local_offer.get(), ++ remote_answer.get()) + .ok()); + } + +@@ -2371,11 +2452,13 @@ TEST_F(JsepTransportControllerTest, + answer_bundle_group.AddContentName(kAudioMid1); + answer_bundle_group.AddContentName(kVideoMid1); + remote_answer->AddGroup(answer_bundle_group); +- EXPECT_TRUE(transport_controller_ +- ->SetLocalDescription(SdpType::kOffer, local_offer.get()) +- .ok()); ++ EXPECT_TRUE( ++ transport_controller_ ++ ->SetLocalDescription(SdpType::kOffer, local_offer.get(), nullptr) ++ .ok()); + EXPECT_FALSE(transport_controller_ +- ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get()) ++ ->SetRemoteDescription(SdpType::kAnswer, local_offer.get(), ++ remote_answer.get()) + .ok()); + } + +@@ -2392,11 +2475,13 @@ TEST_F(JsepTransportControllerTest, RejectBundleGroupWithNonExistingMid) { + local_offer->AddGroup(invalid_bundle_group); + remote_answer->AddGroup(invalid_bundle_group); + ++ EXPECT_FALSE( ++ transport_controller_ ++ ->SetLocalDescription(SdpType::kOffer, local_offer.get(), nullptr) ++ .ok()); + EXPECT_FALSE(transport_controller_ +- ->SetLocalDescription(SdpType::kOffer, local_offer.get()) +- .ok()); +- EXPECT_FALSE(transport_controller_ +- ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get()) ++ ->SetRemoteDescription(SdpType::kAnswer, local_offer.get(), ++ remote_answer.get()) + .ok()); + } + +@@ -2407,16 +2492,19 @@ TEST_F(JsepTransportControllerTest, RemoveContentFromBundleGroup) { + + auto local_offer = CreateSessionDescriptionWithBundleGroup(); + auto remote_answer = CreateSessionDescriptionWithBundleGroup(); ++ EXPECT_TRUE( ++ transport_controller_ ++ ->SetLocalDescription(SdpType::kOffer, local_offer.get(), nullptr) ++ .ok()); + EXPECT_TRUE(transport_controller_ +- ->SetLocalDescription(SdpType::kOffer, local_offer.get()) +- .ok()); +- EXPECT_TRUE(transport_controller_ +- ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get()) ++ ->SetRemoteDescription(SdpType::kAnswer, local_offer.get(), ++ remote_answer.get()) + .ok()); + + // Do an re-offer/answer. + EXPECT_TRUE(transport_controller_ +- ->SetLocalDescription(SdpType::kOffer, local_offer.get()) ++ ->SetLocalDescription(SdpType::kOffer, local_offer.get(), ++ remote_answer.get()) + .ok()); + auto new_answer = CreateSessionDescriptionWithoutBundle(); + cricket::ContentGroup new_bundle_group(cricket::GROUP_TYPE_BUNDLE); +@@ -2427,7 +2515,8 @@ TEST_F(JsepTransportControllerTest, RemoveContentFromBundleGroup) { + + // Applying invalid answer is expected to fail. + EXPECT_FALSE(transport_controller_ +- ->SetRemoteDescription(SdpType::kAnswer, new_answer.get()) ++ ->SetRemoteDescription(SdpType::kAnswer, local_offer.get(), ++ new_answer.get()) + .ok()); + + // Rejected the video content. +@@ -2435,7 +2524,8 @@ TEST_F(JsepTransportControllerTest, RemoveContentFromBundleGroup) { + ASSERT_TRUE(video_content); + video_content->rejected = true; + EXPECT_TRUE(transport_controller_ +- ->SetRemoteDescription(SdpType::kAnswer, new_answer.get()) ++ ->SetRemoteDescription(SdpType::kAnswer, local_offer.get(), ++ new_answer.get()) + .ok()); + } + +@@ -2453,14 +2543,16 @@ TEST_F(JsepTransportControllerTest, ChangeTaggedMediaSectionMaxBundle) { + cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE); + bundle_group.AddContentName(kAudioMid1); + local_offer->AddGroup(bundle_group); +- EXPECT_TRUE(transport_controller_ +- ->SetLocalDescription(SdpType::kOffer, local_offer.get()) +- .ok()); ++ EXPECT_TRUE( ++ transport_controller_ ++ ->SetLocalDescription(SdpType::kOffer, local_offer.get(), nullptr) ++ .ok()); + + std::unique_ptr remote_answer( + local_offer->Clone()); + EXPECT_TRUE(transport_controller_ +- ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get()) ++ ->SetRemoteDescription(SdpType::kAnswer, local_offer.get(), ++ remote_answer.get()) + .ok()); + + std::unique_ptr local_reoffer( +@@ -2475,14 +2567,15 @@ TEST_F(JsepTransportControllerTest, ChangeTaggedMediaSectionMaxBundle) { + local_reoffer->AddGroup(new_bundle_group); + + EXPECT_TRUE(transport_controller_ +- ->SetLocalDescription(SdpType::kOffer, local_reoffer.get()) ++ ->SetLocalDescription(SdpType::kOffer, local_reoffer.get(), ++ remote_answer.get()) + .ok()); + std::unique_ptr remote_reanswer( + local_reoffer->Clone()); +- EXPECT_TRUE( +- transport_controller_ +- ->SetRemoteDescription(SdpType::kAnswer, remote_reanswer.get()) +- .ok()); ++ EXPECT_TRUE(transport_controller_ ++ ->SetRemoteDescription(SdpType::kAnswer, local_reoffer.get(), ++ remote_reanswer.get()) ++ .ok()); + } + + TEST_F(JsepTransportControllerTest, RollbackRestoresRejectedTransport) { +@@ -2496,11 +2589,13 @@ TEST_F(JsepTransportControllerTest, RollbackRestoresRejectedTransport) { + nullptr); + std::unique_ptr remote_answer( + local_offer->Clone()); ++ EXPECT_TRUE( ++ transport_controller_ ++ ->SetLocalDescription(SdpType::kOffer, local_offer.get(), nullptr) ++ .ok()); + EXPECT_TRUE(transport_controller_ +- ->SetLocalDescription(SdpType::kOffer, local_offer.get()) +- .ok()); +- EXPECT_TRUE(transport_controller_ +- ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get()) ++ ->SetRemoteDescription(SdpType::kAnswer, local_offer.get(), ++ remote_answer.get()) + .ok()); + + auto mid1_transport = transport_controller_->GetRtpTransport(kMid1Audio); +@@ -2514,7 +2609,8 @@ TEST_F(JsepTransportControllerTest, RollbackRestoresRejectedTransport) { + local_reoffer->contents()[0].rejected = true; + + EXPECT_TRUE(transport_controller_ +- ->SetLocalDescription(SdpType::kOffer, local_reoffer.get()) ++ ->SetLocalDescription(SdpType::kOffer, local_reoffer.get(), ++ remote_answer.get()) + .ok()); + auto old_mid1_transport = mid1_transport; + mid1_transport = transport_controller_->GetRtpTransport(kMid1Audio); +@@ -2556,11 +2652,13 @@ TEST_F(JsepTransportControllerTest, RollbackRestoresPreviousTransportMapping) { + std::unique_ptr remote_answer( + local_offer->Clone()); + ++ EXPECT_TRUE( ++ transport_controller_ ++ ->SetLocalDescription(SdpType::kOffer, local_offer.get(), nullptr) ++ .ok()); + EXPECT_TRUE(transport_controller_ +- ->SetLocalDescription(SdpType::kOffer, local_offer.get()) +- .ok()); +- EXPECT_TRUE(transport_controller_ +- ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get()) ++ ->SetRemoteDescription(SdpType::kAnswer, local_offer.get(), ++ remote_answer.get()) + .ok()); + + auto mid1_transport = transport_controller_->GetRtpTransport(kMid1Audio); +@@ -2585,7 +2683,8 @@ TEST_F(JsepTransportControllerTest, RollbackRestoresPreviousTransportMapping) { + local_reoffer->AddGroup(bundle_group); + + EXPECT_TRUE(transport_controller_ +- ->SetLocalDescription(SdpType::kOffer, local_reoffer.get()) ++ ->SetLocalDescription(SdpType::kOffer, local_reoffer.get(), ++ remote_answer.get()) + .ok()); + + // Store the old transport pointer and verify that the offer actually changed +@@ -2633,11 +2732,13 @@ TEST_F(JsepTransportControllerTest, RollbackAndAddToDifferentBundleGroup) { + std::unique_ptr remote_answer( + local_offer->Clone()); + ++ EXPECT_TRUE( ++ transport_controller_ ++ ->SetLocalDescription(SdpType::kOffer, local_offer.get(), nullptr) ++ .ok()); + EXPECT_TRUE(transport_controller_ +- ->SetLocalDescription(SdpType::kOffer, local_offer.get()) +- .ok()); +- EXPECT_TRUE(transport_controller_ +- ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get()) ++ ->SetRemoteDescription(SdpType::kAnswer, local_offer.get(), ++ remote_answer.get()) + .ok()); + + // Apply an offer that adds kMid3Audio to the first BUNDLE group., +@@ -2657,10 +2758,11 @@ TEST_F(JsepTransportControllerTest, RollbackAndAddToDifferentBundleGroup) { + subsequent_offer_1->AddGroup(modified_bundle_group1); + subsequent_offer_1->AddGroup(bundle_group2); + +- EXPECT_TRUE( +- transport_controller_ +- ->SetLocalDescription(SdpType::kOffer, subsequent_offer_1.get()) +- .ok()); ++ EXPECT_TRUE(transport_controller_ ++ ->SetLocalDescription(SdpType::kOffer, ++ subsequent_offer_1.get(), ++ remote_answer.get()) ++ .ok()); + + auto mid1_transport = transport_controller_->GetRtpTransport(kMid1Audio); + auto mid2_transport = transport_controller_->GetRtpTransport(kMid2Audio); +@@ -2689,10 +2791,11 @@ TEST_F(JsepTransportControllerTest, RollbackAndAddToDifferentBundleGroup) { + subsequent_offer_2->AddGroup(bundle_group1); + subsequent_offer_2->AddGroup(modified_bundle_group2); + +- EXPECT_TRUE( +- transport_controller_ +- ->SetLocalDescription(SdpType::kOffer, subsequent_offer_2.get()) +- .ok()); ++ EXPECT_TRUE(transport_controller_ ++ ->SetLocalDescription(SdpType::kOffer, ++ subsequent_offer_2.get(), ++ remote_answer.get()) ++ .ok()); + + mid1_transport = transport_controller_->GetRtpTransport(kMid1Audio); + mid2_transport = transport_controller_->GetRtpTransport(kMid2Audio); +@@ -2722,9 +2825,9 @@ TEST_F(JsepTransportControllerTest, BundleOnlySectionDoesNotNeedRtcpMux) { + offer->contents()[1].media_description()->set_rtcp_mux(false); + offer->contents()[1].bundle_only = true; + +- EXPECT_TRUE( +- transport_controller_->SetRemoteDescription(SdpType::kOffer, offer.get()) +- .ok()); ++ EXPECT_TRUE(transport_controller_ ++ ->SetRemoteDescription(SdpType::kOffer, nullptr, offer.get()) ++ .ok()); + } + + // Test that with max-bundle a single unbundled m-line is accepted. +@@ -2738,9 +2841,9 @@ TEST_F(JsepTransportControllerTest, + AddAudioSection(offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1, + cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS, + nullptr); +- EXPECT_TRUE( +- transport_controller_->SetRemoteDescription(SdpType::kOffer, offer.get()) +- .ok()); ++ EXPECT_TRUE(transport_controller_ ++ ->SetRemoteDescription(SdpType::kOffer, nullptr, offer.get()) ++ .ok()); + } + + } // namespace webrtc +diff --git a/pc/sdp_offer_answer.cc b/pc/sdp_offer_answer.cc +index 06303de4412d7e8f2b29920e29004daeae4ef54c..56321e7a80b3903376b812b5f7e357cc15711c95 100644 +--- a/pc/sdp_offer_answer.cc ++++ b/pc/sdp_offer_answer.cc +@@ -1975,8 +1975,11 @@ RTCError SdpOfferAnswerHandler::ReplaceRemoteDescription( + const cricket::SessionDescription* session_desc = + remote_description()->description(); + ++ const auto* local = local_description(); ++ + // NOTE: This will perform a BlockingCall() to the network thread. +- return transport_controller_s()->SetRemoteDescription(sdp_type, session_desc); ++ return transport_controller_s()->SetRemoteDescription( ++ sdp_type, local ? local->description() : nullptr, session_desc); + } + + void SdpOfferAnswerHandler::ApplyRemoteDescription( +@@ -4893,13 +4896,15 @@ RTCError SdpOfferAnswerHandler::PushdownTransportDescription( + if (source == cricket::CS_LOCAL) { + const SessionDescriptionInterface* sdesc = local_description(); + RTC_DCHECK(sdesc); +- return transport_controller_s()->SetLocalDescription(type, +- sdesc->description()); ++ const auto* remote = remote_description(); ++ return transport_controller_s()->SetLocalDescription( ++ type, sdesc->description(), remote ? remote->description() : nullptr); + } else { + const SessionDescriptionInterface* sdesc = remote_description(); + RTC_DCHECK(sdesc); +- return transport_controller_s()->SetRemoteDescription(type, +- sdesc->description()); ++ const auto* local = local_description(); ++ return transport_controller_s()->SetRemoteDescription( ++ type, local ? local->description() : nullptr, sdesc->description()); + } + } + +diff --git a/test/peer_scenario/scenario_connection.cc b/test/peer_scenario/scenario_connection.cc +index 66eca275d18d0af4941cb52c6f07cf3f61981a73..338de74401c76aed89c447ffe24ad49395e13c5f 100644 +--- a/test/peer_scenario/scenario_connection.cc ++++ b/test/peer_scenario/scenario_connection.cc +@@ -173,7 +173,9 @@ void ScenarioIceConnectionImpl::SetRemoteSdp(SdpType type, + }); + + auto res = jsep_controller_->SetRemoteDescription( +- remote_description_->GetType(), remote_description_->description()); ++ remote_description_->GetType(), ++ local_description_ ? local_description_->description() : nullptr, ++ remote_description_->description()); + RTC_CHECK(res.ok()) << res.message(); + RtpDemuxerCriteria criteria; + for (const auto& content : remote_description_->description()->contents()) { +@@ -203,7 +205,8 @@ void ScenarioIceConnectionImpl::SetLocalSdp(SdpType type, + RTC_DCHECK_RUN_ON(signaling_thread_); + local_description_ = webrtc::CreateSessionDescription(type, local_sdp); + auto res = jsep_controller_->SetLocalDescription( +- local_description_->GetType(), local_description_->description()); ++ local_description_->GetType(), local_description_->description(), ++ remote_description_ ? remote_description_->description() : nullptr); + RTC_CHECK(res.ok()) << res.message(); + jsep_controller_->MaybeStartGathering(); + }