fixup! fixup! [GS] Allowing software fallback when using MCH PCM 03/324003/3
authorAdam Bujalski <a.bujalski@samsung.com>
Wed, 7 May 2025 13:49:54 +0000 (15:49 +0200)
committerj.gajownik2 <j.gajownik2@samsung.com>
Mon, 12 May 2025 07:21:41 +0000 (07:21 +0000)
Fixing crashes in GFN, resulting from double deletion.

Bug: https://jira-eu.sec.samsung.net/browse/VDWASM-2382
Change-Id: Ia1d4cf4810a53c7c786ae57e6382429c5784efe2

tizen_src/chromium_impl/media/audio/tizen/mch_pcm_mixable_stream.cc
tizen_src/chromium_impl/media/audio/tizen/mch_pcm_mixable_stream.h
tizen_src/chromium_impl/media/audio/tizen/mch_pcm_mixable_stream_test.cc [new file with mode: 0644]
tizen_src/chromium_impl/media/test/BUILD.gn

index f9824def4fddfea3354f9c307cdc90c9278a7b74..85f0a942c0ab252090dfc50f12710a0fc1261901 100644 (file)
@@ -28,40 +28,78 @@ MchPcmMixableStream::MchPcmMixableStream(
 
 MchPcmMixableStream::~MchPcmMixableStream() {
   TIZEN_MEDIA_LOG(INFO);
-  Stop();
+  DCHECK_EQ(mixable_stream_, nullptr);  // Stream has been closed
 }
 
 bool MchPcmMixableStream::Open() {
   TIZEN_MEDIA_LOG(INFO);
+  DCHECK_NE(mixable_stream_, nullptr);
+  if (mixable_stream_ == nullptr) {
+    LOG(ERROR) << "Called on Closed stream!";
+    return false;
+  }
   return mixable_stream_->Open();
 }
 
 void MchPcmMixableStream::Start(AudioSourceCallback* callback) {
   TIZEN_MEDIA_LOG(INFO);
+  DCHECK_NE(mixable_stream_, nullptr);
+  if (mixable_stream_ == nullptr) {
+    LOG(ERROR) << "Called on Closed stream!";
+    return;
+  }
+
   mixer_manager_->StreamStarted(this);
   mixable_stream_->Start(callback);
 }
 
 void MchPcmMixableStream::Stop() {
   TIZEN_MEDIA_LOG(INFO);
+  DCHECK_NE(mixable_stream_, nullptr);
+  if (mixable_stream_ == nullptr) {
+    LOG(ERROR) << "Called on Closed stream!";
+    return;
+  }
+
   mixer_manager_->StreamStopped(this);
   mixable_stream_->Stop();
 }
 
 void MchPcmMixableStream::SetVolume(double volume) {
   TIZEN_MEDIA_LOG(INFO) << "volume: " << volume;
+  DCHECK_NE(mixable_stream_, nullptr);
+  if (mixable_stream_ == nullptr) {
+    LOG(ERROR) << "Called on Closed stream!";
+    return;
+  }
+
   mixable_stream_->SetVolume(volume);
 }
 
 void MchPcmMixableStream::GetVolume(double* volume) {
   TIZEN_MEDIA_LOG(INFO);
+  DCHECK_NE(mixable_stream_, nullptr);
+  if (mixable_stream_ == nullptr) {
+    LOG(ERROR) << "Called on Closed stream!";
+    return;
+  }
+
   mixable_stream_->GetVolume(volume);
 }
 
 void MchPcmMixableStream::Close() {
   TIZEN_MEDIA_LOG(INFO);
+  DCHECK_NE(mixable_stream_, nullptr);
+  if (mixable_stream_ == nullptr) {
+    LOG(ERROR) << "Called on Closed stream!";
+    return;
+  }
+
   mixer_manager_->StreamStopped(this);
+
+  // `Close` will delete `mixable_stream_`.
   mixable_stream_->Close();
+  mixable_stream_ = nullptr;
 
   // `ReleaseOutputStream` deletes "this", must be last in this method.
   if (manager_) {
@@ -71,6 +109,12 @@ void MchPcmMixableStream::Close() {
 
 void MchPcmMixableStream::Flush() {
   TIZEN_MEDIA_LOG(INFO);
+  DCHECK_NE(mixable_stream_, nullptr);
+  if (mixable_stream_ == nullptr) {
+    LOG(ERROR) << "Called on Closed stream!";
+    return;
+  }
+
   mixable_stream_->Flush();
 }
 
index f62a9ee3d799d13cc9a70626d3c76b2c37e5f3ea..5123d06bf308ae37f2e416dd9dc69e0530cc4c01 100644 (file)
@@ -35,7 +35,7 @@ class MchPcmMixableStream : public AudioOutputStream {
   void Flush() override;
 
  private:
-  std::unique_ptr<AudioOutputStream> mixable_stream_;
+  raw_ptr<AudioOutputStream> mixable_stream_;
   scoped_refptr<MchPcmMixerManager> mixer_manager_;
   raw_ptr<AudioManagerBase> manager_;
 };
diff --git a/tizen_src/chromium_impl/media/audio/tizen/mch_pcm_mixable_stream_test.cc b/tizen_src/chromium_impl/media/audio/tizen/mch_pcm_mixable_stream_test.cc
new file mode 100644 (file)
index 0000000..638d41d
--- /dev/null
@@ -0,0 +1,199 @@
+// Copyright 2025 Samsung Electronics Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "media/audio/tizen/mch_pcm_mixable_stream.h"
+
+#include <memory>
+#include <vector>
+
+#include "base/test/task_environment.h"
+#include "media/audio/fake_audio_log_factory.h"
+#include "media/audio/fake_audio_manager.h"
+#include "media/audio/test_audio_thread.h"
+#include "media/audio/tizen/mch_pcm_manager.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace media {
+
+namespace {
+
+class MockAudioSourceCallback : public AudioOutputStream::AudioSourceCallback {
+ public:
+  int OnMoreData(base::TimeDelta /* delay */,
+                 base::TimeTicks /* delay_timestamp */,
+                 const media::AudioGlitchInfo& /* glitch_info */,
+                 AudioBus* dest) override {
+    dest->Zero();
+    return dest->frames();
+  }
+  MOCK_METHOD1(OnError, void(ErrorType));
+};
+
+}  // namespace
+
+class MchPcmMixableStreamTest : public testing::Test {
+ public:
+  AudioOutputStream* Create51Stream() {
+    return MchPcmManager::GetInstance().CreateOutputStream(
+        Get51Params(), &fake_audio_manager_);
+  }
+
+  AudioOutputStream* CreateStereoStream() {
+    return MchPcmManager::GetInstance().CreateOutputStream(
+        GetStereoParams(), &fake_audio_manager_);
+  }
+
+  AudioParameters GetStereoParams() const {
+    return AudioParameters{AudioParameters::AUDIO_PCM_LOW_LATENCY,
+                           ChannelLayoutConfig::Stereo(), 48000, 512};
+  }
+
+  AudioParameters Get51Params() const {
+    return AudioParameters{
+        AudioParameters::AUDIO_PCM_LOW_LATENCY,
+        ChannelLayoutConfig::FromLayout<CHANNEL_LAYOUT_5_1>(), 48000, 512};
+  }
+
+ protected:
+  base::test::TaskEnvironment task_environment_{
+      base::test::TaskEnvironment::TimeSource::MOCK_TIME};
+  FakeAudioLogFactory fake_audio_log_factory_;
+  FakeAudioManager fake_audio_manager_{std::make_unique<TestAudioThread>(),
+                                       &fake_audio_log_factory_};
+};
+
+TEST_F(MchPcmMixableStreamTest, CreateSingle) {
+  auto* stream = Create51Stream();
+  ASSERT_NE(stream, nullptr);
+  stream->Close();
+  task_environment_.RunUntilIdle();
+}
+
+TEST_F(MchPcmMixableStreamTest, OpenSingle) {
+  auto* stream = Create51Stream();
+  ASSERT_NE(stream, nullptr);
+  EXPECT_TRUE(stream->Open());
+  task_environment_.RunUntilIdle();
+
+  stream->Close();
+  task_environment_.RunUntilIdle();
+}
+
+// TODO(a.bujalski):
+// Refactor `MchPcmMizeManager` to allow mocking audio output, so tests won't
+// hang when run under GBS.
+TEST_F(MchPcmMixableStreamTest, DISABLED_StartAndStopSingle) {
+  auto* stream = Create51Stream();
+  ASSERT_NE(stream, nullptr);
+  EXPECT_TRUE(stream->Open());
+  task_environment_.RunUntilIdle();
+
+  MockAudioSourceCallback audio_callback;
+  stream->Start(&audio_callback);
+  task_environment_.RunUntilIdle();
+
+  stream->Stop();
+  stream->Close();
+  task_environment_.RunUntilIdle();
+}
+
+TEST_F(MchPcmMixableStreamTest, SetVolumeSingle) {
+  auto* stream = Create51Stream();
+  ASSERT_NE(stream, nullptr);
+  EXPECT_TRUE(stream->Open());
+  task_environment_.RunUntilIdle();
+
+  constexpr double kDummyVolume1 = 0.1;
+  stream->SetVolume(kDummyVolume1);
+  double vol1 = 0.0;
+  stream->GetVolume(&vol1);
+  EXPECT_DOUBLE_EQ(vol1, kDummyVolume1);
+
+  task_environment_.RunUntilIdle();
+
+  constexpr double kDummyVolume2 = 0.42;
+  stream->SetVolume(kDummyVolume2);
+  double vol2 = 0.0;
+  stream->GetVolume(&vol2);
+  EXPECT_DOUBLE_EQ(vol2, kDummyVolume2);
+
+  stream->Stop();
+  stream->Close();
+  task_environment_.RunUntilIdle();
+}
+
+TEST_F(MchPcmMixableStreamTest, CreateTwoStreams) {
+  std::vector<AudioOutputStream*> streams;
+  streams.push_back(Create51Stream());
+  streams.push_back(CreateStereoStream());
+
+  for (const auto* stream : streams) {
+    ASSERT_NE(stream, nullptr);
+  }
+
+  for (auto* stream : streams) {
+    stream->Close();
+  }
+
+  task_environment_.RunUntilIdle();
+}
+
+TEST_F(MchPcmMixableStreamTest, OpenTwoStreams) {
+  std::vector<AudioOutputStream*> streams;
+  streams.push_back(Create51Stream());
+  streams.push_back(CreateStereoStream());
+
+  for (const auto* stream : streams) {
+    ASSERT_NE(stream, nullptr);
+  }
+
+  for (auto* stream : streams) {
+    EXPECT_TRUE(stream->Open());
+  }
+  task_environment_.RunUntilIdle();
+
+  for (auto* stream : streams) {
+    stream->Close();
+  }
+
+  task_environment_.RunUntilIdle();
+}
+
+// TODO(a.bujalski):
+// Refactor `MchPcmMizeManager` to allow mocking audio output, so tests won't
+// hang when run under GBS.
+TEST_F(MchPcmMixableStreamTest, DISABLED_StartAndStopStreams) {
+  std::vector<AudioOutputStream*> streams;
+  streams.push_back(Create51Stream());
+  streams.push_back(CreateStereoStream());
+
+  for (const auto* stream : streams) {
+    ASSERT_NE(stream, nullptr);
+  }
+
+  for (auto* stream : streams) {
+    EXPECT_TRUE(stream->Open());
+  }
+  task_environment_.RunUntilIdle();
+
+  MockAudioSourceCallback audio_callback;
+  for (auto* stream : streams) {
+    stream->Start(&audio_callback);
+  }
+
+  task_environment_.RunUntilIdle();
+
+  for (auto* stream : streams) {
+    stream->Stop();
+  }
+
+  for (auto* stream : streams) {
+    stream->Close();
+  }
+
+  task_environment_.RunUntilIdle();
+}
+
+}  // namespace media
index e01a8da20d6eed5ec9cae9a1444750ec851274e7..c08e26394fbb09628a4841cda92e4fb7f1fd31ea 100644 (file)
@@ -16,7 +16,7 @@ test("tizen_media_unittests") {
   deps = [
     "//base",
     "//base/test:test_support",
-    "//media/",
+    "//media",
     "//media/filters/tizen:ttvd",
     "//media/gpu:test_support",
     "//media/mojo:test_support",
@@ -31,10 +31,20 @@ test("tizen_media_unittests") {
     "//media/filters/tizen/decoder_promotion_test.cc",
     "//media/filters/tizen/lazy_frame_ranges_test.cc",
     "//media/filters/tizen/ttvd_video_decoder_test.cc",
-    "//tizen_src/chromium_impl/media/audio/tizen/mch_pcm_with_software_fallback_output_test.cc",
     "//tizen_src/chromium_impl/ui/ozone/platform/efl/output_surface_proxy_test.cc",
   ]
 
+  if (tizen_tv_use_mch_pcm) {
+    deps += [
+      "//services/audio",
+    ]
+
+    sources += [
+      "//tizen_src/chromium_impl/media/audio/tizen/mch_pcm_mixable_stream_test.cc",
+      "//tizen_src/chromium_impl/media/audio/tizen/mch_pcm_with_software_fallback_output_test.cc",
+    ]
+  }
+
   if (tizen_tv_upstream_multimedia_omx || tizen_tv_upstream_multimedia_omx_ppi) {
     sources += [
       "//media/filters/tizen/omx/mock_omx_wrapper.cc",