Ver código fonte

添加绘本合成,整理代码

hwh97 5 anos atrás
pai
commit
f7aeeef8b4

+ 132 - 65
.idea/workspace.xml

@@ -2,37 +2,7 @@
 <project version="4">
   <component name="ChangeListManager">
     <list default="true" id="96a4f947-f66a-4efc-b495-ae979b3315bb" name="Default Changelist" comment="">
-      <change beforePath="$PROJECT_DIR$/.idea/codeStyles/Project.xml" beforeDir="false" />
-      <change beforePath="$PROJECT_DIR$/.idea/libraries/Dart_SDK.xml" beforeDir="false" />
-      <change beforePath="$PROJECT_DIR$/.idea/libraries/Flutter_Plugins.xml" beforeDir="false" />
-      <change beforePath="$PROJECT_DIR$/.idea/libraries/Flutter_for_Android.xml" beforeDir="false" />
-      <change beforePath="$PROJECT_DIR$/.idea/misc.xml" beforeDir="false" />
-      <change beforePath="$PROJECT_DIR$/.idea/modules.xml" beforeDir="false" />
-      <change beforePath="$PROJECT_DIR$/.idea/runConfigurations/example_lib_main_dart.xml" beforeDir="false" />
-      <change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" />
-      <change beforePath="$PROJECT_DIR$/android/.gitignore" beforeDir="false" />
-      <change beforePath="$PROJECT_DIR$/android/.idea/.name" beforeDir="false" />
-      <change beforePath="$PROJECT_DIR$/android/.idea/codeStyles/Project.xml" beforeDir="false" />
-      <change beforePath="$PROJECT_DIR$/android/.idea/dictionaries/hwhong.xml" beforeDir="false" />
-      <change beforePath="$PROJECT_DIR$/android/.idea/gradle.xml" beforeDir="false" />
-      <change beforePath="$PROJECT_DIR$/android/.idea/kotlinc.xml" beforeDir="false" />
-      <change beforePath="$PROJECT_DIR$/android/.idea/misc.xml" beforeDir="false" />
-      <change beforePath="$PROJECT_DIR$/android/.idea/modules.xml" beforeDir="false" />
-      <change beforePath="$PROJECT_DIR$/android/.idea/runConfigurations.xml" beforeDir="false" />
-      <change beforePath="$PROJECT_DIR$/android/.idea/vcs.xml" beforeDir="false" />
-      <change beforePath="$PROJECT_DIR$/android/gradle/wrapper/gradle-wrapper.properties" beforeDir="false" />
-      <change beforePath="$PROJECT_DIR$/dubbing_lib.iml" beforeDir="false" afterPath="$PROJECT_DIR$/dubbing_lib.iml" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/example/ios/Flutter/Debug.xcconfig" beforeDir="false" afterPath="$PROJECT_DIR$/example/ios/Flutter/Debug.xcconfig" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/example/ios/Flutter/Release.xcconfig" beforeDir="false" afterPath="$PROJECT_DIR$/example/ios/Flutter/Release.xcconfig" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/example/ios/Runner.xcodeproj/project.pbxproj" beforeDir="false" afterPath="$PROJECT_DIR$/example/ios/Runner.xcodeproj/project.pbxproj" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/example/ios/Runner.xcworkspace/contents.xcworkspacedata" beforeDir="false" afterPath="$PROJECT_DIR$/example/ios/Runner.xcworkspace/contents.xcworkspacedata" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/example/ios/Runner/Info.plist" beforeDir="false" afterPath="$PROJECT_DIR$/example/ios/Runner/Info.plist" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/example/ios/Runner/Runner-Bridging-Header.h" beforeDir="false" afterPath="$PROJECT_DIR$/example/ios/Runner/Runner-Bridging-Header.h" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/example/lib/main.dart" beforeDir="false" afterPath="$PROJECT_DIR$/example/lib/main.dart" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/example/pubspec.lock" beforeDir="false" afterPath="$PROJECT_DIR$/example/pubspec.lock" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/example/pubspec.yaml" beforeDir="false" afterPath="$PROJECT_DIR$/example/pubspec.yaml" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/lib/dubbing_lib.dart" beforeDir="false" afterPath="$PROJECT_DIR$/lib/dubbing_lib.dart" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/pubspec.lock" beforeDir="false" />
+      <change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
     </list>
     <ignored path="$PROJECT_DIR$/.dart_tool/" />
     <ignored path="$PROJECT_DIR$/.idea/" />
@@ -49,30 +19,47 @@
   <component name="DefaultGradleProjectSettings">
     <option name="isMigrated" value="true" />
   </component>
-  <component name="ExecutionTargetManager" SELECTED_TARGET="Nexus_5X_API_29_x86" />
   <component name="FileEditorManager">
     <leaf SIDE_TABS_SIZE_LIMIT_KEY="300">
-      <file pinned="false" current-in-tab="false">
+      <file pinned="false" current-in-tab="true">
         <entry file="file://$PROJECT_DIR$/lib/dubbing_lib.dart">
           <provider selected="true" editor-type-id="text-editor">
-            <state relative-caret-position="213">
-              <caret line="65" column="41" selection-start-line="65" selection-start-column="41" selection-end-line="65" selection-end-column="41" />
+            <state relative-caret-position="537">
+              <caret line="95" column="26" selection-start-line="95" selection-end-line="96" />
             </state>
           </provider>
         </entry>
       </file>
-      <file pinned="false" current-in-tab="true">
-        <entry file="file://$PROJECT_DIR$/example/lib/main.dart">
+      <file pinned="false" current-in-tab="false">
+        <entry file="file://$PROJECT_DIR$/android/src/main/kotlin/cn/i2edu/dubbing_lib/DubbingLibPlugin.kt">
           <provider selected="true" editor-type-id="text-editor">
-            <state relative-caret-position="690">
-              <caret line="46" column="1" selection-start-line="46" selection-start-column="1" selection-end-line="46" selection-end-column="1" />
+            <state relative-caret-position="720">
+              <caret line="60" column="65" selection-start-line="60" selection-start-column="54" selection-end-line="60" selection-end-column="65" />
               <folding>
-                <element signature="e#0#39#0" expanded="true" />
+                <element signature="e#10138#11757#0" />
               </folding>
             </state>
           </provider>
         </entry>
       </file>
+      <file pinned="false" current-in-tab="false">
+        <entry file="file://$PROJECT_DIR$/android/src/main/kotlin/cn/i2edu/dubbing_lib/audioUtils/compose/AudioComposer.java">
+          <provider selected="true" editor-type-id="text-editor">
+            <state relative-caret-position="2700">
+              <caret line="142" column="52" selection-start-line="142" selection-start-column="32" selection-end-line="142" selection-end-column="52" />
+            </state>
+          </provider>
+        </entry>
+      </file>
+      <file pinned="false" current-in-tab="false">
+        <entry file="file://$PROJECT_DIR$/android/src/main/kotlin/cn/i2edu/dubbing_lib/audioUtils/compose/FileFunction.java">
+          <provider selected="true" editor-type-id="text-editor">
+            <state relative-caret-position="780">
+              <caret line="45" column="62" selection-start-line="45" selection-start-column="35" selection-end-line="45" selection-end-column="62" />
+            </state>
+          </provider>
+        </entry>
+      </file>
     </leaf>
   </component>
   <component name="FindInProjectRecents">
