add In-app Multiview API
authorkw0530-kang <kw0530.kang@samsung.com>
Tue, 12 Sep 2023 10:35:25 +0000 (10:35 +0000)
committerkw0530-kang <kw0530.kang@samsung.com>
Tue, 12 Sep 2023 10:35:25 +0000 (10:35 +0000)
include/esplusplayer/esplusplayer.h
include/esplusplayer_capi/esplusplayer_capi.h
packaging/esplusplayer.spec
src/esplusplayer/include_internal/esplayer/esplayer.h
src/esplusplayer/src/esplayer.cpp
src/esplusplayer/src/esplusplayer_capi.cpp
src/plusplayer-core/include_internal/core/trackrendereradapter.h
src/plusplayer-core/src/trackrendereradapter.cpp
ut/src/esplusplayer/ut_inapp_multiview.cpp

index b08dc1a..5d46e56 100644 (file)
@@ -277,19 +277,23 @@ class EsPlusPlayer : private boost::noncopyable {
   virtual bool Close() { return false; }
 
   /**
-   * @brief     Flush the specific buffered stream data and release TV resource
-   *            to change stream.
-   * @remark    To activate, the stream must be set again.
+   * @brief     Not play the specific stream anymore.
+   * @remark    The submitted es packets will be dropped after deactivated.
+   *            It recommands to stop feeding the specific stream's packets.
    * @pre       The player must be set to at least #EsState::kReady
-   * @post       The player state is same as before calling Deactivate().
+   * @post      The player state is same as before calling Deactivate().
    * @return    @c True on success, otherwise @c False.
    * @see       EsPlusPlayer::Deactivate().
    */
   virtual bool Deactivate(const StreamType type) { return false; }
 
   /**
-   * @brief     Reprepare for the specific stream playback.
-   * @remark    There must be active stream to prepare playback.
+   * @brief     Restart to play the specific stream.
+   * @remark    If user wants to change the specific stream info,
+   *            new stream info has to be set before activate. 
+   *            User has to submit the specific stream from the
+   *            current playing time for activating.
+   *            The video stream has to be submitted from Iframe.
    * @pre       The player must be set to at least #EsState::kReady
    *            The StreamType must be deactivated in advance.
    *            Stream should be set in advance.
@@ -310,6 +314,40 @@ class EsPlusPlayer : private boost::noncopyable {
   virtual bool Activate(const StreamType type) { return false; }
 
   /**
+   * @brief     Not play the audio stream anymore.
+   * @remark    User has to keep feeding audio packets like when playing audio.
+   * @pre       The player must be set to at least #EsState::kIdle
+   * @post      The player state is same as before calling DeactivateAudio().
+   * @return    @c True on success, otherwise @c False.
+   * @see       EsPlusPlayer::DeactivateAudio()
+   */
+  virtual bool DeactivateAudio() { return false; }
+
+  /**
+   * @brief     Restart to play the audio stream.
+   * @remark    User can't change the audio stream info before activate.
+   * @pre       The player must be set to at least #EsState::kReady
+   *            The audio stream must be deactivated in advance.
+   *            Audio stream should be set in advance.
+   * @return    @c True on success, otherwise @c False
+   * @code
+      VideoStreamPtr audio_stream = AudioStream::Create();
+      audio_stream->SetMimeType(AudioMimeType::kAAC);
+      audio_stream->SetSamplerate(44100);
+      audio_stream->SetChannels(2);
+      SetStream(audio_stream);
+      DeactivateAudio();
+      PrepareAsync();
+      Start();
+      ActivateAudio();
+      DeactivateAudio();
+      ActivateAudio();
+   * @endcode
+   * @see       EsPlusPlayer::ActivateAudio()
+   */
+  virtual bool ActivateAudio() { return false; }
+
+  /**
    * @brief     Prepare the player for playback, asynchronously.
    * @remarks   EsEventListener::OnPrepareDone() will be called when prepare is
    * finished
index 6d8114d..86ef898 100644 (file)
@@ -557,25 +557,25 @@ int esplusplayer_close(esplusplayer_handle handle);
 int esplusplayer_destroy(esplusplayer_handle handle);
 
 /**
- * @brief     Flush the specific buffered stream data and release TV resource
- *            to change stream.
- * @remark    To activate, the stream must be set again.
+ * @brief     Not play the specific stream anymore.
+ * @remark    The submitted es packets will be dropped after deactivated.
+ *            It recommands to stop feeding the specific stream's packets.
  * @param     [in] handle : esplusplayer handle.
  * @param     [in] type : stream type which user want to deactivate.
  * @return    @c ESPLUSPLAYER_ERROR_TYPE_NONE on success,otherwise @c one of
- esplusplayer_error_type
esplusplayer_error_type
  *            values will be returned.
  * @retval    #ESPLUSPLAYER_ERROR_TYPE_NONE Successful
  * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER Invalid parameter
  * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_OPERATION Internal operation
- failed
failed
  * @code
             refer to the sample code of esplusplayer_activate()
- * @endcode
*            refer to the sample code of esplusplayer_activate()
+ * @endcode 
  * @pre       The player state must be at least #ESPLUSPLAYER_STATE_READY
  * @post      The player state is same as before calling
- *            esplusplayer_deactivate(). The deactivated stream will stop
- *            rendering and release the decorer, renderer resources.
+ *            esplusplayer_deactivate(). The buffered data of the deactivated stream 
+ *            will be flushed and the resources for decoding and rendering will be released.
  * @exception None
  * @see       esplusplayer_activate
  */
@@ -583,8 +583,11 @@ int esplusplayer_deactivate(esplusplayer_handle handle,
                             esplusplayer_stream_type type);
 
 /**
- * @brief     Reprepare for the specific stream playback.
- * @remark    There must be active stream to prepare playback.
+ * @brief     Restart to play the specific stream.
+ * @remark    If user wants to change the specific stream info, new stream info has to be set
+ *            before activate. 
+ *            User has to submit the specific stream from the current playing time for activating.
+ *            The video stream has to be submitted from Iframe.
  * @param     [in] handle : esplusplayer handle.
  * @param     [in] type : stream type which user want to activate.
  * @return    @c ESPLUSPLAYER_ERROR_TYPE_NONE on success,otherwise @c one of
@@ -620,6 +623,86 @@ int esplusplayer_activate(esplusplayer_handle handle,
                           esplusplayer_stream_type type);
 
 /**
+ * @brief     Not play the audio stream anymore.
+ * @remark    User has to keep feeding audio packets like when playing audio.
+ * @param     [in] handle : esplusplayer handle.
+ * @return    @c ESPLUSPLAYER_ERROR_TYPE_NONE on success,otherwise @c one of
+ * esplusplayer_error_type
+ *            values will be returned.
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_NONE Successful
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER Invalid parameter
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_OPERATION Internal operation
+ * failed
+ * @code      
+ *             refer to the sample code of esplusplayer_activate_audio()
+ * @endcode
+ * @pre       The player state must be at least #ESPLUSPLAYER_STATE_IDLE
+ * @post      The player state is same as before calling
+ *            esplusplayer_deactivate_audio(). The player will keep buffering 
+ *            the audio packets and consuming it at the rendering time.
+ *            All audio resources of decoder and renderer will be released.
+ * @exception None
+ * @version   6.0
+ * @see       esplusplayer_activate_audio
+ */
+int esplusplayer_deactivate_audio(esplusplayer_handle handle);
+
+/**
+ * @brief     Restart to play the audio stream.
+ * @remark    User can't change the audio stream info before activate.
+ * @param     [in] handle : esplusplayer handle.
+ * @return    @c ESPLUSPLAYER_ERROR_TYPE_NONE on success,otherwise @c one of
+ * esplusplayer_error_type
+ *            values will be returned.
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_NONE Successful
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER Invalid parameter
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_OPERATION Internal operation
+ * failed
+ * @code      
+ *            // play one esplayer in normal
+ *            esplusplayer_handle esplayer1 = esplusplayer_create();
+ *            esplusplayer_open(esplayer1);
+ *            esplusplayer_audio_stream_info audio_stream_1;
+ *            audio_stream_1.codec_data = nullptr;
+ *            audio_stream_1.codec_data_length = 0;
+ *            esplusplayer_set_audio_stream_info(esplayer1, &audio_stream_1);
+ *            // ... your codes ...
+ *            esplusplayer_prepare_async(esplayer1);
+ *            esplusplayer_start(esplayer1);
+ *
+ *            // play one more esplayer started in deactivate
+ *            esplusplayer_handle esplayer2 = esplusplayer_create();
+ *            esplusplayer_open(esplayer2);
+ *            esplusplayer_audio_stream_info audio_stream_2;
+ *            audio_stream_2.codec_data = nullptr;
+ *            audio_stream_2.codec_data_length = 0;
+ *            esplusplayer_set_audio_stream_info(esplayer2, &audio_stream_2);
+ *            // ... your codes ...
+ *            esplusplayer_deactivate_audio(esplayer2);
+ *            esplusplayer_prepare_async(esplayer2);
+ *            esplusplayer_start(esplayer2);
+ *
+ *            // if you want to play esplayer2, deactivate esplayer1 first
+ *            // and then activate esplayer2
+ *            esplusplayer_deactivate_audio(esplayer1);
+ *            esplusplayer_activate_audio(esplayer2);
+ *            // ... your codes ...
+ *            esplusplayer_close(esplayer1);
+ *            esplusplayer_destroy(esplayer1);
+ *            esplusplayer_close(esplayer2);
+ *            esplusplayer_destroy(esplayer2);
+ * @endcode
+ * @pre       The player state must be at least #ESPLUSPLAYER_STATE_READY
+ * @post      The player state is same as before calling
+ *            esplusplayer_activate_audio(). Rebuild audio pipeline to render
+ *            the audio stream.
+ * @exception None
+ * @version   6.0
+ * @see       esplusplayer_deactivate_audio
+ */
+int esplusplayer_activate_audio(esplusplayer_handle handle);
+
+/**
  * @brief     Prepare the player for playback, asynchronously.
  * @param     [in] handle : esplusplayer handle.
  * @return    @c ESPLUSPLAYER_ERROR_TYPE_NONE on success,otherwise @c one of
index 3bae33f..9e99937 100755 (executable)
@@ -7,7 +7,7 @@
 #echo "Product Type: %{_vd_cfg_product_type}"
 Name:       esplusplayer
 Summary:    new multimedia streaming player
-Version:    1.1.2
+Version:    1.2.0
 Release:    0
 Group:      Multimedia/Libraries
 License:    Apache-2.0
index cdd7d1b..50c0dac 100644 (file)
@@ -56,6 +56,8 @@ class EsPlayer : public EsPlusPlayer {
   bool PrepareAsync() override;
   bool Deactivate(const StreamType type) override;
   bool Activate(const StreamType type) override;
+  bool DeactivateAudio() override;
+  bool ActivateAudio() override;
   bool Start() override;
   bool Stop() override;
   bool Pause() override;
@@ -285,6 +287,7 @@ class EsPlayer : public EsPlusPlayer {
   std::mutex eos_mutex_;
   EsEventListener* eventlistener_ = nullptr;
   EsEventListener::UserData eventlistener_userdata_ = nullptr;
+  bool is_audio_stream_info_frozen_ = false;
 
   EsStateManager state_manager_;
 
index f3f76c7..a3a7efa 100755 (executable)
@@ -456,6 +456,53 @@ bool EsPlayer::Activate(const StreamType type) {
   return false;
 }
 
+bool EsPlayer::DeactivateAudio() {
+  LOG_ENTER_P(this);
+  if (state_manager_.GetState() < EsState::kIdle) {
+    LOG_ERROR_P(this, "Invalid State , current %d",
+                state_manager_.GetStateEnum());
+    return false;
+  }
+#ifndef IS_AUDIO_PRODUCT
+  if (!enable_audio_pipeline_handle_) {
+    LOG_ERROR_P(
+        this, "can't deactivate audio stream, mixer will control audio stream");
+    return false;
+  }
+#endif
+  if (!trackrenderer_->DeactivateAudio()) {
+    return false;
+  }
+  is_audio_stream_info_frozen_ = true;
+  return true;
+}
+
+bool EsPlayer::ActivateAudio() {
+  LOG_ENTER_P(this);
+  const StreamType type = StreamType::kAudio;
+  if (state_manager_.GetState() < EsState::kReady) {
+    LOG_ERROR_P(this, "Invalid State , current %d",
+                state_manager_.GetStateEnum());
+    return false;
+  }
+#ifndef IS_AUDIO_PRODUCT
+  if (!enable_audio_pipeline_handle_) {
+    LOG_ERROR_P(this,
+                "can't activate audio stream, mixer will control audio stream");
+    return false;
+  }
+#endif
+  if (track_.empty()) {
+    return false;
+  }
+  if (!trackrenderer_->ActivateAudio()) {
+    return false;
+  }
+  eos_status_ =
+      internal::ResetEosStatus(static_cast<TrackType>(type), eos_status_);
+  return true;
+}
+
 bool EsPlayer::Start() {
   LOG_ENTER_P(this);
   if (is_stopped_) {
@@ -1145,6 +1192,10 @@ bool EsPlayer::SetStream(const AudioStreamPtr& stream) {
   }
   Track track = stream->GetTrack_();
   if (state_manager_.GetState() >= EsState::kReady) {
+    if (is_audio_stream_info_frozen_) {
+      LOG_ERROR_P(this, "can't change audio stream in audio deactivate mode");
+      return ret;
+    }
     track.active = false;
     ret = ChangeStream_(track);
     return ret;
index fe04296..c4a3263 100644 (file)
@@ -942,6 +942,20 @@ int esplusplayer_activate(esplusplayer_handle handle,
       cast_(handle)->Activate(static_cast<StreamType>(type)));
 }
 
+int esplusplayer_deactivate_audio(esplusplayer_handle handle) {
+  LOG_ENTER_P(cast_(handle))
+  if (is_null_(handle)) return ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER;
+
+  return convert_return_type_(cast_(handle)->DeactivateAudio());
+}
+
+int esplusplayer_activate_audio(esplusplayer_handle handle) {
+  LOG_ENTER_P(cast_(handle))
+  if (is_null_(handle)) return ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER;
+
+  return convert_return_type_(cast_(handle)->ActivateAudio());
+}
+
 int esplusplayer_prepare_async(esplusplayer_handle handle) {
   LOG_ENTER_P(cast_(handle))
   if (is_null_(handle)) return ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER;
index bc49e81..30908c2 100755 (executable)
@@ -150,6 +150,8 @@ class TrackRendererAdapter {
   bool GetDroppedFramesForCatchup(TrackType type, void* counts);
   bool Deactivate(TrackType type);
   bool Activate(TrackType type, const Track& track);
+  bool DeactivateAudio();
+  bool ActivateAudio();
   bool SubmitPacket(const DecoderInputBufferPtr& data);
   bool SubmitPacket(const DecoderInputBufferPtr& data, SubmitStatus* status);
   bool SubmitPacket2(const DecoderInputBufferPtr& data, SubmitStatus* status);
index f782b94..86a6df9 100644 (file)
@@ -164,6 +164,20 @@ bool TrackRendererAdapter::Activate(TrackType type, const Track& trackinfo) {
   return true;
 }
 
+bool TrackRendererAdapter::DeactivateAudio() {
+  if (trackrenderer_deactivate_audio(handle_) == kFailed) {
+    return false;
+  }
+  return true;
+}
+
+bool TrackRendererAdapter::ActivateAudio() {
+  if (trackrenderer_activate_audio(handle_) == kFailed) {
+    return false;
+  }
+  return true;
+}
+
 // LCOV_EXCL_START
 bool TrackRendererAdapter::SubmitPacket(const DecoderInputBufferPtr& data) {
 #ifdef TRACKRENDERER_GST_DEPENDENCY_REMOVAL
index 4229fa3..d87eefb 100644 (file)
@@ -56,14 +56,18 @@ class EsInAppMultiViewTest : public ::testing::TestWithParam<std::string> {
     std::cout << "uri_: " << uri_ << std::endl;
     video_reader1_ =
         new EsStreamReader(uri_ + "video/", ESPLUSPLAYER_STREAM_TYPE_VIDEO);
+    audio_reader1_ =
+        new EsStreamReader(uri_ + "audio/", ESPLUSPLAYER_STREAM_TYPE_AUDIO);
     callback1_ =
-        new EsPlayerEventCallback(esplayer1_, video_reader1_, nullptr); 
+        new EsPlayerEventCallback(esplayer1_, video_reader1_, audio_reader1_); 
     callback1_->SetCallback();
 
     video_reader2_ =
         new EsStreamReader(uri_ + "video/", ESPLUSPLAYER_STREAM_TYPE_VIDEO);
+    audio_reader2_ =
+        new EsStreamReader(uri_ + "audio/", ESPLUSPLAYER_STREAM_TYPE_AUDIO);
     callback2_ =
-        new EsPlayerEventCallback(esplayer2_, video_reader2_, nullptr);
+        new EsPlayerEventCallback(esplayer2_, video_reader2_, audio_reader2_);
     callback2_->SetCallback();
 
     std::cout << "SetUp()" << std::endl;
@@ -80,6 +84,8 @@ class EsInAppMultiViewTest : public ::testing::TestWithParam<std::string> {
     delete callback2_;
     delete video_reader1_;
     delete video_reader2_;
+    delete audio_reader1_;
+    delete audio_reader2_;
 
     std::cout << "TearDown()" << std::endl;
   }
@@ -88,6 +94,8 @@ class EsInAppMultiViewTest : public ::testing::TestWithParam<std::string> {
   std::string uri_;
   EsStreamReader* video_reader1_;
   EsStreamReader* video_reader2_;
+  EsStreamReader* audio_reader1_;
+  EsStreamReader* audio_reader2_;
   static esplusplayer_handle esplayer1_;
   static esplusplayer_handle esplayer2_;
   EsPlayerEventCallback* callback1_;
@@ -98,8 +106,7 @@ Environment* EsInAppMultiViewTest::window_ = nullptr;
 esplusplayer_handle EsInAppMultiViewTest::esplayer1_ = nullptr;
 esplusplayer_handle EsInAppMultiViewTest::esplayer2_ = nullptr;
 
-#if 0
-TEST_P(EsInAppMultiViewTest, vdapi_inappmultiview_esplusplayer_start_p_1) {
+TEST_P(EsInAppMultiViewTest, vdapi_inappmultiview_esplusplayer_set_resource_allocate_policy_no_explicit_p_1) {
   ASSERT_EQ(esplusplayer_open(esplayer1_), ESPLUSPLAYER_ERROR_TYPE_NONE);
   ASSERT_EQ(
       esplusplayer_set_display(esplayer1_, ESPLUSPLAYER_DISPLAY_TYPE_OVERLAY,
@@ -131,10 +138,147 @@ TEST_P(EsInAppMultiViewTest, vdapi_inappmultiview_esplusplayer_start_p_1) {
   ASSERT_EQ(esplusplayer_start(esplayer1_), ESPLUSPLAYER_ERROR_TYPE_NONE);
   ASSERT_EQ(esplusplayer_start(esplayer2_), ESPLUSPLAYER_ERROR_TYPE_NONE);
   std::this_thread::sleep_for(std::chrono::seconds(10));
+  std::cout << "EsInAppMultiViewTest, Play, END" << std::endl;
+}
+
+TEST_P(EsInAppMultiViewTest, vdapi_inappmultiview_esplusplayer_set_alternative_video_resource_no_explicit_n_1) {
+  ASSERT_EQ(esplusplayer_open(esplayer1_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_EQ(
+      esplusplayer_set_display(esplayer1_, ESPLUSPLAYER_DISPLAY_TYPE_OVERLAY,
+                               window_->Window()),
+      ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_EQ(esplusplayer_set_display_mode(esplayer1_,
+                                             ESPLUSPLAYER_DISPLAY_MODE_DST_ROI),
+            ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_EQ(esplusplayer_set_display_roi(esplayer1_,0,0,640,360), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_TRUE(video_reader1_->SetStreamInfo(esplayer1_));
+  ASSERT_EQ(esplusplayer_set_resource_allocate_policy(esplayer1_, ESPLUSPLAYER_RSC_ALLOC_EXCLUSIVE_NO_EXPLICIT), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_EQ(esplusplayer_set_alternative_video_resource(esplayer1_, 2), ESPLUSPLAYER_ERROR_TYPE_INVALID_OPERATION);
+  ASSERT_EQ(esplusplayer_prepare_async(esplayer1_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  callback1_->WaitForPrepareDone();
+
+  ASSERT_EQ(esplusplayer_start(esplayer1_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  std::this_thread::sleep_for(std::chrono::seconds(10));
+  std::cout << "EsInAppMultiViewTest, Play, END" << std::endl;
+}
+
+TEST_P(EsInAppMultiViewTest, vdapi_inappmultiview_esplusplayer_set_alternative_audio_resource_no_explicit_n_1) {
+  ASSERT_EQ(esplusplayer_open(esplayer1_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_TRUE(audio_reader1_->SetStreamInfo(esplayer1_));
+  ASSERT_EQ(esplusplayer_deactivate_audio(esplayer1_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_EQ(esplusplayer_set_resource_allocate_policy(esplayer1_, ESPLUSPLAYER_RSC_ALLOC_EXCLUSIVE_NO_EXPLICIT), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_EQ(esplusplayer_set_alternative_audio_resource(esplayer1_, ESPLUSPLAYER_AUDIO_RESOURCE_MAIN), ESPLUSPLAYER_ERROR_TYPE_INVALID_OPERATION);
+  ASSERT_EQ(esplusplayer_prepare_async(esplayer1_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  callback1_->WaitForPrepareDone();
+
+  ASSERT_EQ(esplusplayer_start(esplayer1_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  std::this_thread::sleep_for(std::chrono::seconds(5));
+  std::cout << "EsInAppMultiViewTest, Play, END" << std::endl;
+}
+
+TEST_P(EsInAppMultiViewTest, vdapi_inappmultiview_esplusplayer_set_audio_stream_info_n_1) {
+  esplusplayer_audio_stream_info audio_stream;
+  audio_stream.codec_data = nullptr;
+  audio_stream.codec_data_length = 0;
+  audio_stream.mime_type = ESPLUSPLAYER_AUDIO_MIME_TYPE_PCM_S16LE;
+  audio_stream.bitrate = 0;
+  audio_stream.sample_rate = 48000;
+  audio_stream.channels = 2;
+
+  ASSERT_EQ(esplusplayer_open(esplayer1_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_TRUE(audio_reader1_->SetStreamInfo(esplayer1_));
+  ASSERT_EQ(esplusplayer_deactivate_audio(esplayer1_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_EQ(esplusplayer_set_audio_stream_info(esplayer1_, &audio_stream), ESPLUSPLAYER_ERROR_TYPE_INVALID_OPERATION);
+  ASSERT_EQ(esplusplayer_prepare_async(esplayer1_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  callback1_->WaitForPrepareDone();
+
+  ASSERT_EQ(esplusplayer_open(esplayer2_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_TRUE(audio_reader2_->SetStreamInfo(esplayer2_));
+  ASSERT_EQ(esplusplayer_deactivate_audio(esplayer2_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_EQ(esplusplayer_prepare_async(esplayer2_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  callback2_->WaitForPrepareDone();
+
+  ASSERT_EQ(esplusplayer_start(esplayer1_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_EQ(esplusplayer_start(esplayer2_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_EQ(esplusplayer_activate_audio(esplayer2_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  std::this_thread::sleep_for(std::chrono::seconds(3));
+
+  ASSERT_EQ(esplusplayer_set_audio_stream_info(esplayer2_, &audio_stream), ESPLUSPLAYER_ERROR_TYPE_INVALID_OPERATION);
+  std::this_thread::sleep_for(std::chrono::seconds(10));
+  std::cout << "EsInAppMultiViewTest, Play, END" << std::endl;
+}
+
+TEST_P(EsInAppMultiViewTest, vdapi_inappmultiview_esplusplayer_audio_activate_p_1) {
+  ASSERT_EQ(esplusplayer_open(esplayer1_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_TRUE(audio_reader1_->SetStreamInfo(esplayer1_));
+  ASSERT_EQ(esplusplayer_deactivate_audio(esplayer1_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_EQ(esplusplayer_prepare_async(esplayer1_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  callback1_->WaitForPrepareDone();
+
+  ASSERT_EQ(esplusplayer_open(esplayer2_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_TRUE(audio_reader2_->SetStreamInfo(esplayer2_));
+  ASSERT_EQ(esplusplayer_deactivate_audio(esplayer2_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_EQ(esplusplayer_prepare_async(esplayer2_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  callback2_->WaitForPrepareDone();
+
+  ASSERT_EQ(esplusplayer_start(esplayer1_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_EQ(esplusplayer_start(esplayer2_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_EQ(esplusplayer_activate_audio(esplayer2_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  std::this_thread::sleep_for(std::chrono::seconds(3));
+
+  ASSERT_EQ(esplusplayer_deactivate_audio(esplayer2_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_EQ(esplusplayer_activate_audio(esplayer1_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  std::this_thread::sleep_for(std::chrono::seconds(10));
+  std::cout << "EsInAppMultiViewTest, Play, END" << std::endl;
+}
+
+TEST_P(EsInAppMultiViewTest, vdapi_inappmultiview_esplusplayer_audio_activate_p_2) {
+  ASSERT_EQ(esplusplayer_open(esplayer1_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_TRUE(audio_reader1_->SetStreamInfo(esplayer1_));
+  ASSERT_EQ(esplusplayer_deactivate_audio(esplayer1_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_EQ(esplusplayer_prepare_async(esplayer1_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  callback1_->WaitForPrepareDone();
+
+  ASSERT_EQ(esplusplayer_open(esplayer2_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_TRUE(audio_reader2_->SetStreamInfo(esplayer2_));
+  ASSERT_EQ(esplusplayer_deactivate_audio(esplayer2_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+
+  ASSERT_EQ(esplusplayer_start(esplayer1_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_EQ(esplusplayer_activate_audio(esplayer1_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_EQ(esplusplayer_prepare_async(esplayer2_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  callback2_->WaitForPrepareDone();
+
+  ASSERT_EQ(esplusplayer_start(esplayer2_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  std::this_thread::sleep_for(std::chrono::seconds(10));
+
+  std::cout << "EsInAppMultiViewTest, Play, END" << std::endl;
+}
+
+TEST_P(EsInAppMultiViewTest, vdapi_inappmultiview_esplusplayer_audio_activate_p_3) {
+  ASSERT_EQ(esplusplayer_open(esplayer1_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_TRUE(audio_reader1_->SetStreamInfo(esplayer1_));
+  ASSERT_EQ(esplusplayer_deactivate_audio(esplayer1_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_EQ(esplusplayer_prepare_async(esplayer1_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  callback1_->WaitForPrepareDone();
+
+  ASSERT_EQ(esplusplayer_open(esplayer2_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_TRUE(audio_reader2_->SetStreamInfo(esplayer2_));
+  ASSERT_EQ(esplusplayer_deactivate_audio(esplayer2_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+
+  ASSERT_EQ(esplusplayer_start(esplayer1_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_EQ(esplusplayer_activate_audio(esplayer1_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_EQ(esplusplayer_prepare_async(esplayer2_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  callback2_->WaitForPrepareDone();
+
+  ASSERT_EQ(esplusplayer_start(esplayer2_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  std::this_thread::sleep_for(std::chrono::seconds(5));
 
+  ASSERT_EQ(esplusplayer_deactivate_audio(esplayer1_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_EQ(esplusplayer_activate_audio(esplayer2_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  std::this_thread::sleep_for(std::chrono::seconds(7));
   std::cout << "EsInAppMultiViewTest, Play, END" << std::endl;
 }
-#endif
 
 INSTANTIATE_TEST_CASE_P(ESPlusplayer, EsInAppMultiViewTest,
                         ::testing::ValuesIn(es_tc::inapp_multiview_tc_list));
\ No newline at end of file