@@ -87,6 +74,14 @@
       <find>startMixinAudio</find>
       <find>videoPath</find>
       <find>content</find>
+      <find>decodeResult</find>
+      <find>pathBgmDecodeDir</find>
+      <find>fileName</find>
+      <find>doDecode</find>
+      <find>GetFileOutputStreamFromFile</find>
+      <find>composeAudioFilePath</find>
+      <find>secondAudioFilePaths</find>
+      <find>audioDecodePaths</find>
     </findStrings>
   </component>
   <component name="Git.Settings">
@@ -103,11 +98,11 @@
       </list>
     </option>
   </component>
-  <component name="ProjectFrameBounds" extendedState="6">
-    <option name="x" value="602" />
-    <option name="y" value="184" />
-    <option name="width" value="1305" />
-    <option name="height" value="781" />
+  <component name="ProjectFrameBounds">
+    <option name="x" value="395" />
+    <option name="y" value="42" />
+    <option name="width" value="1346" />
+    <option name="height" value="955" />
   </component>
   <component name="ProjectLevelVcsManager" settingsEditedManually="true" />
   <component name="ProjectView">
@@ -115,8 +110,6 @@
       <foldersAlwaysOnTop value="true" />
     </navigator>
     <panes>
-      <pane id="PackagesPane" />
-      <pane id="Scope" />
       <pane id="ProjectPane">
         <subPane>
           <expand>
@@ -132,13 +125,32 @@
             <path>
               <item name="dubbing_lib" type="b2602c69:ProjectViewProjectNode" />
               <item name="dubbing_lib" type="462c0819:PsiDirectoryNode" />
-              <item name="example" type="462c0819:PsiDirectoryNode" />
+              <item name="android" type="462c0819:PsiDirectoryNode" />
+              <item name="main" type="462c0819:PsiDirectoryNode" />
             </path>
             <path>
               <item name="dubbing_lib" type="b2602c69:ProjectViewProjectNode" />
               <item name="dubbing_lib" type="462c0819:PsiDirectoryNode" />
-              <item name="example" type="462c0819:PsiDirectoryNode" />
-              <item name="lib" type="462c0819:PsiDirectoryNode" />
+              <item name="android" type="462c0819:PsiDirectoryNode" />
+              <item name="main" type="462c0819:PsiDirectoryNode" />
+              <item name="dubbing_lib" type="462c0819:PsiDirectoryNode" />
+            </path>
+            <path>
+              <item name="dubbing_lib" type="b2602c69:ProjectViewProjectNode" />
+              <item name="dubbing_lib" type="462c0819:PsiDirectoryNode" />
+              <item name="android" type="462c0819:PsiDirectoryNode" />
+              <item name="main" type="462c0819:PsiDirectoryNode" />
+              <item name="dubbing_lib" type="462c0819:PsiDirectoryNode" />
+              <item name="audioUtils" type="462c0819:PsiDirectoryNode" />
+            </path>
+            <path>
+              <item name="dubbing_lib" type="b2602c69:ProjectViewProjectNode" />
+              <item name="dubbing_lib" type="462c0819:PsiDirectoryNode" />
+              <item name="android" type="462c0819:PsiDirectoryNode" />
+              <item name="main" type="462c0819:PsiDirectoryNode" />
+              <item name="dubbing_lib" type="462c0819:PsiDirectoryNode" />
+              <item name="audioUtils" type="462c0819:PsiDirectoryNode" />
+              <item name="compose" type="462c0819:PsiDirectoryNode" />
             </path>
             <path>
               <item name="dubbing_lib" type="b2602c69:ProjectViewProjectNode" />
@@ -149,6 +161,8 @@
           <select />
         </subPane>
       </pane>
+      <pane id="PackagesPane" />
+      <pane id="Scope" />
     </panes>
   </component>
   <component name="PropertiesComponent">
@@ -190,10 +204,9 @@
     <servers />
   </component>
   <component name="ToolWindowManager">
-    <frame x="0" y="23" width="1920" height="977" extended-state="6" />
-    <editor active="true" />
+    <frame x="395" y="42" width="1346" height="955" extended-state="0" />
     <layout>
-      <window_info active="true" content_ui="combo" id="Project" order="0" visible="true" weight="0.16134185" />
+      <window_info active="true" content_ui="combo" id="Project" order="0" visible="true" weight="0.21073096" />
       <window_info id="Captures" order="1" side_tool="true" />
       <window_info id="Structure" order="2" side_tool="true" />
       <window_info id="Image Layers" order="3" />
@@ -208,10 +221,10 @@
       <window_info anchor="bottom" id="Android Profiler" order="3" show_stripe_button="false" />
       <window_info anchor="bottom" id="Logcat" order="4" />
       <window_info anchor="bottom" id="Debug" order="5" />
-      <window_info anchor="bottom" id="Terminal" order="6" visible="true" weight="0.2259887" />
+      <window_info anchor="bottom" id="Terminal" order="6" weight="0.18743229" />
       <window_info anchor="bottom" id="Event Log" order="7" side_tool="true" />
       <window_info anchor="bottom" id="Flutter Performance" order="8" side_tool="true" />
-      <window_info anchor="bottom" id="Version Control" order="9" />
+      <window_info anchor="bottom" id="Version Control" order="9" visible="true" weight="0.37028015" />
       <window_info anchor="bottom" id="Messages" order="10" visible="true" weight="0.329718" />
       <window_info anchor="right" id="Device File Explorer" order="0" side_tool="true" />
       <window_info anchor="right" id="Capture Analysis" order="1" />
@@ -221,6 +234,46 @@
       <window_info anchor="right" id="Palette&#9;" order="5" />
     </layout>
   </component>
+  <component name="Vcs.Log.Tabs.Properties">
+    <option name="TAB_STATES">
+      <map>
+        <entry key="MAIN">
+          <value>
+            <State>
+              <option name="RECENTLY_FILTERED_USER_GROUPS">
+                <collection />
+              </option>
+              <option name="RECENTLY_FILTERED_BRANCH_GROUPS">
+                <collection />
+              </option>
+              <option name="COLUMN_ORDER">
+                <list>
+                  <option value="0" />
+                  <option value="1" />
+                  <option value="2" />
+                  <option value="3" />
+                </list>
+              </option>
+            </State>
+          </value>
+        </entry>
+      </map>
+    </option>
+    <option name="RECENT_FILTERS">
+      <map>
+        <entry key="Branch">
+          <value>
+            <list />
+          </value>
+        </entry>
+        <entry key="User">
+          <value>
+            <list />
+          </value>
+        </entry>
+      </map>
+    </option>
+  </component>
   <component name="editorHistoryManager">
     <entry file="file://C:/flutter/flutter_windows_v1.9.1+hotfix.4-stable/flutter/packages/flutter/lib/src/services/platform_channel.dart" />
     <entry file="file://C:/flutter/flutter_windows_v1.9.1+hotfix.4-stable/flutter/bin/cache/pkg/sky_engine/lib/async/stream_controller.dart" />
@@ -260,32 +313,46 @@
         </state>
       </provider>
     </entry>
-    <entry file="file://$PROJECT_DIR$/android/src/main/kotlin/cn/i2edu/dubbing_lib/DubbingLibPlugin.kt">
+    <entry file="file://$PROJECT_DIR$/example/lib/main.dart">
       <provider selected="true" editor-type-id="text-editor">
-        <state relative-caret-position="166">
-          <caret line="281" column="16" lean-forward="true" selection-start-line="281" selection-start-column="16" selection-end-line="281" selection-end-column="16" />
+        <state relative-caret-position="690">
+          <caret line="46" column="1" selection-start-line="46" selection-start-column="1" selection-end-line="46" selection-end-column="1" />
           <folding>
-            <element signature="e#10138#11757#0" />
+            <element signature="e#0#39#0" expanded="true" />
           </folding>
         </state>
       </provider>
     </entry>
     <entry file="file://$PROJECT_DIR$/lib/dubbing_lib.dart">
       <provider selected="true" editor-type-id="text-editor">
-        <state relative-caret-position="213">
-          <caret line="65" column="41" selection-start-line="65" selection-start-column="41" selection-end-line="65" selection-end-column="41" />
+        <state relative-caret-position="537">
+          <caret line="95" column="26" selection-start-line="95" selection-end-line="96" />
         </state>
       </provider>
     </entry>
-    <entry file="file://$PROJECT_DIR$/example/lib/main.dart">
+    <entry file="file://$PROJECT_DIR$/android/src/main/kotlin/cn/i2edu/dubbing_lib/DubbingLibPlugin.kt">
       <provider selected="true" editor-type-id="text-editor">
-        <state relative-caret-position="690">
-          <caret line="46" column="1" selection-start-line="46" selection-start-column="1" selection-end-line="46" selection-end-column="1" />
+        <state relative-caret-position="720">
+          <caret line="60" column="65" selection-start-line="60" selection-start-column="54" selection-end-line="60" selection-end-column="65" />
           <folding>
-            <element signature="e#0#39#0" expanded="true" />
+            <element signature="e#10138#11757#0" />
           </folding>
         </state>
       </provider>
     </entry>
+    <entry file="file://$PROJECT_DIR$/android/src/main/kotlin/cn/i2edu/dubbing_lib/audioUtils/compose/AudioComposer.java">
+      <provider selected="true" editor-type-id="text-editor">
+        <state relative-caret-position="2700">
+          <caret line="142" column="52" selection-start-line="142" selection-start-column="32" selection-end-line="142" selection-end-column="52" />
+        </state>
+      </provider>
+    </entry>
+    <entry file="file://$PROJECT_DIR$/android/src/main/kotlin/cn/i2edu/dubbing_lib/audioUtils/compose/FileFunction.java">
+      <provider selected="true" editor-type-id="text-editor">
+        <state relative-caret-position="780">
+          <caret line="45" column="62" selection-start-line="45" selection-start-column="35" selection-end-line="45" selection-end-column="62" />
+        </state>
+      </provider>
+    </entry>
   </component>
 </project>

BIN
android/.idea/caches/build_file_checksums.ser


+ 259 - 437
android/src/main/kotlin/cn/i2edu/dubbing_lib/DubbingLibPlugin.kt

@@ -5,17 +5,12 @@ import android.app.Activity
 import android.media.MediaPlayer
 import android.media.MediaRecorder
 import android.os.Build
-import android.os.Handler
-import android.os.Message
 import android.text.TextUtils
 import android.view.View
 import cn.i2edu.dubbing_lib.audioUtils.AudioDecoder
 import cn.i2edu.dubbing_lib.audioUtils.AudioEncoder
-import cn.i2edu.dubbing_lib.audioUtils.VideoAudioMixer
 import cn.i2edu.dubbing_lib.audioUtils.compose.AudioComposer
-import cn.i2edu.dubbing_lib.bean.VideoData
-import cn.i2edu.dubbing_lib.callback.MixinHandlerCallback
-import cn.i2edu.dubbing_lib.util.PausableThreadPool
+import cn.i2edu.dubbing_lib.util.*
 import io.flutter.plugin.common.MethodCall
 import io.flutter.plugin.common.MethodChannel
 import io.flutter.plugin.common.MethodChannel.MethodCallHandler
@@ -23,474 +18,301 @@ import io.flutter.plugin.common.MethodChannel.Result
 import io.flutter.plugin.common.PluginRegistry.Registrar
 import java.io.File
 import java.io.IOException
-import java.lang.ref.WeakReference
 import java.util.*
 
-class DubbingLibPlugin: MethodCallHandler, MixinHandlerCallback {
+class DubbingLibPlugin : MethodCallHandler {
 
-  private val activity: Activity
-  private var mediaRecorder: MediaRecorder? = null
-  private var mediaPlayer: MediaPlayer? = null
-  private var isRecording: Boolean = false
-  private var timer: Timer? = null
-  private val pausableThreadPool: PausableThreadPool = PausableThreadPool(1)
-  private val mixinHandler: MixinHandler = MixinHandler(this)
-  private var mixinResult: Result? = null
-  private var videoData: VideoData? = null
-  private var videoAudioMixer: VideoAudioMixer? = null
-  private val Tag: String = "DubbingPlugin"
-  // mix in 时用到的目录
-  private var pathBgmDecodeDir: String? = null
-  private var pathBgmRecordSyncDir: String? = null
-  private var pathBgmRecordDecodeSyncDir: String? = null
-  private var pathVideoMixinDir: String? = null
+    private val activity: Activity
+    private var mediaRecorder: MediaRecorder? = null
+    private var mediaPlayer: MediaPlayer? = null
+    private var isRecording: Boolean = false
+    private var timer: Timer? = null
+    private val pausableThreadPool: PausableThreadPool = PausableThreadPool(1)
+    private val Tag: String = "DubbingPlugin"
 
-  companion object {
-    
-    private lateinit var channel: MethodChannel
-    val CHANNEL_NAME = "cn.hwwwwh.flutter.plugins/DubbingPlugin"
-    private val BGM_DOWNLOAD_FINISHED = 0X3999
-    private val AUDIO_SYN_FINISHED = 0X4001
-    private val AUDIO_MIX_VIDIO_FINISHED = 0X4002
-    private val AUDIO_DECODE_FINISHED = 0x4003
-    private val AUDIO_ENCODE_FINISHED = 0x4004
-    
-    @JvmStatic
-    fun registerWith(registrar: Registrar) {
-      if (registrar.activity() == null) return
-      channel = MethodChannel(registrar.messenger(), "dubbing_lib")
-      channel.setMethodCallHandler(DubbingLibPlugin(registrar.activity()))
-    }
+    companion object {
 
-    private class MixinHandler(plugin: DubbingLibPlugin): Handler() {
-      private val plugin: WeakReference<DubbingLibPlugin> = WeakReference(plugin)
+        private lateinit var channel: MethodChannel
+        val CHANNEL_NAME = "cn.hwwwwh.flutter.plugins/DubbingPlugin"
 
-      override fun handleMessage(msg: Message) {
-        if (plugin.get() != null) {
-          plugin.get()?.onHandleMessage(msg)
+        @JvmStatic
+        fun registerWith(registrar: Registrar) {
+            if (registrar.activity() == null) return
+            channel = MethodChannel(registrar.messenger(), "dubbing_lib")
+            channel.setMethodCallHandler(DubbingLibPlugin(registrar.activity()))
         }
-      }
     }
-  }
-
-  @SuppressLint("CheckResult")
-  constructor(activity: Activity) {
-    this.activity = activity
-  }
 
-  override fun onMethodCall(call: MethodCall, result: Result) {
-    when (call.method) {
-      "getPlatformVersion" -> result.success("Android ${android.os.Build.VERSION.RELEASE}")
-      "setExtraFullScreen" -> {
-        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
-          activity.window.decorView.systemUiVisibility = activity.window.decorView.systemUiVisibility.or(View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY)
-        }
-      }
-      "startRecord" -> {
-        val duration = call.argument<Int>("duration")!!
-        val fileName = call.argument<String>("fileName")!!
-        val index = call.argument<Int>("index")!!
-        val pathAudio = call.argument<String>("pathAudio")!!
-        val pathAudioDecode = call.argument<String>("pathAudioDecode")!!
-        // 开启录音
-        initMediaRecorder(pathAudio, pathAudioDecode, index, duration, fileName, result)
-      }
-      "playRecordAudio" -> {
-        val fileName = call.argument<String>("fileName")!!
-        playRecord(fileName, result)
-      }
-      "pauseRecordAudio" -> {
-        mediaPlayer?.pause()
-        result.success(true)
-      }
-      "getIsMediaPlayPause" -> {
-        result.success(mediaPlayer != null && !mediaPlayer!!.isPlaying)
-      }
-      "cleanAudioData" -> {
-        try {
-          // 取得 video id, 根据前缀进行删除操作
-          val videoId = call.argument<String>("videoId")!!
-          val pathAudio = call.argument<String>("pathAudio")!!
-          val pathAudioDecode = call.argument<String>("pathAudioDecode")!!
-          deleteFileWithPrefix(videoId, pathAudio)
-          deleteFileWithPrefix(videoId, pathAudioDecode)
-          result.success(true)
-        } catch (e: Exception){
-          e.printStackTrace()
-          result.error("1003", "clean cache file failed", null)
-        }
-      }
-      "startMixinAudio" -> {
-        try {
-          videoData = VideoData(
-                  videoId = call.argument<String>("videoId")!!,
-                  bgmUrl = call.argument<String>("bgmUrl")!!,
-                  durationList = call.argument<List<Long>>("durationList")!!,
-                  endTimeList = call.argument<List<Long>>("endTimeList")!!,
-                  audioDecodePaths =  call.argument<List<String>>("audioDecodePaths")!!,
-                  videoPath = call.argument<String>("videoPath")!!
-          )
-          videoData!!.bgmPath = call.argument<String>("bgmPath")!!
-          pathBgmDecodeDir = call.argument<String>("pathBgmDecode")!!
-          pathBgmRecordSyncDir = call.argument<String>("pathBgmRecordSync")!!
-          pathBgmRecordDecodeSyncDir = call.argument<String>("pathBgmRecordDecodeSync")!!
-          pathVideoMixinDir = call.argument<String>("pathVideoMixin")!!
+    @SuppressLint("CheckResult")
+    constructor(activity: Activity) {
+        this.activity = activity
+    }
 
-          mixinResult = result
-          startMixinAudio()
-        } catch (e: Exception){
-          e.printStackTrace()
-          result.error("1005", "mixin audio failed", null)
+    override fun onMethodCall(call: MethodCall, result: Result) {
+        when (call.method) {
+            "getPlatformVersion" -> result.success("Android ${android.os.Build.VERSION.RELEASE}")
+            "setExtraFullScreen" -> {
+                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
+                    activity.window.decorView.systemUiVisibility = activity.window.decorView.systemUiVisibility.or(View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY)
+                }
+            }
+            "startRecord" -> {
+                val duration = call.argument<Int>("duration")!!
+                val fileName = call.argument<String>("fileName")!!
+                val index = call.argument<Int>("index")!!
+                val pathAudio = call.argument<String>("pathAudio")!!
+                val pathAudioDecode = call.argument<String>("pathAudioDecode")!!
+                // 开启录音
+                initMediaRecorder(pathAudio, pathAudioDecode, index, duration, fileName, result)
+            }
+            "playRecordAudio" -> {
+                val fileName = call.argument<String>("fileName")!!
+                playRecord(fileName, result)
+            }
+            "pauseRecordAudio" -> {
+                mediaPlayer?.pause()
+                result.success(true)
+            }
+            "getIsMediaPlayPause" -> {
+                result.success(mediaPlayer != null && !mediaPlayer!!.isPlaying)
+            }
+            "cleanAudioData" -> {
+                try {
+                    // 取得 video id, 根据前缀进行删除操作
+                    val videoId = call.argument<String>("videoId")!!
+                    val pathAudio = call.argument<String>("pathAudio")!!
+                    val pathAudioDecode = call.argument<String>("pathAudioDecode")!!
+                    deleteFileWithPrefix(videoId, pathAudio)
+                    deleteFileWithPrefix(videoId, pathAudioDecode)
+                    result.success(true)
+                } catch (e: Exception) {
+                    e.printStackTrace()
+                    result.error("1003", "clean cache file failed", null)
+                }
+            }
+            "startMixinAudio" -> {
+                try {
+                    MixinVideoUtil.getInstance(context = activity.applicationContext)
+                            .initParams(videoId = call.argument<String>("videoId")!!, bgmPath = call.argument<String>("bgmPath")!!,
+                                    videoPath = call.argument<String>("videoPath")!!, durationList = call.argument<List<Long>>("durationList")!!,
+                                    endTimeList = call.argument<List<Long>>("endTimeList")!!, audioDecodePaths = call.argument<List<String>>("audioDecodePaths")!!,
+                                    pathBgmDecodeDir = call.argument<String>("pathBgmDecode")!!, pathBgmRecordSyncDir = call.argument<String>("pathBgmRecordSync")!!,
+                                    pathBgmRecordDecodeSyncDir = call.argument<String>("pathBgmRecordDecodeSync")!!, pathVideoMixinDir = call.argument<String>("pathVideoMixin")!!)
+                            .setComposeCallBack(
+                                    object: MixinVideoCallBack {
+                                        override fun onResult(resultPath: String) {
+                                            activity.runOnUiThread {
+                                                result.success(resultPath)
+                                            }
+                                        }
+
+                                        override fun onError(message: String) {
+                                            activity.runOnUiThread {
+                                                result.error("1005", "message", null)
+                                            }
+                                        }
+                                    }
+                            )
+                            .startMixin()
+                } catch (e: Exception) {
+                    e.printStackTrace()
+                    result.error("1005", "mixin audio failed", null)
+                }
+            }
+            "startMixinPaintedAudio" -> {
+                try {
+                    MixinPaintedUtil.getInstance(context = activity.applicationContext)
+                            .initParams(audioPaths = call.argument<List<String>>("audioPaths")!!, bgmPath = call.argument<String>("bgmPath")!!,
+                                    durationList = call.argument<List<Long>>("durationList")!!, endTimeList = call.argument<List<Long>>("endTimeList")!!,
+                                    audioDecodePath = call.argument<String>("audioDecodePath")!!, mixinFilePath = call.argument<String>("mixinFilePath")!!,
+                                    encodePath = call.argument<String>("encodePath")!!)
+                            .setComposeCallBack(
+                                    object: MixinPaintedCallBack {
+                                        override fun onResult(resultPath: String) {
+                                            activity.runOnUiThread {
+                                                result.success(resultPath)
+                                            }
+                                        }
+
+                                        override fun onError(message: String) {
+                                            activity.runOnUiThread {
+                                                result.error("1005", "message", null)
+                                            }
+                                        }
+                                    }
+                            )
+                            .startMixin()
+                } catch (e: Exception) {
+                    e.printStackTrace()
+                    result.error("1006", "mixin painted failed", null)
+                }
+            }
+            else -> result.notImplemented()
         }
-      }
-      else -> result.notImplemented()
     }
-  }
 
-  private fun initMediaRecorder(pathAudio: String, pathAudioDecode: String,
-                                index: Int, duration: Int, fileName: String, result: Result) {
-    // create file
-    stopRecord()
-    // config media recorder
-    if (mediaRecorder == null) {
-      mediaRecorder = MediaRecorder()
-      mediaRecorder?.setAudioSource(MediaRecorder.AudioSource.MIC)
-      mediaRecorder?.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4)// 设置所录制的音视频文件的格式
-      mediaRecorder?.setAudioEncoder(MediaRecorder.AudioEncoder.AAC)// 设置所录制的声音的编码格式
-      mediaRecorder?.setAudioEncodingBitRate(96000)// 比特率
-      mediaRecorder?.setAudioChannels(2)// 通道
-      mediaRecorder?.setAudioSamplingRate(44100)// 采样率
+    private fun initMediaRecorder(pathAudio: String, pathAudioDecode: String,
+                                  index: Int, duration: Int, fileName: String, result: Result) {
+        // create file
+        stopRecord()
+        // config media recorder
+        if (mediaRecorder == null) {
+            mediaRecorder = MediaRecorder()
+            mediaRecorder?.setAudioSource(MediaRecorder.AudioSource.MIC)
+            mediaRecorder?.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4)// 设置所录制的音视频文件的格式
+            mediaRecorder?.setAudioEncoder(MediaRecorder.AudioEncoder.AAC)// 设置所录制的声音的编码格式
+            mediaRecorder?.setAudioEncodingBitRate(96000)// 比特率
+            mediaRecorder?.setAudioChannels(2)// 通道
+            mediaRecorder?.setAudioSamplingRate(44100)// 采样率
+        }
+        // start record
+        startRecord(pathAudio, pathAudioDecode, index, duration, fileName, result)
     }
-    // start record
-    startRecord(pathAudio, pathAudioDecode, index, duration, fileName, result)
-  }
 
-  private fun startRecord(pathAudio: String, pathAudioDecode: String, index: Int, duration: Int, fileName: String, result: Result) {
-    if (mediaRecorder == null) return
-    val filePath = pathAudio + fileName
-    try {
-      mediaRecorder?.setOutputFile(filePath)
-      mediaRecorder?.prepare()
-      isRecording = true
-      mediaRecorder?.start()
-    } catch (e: IOException) {
-      e.printStackTrace()
-      isRecording = false
-    }
-    if (isRecording) {
-      var piecePosition = 0
-      if (timer != null) {
-        timer?.cancel()
-      }
-      timer = Timer()
-      // 这里参照少儿英语秀之前的逻辑
-      timer?.schedule(object : TimerTask() {
-        override fun run() {
-          activity.runOnUiThread {
+    private fun startRecord(pathAudio: String, pathAudioDecode: String, index: Int, duration: Int, fileName: String, result: Result) {
+        if (mediaRecorder == null) return
+        val filePath = pathAudio + fileName
+        try {
+            mediaRecorder?.setOutputFile(filePath)
+            mediaRecorder?.prepare()
             isRecording = true
-            piecePosition++
-            // 传递进度
-            channel.invokeMethod("recordProgress", mapOf("progress" to piecePosition * 5))
-            while (piecePosition * 5 >= duration) {
-              // 录制完毕
-              try {
-                result.success(filePath)
-              } catch (e: Exception) {
-                e.printStackTrace()
-              } finally {
+            mediaRecorder?.start()
+        } catch (e: IOException) {
+            e.printStackTrace()
+            isRecording = false
+        }
+        if (isRecording) {
+            var piecePosition = 0
+            if (timer != null) {
                 timer?.cancel()
-                stopRecord()
-                // 解码音频
-                Thread {
-                  decodeRecord(pathAudioDecode, index, fileName, filePath)
-                }.start()
-              }
-              break
             }
-          }
-        }
-      }, 0, 5)
-    } else {
-      result.error("1002", "start record failed", null)
-    }
-  }
-
-  private fun decodeRecord(pathAudioDecode: String, index: Int, fileName: String, recordPath: String) {
-    val decodePath = doDecode(fileName, recordPath, pathAudioDecode)
-    if (decodePath != null && File(decodePath).exists()) {
-      // 解码成功
-      activity.runOnUiThread {
-        channel.invokeMethod("decodeResult", mapOf("index" to index, "path" to decodePath))
-      }
-    } else {
-      // 解码失败
-      activity.runOnUiThread {
-        channel.invokeMethod("decodeResult", mapOf("index" to index, "path" to ""))
-      }
-    }
-  }
-
-  private fun stopRecord() {
-    try {
-      mediaRecorder?.stop()
-    } catch (e: Exception) {
-      // TODO from i2 dubit
-      // 这里有可能会抛出两种异常,一种是IllegalStateException,抛出这种异常是由于在没有start的情况下使用了stop
-      // 另外一种是RuntimeException, 这种异常的产生原因是在执行了start()过后马上执行stop(),具体可看mRecorder.stop()的源码注释
-      e.printStackTrace()
-    } finally {
-      isRecording = false
-      try {
-        mediaRecorder?.reset()
-        mediaRecorder?.release()
-        mediaRecorder = null
-      } catch (e: Exception) {
-        e.printStackTrace()
-      }
-    }
-  }
-
-  private fun playRecord(fileName: String, result: Result) {
-    resetMediaPlayer()
-    mediaPlayer = MediaPlayer()
-    mediaPlayer?.setDataSource(fileName)
-    mediaPlayer?.prepare()
-    mediaPlayer?.start()
-
-    mediaPlayer?.setOnCompletionListener {
-      resetMediaPlayer()
-      // 播放完成
-      result.success(true)
-    }
-  }
-
-  private fun resetMediaPlayer() {
-    mediaPlayer?.stop()
-    mediaPlayer?.release()
-    mediaPlayer = null
-  }
-
-  @Throws(Exception::class)
-  private fun deleteFileWithPrefix(video: String, path: String): Boolean {
-    val file = File(path)
-    if (!file.exists()) return false
-    // 取得所有文件
-    val files = file.listFiles()
-    if (files == null || files.isEmpty()) return false
-    for (fileExist in files) {
-      if (fileExist.isFile) {
-        // 验证文件名
-        if (fileExist.name.startsWith("${video}_")) {
-          fileExist.delete()
+            timer = Timer()
+            // 这里参照少儿英语秀之前的逻辑
+            timer?.schedule(object : TimerTask() {
+                override fun run() {
+                    activity.runOnUiThread {
+                        isRecording = true
+                        piecePosition++
+                        // 传递进度
+                        channel.invokeMethod("recordProgress", mapOf("progress" to piecePosition * 5))
+                        while (piecePosition * 5 >= duration) {
+                            // 录制完毕
+                            try {
+                                result.success(filePath)
+                            } catch (e: Exception) {
+                                e.printStackTrace()
+                            } finally {
+                                timer?.cancel()
+                                stopRecord()
+                                // 解码音频
+                                Thread {
+                                    decodeRecord(pathAudioDecode, index, fileName, filePath)
+                                }.start()
+                            }
+                            break
+                        }
+                    }
+                }
+            }, 0, 5)
+        } else {
+            result.error("1002", "start record failed", null)
         }
-      }
     }
-    return true
-  }
-
-/*  @Throws(Exception::class)
-  private fun getExistCache(video: String, pathAudio: String, pathAudioDecode: String): Map<Int, String> {
-    val map = hashMapOf<Int, String>()
 
-    // 取得所有文件
-    val file = File(pathAudio)
-    if (!file.exists()) return map
-    val files = file.listFiles()
-    if (files == null || files.isEmpty()) return map
-
-    // 取得所有文件(这里取decode的文件)
-    val decodeFile = File(pathAudioDecode)
-    if (!decodeFile.exists()) return map
-    val decodeFiles = decodeFile.listFiles()
-    if (decodeFiles == null || decodeFiles.isEmpty()) return map
-
-    for (i in 0 until files.size) {
-      val fileExist = files[i]
-      if (fileExist.isFile) {
-        // 验证文件名
-        if (fileExist.name.startsWith("${video}_")) {
-          // 填充map
-          try {
-            val videoIndex = fileExist.name.substring(fileExist.name.indexOf("_") + 1, fileExist.name.length).toInt()
-            map[videoIndex]= fileExist.absolutePath.toString()
-            // 取decode的文件
-            var decodePath = ""
-            for (decodeFile in decodeFiles) {
-              val decodeVideoIndex = decodeFile.name.substring(decodeFile.name.indexOf("_") + 1, decodeFile.name.length).toInt()
-              if (decodeVideoIndex == videoIndex) {
-                decodePath = decodeFile.absolutePath
-              }
-            }
-            if (decodePath.isEmpty()) {
-              map.remove(videoIndex)
+    private fun decodeRecord(pathAudioDecode: String, index: Int, fileName: String, recordPath: String) {
+        pausableThreadPool.execute {
+            val decodePath = doDecode(fileName, recordPath, pathAudioDecode)
+            if (decodePath != null && File(decodePath).exists()) {
+                // 解码成功
+                activity.runOnUiThread {
+                    channel.invokeMethod("decodeResult", mapOf("index" to index, "path" to decodePath))
+                }
             } else {
-              map[videoIndex] = "${map[videoIndex]}|$decodePath"
+                // 解码失败
+                activity.runOnUiThread {
+                    channel.invokeMethod("decodeResult", mapOf("index" to index, "path" to ""))
+                }
             }
-          } catch (e: Exception) {
-            e.printStackTrace()
-          }
         }
-      }
-    }
-    return map
-  }*/
-
-  // -------------- 合成录音相关
-
-  override fun onHandleMessage(msg: Message) {
-    when (msg.what) {
-      BGM_DOWNLOAD_FINISHED -> {
-        // step2 解码背景音乐
-//        Toast.makeText(activity.applicationContext, "BGM_DOWNLOAD_FINISHED", Toast.LENGTH_SHORT).show()
-        val i = videoData?.bgmUrl?.lastIndexOf('/')
-        val name = videoData?.bgmUrl?.substring(i!!)
-        decodeBgmAudio(name!!, videoData?.bgmPath!!)
-      }
-      AUDIO_DECODE_FINISHED -> {
-        // step3  背景音乐与录音合成
-//        Toast.makeText(activity.applicationContext, "AUDIO_DECODE_FINISHED", Toast.LENGTH_SHORT).show()
-        syncAudios()
-      }
-      AUDIO_SYN_FINISHED -> {
-        // step4 编码音频
-//        Toast.makeText(activity.applicationContext, "AUDIO_SYN_FINISHED", Toast.LENGTH_SHORT).show()
-        encodeAsynAudio()
-      }
-      AUDIO_ENCODE_FINISHED -> {
-//        Toast.makeText(activity.applicationContext, "AUDIO_ENCODE_FINISHED", Toast.LENGTH_SHORT).show()
-        mixinAudioAndVideo()
-      }
-      AUDIO_MIX_VIDIO_FINISHED -> {
-//        Toast.makeText(activity.applicationContext, "AUDIO_MIX_VIDIO_FINISHED", Toast.LENGTH_SHORT).show()
-        audioMixVideoFinish()
-      }
     }
-  }
 
-  private fun startMixinAudio() {
-    activity.runOnUiThread {
-      // step2 解码背景音乐
-      val message = Message.obtain()
-      message.what = BGM_DOWNLOAD_FINISHED
-      mixinHandler.sendMessage(message)
+    private fun stopRecord() {
+        try {
+            mediaRecorder?.stop()
+        } catch (e: Exception) {
+            // TODO from i2 dubit
+            // 这里有可能会抛出两种异常,一种是IllegalStateException,抛出这种异常是由于在没有start的情况下使用了stop
+            // 另外一种是RuntimeException, 这种异常的产生原因是在执行了start()过后马上执行stop(),具体可看mRecorder.stop()的源码注释
+            e.printStackTrace()
+        } finally {
+            isRecording = false
+            try {
+                mediaRecorder?.reset()
+                mediaRecorder?.release()
+                mediaRecorder = null
+            } catch (e: Exception) {
+                e.printStackTrace()
+            }
+        }
     }
-  }
 
-  private fun decodeBgmAudio(fileName:String, localPath: String) {
-    if (TextUtils.isEmpty(localPath)) return
-    pausableThreadPool.execute {
-      val decodedPath = doDecode(fileName, localPath, pathBgmDecodeDir!!)
-      videoData?.decodeBgmPath = decodedPath
-      // step3  背景音乐与录音合成
-      val message = Message.obtain()
-      message.what = AUDIO_DECODE_FINISHED
-      mixinHandler.sendMessage(message)
+    private fun playRecord(fileName: String, result: Result) {
+        resetMediaPlayer()
+        mediaPlayer = MediaPlayer()
+        mediaPlayer?.setDataSource(fileName)
+        mediaPlayer?.prepare()
+        mediaPlayer?.start()
+
+        mediaPlayer?.setOnCompletionListener {
+            resetMediaPlayer()
+            // 播放完成
+            result.success(true)
+        }
     }
-  }
 
-  private fun syncAudios() {
-    // 合成背景音乐和录音 (从尾部开始)
-    val fileDIR = File(pathBgmRecordSyncDir)
-    if (!fileDIR.exists()) {
-      fileDIR.mkdirs()
+    private fun resetMediaPlayer() {
+        mediaPlayer?.stop()
+        mediaPlayer?.release()
+        mediaPlayer = null
     }
-    val mixFilePath = File(fileDIR.absolutePath + "/" + "mixin.mp3")
-//        mixFilePath.createNewFile()
-    // 合成操作
-    val tempPath = arrayOf<String>(videoData?.decodeBgmPath!!)
-    pausableThreadPool.execute {
-      AudioComposer.composeAudio(tempPath[0],
-              videoData?.audioDecodePaths,
-              mixFilePath.absolutePath,
-              false,
-              videoData?.endTimeList,
-              videoData?.durationList,
-              object : AudioComposer.ComposeAudioInterface {
-                override fun composeSuccess(result: String?) {
-                  videoData?.decodeAsyncBgmPath = result!!
-                  val message = Message.obtain()
-                  message.what = AUDIO_SYN_FINISHED
-                  mixinHandler.sendMessage(message)
-                }
 
-                override fun composeFail() {
-                  activity.runOnUiThread {
-                    mixinResult?.error("1005", "async bgm and record failed", "")
-                  }
+    @Throws(Exception::class)
+    private fun deleteFileWithPrefix(video: String, path: String): Boolean {
+        val file = File(path)
+        if (!file.exists()) return false
+        // 取得所有文件
+        val files = file.listFiles()
+        if (files == null || files.isEmpty()) return false
+        for (fileExist in files) {
+            if (fileExist.isFile) {
+                // 验证文件名
+                if (fileExist.name.startsWith("${video}_")) {
+                    fileExist.delete()
                 }
-              })
-    }
-  }
-
-  private fun encodeAsynAudio() {
-    pausableThreadPool.execute {
-      val accEncoder = AudioEncoder
-              .createAccEncoder(videoData?.decodeAsyncBgmPath)
-//                String finalMixPath = FileBiz.get_temp_recorders_dir() + "/" + UUID.randomUUID() + ".mp4";
-      val file = File(pathBgmRecordDecodeSyncDir)
-      if (!file.exists()) file.mkdirs()
-      val finalMixPath = pathBgmRecordDecodeSyncDir + "mixinDecode.aac"
-      val isEncodeFinished = !TextUtils.isEmpty(accEncoder.encodeToFile(finalMixPath))
-      if (!isEncodeFinished) {
-        activity.runOnUiThread{
-          mixinResult?.error("1005", "encode async audio failed", "")
+            }
         }
-        return@execute
-      }
-      videoData?.encodeAudioWithBgmPath = finalMixPath
-      val message = Message.obtain()
-      message.what = AUDIO_ENCODE_FINISHED
-      mixinHandler.sendMessage(message)
+        return true
     }
-  }
-
-  private fun mixinAudioAndVideo() {
-    pausableThreadPool.execute {
-      if (videoAudioMixer == null) {
-        videoAudioMixer = VideoAudioMixer(activity.applicationContext)
-      }
-      videoAudioMixer?.setListener(object: VideoAudioMixer.VideoAudioMixListener {
-        override fun mixSuccess() {
-          videoData?.mixVideoPath = pathVideoMixinDir + "${videoData?.videoId}_mix.mp4"
-          val msg = Message()
-          msg.what = AUDIO_MIX_VIDIO_FINISHED
-          mixinHandler.sendMessage(msg)
-        }
 
-        override fun mixFail(reason: String?) {
-          activity.runOnUiThread{
-            mixinResult?.error("1005", "mix video and audio failed", "")
-          }
+    private fun doDecode(fileName: String, path: String, saveDirPath: String): String? {
+        try {
+            // 解码后的路径
+            val decodeFile = File(saveDirPath)
+            if (!decodeFile.exists()) {
+                decodeFile.mkdirs()
+            }
+            val finalFile = File(decodeFile.absolutePath + "/" + fileName)
+            if (!finalFile.exists()) {
+                finalFile.createNewFile()
+            }
+            val audioDec = AudioDecoder
+                    .createDefualtDecoder(path)
+            audioDec.decodeToFile(finalFile.absolutePath)
+            return finalFile.absolutePath
+        } catch (e: Exception) {
+            e.printStackTrace()
         }
-      })
-      videoAudioMixer?.mux(videoData?.encodeAudioWithBgmPath, videoData?.videoPath,
-              "${videoData?.videoId}_mix.mp4", pathVideoMixinDir)
-    }
-  }
-
-  private fun audioMixVideoFinish() {
-    mixinResult?.success(videoData?.mixVideoPath)
-  }
-
-  private fun doDecode(fileName: String, path: String, saveDirPath: String): String? {
-    try {
-      // 解码后的路径
-      val decodeFile = File(saveDirPath)
-      if (!decodeFile.exists()) {
-        decodeFile.mkdirs()
-      }
-      val finalFile = File(decodeFile.absolutePath + "/" + fileName)
-      if (!finalFile.exists()) {
-        finalFile.createNewFile()
-      }
-      val audioDec = AudioDecoder
-              .createDefualtDecoder(path)
-      audioDec.decodeToFile(finalFile.absolutePath)
-      return finalFile.absolutePath
-    } catch (e: Exception) {
-      e.printStackTrace()
+        return null
     }
-    return null
-  }
 
 }

+ 3 - 0
android/src/main/kotlin/cn/i2edu/dubbing_lib/audioUtils/AACAudioEncoder.java

@@ -123,6 +123,9 @@ class AACAudioEncoder extends AudioEncoder {
 //            CustomBugReporter.reportError(AACAudioEncoder.class.getName(), "file not found exception", e);
             e.printStackTrace();
         } catch (IOException e) {
+//            CustomBugReporter.reportError(AACAudioEncoder.class.getName(), "ioexception" ,e);
+            e.printStackTrace();
+        } catch (Exception e) {
 //            CustomBugReporter.reportError(AACAudioEncoder.class.getName(), "ioexception" ,e);
             e.printStackTrace();
         } finally {

+ 5 - 0
android/src/main/kotlin/cn/i2edu/dubbing_lib/bean/PaintedAudioData.kt

@@ -0,0 +1,5 @@
+package cn.i2edu.dubbing_lib.bean
+
+data class PaintedAudioData (val paintedId: String, val bgmUrl: String, val endTimeList: List<Long>, val durationList: List<Long>,
+                      val audioDecodePaths: List<String>, var bgmPath: String?=null, var decodeBgmPath: String?=null, var decodeAsyncBgmPath: String?=null,
+                      var encodeAudioWithBgmPath: String?=null, var mixVideoPath: String?=null)

+ 50 - 20
lib/dubbing_lib.dart

@@ -10,14 +10,14 @@ class DubbingLib {
   static DubbingLib get instance => _instance;
 
   static const MethodChannel _channel =
-      const MethodChannel('dubbing_lib');
+  const MethodChannel('dubbing_lib');
 
   StreamController _onProgressChange;
   StreamController _onRecordProgressChange;
   StreamController _onDecodeResultChange;
-
-  Stream<int> get progressChange => _onProgressChange.stream;
+  
   Stream<int> get recordProgressChange => _onRecordProgressChange.stream;
+
   Stream<Map> get decodeResultChange => _onDecodeResultChange.stream;
 
   /// 路径文件夹地址
@@ -55,29 +55,62 @@ class DubbingLib {
   /// 返回录音文件地址
   Future<String> startRecord(int index, int duration, String fileName) {
     return _channel.invokeMethod("startRecord",
-        {"duration": duration, "fileName": fileName, "index": index, "pathAudio": recordPath, "pathAudioDecode": recordDecodePath}
-        );
+        {
+          "duration": duration,
+          "fileName": fileName,
+          "index": index,
+          "pathAudio": recordPath,
+          "pathAudioDecode": recordDecodePath
+        }
+    );
   }
 
   Future<void> playRecordAudio(String filePath) {
     return _channel.invokeMethod("playRecordAudio", {"fileName": filePath});
   }
 
-  Future<String> startMixinAudio(String videoId, String bgmUrl, String bgmPath, List<int> endTimeList,
-      List<String> decodeAudioPathList, List<String> audioPathList, List<int> durationList, String localVideoPath, List<double> startTimeList) {
-    return _channel.invokeMethod("startMixinAudio", {"videoId": videoId, "bgmUrl": bgmUrl,
-      "endTimeList": endTimeList, "audioDecodePaths": decodeAudioPathList, "audioPathList": audioPathList, "durationList": durationList, "videoPath": localVideoPath,
-      "bgmPath": bgmPath, "pathBgmDecode": bgmDecodePath, "pathBgmRecordSync": audioSyncPath, "pathBgmRecordDecodeSync": audioSyncDecodePath, "pathVideoMixin": videoMixInPath, "startTimeList": startTimeList});
+  Future<String> startMixinAudio(String videoId, String bgmUrl, String bgmPath,
+      List<int> endTimeList,
+      List<String> decodeAudioPathList,
+      List<int> durationList, String localVideoPath,
+      List<double> startTimeList) {
+    return _channel.invokeMethod(
+        "startMixinAudio", {
+      "videoId": videoId,
+      "bgmUrl": bgmUrl,
+      "endTimeList": endTimeList,
+      "audioDecodePaths": decodeAudioPathList,
+      "durationList": durationList,
+      "videoPath": localVideoPath,
+      "bgmPath": bgmPath,
+      "pathBgmDecode": bgmDecodePath,
+      "pathBgmRecordSync": audioSyncPath,
+      "pathBgmRecordDecodeSync": audioSyncDecodePath,
+      "pathVideoMixin": videoMixInPath,
+      "startTimeList": startTimeList
+    });
   }
-  
+
   Future<void> cleanAudioData(String videoId) {
-    return _channel.invokeMethod("cleanAudioData", {"videoId": videoId, "pathAudio": recordPath, "pathAudioDecode": recordDecodePath});
+    return _channel.invokeMethod("cleanAudioData", {
+      "videoId": videoId,
+      "pathAudio": recordPath,
+      "pathAudioDecode": recordDecodePath
+    });
   }
 
+  Future<String> startMixinPaintedAudio(List<String> audioPaths, String bgmPath, List<int> durationList, List<int> endTimeList, 
+      String audioDecodePath, String mixinFilePath, String encodePath) {
+    return _channel.invokeMethod("startMixinPaintedAudio",
+        {"audioPaths": audioPaths, "bgmPath": bgmPath, "durationList": durationList, "endTimeList": endTimeList,
+        "audioDecodePath": audioDecodePath, "mixinFilePath": mixinFilePath, "encodePath": encodePath});
+  }
+  
   /// 初始化路径
-  void initPath({@required String videoPath, @required String recordPath, @required String recordDecodePath,
-    @required String bgmPath, @required String bgmDecodePath, @required String audioSyncPath, @required String audioSyncDecodePath,
-    @required String videoMixInPath}) {
+  void initPath(
+      {@required String videoPath, @required String recordPath, @required String recordDecodePath,
+        @required String bgmPath, @required String bgmDecodePath, @required String audioSyncPath, @required String audioSyncDecodePath,
+        @required String videoMixInPath}) {
     this.videoPath = videoPath;
     this.recordPath = recordPath;
     this.recordDecodePath = recordDecodePath;
@@ -85,7 +118,7 @@ class DubbingLib {
     this.bgmDecodePath = bgmDecodePath;
     this.audioSyncPath = audioSyncPath;
     this.audioSyncDecodePath = audioSyncDecodePath;
-    this. videoMixInPath = videoMixInPath;
+    this.videoMixInPath = videoMixInPath;
   }
 
   /// 初始化listener 进入录音页面时调用
@@ -96,12 +129,9 @@ class DubbingLib {
     _channel.setMethodCallHandler(_onMethodCallHandler);
   }
 
-  /// 1,下载视频进度 2.录音进度 3.解码录音回调 4.语音评测结果
+  /// 1.录音进度 2.解码录音回调 
   Future _onMethodCallHandler(MethodCall call) {
     switch (call.method) {
-      case "downloadUpdate":
-        _onProgressChange.add(call.arguments['progress']);
-        break;
       case "recordProgress":
         _onRecordProgressChange.add(call.arguments['progress']);
         break;