[Tizen.AIAvatar] Refactor AIAvatar (#6146)
authorhuiyu <35286162+huiyueun@users.noreply.github.com>
Fri, 31 May 2024 09:43:38 +0000 (18:43 +0900)
committerEunki Hong <h.pichulia@gmail.com>
Tue, 11 Jun 2024 10:37:05 +0000 (19:37 +0900)
* Avatar Modify

Signed-off-by: huiyu.eun <huiyu.eun@samsung.com>
* AIAvatar test

Signed-off-by: huiyu.eun <huiyu.eun@samsung.com>
* Tizen.AIAvatar.Example

Signed-off-by: huiyu.eun <huiyu.eun@samsung.com>
* Modify sample & APIs

Signed-off-by: huiyu.eun <huiyu.eun@samsung.com>
* Modify Test Code & Bug

Signed-off-by: huiyu.eun <huiyu.eun@samsung.com>
* Modify Tizen.AIAvatar.Sample

Signed-off-by: huiyu.eun <huiyu.eun@samsung.com>
* Delete unused log

Signed-off-by: huiyu.eun <huiyu.eun@samsung.com>
* Internal class

Signed-off-by: huiyu.eun <huiyu.eun@samsung.com>
* Extension hidden

Signed-off-by: huiyu.eun <huiyu.eun@samsung.com>
---------

Signed-off-by: huiyu.eun <huiyu.eun@samsung.com>
124 files changed:
src/Tizen.AIAvatar/src/Animations/AnimationInfo.cs [new file with mode: 0644]
src/Tizen.AIAvatar/src/Animations/AvatarMotionChangedEventArgs.cs [new file with mode: 0644]
src/Tizen.AIAvatar/src/Animations/AvatarMotionState.cs [new file with mode: 0644]
src/Tizen.AIAvatar/src/Animations/EyeBlinker.cs [new file with mode: 0644]
src/Tizen.AIAvatar/src/Animations/IBlendShapeModule.cs [new file with mode: 0644]
src/Tizen.AIAvatar/src/Animations/MotionPlayer.cs [new file with mode: 0644]
src/Tizen.AIAvatar/src/Common/Avatar.cs [new file with mode: 0644]
src/Tizen.AIAvatar/src/Common/AvatarInfo.cs [new file with mode: 0644]
src/Tizen.AIAvatar/src/Common/AvatarProperties.cs [new file with mode: 0644]
src/Tizen.AIAvatar/src/Common/AvatarPropertyMapper.cs [new file with mode: 0644]
src/Tizen.AIAvatar/src/Common/BlendShapeType.cs [new file with mode: 0644]
src/Tizen.AIAvatar/src/Common/JointType.cs [new file with mode: 0644]
src/Tizen.AIAvatar/src/Common/NodeType.cs [new file with mode: 0644]
src/Tizen.AIAvatar/src/Emotion/EmotionAnalyzer.cs [new file with mode: 0644]
src/Tizen.AIAvatar/src/Emotion/EmotionController.cs [new file with mode: 0644]
src/Tizen.AIAvatar/src/Extensions/AvatarExtension.cs
src/Tizen.AIAvatar/src/Extensions/AvatarScene.cs
src/Tizen.AIAvatar/src/Extensions/Interop.SceneView.cs [new file with mode: 0644]
src/Tizen.AIAvatar/src/Extensions/SceneViewExtension.cs
src/Tizen.AIAvatar/src/Internal/AIAvatar.cs [new file with mode: 0644]
src/Tizen.AIAvatar/src/Internal/AvatarBlendShapeIndex.cs [new file with mode: 0644]
src/Tizen.AIAvatar/src/Internal/AvatarJointTransformIndex.cs [new file with mode: 0644]
src/Tizen.AIAvatar/src/Internal/DefaultAvatarProperties.cs [new file with mode: 0644]
src/Tizen.AIAvatar/src/Internal/Utils.cs [new file with mode: 0644]
src/Tizen.AIAvatar/src/Lipsync/AsyncLipSyncer.cs [new file with mode: 0644]
src/Tizen.AIAvatar/src/Lipsync/LipSyncController.cs [new file with mode: 0644]
src/Tizen.AIAvatar/src/Lipsync/LipSyncer.cs [new file with mode: 0644]
src/Tizen.AIAvatar/src/Lipsync/VowelConverter/Audio2Vowel/inMFCC/Algorithm/CustomMfccExtractor.cs [new file with mode: 0644]
src/Tizen.AIAvatar/src/Lipsync/VowelConverter/Audio2Vowel/inMFCC/Algorithm/DCT.cs [new file with mode: 0644]
src/Tizen.AIAvatar/src/Lipsync/VowelConverter/Audio2Vowel/inMFCC/Algorithm/FFT.cs [new file with mode: 0644]
src/Tizen.AIAvatar/src/Lipsync/VowelConverter/Audio2Vowel/inMFCC/Algorithm/FilterBank.cs [new file with mode: 0644]
src/Tizen.AIAvatar/src/Lipsync/VowelConverter/Audio2Vowel/inMFCC/Algorithm/IMFccExtractor.cs [new file with mode: 0644]
src/Tizen.AIAvatar/src/Lipsync/VowelConverter/Audio2Vowel/inMFCC/Algorithm/PreEmphasis.cs [new file with mode: 0644]
src/Tizen.AIAvatar/src/Lipsync/VowelConverter/Audio2Vowel/inMFCC/Algorithm/Window.cs [new file with mode: 0644]
src/Tizen.AIAvatar/src/Lipsync/VowelConverter/ISingleShotModel.cs [new file with mode: 0644]
src/Tizen.AIAvatar/src/Lipsync/VowelConverter/SoftmaxLinqExtension.cs [new file with mode: 0644]
src/Tizen.AIAvatar/src/Lipsync/VowelConverter/TFVowel6.cs [new file with mode: 0644]
src/Tizen.AIAvatar/src/Lipsync/VowelConverter/Vowel2Animation/AnimationConverter.cs [new file with mode: 0644]
src/Tizen.AIAvatar/src/Lipsync/VowelConverter/Vowel2Animation/DTO/AnimationKeyFrame.cs [new file with mode: 0644]
src/Tizen.AIAvatar/src/Lipsync/VowelConverter/Vowel2Animation/DTO/BlendShapeInfo.cs [new file with mode: 0644]
src/Tizen.AIAvatar/src/Lipsync/VowelConverter/Vowel2Animation/Exception.cs [new file with mode: 0644]
src/Tizen.AIAvatar/src/Lipsync/VowelConverter/VowelClassifier.cs [new file with mode: 0644]
src/Tizen.AIAvatar/src/Lipsync/VowelConverter/VowelConverter.cs [new file with mode: 0644]
src/Tizen.AIAvatar/src/Multimedia/Audio/AudioOptions.cs [new file with mode: 0644]
src/Tizen.AIAvatar/src/Multimedia/Audio/AudioPlayer.cs [new file with mode: 0644]
src/Tizen.AIAvatar/src/Multimedia/Audio/AudioRecorder.cs [new file with mode: 0644]
src/Tizen.AIAvatar/src/Multimedia/Audio/RecordBufferChangedEventArgs.cs [new file with mode: 0644]
src/Tizen.AIAvatar/src/Multimedia/TTS/TTSController.cs [new file with mode: 0644]
src/Tizen.AIAvatar/src/Multimedia/TTS/UtteranceText.cs [new file with mode: 0644]
src/Tizen.AIAvatar/src/Multimedia/TTS/VoiceInfo.cs [new file with mode: 0644]
src/Tizen.AIAvatar/src/Multimedia/TTS/VoiceType.cs [new file with mode: 0644]
src/Tizen.AIAvatar/src/RestClient/IRestClient.cs [new file with mode: 0644]
src/Tizen.AIAvatar/src/RestClient/RestClient.cs [new file with mode: 0644]
src/Tizen.AIAvatar/src/RestClient/RestClientFactory.cs [new file with mode: 0644]
src/Tizen.AIAvatar/src/Tracking/TrackingController.cs [new file with mode: 0644]
src/Tizen.AIAvatar/src/Tracking/TrackingOptions.cs [new file with mode: 0644]
src/Tizen.AIAvatar/src/internal/Avatar/AIAvatar.cs [deleted file]
src/Tizen.AIAvatar/src/internal/Avatar/Interop.SceneView.cs [deleted file]
src/Tizen.AIAvatar/src/internal/Avatar/Utils.cs [deleted file]
src/Tizen.AIAvatar/src/internal/BlendShapeInfo/BlendShapeInfo.cs [deleted file]
src/Tizen.AIAvatar/src/internal/BlendShapeInfo/BlendShapeModelInfo.cs [deleted file]
src/Tizen.AIAvatar/src/internal/BlendShapeInfo/BlendShapeValue.cs [deleted file]
src/Tizen.AIAvatar/src/internal/BlendShapeInfo/BlendShapeVisemeInfo.cs [deleted file]
src/Tizen.AIAvatar/src/internal/Common/IRestClient.cs [deleted file]
src/Tizen.AIAvatar/src/internal/Common/RestClient.cs [deleted file]
src/Tizen.AIAvatar/src/internal/Common/RestClientFactory.cs [deleted file]
src/Tizen.AIAvatar/src/internal/DefaultAvatar/DefaultAvatarProperties.cs [deleted file]
src/Tizen.AIAvatar/src/internal/LipSync/LipInfo.cs [deleted file]
src/Tizen.AIAvatar/src/internal/LipSync/Models/ISingleShotModel.cs [deleted file]
src/Tizen.AIAvatar/src/internal/LipSync/Models/SoftmaxLinqExtension.cs [deleted file]
src/Tizen.AIAvatar/src/internal/LipSync/Models/TFVowel6.cs [deleted file]
src/Tizen.AIAvatar/src/internal/LipSync/Viseme.cs [deleted file]
src/Tizen.AIAvatar/src/internal/Multimedia/AudioPlayer.cs [deleted file]
src/Tizen.AIAvatar/src/internal/Multimedia/AudioRecorder.cs [deleted file]
src/Tizen.AIAvatar/src/internal/Multimedia/RecordBufferChangedEventArgs.cs [deleted file]
src/Tizen.AIAvatar/src/internal/Uix/TTSLipSyncer.cs [deleted file]
src/Tizen.AIAvatar/src/internal/Uix/UtteranceText.cs [deleted file]
src/Tizen.AIAvatar/src/public/Avatar/Animations/AnimationModule/AnimationModule.cs [deleted file]
src/Tizen.AIAvatar/src/public/Avatar/Animations/AnimationModule/AsyncLipSyncer.cs [deleted file]
src/Tizen.AIAvatar/src/public/Avatar/Animations/AnimationModule/AvatarMotions.cs [deleted file]
src/Tizen.AIAvatar/src/public/Avatar/Animations/AnimationModule/BlendShapePlayer.cs [deleted file]
src/Tizen.AIAvatar/src/public/Avatar/Animations/AnimationModule/EyeBlinker.cs [deleted file]
src/Tizen.AIAvatar/src/public/Avatar/Animations/AnimationModule/JointTransformer.cs [deleted file]
src/Tizen.AIAvatar/src/public/Avatar/Animations/AnimationModule/LipSyncer.cs [deleted file]
src/Tizen.AIAvatar/src/public/Avatar/Animations/AnimationModule/MotionPlayer.cs [deleted file]
src/Tizen.AIAvatar/src/public/Avatar/Animations/AnimationModuleData/IAnimationModuleData.cs [deleted file]
src/Tizen.AIAvatar/src/public/Avatar/Animations/AnimationModuleData/LipSyncData.cs [deleted file]
src/Tizen.AIAvatar/src/public/Avatar/Animations/AnimationModuleData/MotionBehaviorData.cs [deleted file]
src/Tizen.AIAvatar/src/public/Avatar/Animations/AvatarMotionChangedEventArgs.cs [deleted file]
src/Tizen.AIAvatar/src/public/Avatar/Animations/AvatarMotionState.cs [deleted file]
src/Tizen.AIAvatar/src/public/Avatar/AudioOptions.cs [deleted file]
src/Tizen.AIAvatar/src/public/Avatar/Avatar.cs [deleted file]
src/Tizen.AIAvatar/src/public/Avatar/Common/BlendShapeType.cs [deleted file]
src/Tizen.AIAvatar/src/public/Avatar/Common/JointType.cs [deleted file]
src/Tizen.AIAvatar/src/public/Avatar/Common/NodeType.cs [deleted file]
src/Tizen.AIAvatar/src/public/Avatar/Controller/AvatarLLM.cs [deleted file]
src/Tizen.AIAvatar/src/public/Avatar/Controller/AvatarMic.cs [deleted file]
src/Tizen.AIAvatar/src/public/Avatar/Controller/AvatarTTS.cs [deleted file]
src/Tizen.AIAvatar/src/public/Avatar/Info/AnimationInfo.cs [deleted file]
src/Tizen.AIAvatar/src/public/Avatar/Info/AvatarInfo.cs [deleted file]
src/Tizen.AIAvatar/src/public/Avatar/Info/VoiceInfo.cs [deleted file]
src/Tizen.AIAvatar/src/public/Avatar/Properties/AvatarBlendShapeIndex.cs [deleted file]
src/Tizen.AIAvatar/src/public/Avatar/Properties/AvatarJointTransformIndex.cs [deleted file]
src/Tizen.AIAvatar/src/public/Avatar/Properties/AvatarProperties.cs [deleted file]
src/Tizen.AIAvatar/src/public/Avatar/Properties/AvatarPropertyMapper.cs [deleted file]
src/Tizen.AIAvatar/test/Test.cs [new file with mode: 0644]
test/Tizen.AIAvatar.Example/Tizen.AIAvatar.Sample.csproj [new file with mode: 0644]
test/Tizen.AIAvatar.Example/Tizen.AIAvatar.Sample.sln [new file with mode: 0644]
test/Tizen.AIAvatar.Example/res/audio2vowel_7.tflite [new file with mode: 0644]
test/Tizen.AIAvatar.Example/res/images/Irradiance.ktx [new file with mode: 0644]
test/Tizen.AIAvatar.Example/res/images/Radiance.ktx [new file with mode: 0644]
test/Tizen.AIAvatar.Example/res/images/UI_BG.png [new file with mode: 0644]
test/Tizen.AIAvatar.Example/res/voice/cs-CZ-Wavenet-A.wav [new file with mode: 0644]
test/Tizen.AIAvatar.Example/res/voice/da-DK-Wavenet-A.wav [new file with mode: 0644]
test/Tizen.AIAvatar.Example/res/voice/el-GR-Wavenet-A.wav [new file with mode: 0644]
test/Tizen.AIAvatar.Example/res/voice/voice_0.bin [new file with mode: 0644]
test/Tizen.AIAvatar.Example/res/voice/voice_1.bin [new file with mode: 0644]
test/Tizen.AIAvatar.Example/shared/res/Tizen.AIAvatar.Example.png [new file with mode: 0644]
test/Tizen.AIAvatar.Example/src/AvatarScene.cs [new file with mode: 0644]
test/Tizen.AIAvatar.Example/src/ControlPannelComponent.cs [new file with mode: 0644]
test/Tizen.AIAvatar.Example/src/SampleMain.cs [new file with mode: 0644]
test/Tizen.AIAvatar.Example/src/Styles.cs [new file with mode: 0644]
test/Tizen.AIAvatar.Example/src/Utils.cs [new file with mode: 0644]
test/Tizen.AIAvatar.Example/tizen-manifest.xml [new file with mode: 0644]

diff --git a/src/Tizen.AIAvatar/src/Animations/AnimationInfo.cs b/src/Tizen.AIAvatar/src/Animations/AnimationInfo.cs
new file mode 100644 (file)
index 0000000..c6da89f
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Copyright(c) 2024 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+using System.ComponentModel;
+using Tizen.NUI.Scene3D;
+
+namespace Tizen.AIAvatar
+{
+    /// <summary>  
+    /// The AnimationInfo class manages animation data for an Avatar, including motion data and names. It is not meant to be directly edited by users or editors.  
+    /// </summary>  
+    [EditorBrowsable(EditorBrowsableState.Never)]
+    public class AnimationInfo
+    {
+        /// <summary>  
+        /// Gets the motion data associated with this animation.  
+        /// </summary>  
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public MotionData MotionData { get; private set; }
+
+        /// <summary>  
+        /// Gets the name of this animation.  
+        /// </summary>  
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public string MotionName { get; private set; }
+
+        /// <summary>  
+        /// Initializes a new instance of the AnimationInfo class with the specified motion data and name.  
+        /// </summary>  
+        /// <param name="motionData">TheThe motion data associated with this animation.</param>
+        /// <param name="motionName">The name of this animation.</param>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public AnimationInfo(MotionData motionData, string motionName)
+        {
+            MotionData = motionData;
+            MotionName = motionName;
+        }
+    }
+}
diff --git a/src/Tizen.AIAvatar/src/Animations/AvatarMotionChangedEventArgs.cs b/src/Tizen.AIAvatar/src/Animations/AvatarMotionChangedEventArgs.cs
new file mode 100644 (file)
index 0000000..4210248
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Copyright(c) 2024 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+using System;
+using System.ComponentModel;
+
+namespace Tizen.AIAvatar
+{
+    /// <summary>   
+    /// This class provides arguments for handling avatar motion change events.
+    /// <member name = "Previous" > The previous state of the avatar's motion.</member>  
+    /// <member name = "Current" > The current state of the avatar's motion.</member>  
+    /// </summary>  
+    [EditorBrowsable(EditorBrowsableState.Never)]
+    public class AvatarMotionChangedEventArgs : EventArgs
+    {
+        /// <summary>  
+        /// Initializes a new instance of the AvatarMotionChangedEventArgs class with the specified previous and current states.  
+        /// </summary>  
+        /// <param name="previous">The previous state of the avatar's motion.</param>  
+        /// <param name="current">The current state of the avatar's motion.</param>  
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public AvatarMotionChangedEventArgs(AvatarMotionState previous, AvatarMotionState current)
+        {
+            Previous = previous;
+            Current = current;
+        }
+
+        /// <summary>
+        /// The previous state.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public AvatarMotionState Previous
+        {
+            get;
+            internal set;
+        }
+
+        /// <summary>
+        /// The current state.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public AvatarMotionState Current
+        {
+            get;
+            internal set;
+        }
+    }
+}
diff --git a/src/Tizen.AIAvatar/src/Animations/AvatarMotionState.cs b/src/Tizen.AIAvatar/src/Animations/AvatarMotionState.cs
new file mode 100644 (file)
index 0000000..aa62b0d
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * Copyright(c) 2024 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+using System.ComponentModel;
+
+namespace Tizen.AIAvatar
+{
+    /// <summary>
+    /// Enumeration for the states.
+    /// </summary>
+    [EditorBrowsable(EditorBrowsableState.Never)]
+    public enum AvatarMotionState
+    {
+        /// <summary>
+        ///  Created state.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        Failed = -1,
+
+        /// <summary>
+        /// Ready state.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        Ready = 0,
+
+        /// <summary>
+        /// Playing state.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        Playing = 3,
+
+        /// <summary>
+        /// Paused state.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        Paused = 4,
+
+        /// <summary>
+        /// Stopped state.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        Stopped = 5,
+
+        /// <summary>
+        /// Unavailable state.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        Unavailable
+    };
+}
diff --git a/src/Tizen.AIAvatar/src/Animations/EyeBlinker.cs b/src/Tizen.AIAvatar/src/Animations/EyeBlinker.cs
new file mode 100644 (file)
index 0000000..1431902
--- /dev/null
@@ -0,0 +1,186 @@
+/*
+ * Copyright(c) 2024 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+using System;
+using Tizen.NUI;
+
+using static Tizen.AIAvatar.AIAvatar;
+
+namespace Tizen.AIAvatar
+{
+    internal class EyeBlinker : IBlendShapeModule, IDisposable
+    {
+        private AvatarMotionState currentMotionState = AvatarMotionState.Unavailable;
+
+        private readonly Object motionChangedLock = new Object();
+        private event EventHandler<AvatarMotionChangedEventArgs> motionChanged;
+
+        private const int blinkIntervalMinimum = 800;
+        private const int blinkIntervalMaximum = 3000;
+        private Animation eyeAnimation;
+
+        private Timer blinkTimer;
+
+        private bool isPlaying = false;
+        private const int blinkDuration = 200;
+
+        public AvatarMotionState CurrentMotionState
+        {
+            get
+            {
+                return currentMotionState;
+            }
+            set
+            {
+                if (currentMotionState == value)
+                {
+                    return;
+                }
+                var preState = currentMotionState;
+                currentMotionState = value;
+                if (motionChanged != null)
+                {
+                    motionChanged?.Invoke(this, new AvatarMotionChangedEventArgs(preState, currentMotionState));
+                }
+            }
+        }
+
+        public event EventHandler<AvatarMotionChangedEventArgs> MotionStateChanged
+        {
+            add
+            {
+                lock (motionChangedLock)
+                {
+                    motionChanged += value;
+                }
+
+            }
+
+            remove
+            {
+                lock (motionChangedLock)
+                {
+                    if (motionChanged == null)
+                    {
+                        Log.Error(LogTag, "Remove StateChanged Failed : motionChanged is null");
+                        return;
+                    }
+                    motionChanged -= value;
+                }
+            }
+        }
+
+        public EyeBlinker()
+        {
+
+        }
+
+        public void Dispose()
+        {
+            DestroyAnimation();
+        }
+
+        public void Init(Animation eyeAnimation)
+        {
+            this.eyeAnimation = eyeAnimation;
+        }
+
+        public void Play()
+        {
+            //data
+            StartEyeBlink();
+        }
+
+        public void Stop()
+        {
+            StopEyeBlink();
+        }
+
+        public void Pause()
+        {
+            eyeAnimation?.Pause();
+        }
+
+        public void Destroy()
+        {
+            DestroyAnimation();
+        }
+
+        private void StartEyeBlink()
+        {
+            DestroyBlinkTimer();
+
+            blinkTimer = new Timer(blinkDuration);
+            if (blinkTimer != null)
+            {
+                blinkTimer.Tick += OnBlinkTimer;
+                blinkTimer?.Start();
+                isPlaying = true;
+            }
+        }
+
+        private void PauseEyeBlink()
+        {
+            blinkTimer?.Stop();
+            isPlaying = false;
+        }
+
+        private void StopEyeBlink()
+        {
+            blinkTimer?.Stop();
+            isPlaying = false;
+        }
+
+        private void DestroyAnimation()
+        {
+            DestroyBlinkTimer();
+            if (eyeAnimation != null)
+            {
+                eyeAnimation.Stop();
+                eyeAnimation.Dispose();
+                eyeAnimation = null;
+            }
+            isPlaying = false;
+        }
+
+        private bool OnBlinkTimer(object source, Timer.TickEventArgs e)
+        {
+            if (eyeAnimation == null)
+            {
+                Log.Error(LogTag, "eye animation is not ready");
+                return false;
+            }
+            eyeAnimation?.Play();
+
+            var random = new Random();
+            var fortimerinterval = (uint)random.Next(blinkIntervalMinimum, blinkIntervalMaximum);
+            blinkTimer.Interval = fortimerinterval;
+            return true;
+        }
+
+        private void DestroyBlinkTimer()
+        {
+            if (blinkTimer != null)
+            {
+                blinkTimer.Tick -= OnBlinkTimer;
+                blinkTimer.Stop();
+                blinkTimer.Dispose();
+                blinkTimer = null;
+            }
+        }
+    }
+}
diff --git a/src/Tizen.AIAvatar/src/Animations/IBlendShapeModule.cs b/src/Tizen.AIAvatar/src/Animations/IBlendShapeModule.cs
new file mode 100644 (file)
index 0000000..7f9daf6
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright(c) 2024 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+using Tizen.NUI;
+
+namespace Tizen.AIAvatar
+{
+    internal interface IBlendShapeModule
+    {
+        public void Init(Animation animation);
+
+        public void Play();
+
+        public void Stop();
+
+        public void Pause();
+
+        public void Destroy();
+    }
+
+}
diff --git a/src/Tizen.AIAvatar/src/Animations/MotionPlayer.cs b/src/Tizen.AIAvatar/src/Animations/MotionPlayer.cs
new file mode 100644 (file)
index 0000000..a590ba9
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * Copyright(c) 2024 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+using Tizen.NUI;
+using Tizen.NUI.Scene3D;
+using static Tizen.AIAvatar.AIAvatar;
+
+namespace Tizen.AIAvatar
+{
+    internal class MotionPlayer
+    {
+        private Animation motionAnimation;
+        private EyeBlinker eyeBlinker;
+
+        internal Animation MotionAnimation { get => motionAnimation; private set => motionAnimation = value; }
+
+        internal MotionPlayer()
+        {
+            eyeBlinker = new EyeBlinker();
+
+
+        }
+
+        internal void PlayAnimation(Animation motionAnimation, int duration = 3000, bool isLooping = false, int loopCount = 1)
+        {
+            ResetAnimations();
+            if (motionAnimation != null)
+            {
+                MotionAnimation = motionAnimation;
+                MotionAnimation?.Play();
+            }
+            else
+            {
+                Tizen.Log.Error(LogTag, "motionAnimation is null");
+            }
+        }
+
+        internal void PauseMotionAnimation()
+        {
+            MotionAnimation?.Pause();
+        }
+
+        internal void StopMotionAnimation()
+        {
+            MotionAnimation?.Stop();
+        }
+
+        internal void SetBlinkAnimation(Animation blinkerAnimation)
+        {
+            eyeBlinker?.Init(blinkerAnimation);
+        }
+
+        internal void StartEyeBlink()
+        {
+            eyeBlinker?.Play();
+        }
+
+        internal void PauseEyeBlink()
+        {
+            eyeBlinker?.Pause();
+        }
+
+
+        internal void StopEyeBlink()
+        {
+            eyeBlinker?.Stop();
+        }
+
+        internal void DestroyAnimations()
+        {
+            eyeBlinker?.Destroy();
+        }
+
+        private void ResetAnimations()
+        {
+            if (MotionAnimation != null)
+            {
+                MotionAnimation.Stop();
+                MotionAnimation.Dispose();
+                MotionAnimation = null;
+            }
+        }
+
+    }
+}
diff --git a/src/Tizen.AIAvatar/src/Common/Avatar.cs b/src/Tizen.AIAvatar/src/Common/Avatar.cs
new file mode 100644 (file)
index 0000000..8ff4306
--- /dev/null
@@ -0,0 +1,272 @@
+/*
+ * Copyright(c) 2024 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+using System.ComponentModel;
+using Tizen.NUI.Scene3D;
+using Tizen.NUI;
+
+using static Tizen.AIAvatar.AIAvatar;
+
+namespace Tizen.AIAvatar
+{
+    /// <summary>
+    /// The Avatar class displays 3D avatars and provides easy access to their animations.
+    /// This class is a sub-class of the Model class which allows us to easily control the Avatar's animations.
+    /// Avatar also supports AR Emoji for humanoid-based 3D models.
+    /// </summary>
+    [EditorBrowsable(EditorBrowsableState.Never)]
+    public class Avatar : Model
+    {
+        private AvatarProperties avatarProperties = new DefaultAvatarProperties();
+
+        private MotionPlayer motionPlayer;
+
+        /// <summary>  
+        /// The AvatarProperties property gets or sets the AvatarProperties object containing various information about the Avatar.  
+        /// </summary>  
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public AvatarProperties Properties
+        {
+            get => avatarProperties;
+            set
+            {
+                avatarProperties = value;
+            }
+        }
+
+        /// <summary>
+        /// Create an initialized AvatarModel.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public Avatar() : base()
+        {
+            InitAvatar();
+        }
+
+        /// <summary>
+        /// Create an initialized AREmojiDefaultAvatar.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public Avatar(AvatarInfo avatarInfo) : base(avatarInfo.ResourcePath)
+        {
+            InitAvatar();
+        }
+
+        /// <summary>
+        /// Create an initialized Avatar.
+        /// </summary>
+        /// <param name="avatarUrl">avatar file url.(e.g. glTF).</param>
+        /// <param name="resourceDirectoryUrl"> The url to derectory containing resources: binary, image etc.</param>
+        /// <remarks>
+        /// If resourceDirectoryUrl is empty, the parent directory url of avatarUrl is used for resource url.
+        ///
+        /// http://tizen.org/privilege/mediastorage for local files in media storage.
+        /// http://tizen.org/privilege/externalstorage for local files in external storage.
+        /// </remarks>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public Avatar(string avatarUrl, string resourceDirectoryUrl = "") : base(avatarUrl, resourceDirectoryUrl)
+        {
+            InitAvatar();
+        }
+
+        /// <summary>
+        /// Copy constructor.
+        /// </summary>
+        /// <param name="avatar">Source object to copy.</param>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public Avatar(Avatar avatar) : base(avatar)
+        {
+            InitAvatar();
+        }
+
+        #region Manage Animating
+
+        /// <summary>  
+        /// Plays the specified avatar animation with an optional duration and loop count.  
+        /// </summary>  
+        /// <param name="animationInfo">The AnimationInfo object containing information about the desired avatar animation.</param>  
+        /// <param name="duration">The duration of the animation in milliseconds (default is 3000).</param>  
+        /// <param name="isLooping">A boolean indicating whether the animation should be looped or not.</param>  
+        /// <param name="loopCount">The number of times to repeat the animation if it's set to loop.</param>  
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public void PlayAnimation(AnimationInfo animationInfo, int duration = 3000, bool isLooping = false, int loopCount = 1)
+        {
+            if (animationInfo == null)
+            {
+                Tizen.Log.Error(LogTag, "animationInfo is null");
+                return;
+            }
+            if (animationInfo.MotionData == null)
+            {
+                Tizen.Log.Error(LogTag, "animationInfo.MotionData is null");
+                return;
+            }
+            motionAnimation = GenerateMotionDataAnimation(animationInfo.MotionData);
+            if (motionAnimation != null)
+            {
+                motionAnimation.Duration = duration;
+                motionAnimation.Looping = isLooping;
+                motionAnimation.LoopCount = loopCount;
+                motionAnimation.BlendPoint = 0.2f;
+                motionPlayer.PlayAnimation(motionAnimation);
+            }
+            else
+            {
+                Tizen.Log.Error(LogTag, "motionAnimation is null");
+            }
+        }
+
+        Animation motionAnimation;
+
+        /// <summary>  
+        /// Plays the specified avatar animation with MotionData and an optional duration and loop count.  
+        /// </summary>  
+        /// <param name="motionData">The MotionData object containing information about the desired avatar animation.</param>  
+        /// <param name="duration">The duration of the animation in milliseconds (default is 3000).</param>  
+        /// <param name="isLooping">A boolean indicating whether the animation should be looped or not.</param>  
+        /// <param name="loopCount">The number of times to repeat the animation if it's set to loop.</param>  
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public void PlayAnimation(MotionData motionData, int duration = 3000, bool isLooping = false, int loopCount = 1)
+        {
+
+            if (motionData == null)
+            {
+                Tizen.Log.Error(LogTag, "motionData is null");
+                return;
+            }
+            var motionAnimation = GenerateMotionDataAnimation(motionData);
+            if (motionAnimation != null)
+            {
+                motionAnimation.Duration = duration;
+                motionAnimation.Looping = isLooping;
+                motionAnimation.LoopCount = loopCount;
+                motionAnimation.BlendPoint = 0.2f;
+                motionPlayer.PlayAnimation(motionAnimation);
+            }
+            else
+            {
+                Tizen.Log.Error(LogTag, "motionAnimation is null");
+            }
+        }
+
+        /// <summary>  
+        /// Plays the specified avatar animation based on its index within the available animations and an optional duration and loop count.  
+        /// </summary>  
+        /// <param name="index">The zero-based index of the desired avatar animation within the list of available animations.</param>  
+        /// <param name="duration">The duration of the animation in milliseconds (default is 3000).</param>  
+        /// <param name="isLooping">A boolean indicating whether the animation should be looped or not.</param>  
+        /// <param name="loopCount">The number of times to repeat the animation if it's set to loop.</param>  
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public void PlayAnimation(int index, int duration = 3000, bool isLooping = false, int loopCount = 1)
+        {
+            //TODO by index
+            //var motionAnimation = GenerateMotionDataAnimation(animationInfoList[index].MotionData);
+            /*motionAnimation.Duration = duration;
+            motionAnimation.Looping = isLooping;
+            motionAnimation.LoopCount = loopCount;
+            motionAnimation.BlendPoint = 0.2f;
+
+            motionPlayer.PlayAnimation(motionAnimation);*/
+        }
+
+        /// <summary>  
+        /// Pauses the currently playing avatar animation.  
+        /// </summary>  
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public void PauseMotionAnimation()
+        {
+            motionPlayer.PauseMotionAnimation();
+        }
+
+        /// <summary>  
+        /// Stops the currently playing avatar animation.  
+        /// </summary>  
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public void StopMotionAnimation()
+        {
+            motionPlayer?.StopMotionAnimation();
+        }
+
+        /// <summary>  
+        /// Starts the eye blink animation for the current avatar.  
+        /// </summary>  
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public void StartEyeBlink()
+        {
+            motionPlayer?.StartEyeBlink();
+        }
+
+        /// <summary>  
+        /// Pauses the eye blink animation for the current avatar.  
+        /// </summary>  
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public void PauseEyeBlink()
+        {
+            motionPlayer?.PauseEyeBlink();
+        }
+
+        /// <summary>  
+        /// Stops the eye blink animation for the current avatar.  
+        /// </summary>  
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public void StopEyeBlink()
+        {
+            motionPlayer?.StopEyeBlink();
+        }
+        #endregion
+        
+        private void InitAvatar()
+        {
+            motionPlayer = new MotionPlayer();
+            var eyeMotionData = CreateEyeBlinkMotionData(200);
+            if (eyeMotionData == null)
+            {
+                Tizen.Log.Info(LogTag, "Failed Loading eyeAnimation");
+            }
+
+            ResourcesLoaded += (s, e) =>
+            {
+                var eyeAnimation = GenerateMotionDataAnimation(eyeMotionData);
+                if (eyeAnimation != null)
+                {
+                    motionPlayer.SetBlinkAnimation(eyeAnimation);
+                }
+            };
+        }
+
+        private MotionData CreateEyeBlinkMotionData(int ms)
+        {
+            var keyFrames = new KeyFrames();
+            keyFrames.Add(0.1f, 0.0f);
+            keyFrames.Add(0.5f, 1.0f);
+            keyFrames.Add(0.9f, 0.0f);
+
+            var headBlendShapeEyeLeft = new AvatarBlendShapeIndex(avatarProperties.NodeMapper, NodeType.HeadGeo, avatarProperties.BlendShapeMapper, BlendShapeType.EyeBlinkLeft);
+            var headBlendShapeEyeRight = new AvatarBlendShapeIndex(avatarProperties.NodeMapper, NodeType.HeadGeo, avatarProperties.BlendShapeMapper, BlendShapeType.EyeBlinkRight);
+            var eyelashBlendShapeEyeLeft = new AvatarBlendShapeIndex(avatarProperties.NodeMapper, NodeType.EyelashGeo, avatarProperties.BlendShapeMapper, BlendShapeType.EyeBlinkLeft);
+            var eyelashBlendShapeEyeRight = new AvatarBlendShapeIndex(avatarProperties.NodeMapper, NodeType.EyelashGeo, avatarProperties.BlendShapeMapper, BlendShapeType.EyeBlinkRight);
+
+            var motionData = new MotionData(ms);
+            motionData.Add(headBlendShapeEyeLeft, new MotionValue(keyFrames));
+            motionData.Add(headBlendShapeEyeRight, new MotionValue(keyFrames));
+            motionData.Add(eyelashBlendShapeEyeLeft, new MotionValue(keyFrames));
+            motionData.Add(eyelashBlendShapeEyeRight, new MotionValue(keyFrames));
+
+            return motionData;
+        }
+    }
+}
diff --git a/src/Tizen.AIAvatar/src/Common/AvatarInfo.cs b/src/Tizen.AIAvatar/src/Common/AvatarInfo.cs
new file mode 100644 (file)
index 0000000..3a4cf3d
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * Copyright(c) 2024 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+using System.ComponentModel;
+
+using static Tizen.AIAvatar.AIAvatar;
+
+namespace Tizen.AIAvatar
+{
+    /// <summary>
+    /// The AvatarInfo class describes the properties of an Avatar object.
+    /// It includes information such as the name of the avatar, its thumbnail image, and associated resources.
+    /// This class helps users manage and organize their Avatar assets more effectively.
+    /// </summary>
+    [EditorBrowsable(EditorBrowsableState.Never)]
+    public class AvatarInfo
+    {
+        /// <summary>  
+        /// The Name property gets the name of the Avatar.   
+        /// This value is read-only and cannot be modified directly.  
+        /// </summary>  
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public string Name { get; private set; }
+
+        /// <summary>  
+        /// The ThumbnailPath property gets the path to the thumbnail image representing the Avatar.  
+        /// This value is read-only and cannot be modified directly.  
+        /// </summary>  
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public string ThumbnailPath { get; private set; }
+
+        /// <summary>  
+        /// The ResourcePath property gets the path to the resource files associated with the Avatar.  
+        /// This value is intended for internal use only and should not be accessed by users directly.  
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        internal string ResourcePath { get; private set; }
+
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        internal AvatarInfoOption avatarInfoOption { get; private set; }
+
+        /// <summary>
+        /// Initializes a new instance of the AvatarInfo class with the specified file path, name, and option.
+        /// If no option is provided, the default is AvatarInfoOption.Thumbnail.
+        /// </summary>
+        /// <param name="name">The name of the Avatar.</param>
+        /// <param name="path">The full path to the Avatar file.</param>
+        /// <param name="info">The option specifying what type of information should be loaded from the file (thumbnail or resource).</param>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public AvatarInfo(string name, string path, AvatarInfoOption info = AvatarInfoOption.Thumbnail)
+        {
+            this.Name = name;
+            this.avatarInfoOption = info;
+
+            if (info == AvatarInfoOption.Thumbnail)
+            {
+                ThumbnailPath = path;
+            }
+            else
+            {
+                ResourcePath = path;
+            }
+        }
+
+        internal AvatarInfo(string directoryPath)
+        {
+            string path = ApplicationResourcePath + EmojiAvatarResourcePath;
+            Name = directoryPath.Substring(path.Length, directoryPath.Length - path.Length);
+            ResourcePath = $"{directoryPath}/{AIAvatar.ExternalModel}";
+        }
+    }
+
+    /// <summary>
+    /// The AvatarInfoOption enumeration defines the options that determine how AvatarInfo instances are displayed or managed.
+    /// Currently it has two values: Thumbnail and Resource.
+    /// </summary>
+    [EditorBrowsable(EditorBrowsableState.Never)]
+    public enum AvatarInfoOption
+    {
+
+        /// <summary>  
+        /// Thumbnail indicates that the AvatarInfo instance should display or manipulate the thumbnail image of the Avatar.  
+        /// </summary>  
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        Thumbnail = 0,
+        /// <summary>  
+        /// Resource indicates that the AvatarInfo instance should display or manipulate the resource files associated with the Avatar.  
+        /// </summary>  
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        Resource = 1,
+    }
+}
diff --git a/src/Tizen.AIAvatar/src/Common/AvatarProperties.cs b/src/Tizen.AIAvatar/src/Common/AvatarProperties.cs
new file mode 100644 (file)
index 0000000..6a3f73f
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ * Copyright(c) 2024 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+using System;
+using System.ComponentModel;
+using Tizen.NUI.Scene3D;
+
+namespace Tizen.AIAvatar
+{
+
+    /// <summary>
+    /// The Avatar class contains an inner AvatarProperties class. 
+    /// This class manages AvatarProperty information using the AvatarPropertyMapper class. 
+    /// By default, it includes jointMapper, blendShapeMapper, and nodeMapper, which automatically generate Properties based on model information.
+    /// This structure enables users to work with Avatar properties in a more convenient way.
+    /// </summary>
+    [EditorBrowsable(EditorBrowsableState.Never)]
+    public class AvatarProperties
+    {
+        private AvatarPropertyMapper jointMapper;
+        private AvatarPropertyMapper blendShapeMapper;
+        private AvatarPropertyMapper nodeMapper;
+
+        internal event EventHandler<AvatarProperties> PropertiesChanged;
+
+        /// <summary>
+        /// The JointMapper property gets or sets the AvatarPropertyMapper responsible for mapping joint information in the Avatar model.
+        /// When setting this property, any changes made will trigger the AvatarPropertiesChanged event if it has been subscribed to.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public AvatarPropertyMapper JointMapper
+        {
+            get
+            {
+                return jointMapper;
+            }
+            set
+            {
+                jointMapper = value;
+                PropertiesChanged?.Invoke(jointMapper, this);
+            }
+        }
+
+        /// <summary>  
+        /// The BlendShapeMapper property gets or sets the AvatarPropertyMapper responsible for managing blend shape information in the Avatar model.  
+        /// When setting this property, any changes made will trigger the AvatarPropertiesChanged event if it has been subscribed to.  
+        /// </summary>  
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public AvatarPropertyMapper BlendShapeMapper
+        {
+            get
+            {
+                return blendShapeMapper;
+            }
+            set
+            {
+                blendShapeMapper = value;
+                PropertiesChanged?.Invoke(blendShapeMapper, this);
+            }
+        }
+
+        /// <summary>  
+        /// The NodeMapper property gets or sets the AvatarPropertyMapper responsible for managing node information in the Avatar model.  
+        /// When setting this property, any changes made will trigger the AvatarPropertiesChanged event if it has been subscribed to.  
+        /// </summary>  
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public AvatarPropertyMapper NodeMapper
+        {
+            get
+            {
+                return nodeMapper;
+            }
+            set
+            {
+                nodeMapper = value;
+                PropertiesChanged?.Invoke(nodeMapper, this);
+            }
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the AvatarProperties class with the specified joint mapper, blend shape mapper, and node mapper.
+        /// These mappers are used to map between the Avatar's underlying model data and its corresponding properties.
+        /// </summary>
+        /// <param name="jointMapper">The AvatarPropertyMapper for joints.</param>
+        /// <param name="blendShapeMapper">The AvatarPropertyMapper for blend shapes.</param>
+        /// <param name="nodeMapper">The AvatarPropertyMapper for nodes.</param>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public AvatarProperties(AvatarPropertyMapper jointMapper, AvatarPropertyMapper blendShapeMapper, AvatarPropertyMapper nodeMapper)
+        {
+            JointMapper = new AvatarPropertyMapper(jointMapper);
+            BlendShapeMapper = new AvatarPropertyMapper(blendShapeMapper);
+            NodeMapper = new AvatarPropertyMapper(nodeMapper);
+        }
+
+        /// <summary>  
+        /// This method generates a MotionIndex to be used in animations based on the NodeType and BlendShapeType using the model information of an Avatar.  
+        /// </summary>  
+        /// <param name="nodeType">Node type</param>  
+        /// <param name="blendShapeType">Blend shape type</param>  
+        /// <returns>The generated MotionIndex</returns>  
+        public MotionIndex CreateBlendShapeMotionIndex(NodeType nodeType, BlendShapeType blendShapeType)
+        {
+            var motionIndex = new AvatarBlendShapeIndex(NodeMapper, nodeType, BlendShapeMapper, blendShapeType);
+            return motionIndex;
+        }
+    }
+}
diff --git a/src/Tizen.AIAvatar/src/Common/AvatarPropertyMapper.cs b/src/Tizen.AIAvatar/src/Common/AvatarPropertyMapper.cs
new file mode 100644 (file)
index 0000000..8098dd6
--- /dev/null
@@ -0,0 +1,165 @@
+/*
+ * Copyright(c) 2024 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+using System.Collections.Generic;
+using System.ComponentModel;
+
+namespace Tizen.AIAvatar
+{
+    /// <summary>
+    /// The AvatarPropertyMapper class manages property mapping information for specific attributes of an Avatar model.
+    /// It primarily maps the names of AvatarProperty to their actual storage locations.
+    /// By doing so, developers can directly read or write the values of these properties using their respective names.
+    /// This approach provides consistency and convenience when working with Avatar models.
+    /// </summary>
+    [EditorBrowsable(EditorBrowsableState.Never)]
+    public class AvatarPropertyMapper
+    {
+        /// <summary>
+        /// Mapper between index and property name
+        /// </summary>
+        private Dictionary<uint, string> mapper = null;
+
+        /// <summary>
+        /// The counter of index. It will be increased one when we register custom index.
+        /// </summary>
+        private uint customIndexCounter = 0;
+
+        /// <summary>
+        /// Get current mapper information.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public Dictionary<uint, string> Mapper
+        {
+            get
+            {
+                return mapper;
+            }
+        }
+
+        /// <summary>  
+        /// Indexer method. Allows accessing and setting the property names using array notation.  
+        /// </summary>  
+        /// <param name="index">The index of property what we want to set</param>  
+        /// <returns>The index of property, or uint.MaxValue if not exist</returns>  
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public string this[uint index]
+        {
+            set
+            {
+                SetPropertyName(index, value);
+            }
+            get
+            {
+                return GetPropertyName(index);
+            }
+        }
+
+        /// <summary>
+        /// Create an initialized AvatarPropertyNameMapper.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public AvatarPropertyMapper()
+        {
+            mapper = new Dictionary<uint, string>();
+            customIndexCounter = 0u;
+        }
+
+        /// <summary>  
+        /// Copy constructor.  
+        /// Creates a new instance of the AvatarPropertyMapper class by copying the contents of another existing AvatarPropertyMapper instance.  
+        /// </summary>  
+        /// <param name="source">The source AvatarPropertyMapper instance to be copied.</param>  
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public AvatarPropertyMapper(AvatarPropertyMapper source)
+        {
+            if (source != null)
+            {
+                mapper = new Dictionary<uint, string>(source.Mapper);
+                customIndexCounter = source.customIndexCounter;
+            }
+            else
+            {
+                mapper = new Dictionary<uint, string>();
+                customIndexCounter = 0u;
+            }
+        }
+
+        /// <summary>  
+        /// Registers a custom property by name and returns its index.  
+        /// </summary>  
+        /// <param name="name">The name of custom property</param>  
+        /// <returns>The index of property matched with name.</returns>  
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public uint RegisterCustomProperty(string name)
+        {
+            uint ret = GetPropertyIndexByName(name);
+            if (ret >= customIndexCounter)
+            {
+                ret = customIndexCounter++;
+                SetPropertyName(ret, name);
+            }
+            return ret;
+        }
+
+        /// <summary>  
+        /// Returns the index of a property by its name.  
+        /// </summary>  
+        /// <param name="name">The name of property what we want to get index</param>  
+        /// <returns>The index of property, or uint.MaxValue if not exist</returns>  
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public uint GetPropertyIndexByName(string name)
+        {
+            // TODO : Do this without iteration
+            foreach (var pair in mapper)
+            {
+                if (pair.Value == name)
+                {
+                    return pair.Key;
+                }
+            }
+            return uint.MaxValue;
+        }
+
+        /// <summary>  
+        /// Sets the property name at the given index.  
+        /// </summary>  
+        /// <param name="index">The index of property what we want to set</param>  
+        /// <param name="name">The name of property what we want to set</param>  
+        /// <remark>  
+        /// New property will be added if we use index that not exist in mapper.  
+        /// </remark>  
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public void SetPropertyName(uint index, string name)
+        {
+            mapper.TryAdd(index, name);
+        }
+
+        /// <summary>  
+        /// Gets the property name at the given index.  
+        /// </summary>  
+        /// <param name="index">The index of property what we want to set</param>  
+        /// <returns>The name of property, or null if not exist</returns>  
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public string GetPropertyName(uint index)
+        {
+            string ret = null;
+            mapper.TryGetValue(index, out ret);
+            return ret;
+        }
+    }
+}
diff --git a/src/Tizen.AIAvatar/src/Common/BlendShapeType.cs b/src/Tizen.AIAvatar/src/Common/BlendShapeType.cs
new file mode 100644 (file)
index 0000000..78c27f7
--- /dev/null
@@ -0,0 +1,379 @@
+/*
+ * Copyright(c) 2024 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+using System.ComponentModel;
+
+namespace Tizen.AIAvatar
+{
+    /// <summary>
+    /// The type of predefined blendshape. We can customize each type name by "TODO_mapper"
+    /// The basic names provided by AIAvatar to control the default avatar of AREmoji.
+    /// Contains the BlendShape information of AIAvatar.  
+    /// </summary>
+    [EditorBrowsable(EditorBrowsableState.Never)]
+    public enum BlendShapeType
+    {
+        #region Left Eyes
+        /// <summary>
+        /// EyeBlinkLeft blendshape
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        EyeBlinkLeft = 0,
+
+        /// <summary>
+        /// EyeSquintLeft blendshape
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        EyeSquintLeft,
+
+        /// <summary>
+        /// EyeDownLeft blendshape
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        EyeDownLeft,
+
+        /// <summary>
+        /// EyeInLeft blendshape
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        EyeInLeft,
+
+        /// <summary>
+        /// EyeOpenLeft blendshape
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        EyeOpenLeft,
+
+        /// <summary>
+        /// EyeOutLeft blendshape
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        EyeOutLeft,
+
+        /// <summary>
+        /// EyeUpLeft blendshape
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        EyeUpLeft,
+        #endregion
+
+        #region Right Eyes
+        /// <summary>
+        /// EyeBlinkRight blendshape
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        EyeBlinkRight,
+
+        /// <summary>
+        /// EyeSquintRight blendshape
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        EyeSquintRight,
+
+        /// <summary>
+        /// EyeDownRight blendshape
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        EyeDownRight,
+
+        /// <summary>
+        /// EyeInRight blendshape
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        EyeInRight,
+
+        /// <summary>
+        /// EyeOpenRight blendshape
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        EyeOpenRight,
+
+        /// <summary>
+        /// EyeOutRight blendshape
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        EyeOutRight,
+
+        /// <summary>
+        /// EyeUpRight blendshape
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        EyeUpRight,
+        #endregion
+
+        #region Mouth and Jaw
+        /// <summary>
+        /// JawForward blendshape
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        JawForward,
+
+        /// <summary>
+        /// JawOpen blendshape
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        JawOpen,
+
+        /// <summary>
+        /// JawChew blendshape
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        JawChew,
+
+        /// <summary>
+        /// JawLeft blendshape
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        JawLeft,
+
+        /// <summary>
+        /// JawRight blendshape
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        JawRight,
+
+        /// <summary>
+        /// MouthLeft blendshape
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        MouthLeft,
+
+        /// <summary>
+        /// MouthFrownLeft blendshape
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        MouthFrownLeft,
+
+        /// <summary>
+        /// MouthSmileLeft blendshape
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        MouthSmileLeft,
+
+        /// <summary>
+        /// MouthDimpleLeft blendshape
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        MouthDimpleLeft,
+
+        /// <summary>
+        /// MouthRight blendshape
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        MouthRight,
+
+        /// <summary>
+        /// MouthFrownRight blendshape
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        MouthFrownRight,
+
+        /// <summary>
+        /// MouthSmileRight blendshape
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        MouthSmileRight,
+
+        /// <summary>
+        /// MouthDimpleRight blendshape
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        MouthDimpleRight,
+        #endregion
+
+        #region Lips
+        /// <summary>
+        /// LipsStretchLeft blendshape
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        LipsStretchLeft,
+
+        /// <summary>
+        /// LipsStretchRight blendshape
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        LipsStretchRight,
+
+        /// <summary>
+        /// LipsUpperClose blendshape
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        LipsUpperClose,
+
+        /// <summary>
+        /// LipsLowerClose blendshape
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        LipsLowerClose,
+
+        /// <summary>
+        /// LipsUpperUp blendshape
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        LipsUpperUp,
+
+        /// <summary>
+        /// LipsLowerDown blendshape
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        LipsLowerDown,
+
+        /// <summary>
+        /// LipsUpperOpen blendshape
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        LipsUpperOpen,
+
+        /// <summary>
+        /// LipsLowerOpen blendshape
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        LipsLowerOpen,
+
+        /// <summary>
+        /// LipsFunnel blendshape
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        LipsFunnel,
+
+        /// <summary>
+        /// LipsPucker blendshape
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        LipsPucker,
+        #endregion
+
+        #region Eyebrows, Cheeks, and Chin
+        /// <summary>
+        /// BrowDownLeft blendshape
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        BrowDownLeft,
+
+        /// <summary>
+        /// BrowDownRight blendshape
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        BrowDownRight,
+
+        /// <summary>
+        /// BrowUpCenter blendshape
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        BrowUpCenter,
+
+        /// <summary>
+        /// BrowUpLeft blendshape
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        BrowUpLeft,
+
+        /// <summary>
+        /// BrowUpRight blendshape
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        BrowUpRight,
+
+        /// <summary>
+        /// CheekSquintLeft blendshape
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        CheekSquintLeft,
+
+        /// <summary>
+        /// CheekSquintRight blendshape
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        CheekSquintRight,
+
+        /// <summary>
+        /// ChinLowerRaise blendshape
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        ChinLowerRaise,
+
+        /// <summary>
+        /// ChinUpperRaise blendshape
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        ChinUpperRaise,
+        #endregion
+
+        #region Tongue
+        /// <summary>
+        /// TongueOut blendshape
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        TongueOut,
+
+        /// <summary>
+        /// TongueUp blendshape
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        TongueUp,
+
+        /// <summary>
+        /// TongueDown blendshape
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        TongueDown,
+
+        /// <summary>
+        /// TongueLeft blendshape
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        TongueLeft,
+
+        /// <summary>
+        /// TongueRight blendshape
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        TongueRight,
+        #endregion
+
+        #region ETC
+        /// <summary>
+        /// Sneer blendshape
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        Sneer,
+
+        /// <summary>
+        /// Puff blendshape
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        Puff,
+
+        /// <summary>
+        /// PuffLeft blendshape
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        PuffLeft,
+
+        /// <summary>
+        /// PuffRight blendshape
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        PuffRight,
+        #endregion
+        /// <summary>
+        /// Max value of default blendshape. It will be used when we determine the motion index is default or custom.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        DefaultBlendShapeMax,
+    }
+}
diff --git a/src/Tizen.AIAvatar/src/Common/JointType.cs b/src/Tizen.AIAvatar/src/Common/JointType.cs
new file mode 100644 (file)
index 0000000..78589bf
--- /dev/null
@@ -0,0 +1,399 @@
+/*
+ * Copyright(c) 2024 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+using System.ComponentModel;
+
+namespace Tizen.AIAvatar
+{
+    /// <summary>
+    /// The type of predefined skeleton joint. We can customize each type name by "TODO_mapper"
+    /// The basic names provided by AIAvatar to control the default avatar of AREmoji.
+    /// Contains the joint information of AIAvatar.  
+    /// </summary>
+    [EditorBrowsable(EditorBrowsableState.Never)]
+    public enum JointType
+    {
+        #region Head
+        /// <summary>
+        /// Head joint
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        Head = 0,
+
+        /// <summary>
+        /// Neck joint
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        Neck,
+
+        /// <summary>
+        /// EyeLeft joint
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        EyeLeft,
+
+        /// <summary>
+        /// EyeRight joint
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        EyeRight,
+        #endregion
+
+        #region Left Upper Body
+        /// <summary>
+        /// ShoulderLeft joint
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        ShoulderLeft,
+
+        /// <summary>
+        /// ElbowLeft joint
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        ElbowLeft,
+
+        /// <summary>
+        /// WristLeft joint
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        WristLeft,
+        #endregion
+
+        #region Right Upper Body
+        /// <summary>
+        /// ShoulderRight joint
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        ShoulderRight,
+
+        /// <summary>
+        /// ElbowRight joint
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        ElbowRight,
+
+        /// <summary>
+        /// WristRight joint
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        WristRight,
+        #endregion
+
+        #region Left Lower Body
+        /// <summary>
+        /// HipLeft joint
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        HipLeft,
+
+        /// <summary>
+        /// KneeLeft joint
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        KneeLeft,
+
+        /// <summary>
+        /// AnkleLeft joint
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        AnkleLeft,
+
+        /// <summary>
+        /// ForeFootLeft joint
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        ForeFootLeft,
+        #endregion
+
+        #region Right Lower Body
+        /// <summary>
+        /// HipRight joint
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        HipRight,
+
+        /// <summary>
+        /// KneeRight joint
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        KneeRight,
+
+        /// <summary>
+        /// AnkleRight joint
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        AnkleRight,
+
+        /// <summary>
+        /// ForeFootRight joint
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        ForeFootRight,
+        #endregion
+
+        #region Left Hand Finger
+        /// <summary>
+        /// FingerThumb1Left joint
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        FingerThumb1Left,
+
+        /// <summary>
+        /// FingerThumb2Left joint
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        FingerThumb2Left,
+
+        /// <summary>
+        /// FingerThumb3Left joint
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        FingerThumb3Left,
+
+        /// <summary>
+        /// FingerThumb4Left joint
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        FingerThumb4Left,
+
+        /// <summary>
+        /// FingerIndex1Left joint
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        FingerIndex1Left,
+
+        /// <summary>
+        /// FingerIndex2Left joint
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        FingerIndex2Left,
+
+        /// <summary>
+        /// FingerIndex3Left joint
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        FingerIndex3Left,
+
+        /// <summary>
+        /// FingerIndex4Left joint
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        FingerIndex4Left,
+
+        /// <summary>
+        /// FingerMiddle1Left joint
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        FingerMiddle1Left,
+
+        /// <summary>
+        /// FingerMiddle2Left joint
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        FingerMiddle2Left,
+
+        /// <summary>
+        /// FingerMiddle3Left joint
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        FingerMiddle3Left,
+
+        /// <summary>
+        /// FingerMiddle4Left joint
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        FingerMiddle4Left,
+
+        /// <summary>
+        /// FingerRing1Left joint
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        FingerRing1Left,
+
+        /// <summary>
+        /// FingerRing2Left joint
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        FingerRing2Left,
+
+        /// <summary>
+        /// FingerRing3Left joint
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        FingerRing3Left,
+
+        /// <summary>
+        /// FingerRing4Left joint
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        FingerRing4Left,
+
+        /// <summary>
+        /// FingerPinky1Left joint
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        FingerPinky1Left,
+
+        /// <summary>
+        /// FingerPinky2Left joint
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        FingerPinky2Left,
+
+        /// <summary>
+        /// FingerPinky3Left joint
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        FingerPinky3Left,
+
+        /// <summary>
+        /// FingerPinky4Left joint
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        FingerPinky4Left,
+        #endregion
+
+        #region Right Hand Finger
+        /// <summary>
+        /// FingerThumb1Right joint
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        FingerThumb1Right,
+
+        /// <summary>
+        /// FingerThumb2Right joint
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        FingerThumb2Right,
+
+        /// <summary>
+        /// FingerThumb3Right joint
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        FingerThumb3Right,
+
+        /// <summary>
+        /// FingerThumb4Right joint
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        FingerThumb4Right,
+
+        /// <summary>
+        /// FingerIndex1Right joint
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        FingerIndex1Right,
+
+        /// <summary>
+        /// FingerIndex2Right joint
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        FingerIndex2Right,
+
+        /// <summary>
+        /// FingerIndex3Right joint
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        FingerIndex3Right,
+
+        /// <summary>
+        /// FingerIndex4Right joint
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        FingerIndex4Right,
+
+        /// <summary>
+        /// FingerMiddle1Right joint
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        FingerMiddle1Right,
+
+        /// <summary>
+        /// FingerMiddle2Right joint
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        FingerMiddle2Right,
+
+        /// <summary>
+        /// FingerMiddle3Right joint
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        FingerMiddle3Right,
+
+        /// <summary>
+        /// FingerMiddle4Right joint
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        FingerMiddle4Right,
+
+        /// <summary>
+        /// FingerRing1Right joint
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        FingerRing1Right,
+
+        /// <summary>
+        /// FingerRing2Right joint
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        FingerRing2Right,
+
+        /// <summary>
+        /// FingerRing3Right joint
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        FingerRing3Right,
+
+        /// <summary>
+        /// FingerRing4Right joint
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        FingerRing4Right,
+
+        /// <summary>
+        /// FingerPinky1Right joint
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        FingerPinky1Right,
+
+        /// <summary>
+        /// FingerPinky2Right joint
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        FingerPinky2Right,
+
+        /// <summary>
+        /// FingerPinky3Right joint
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        FingerPinky3Right,
+
+        /// <summary>
+        /// FingerPinky4Right joint
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        FingerPinky4Right,
+        #endregion
+
+        /// <summary>
+        /// Max value of default joint. It will be used when we determine the motion index is default or custom.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        DefaultJointMax,
+    }
+
+}
diff --git a/src/Tizen.AIAvatar/src/Common/NodeType.cs b/src/Tizen.AIAvatar/src/Common/NodeType.cs
new file mode 100644 (file)
index 0000000..784f206
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Copyright(c) 2024 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+using System.ComponentModel;
+
+namespace Tizen.AIAvatar
+{
+    /// <summary>
+    /// The type of predefined node. We can customize each type name by "TODO_mapper"
+    /// The basic names provided by AIAvatar to control the default avatar of AREmoji.
+    /// Contains the node information of AIAvatar.  
+    /// </summary>
+    [EditorBrowsable(EditorBrowsableState.Never)]
+    public enum NodeType
+    {
+        /// <summary>
+        /// head geometry
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        HeadGeo,
+        /// <summary>
+        /// mouth geometry
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        MouthGeo,
+        /// <summary>
+        /// eyelash geometry
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        EyelashGeo
+    }
+}
diff --git a/src/Tizen.AIAvatar/src/Emotion/EmotionAnalyzer.cs b/src/Tizen.AIAvatar/src/Emotion/EmotionAnalyzer.cs
new file mode 100644 (file)
index 0000000..ec74d75
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Copyright(c) 2024 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+using Newtonsoft.Json;
+using System.Net.Http;
+using System;
+using System.Threading.Tasks;
+
+namespace Tizen.AIAvatar
+{
+    internal class EmotionAnalyzer
+    {
+        private LipSyncController avatarTTS;
+        private IRestClient restClient;
+        private const string playgroundURL = "https://playground-api.sec.samsung.net";
+
+        internal EmotionAnalyzer()
+        {
+        }
+
+        internal void InitAvatarLLM(LipSyncController avatarTTS)
+        {
+            this.avatarTTS = avatarTTS;
+            // Setup RestClinet
+            var restClientFactory = new RestClientFactory();
+            restClient = restClientFactory.CreateClient(playgroundURL);
+        }
+
+        internal async Task StartTTSWithLLMAsync(string text, string token)
+        {
+            var bearerToken = token;
+            var jsonData = "{\"messages\": [{\"role\": \"user\", \"content\": \"" + text + "\"}]}";
+
+            try
+            {
+                var postResponse = await restClient.SendRequestAsync(HttpMethod.Post, "/api/v1/chat/completions", bearerToken, jsonData);
+                var responseData = JsonConvert.DeserializeObject<dynamic>(postResponse);
+                string content = responseData["response"]["content"];
+                Log.Info("Tizen.AIAvatar", content);
+
+                //TTS 호출
+                var voiceInfo = new VoiceInfo()
+                {
+                    Language = "en_US",
+                    Type = VoiceType.Female,
+                };
+
+                avatarTTS.PlayTTSAsync(content, voiceInfo, (o, e) =>
+                {
+
+                });
+
+            }
+            catch (Exception ex)
+            {
+                Log.Error("Tizen.AIAvatar", "에러 발생: " + ex.Message);
+            }
+        }
+    }
+}
diff --git a/src/Tizen.AIAvatar/src/Emotion/EmotionController.cs b/src/Tizen.AIAvatar/src/Emotion/EmotionController.cs
new file mode 100644 (file)
index 0000000..fd0bd42
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * Copyright(c) 2024 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+using System.ComponentModel;
+
+namespace Tizen.AIAvatar
+{
+    /// <summary>  
+     /// Manages facial expression control for avatars based on input text sentiment analysis results.  
+     /// </summary> 
+    [EditorBrowsable(EditorBrowsableState.Never)]
+    public class EmotionController
+    {
+        /// <summary>
+        /// Initializes a new instance of the <see cref="EmotionController"/> class without an avatar reference.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public EmotionController()
+        {
+
+        }
+
+        /// <summary>  
+        /// Initializes the EmotionController by setting up the necessary components for managing facial expressions in the avatar.  
+        /// </summary> 
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public void Initialize()
+        {
+
+        }
+        /// <summary>  
+        /// This method analyzes emotion the given text.   
+        /// </summary>  
+        /// <param name="text">The text to analyze</param> 
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public void AnalizeEmotion(string text)
+        {
+
+        }
+
+        /// <summary>  
+        /// This method starts playing the emotion facial.   
+        /// </summary>  
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public void PlayEmotionFacial()
+        {
+
+        }
+
+        /// <summary>  
+        /// This method pauses the emotion facial.   
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public void PauseEmotionFacial()
+        {
+
+        }
+
+        /// <summary>  
+        /// This method stops the emotion facial.   
+        /// </summary>  
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public void StopEmotionFacial()
+        {
+
+        }
+    }
+}
index e2a219a7937740a797b354fa2c9d035e3d9348df..afe62cdd856e8e3606c3c2feffd8c12a810ed4ec 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright(c) 2023 Samsung Electronics Co., Ltd.
+ * Copyright(c) 2024 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
 
 using System.Collections.Generic;
 using System.IO;
+using System.ComponentModel;
 
 using static Tizen.AIAvatar.AIAvatar;
 
 namespace Tizen.AIAvatar
 {
-    internal static class AvatarExtension
+    [EditorBrowsable(EditorBrowsableState.Never)]
+    public static class AvatarExtension
     {
-        internal static List<AvatarInfo> GetDefaultAvatarList()
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public static List<AvatarInfo> GetDefaultAvatarList()
         {
             var list = new List<AvatarInfo>();
             var avatarModelFolders = Directory.GetDirectories(ApplicationResourcePath + EmojiAvatarResourcePath);
index 61a606d9382783d78237c6d7a9b9e86b15fe8387..4f498b34e2726758f97760274f45bcdf369fb93a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright(c) 2023 Samsung Electronics Co., Ltd.
+ * Copyright(c) 2024 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/src/Tizen.AIAvatar/src/Extensions/Interop.SceneView.cs b/src/Tizen.AIAvatar/src/Extensions/Interop.SceneView.cs
new file mode 100644 (file)
index 0000000..a75171b
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Copyright(c) 2024 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+namespace Tizen.AIAvatar
+{
+    internal class Interop
+    {
+        internal static partial class Libraries
+        {
+            public const string Scene3D = "libdali2-csharp-binder-scene3d.so";
+        }
+
+        [global::System.Runtime.InteropServices.DllImport(Libraries.Scene3D, EntryPoint = "CSharp_Dali_SceneView_Property_AlphaMaskURL_get")]
+        public static extern int AlphaMaskURLGet();
+
+        [global::System.Runtime.InteropServices.DllImport(Libraries.Scene3D, EntryPoint = "CSharp_Dali_SceneView_Property_MaskContentScale_get")]
+        public static extern int MaskContentScaleGet();
+
+        [global::System.Runtime.InteropServices.DllImport(Libraries.Scene3D, EntryPoint = "CSharp_Dali_SceneView_Property_CropToMask_get")]
+        public static extern int CropToMaskGet();
+
+    }
+}
index b608205383405b6d8ff5246f7a2dc3e655e92e45..ae8552fe86af93d2b2eb47522fb0397f2f93754f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright(c) 2023 Samsung Electronics Co., Ltd.
+ * Copyright(c) 2024 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  *
  */
 
-using System;
-using System.Collections.Generic;
-using System.Text;
 using Tizen.NUI.Scene3D;
+using System.ComponentModel;
 
 namespace Tizen.AIAvatar
 {
-    internal static class SceneViewExtension
+    [EditorBrowsable(EditorBrowsableState.Never)]
+    public static class SceneViewExtension
     {
-        internal static void SetAlphaMaskUrl(this SceneView sceneView, string url)
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public static void SetAlphaMaskUrl(this SceneView sceneView, string url)
         {
             var setValue = new Tizen.NUI.PropertyValue(url);
             sceneView.SetProperty(Interop.AlphaMaskURLGet(), setValue);
             setValue.Dispose();
         }
 
-        internal static string GetAlphaMaskUrl(this SceneView sceneView)
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public static string GetAlphaMaskUrl(this SceneView sceneView)
         {
             var returnValue = "";
             var invertYAxis = sceneView.GetProperty(Interop.AlphaMaskURLGet());
@@ -40,14 +41,16 @@ namespace Tizen.AIAvatar
             return returnValue;
         }
 
-        internal static void SetMaskContentScaleFactor(this SceneView sceneView, float factor)
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public static void SetMaskContentScaleFactor(this SceneView sceneView, float factor)
         {
             var setValue = new Tizen.NUI.PropertyValue(factor);
             sceneView.SetProperty(Interop.MaskContentScaleGet(), setValue);
             setValue.Dispose();
         }
 
-        internal static float GetMaskContentScaleFactor(this SceneView sceneView)
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public static float GetMaskContentScaleFactor(this SceneView sceneView)
         {
             var returnValue = 0.0f;
             var invertYAxis = sceneView.GetProperty(Interop.MaskContentScaleGet());
@@ -56,14 +59,16 @@ namespace Tizen.AIAvatar
             return returnValue;
         }
 
-        internal static void EnableCropToMask(this SceneView sceneView, bool enableCropToMask)
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public static void EnableCropToMask(this SceneView sceneView, bool enableCropToMask)
         {
             var setValue = new Tizen.NUI.PropertyValue(enableCropToMask);
             sceneView.SetProperty(Interop.CropToMaskGet(), setValue);
             setValue.Dispose();
         }
 
-        internal static bool IsEnabledCropToMask(this SceneView sceneView)
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public static bool IsEnabledCropToMask(this SceneView sceneView)
         {
             bool returnValue = false;
             var invertYAxis = sceneView.GetProperty(Interop.CropToMaskGet());
diff --git a/src/Tizen.AIAvatar/src/Internal/AIAvatar.cs b/src/Tizen.AIAvatar/src/Internal/AIAvatar.cs
new file mode 100644 (file)
index 0000000..847866a
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Copyright(c) 2024 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+using Tizen.Multimedia;
+
+namespace Tizen.AIAvatar
+{
+    internal static class AIAvatar
+    {
+        internal const string LogTag = "Tizen.AIAvatar";
+        internal static readonly string ApplicationResourcePath = "/usr/apps/org.tizen.default-avatar-resource/shared/res/";
+        internal static readonly string EmojiAvatarResourcePath = "/models/EmojiAvatar/";
+        internal static readonly string DefaultModelResourcePath = "/models/DefaultAvatar/";
+        internal static readonly string DefaultMotionResourcePath = "/animation/motion/";
+
+        internal static readonly string VisemeInfo = $"{ApplicationResourcePath}/viseme/emoji_viseme_info.json";
+        internal static readonly string DefaultModel = "DefaultAvatar.gltf";
+
+        internal static readonly string AREmojiDefaultAvatarPath = $"{ApplicationResourcePath}{DefaultModelResourcePath}{DefaultModel}";
+
+        internal static readonly string DefaultLowModelResourcePath = "/models/DefaultAvatar_Low/";
+        internal static readonly string ExternalModel = "model_external.gltf";
+        internal static readonly string AREmojiDefaultLowAvatarPath = $"{ApplicationResourcePath}{DefaultLowModelResourcePath}{ExternalModel}";
+
+        internal static AudioOptions DefaultAudioOptions = new AudioOptions(24000, AudioChannel.Mono, AudioSampleType.S16Le);
+        internal static AudioOptions CurrentAudioOptions = DefaultAudioOptions;
+    }
+}
diff --git a/src/Tizen.AIAvatar/src/Internal/AvatarBlendShapeIndex.cs b/src/Tizen.AIAvatar/src/Internal/AvatarBlendShapeIndex.cs
new file mode 100644 (file)
index 0000000..c2185dd
--- /dev/null
@@ -0,0 +1,173 @@
+/*
+ * Copyright(c) 2024 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+using System.ComponentModel;
+using Tizen.NUI;
+using Tizen.NUI.Scene3D;
+
+namespace Tizen.AIAvatar
+{
+    /// <summary>
+    /// Specialized <see cref="BlendShapeIndex"/> to control avatar blend shape.
+    /// </summary>
+    /// <example>
+    /// <code>
+    /// AvatarBlendShapeIndex leftEyeBlink = new AvatarBlendShapeIndex(avatar.BlendShapeMapper, BlendShapeType.EyeBlinkLeft);
+    ///
+    /// // We can change the property later.
+    /// AVatarBlendShapeIndex rightEyeBlink = new AvatarJointTransformIndex(avatar.BlendShapeMapper);
+    /// rightEyeBlink.AvatarBlendShapeType = (uint)BlendShapeType.EyeBlinkRight;
+    /// </code>
+    /// </example>
+    [EditorBrowsable(EditorBrowsableState.Never)]
+    internal class AvatarBlendShapeIndex : BlendShapeIndex
+    {
+        internal AvatarPropertyMapper nameMapper = null;
+        internal uint blendShapeType;
+
+        internal AvatarBlendShapeIndex(AvatarPropertyMapper mapper) : base()
+        {
+            nameMapper = mapper;
+        }
+
+        internal AvatarBlendShapeIndex(AvatarPropertyMapper mapper, PropertyKey blendShapeId) : base(new PropertyKey(GetPropertyNameFromMapper(mapper, blendShapeId)))
+        {
+            nameMapper = mapper;
+        }
+
+        internal AvatarBlendShapeIndex(AvatarPropertyMapper nodeMapper, NodeType nodeType, PropertyKey blendShapeId) 
+            : base(new PropertyKey(GetPropertyNameFromMapper(nodeMapper, (uint)nodeType)), blendShapeId)
+        {
+        }
+
+        internal AvatarBlendShapeIndex(AvatarPropertyMapper blendShapeMapper, BlendShapeType blendShapeType) : this(blendShapeMapper, (uint)blendShapeType)
+        {
+        }
+
+        internal AvatarBlendShapeIndex(AvatarPropertyMapper mapper, uint blendShapeType) : base(new PropertyKey(GetPropertyNameFromMapper(mapper, blendShapeType)))
+        {
+            nameMapper = mapper;
+            this.blendShapeType = blendShapeType;
+        }
+
+        internal AvatarBlendShapeIndex(AvatarPropertyMapper nodeMapper, NodeType nodeType, AvatarPropertyMapper blendShapeMapper, BlendShapeType blendShapeType) 
+            : base(new PropertyKey(GetPropertyNameFromMapper(nodeMapper, (uint)nodeType)), new PropertyKey(GetPropertyNameFromMapper(blendShapeMapper, (uint)blendShapeType)))
+        {
+            nameMapper = blendShapeMapper;
+            this.blendShapeType = (uint)blendShapeType;
+        }
+
+        /// <summary>
+        /// Get the name of given index.
+        /// </summary>
+        /// <param name="mapper">Name mapper for given index</param>
+        /// <param name="id">Target ID what we want to get name</param>
+        /// <returns>Name, or null if invalid</returns>
+        private static string GetPropertyNameFromMapper(AvatarPropertyMapper mapper, PropertyKey id)
+        {
+            if (id == null)
+            {
+                return "";
+            }
+            if (id.Type == PropertyKey.KeyType.String)
+            {
+                return id.StringKey;
+            }
+
+            var str = mapper?.GetPropertyName((uint)id.IndexKey) ?? "";
+            return str;
+        }
+
+        /// <summary>
+        /// Get the name of given BlendShape.
+        /// </summary>
+        /// <param name="mapper">Name mapper for given index</param>
+        /// <param name="type">Type of joint what we want to get name</param>
+        /// <returns>Name, or null if invalid</returns>
+        private static string GetPropertyNameFromMapper(AvatarPropertyMapper mapper, uint type)
+        {
+            var str = mapper?.GetPropertyName(type) ?? "";
+            return str;
+        }
+
+        /// <summary>
+        /// TODO : Explain me
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public AvatarPropertyMapper NameMapper
+        {
+            get
+            {
+                return nameMapper;
+            }
+            set
+            {
+                nameMapper = value;
+
+                using PropertyKey blendShapeId = new(GetPropertyNameFromMapper(nameMapper, blendShapeType));
+                base.BlendShapeId = blendShapeId;
+            }
+        }
+
+        /// <summary>
+        /// TODO : Explain me
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public uint AvatarBlendShapeType
+        {
+            get
+            {
+                return blendShapeType;
+            }
+            set
+            {
+                blendShapeType = value;
+
+                using PropertyKey blendShapeId = new(GetPropertyNameFromMapper(nameMapper, blendShapeType));
+                base.BlendShapeId = blendShapeId;
+            }
+        }
+
+        /// <summary>
+        /// Hijack property to control Avatar specified logic.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public new PropertyKey BlendShapeId
+        {
+            get
+            {
+                return base.BlendShapeId;
+            }
+            set
+            {
+                if (value != null)
+                {
+                    if (value.Type == PropertyKey.KeyType.Index)
+                    {
+                        blendShapeType = (uint)value.IndexKey;
+                    }
+                    using PropertyKey blendShapeId = new(GetPropertyNameFromMapper(nameMapper, value));
+                    base.BlendShapeId = blendShapeId;
+                }
+                else
+                {
+                    base.BlendShapeId = value;
+                }
+            }
+        }
+    }
+}
diff --git a/src/Tizen.AIAvatar/src/Internal/AvatarJointTransformIndex.cs b/src/Tizen.AIAvatar/src/Internal/AvatarJointTransformIndex.cs
new file mode 100644 (file)
index 0000000..bf21dde
--- /dev/null
@@ -0,0 +1,173 @@
+/*
+ * Copyright(c) 2024 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+using System.ComponentModel;
+using Tizen.NUI;
+using Tizen.NUI.Scene3D;
+
+namespace Tizen.AIAvatar
+{
+    /// <summary>
+    /// Specialized <see cref="MotionTransformIndex"/> to control avatar joint transform.
+    /// </summary>
+    /// <example>
+    /// <code>
+    /// AvatarJointTransformIndex position = new AvatarJointTransformIndex(avatar.JointMapper, JointType.Head, MotionTransformIndex.TransformTypes.Position);
+    ///
+    /// // We can change the property later.
+    /// AvatarJointTransformIndex orientation = new AvatarJointTransformIndex(avatar.JointMapper);
+    /// orientation.AvatarJointType = (uint)JointType.Neck;
+    /// orientation.TransformType = MotionTransformIndex.TransformTypes.Orientation;
+    /// </code>
+    /// </example>
+    [EditorBrowsable(EditorBrowsableState.Never)]
+    internal class AvatarJointTransformIndex : MotionTransformIndex
+    {
+        internal AvatarPropertyMapper nameMapper = null;
+        internal uint jointType;
+
+        /// <summary>
+        /// Create an initialized avatar joint transform index.
+        /// </summary>
+        /// <param name="mapper">Name mapper for this index</param>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public AvatarJointTransformIndex(AvatarPropertyMapper mapper) : base()
+        {
+            nameMapper = mapper;
+        }
+
+        /// <summary>
+        /// Create an initialized avatar joint transform index with input node id, and transform type.
+        /// </summary>
+        /// <param name="mapper">Name mapper for this index</param>
+        /// <param name="modelNodeId">Node ID for this motion index</param>
+        /// <param name="transformType">Transform property type for this motion index</param>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public AvatarJointTransformIndex(AvatarPropertyMapper mapper, PropertyKey modelNodeId, TransformTypes transformType) : base(new PropertyKey(GetPropertyNameFromMapper(mapper, modelNodeId)), transformType)
+        {
+            nameMapper = mapper;
+        }
+
+        /// <summary>
+        /// Create an initialized avatar joint transform index with input node id, and transform type.
+        /// </summary>
+        /// <param name="mapper">Name mapper for this index</param>
+        /// <param name="jointType">Type of joint for this motion index</param>
+        /// <param name="transformType">Transform property type for this motion index</param>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        internal AvatarJointTransformIndex(AvatarPropertyMapper mapper, JointType jointType, TransformTypes transformType) : this(mapper, (uint)jointType, transformType)
+        {
+        }
+
+        /// <summary>
+        /// Create an initialized avatar joint transform index with input node id, and transform type.
+        /// </summary>
+        /// <param name="mapper">Name mapper for this index</param>
+        /// <param name="jointType">Type of joint for this motion index</param>
+        /// <param name="transformType">Transform property type for this motion index</param>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public AvatarJointTransformIndex(AvatarPropertyMapper mapper, uint jointType, TransformTypes transformType) : base(new PropertyKey(GetPropertyNameFromMapper(mapper, jointType)), transformType)
+        {
+            nameMapper = mapper;
+            this.jointType = jointType;
+        }
+
+        private static string GetPropertyNameFromMapper(AvatarPropertyMapper mapper, PropertyKey id)
+        {
+            if (id == null)
+            {
+                return "";
+            }
+            if (id.Type == PropertyKey.KeyType.String)
+            {
+                return id.StringKey;
+            }
+            return mapper?.GetPropertyName((uint)id.IndexKey) ?? "";
+        }
+
+        private static string GetPropertyNameFromMapper(AvatarPropertyMapper mapper, uint jointType)
+        {
+            return mapper?.GetPropertyName(jointType) ?? "";
+        }
+
+        /// <summary>
+        /// TODO : Explain me
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public AvatarPropertyMapper NameMapper
+        {
+            get
+            {
+                return nameMapper;
+            }
+            set
+            {
+                nameMapper = value;
+
+                using PropertyKey nodeId = new(GetPropertyNameFromMapper(nameMapper, jointType));
+                base.ModelNodeId = nodeId;
+            }
+        }
+
+        /// <summary>
+        /// TODO : Explain me
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public uint AvatarJointType
+        {
+            get
+            {
+                return jointType;
+            }
+            set
+            {
+                jointType = value;
+
+                using PropertyKey nodeId = new(GetPropertyNameFromMapper(nameMapper, jointType));
+                base.ModelNodeId = nodeId;
+            }
+        }
+
+        /// <summary>
+        /// Hijack property to control Avatar specified logic.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public new PropertyKey ModelNodeId
+        {
+            get
+            {
+                return base.ModelNodeId;
+            }
+            set
+            {
+                if (value != null)
+                {
+                    if (value.Type == PropertyKey.KeyType.Index)
+                    {
+                        jointType = (uint)value.IndexKey;
+                    }
+                    using PropertyKey nodeId = new(GetPropertyNameFromMapper(nameMapper, value));
+                    base.ModelNodeId = nodeId;
+                }
+                else
+                {
+                    base.ModelNodeId = value;
+                }
+            }
+        }
+    }
+}
diff --git a/src/Tizen.AIAvatar/src/Internal/DefaultAvatarProperties.cs b/src/Tizen.AIAvatar/src/Internal/DefaultAvatarProperties.cs
new file mode 100644 (file)
index 0000000..57fe550
--- /dev/null
@@ -0,0 +1,200 @@
+/*
+ * Copyright(c) 2024 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+using System.Collections.Generic;
+
+namespace Tizen.AIAvatar
+{
+    internal class DefaultAvatarProperties : AvatarProperties
+    {
+        private static AvatarPropertyMapper defaultJointMapper = new AvatarPropertyMapper();
+        private static AvatarPropertyMapper defaultBlendShapeNameMapper = new AvatarPropertyMapper();
+        private static AvatarPropertyMapper defaultNodeMapper = new AvatarPropertyMapper();
+
+        internal DefaultAvatarProperties() : base(defaultJointMapper, defaultBlendShapeNameMapper, defaultNodeMapper)
+        {
+            Initialize();
+        }
+
+        private void Initialize()
+        {
+            foreach (var indexNamePair in blendShapeList)
+            {
+                BlendShapeMapper.SetPropertyName((uint)indexNamePair.Item1, indexNamePair.Item2);
+            }
+
+            foreach (var indexNamePair in jointList)
+            {
+                JointMapper.SetPropertyName((uint)indexNamePair.Item1, indexNamePair.Item2);
+            }
+
+            foreach (var indexNamePair in nodeList)
+            {
+                NodeMapper.SetPropertyName((uint)indexNamePair.Item1, indexNamePair.Item2);
+            }
+
+        }
+
+        #region AR Emoji BlendShape name list
+        private static readonly List<(BlendShapeType, string)> blendShapeList = new List<(BlendShapeType, string)>()
+        {
+            (BlendShapeType.EyeBlinkLeft, "EyeBlink_Left"),
+            (BlendShapeType.EyeSquintLeft, "EyeSquint_Left"),
+            (BlendShapeType.EyeDownLeft, "EyeDown_Left"),
+            (BlendShapeType.EyeInLeft, "EyeIn_Left"),
+            (BlendShapeType.EyeOpenLeft, "EyeOpen_Left"),
+            (BlendShapeType.EyeOutLeft, "EyeOut_Left"),
+            (BlendShapeType.EyeUpLeft, "EyeUp_Left"),
+
+            (BlendShapeType.EyeBlinkRight, "EyeBlink_Right"),
+            (BlendShapeType.EyeSquintRight, "EyeSquint_Right"),
+            (BlendShapeType.EyeDownRight, "EyeDown_Right"),
+            (BlendShapeType.EyeInRight, "EyeIn_Right"),
+            (BlendShapeType.EyeOpenRight, "EyeOpen_Right"),
+            (BlendShapeType.EyeOutRight, "EyeOut_Right"),
+            (BlendShapeType.EyeUpRight, "EyeUp_Right"),
+
+            (BlendShapeType.JawForward, "JawFwd"),
+            (BlendShapeType.JawOpen, "JawOpen"),
+            (BlendShapeType.JawChew, "JawChew"),
+            (BlendShapeType.JawLeft, "JawLeft"),
+            (BlendShapeType.JawRight, "JawRight"),
+
+            (BlendShapeType.MouthLeft, "MouthLeft"),
+            (BlendShapeType.MouthFrownLeft, "MouthFrown_Left"),
+            (BlendShapeType.MouthSmileLeft, "MouthSmile_Left"),
+            (BlendShapeType.MouthDimpleLeft, "MouthDimple_Left"),
+
+            (BlendShapeType.MouthRight, "MouthRight"),
+            (BlendShapeType.MouthFrownRight, "MouthFrown_Right"),
+            (BlendShapeType.MouthSmileRight, "MouthSmile_Right"),
+            (BlendShapeType.MouthDimpleRight, "MouthDimple_Right"),
+
+            (BlendShapeType.LipsStretchLeft, "LipsStretch_Left"),
+            (BlendShapeType.LipsStretchRight, "LipsStretch_Right"),
+            (BlendShapeType.LipsUpperClose, "LipsUpperClose"),
+            (BlendShapeType.LipsLowerClose, "LipsLowerClose"),
+            (BlendShapeType.LipsUpperUp, "LipsUpperUp"),
+            (BlendShapeType.LipsLowerDown, "LipsLowerDown"),
+            (BlendShapeType.LipsUpperOpen, "LipsUpperOpen"),
+            (BlendShapeType.LipsLowerOpen, "LipsLowerOpen"),
+            (BlendShapeType.LipsFunnel, "LipsFunnel"),
+            (BlendShapeType.LipsPucker, "LipsPucker"),
+
+            (BlendShapeType.BrowDownLeft, "BrowsDown_Left"),
+            (BlendShapeType.BrowDownRight, "BrowsDown_Right"),
+            (BlendShapeType.BrowUpCenter, "BrowsUp_Center"),
+            (BlendShapeType.BrowUpLeft, "BrowsUp_Left"),
+            (BlendShapeType.BrowUpRight, "BrowsUp_Right"),
+            (BlendShapeType.CheekSquintLeft, "CheekSquint_Left"),
+            (BlendShapeType.CheekSquintRight, "CheekSquint_Right"),
+            (BlendShapeType.ChinLowerRaise, "ChinLowerRaise"),
+            (BlendShapeType.ChinUpperRaise, "ChinUpperRaise"),
+
+            (BlendShapeType.TongueOut, "Tongue_Out"),
+            (BlendShapeType.TongueUp, "Tongue_Up"),
+            (BlendShapeType.TongueDown, "Tongue_Down"),
+            (BlendShapeType.TongueLeft, "Tongue_Left"),
+            (BlendShapeType.TongueRight, "Tongue_Right"),
+
+            (BlendShapeType.Sneer, "Sneer"),
+            (BlendShapeType.Puff, "Puff"),
+            (BlendShapeType.PuffLeft, "Puff_Left"),
+            (BlendShapeType.PuffRight, "Puff_Right"),
+        };
+        #endregion
+
+        #region AR Emoji Joint name list
+        private static readonly List<(JointType, string)> jointList = new List<(JointType, string)>
+        {
+            (JointType.Head, "head_JNT"),
+            (JointType.Neck, "neck_JNT"),
+            (JointType.EyeLeft, "l_eye_JNT"),
+            (JointType.EyeRight, "r_eye_JNT"),
+
+            (JointType.ShoulderLeft, "l_arm_JNT"),
+            (JointType.ElbowLeft, "l_forearm_JNT"),
+            (JointType.WristLeft, "l_hand_JNT"),
+
+            (JointType.ShoulderRight, "r_arm_JNT"),
+            (JointType.ElbowRight, "r_forearm_JNT"),
+            (JointType.WristRight, "r_hand_JNT"),
+
+            (JointType.HipLeft, "l_upleg_JNT"),
+            (JointType.KneeLeft, "l_leg_JNT"),
+            (JointType.AnkleLeft, "l_foot_JNT"),
+            (JointType.ForeFootLeft, "l_toebase_JNT"),
+
+            (JointType.HipRight, "r_upleg_JNT"),
+            (JointType.KneeRight, "r_leg_JNT"),
+            (JointType.AnkleRight, "r_foot_JNT"),
+            (JointType.ForeFootRight, "r_toebase_JNT"),
+
+            (JointType.FingerThumb1Left, "l_handThumb1_JNT"),
+            (JointType.FingerThumb2Left, "l_handThumb2_JNT"),
+            (JointType.FingerThumb3Left, "l_handThumb3_JNT"),
+            (JointType.FingerThumb4Left, "l_handThumb4_JNT"),
+            (JointType.FingerIndex1Left, "l_handIndex1_JNT"),
+            (JointType.FingerIndex2Left, "l_handIndex2_JNT"),
+            (JointType.FingerIndex3Left, "l_handIndex3_JNT"),
+            (JointType.FingerIndex4Left, "l_handIndex4_JNT"),
+            (JointType.FingerMiddle1Left, "l_handMiddle1_JNT"),
+            (JointType.FingerMiddle2Left, "l_handMiddle2_JNT"),
+            (JointType.FingerMiddle3Left, "l_handMiddle3_JNT"),
+            (JointType.FingerMiddle4Left, "l_handMiddle4_JNT"),
+            (JointType.FingerRing1Left, "l_handRing1_JNT"),
+            (JointType.FingerRing2Left, "l_handRing2_JNT"),
+            (JointType.FingerRing3Left, "l_handRing3_JNT"),
+            (JointType.FingerRing4Left, "l_handRing4_JNT"),
+            (JointType.FingerPinky1Left, "l_handPinky1_JNT"),
+            (JointType.FingerPinky2Left, "l_handPinky2_JNT"),
+            (JointType.FingerPinky3Left, "l_handPinky3_JNT"),
+            (JointType.FingerPinky4Left, "l_handPinky4_JNT"),
+
+            (JointType.FingerThumb1Right, "r_handThumb1_JNT"),
+            (JointType.FingerThumb2Right, "r_handThumb2_JNT"),
+            (JointType.FingerThumb3Right, "r_handThumb3_JNT"),
+            (JointType.FingerThumb4Right, "r_handThumb4_JNT"),
+            (JointType.FingerIndex1Right, "r_handIndex1_JNT"),
+            (JointType.FingerIndex2Right, "r_handIndex2_JNT"),
+            (JointType.FingerIndex3Right, "r_handIndex3_JNT"),
+            (JointType.FingerIndex4Right, "r_handIndex4_JNT"),
+            (JointType.FingerMiddle1Right, "r_handMiddle1_JNT"),
+            (JointType.FingerMiddle2Right, "r_handMiddle2_JNT"),
+            (JointType.FingerMiddle3Right, "r_handMiddle3_JNT"),
+            (JointType.FingerMiddle4Right, "r_handMiddle4_JNT"),
+            (JointType.FingerRing1Right, "r_handRing1_JNT"),
+            (JointType.FingerRing2Right, "r_handRing2_JNT"),
+            (JointType.FingerRing3Right, "r_handRing3_JNT"),
+            (JointType.FingerRing4Right, "r_handRing4_JNT"),
+            (JointType.FingerPinky1Right, "r_handPinky1_JNT"),
+            (JointType.FingerPinky2Right, "r_handPinky2_JNT"),
+            (JointType.FingerPinky3Right, "r_handPinky3_JNT"),
+            (JointType.FingerPinky4Right, "r_handPinky4_JNT"),
+        };
+        #endregion
+
+        #region AR Emoji Joint name list
+        private static readonly List<(NodeType, string)> nodeList = new List<(NodeType, string)>
+        {
+            (NodeType.HeadGeo, "head_GEO"),
+            (NodeType.MouthGeo, "mouth_GEO"),
+            (NodeType.EyelashGeo, "eyelash_GEO"),
+        };
+        #endregion
+    }
+}
diff --git a/src/Tizen.AIAvatar/src/Internal/Utils.cs b/src/Tizen.AIAvatar/src/Internal/Utils.cs
new file mode 100644 (file)
index 0000000..e845a02
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ * Copyright(c) 2024 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+using System;
+using System.IO;
+using Tizen.Security;
+using Newtonsoft.Json;
+using System.Collections.Generic;
+using static Tizen.AIAvatar.AIAvatar;
+
+namespace Tizen.AIAvatar
+{
+    internal class Utils
+    {
+        internal static void ConvertAudioToFloat(in byte[] audioBytes, out float[] audioFloat)
+        {
+            audioFloat = new float[audioBytes.Length / 2];
+
+            for (int i = 0, j = 0; i < audioBytes.Length; i += 2, j++)
+            {
+                short sample = BitConverter.ToInt16(audioBytes, i);
+                audioFloat[j] = sample / 32768.0f;
+            }
+        }
+
+        internal static byte[] ReadAllBytes(string path)
+        {
+            try
+            {
+                var bytes = File.ReadAllBytes(path);
+                return bytes;
+            }
+            catch (Exception)
+            {
+                return null;
+            }
+        }
+
+        internal static void SaveFile(string path, string filename, byte[] array)
+        {
+            try
+            {
+                var file = new FileStream($"{path}/{filename}", FileMode.Create);
+                file.Write(array, 0, array.Length);
+                file.Close();
+            }
+            catch (Exception)
+            {
+                return;
+            }
+        }
+
+        internal static void CheckPrivilege(string privilege)
+        {
+            var result = PrivacyPrivilegeManager.CheckPermission(privilege);
+
+            switch (result)
+            {
+                case CheckResult.Allow:
+                    Log.Info(LogTag, $"Privilege \"{privilege}\" : allowed.");
+                    break;
+                case CheckResult.Deny:
+                    Log.Info(LogTag, $"Privilege \"{privilege}\" : denied.");
+                    /// Privilege can't be used
+                    break;
+                case CheckResult.Ask:
+                    /// Request permission to user
+                    PrivacyPrivilegeManager.RequestPermission(privilege);
+                    break;
+            }
+        }
+
+        internal static T ConvertJson<T>(string jsonString)
+        {
+            return JsonConvert.DeserializeObject<T>(jsonString);
+        }
+
+        internal int FindMaxValue<T>(List<T> list, Converter<T, int> projection)
+        {
+            if (list.Count == 0)
+            {
+                throw new InvalidOperationException("Empty list");
+            }
+            int maxValue = int.MinValue;
+            foreach (T item in list)
+            {
+                int value = projection(item);
+                if (value > maxValue)
+                {
+                    maxValue = value;
+                }
+            }
+            return maxValue;
+        }
+    }
+}
+
+internal class SystemUtils
+{
+    internal static string GetFileName(string path)
+    {
+        return System.IO.Path.GetFileName(path);
+    }
+    internal static string GetFileNameWithoutExtension(string path)
+    {
+        return System.IO.Path.GetFileNameWithoutExtension(path);
+    }
+}
diff --git a/src/Tizen.AIAvatar/src/Lipsync/AsyncLipSyncer.cs b/src/Tizen.AIAvatar/src/Lipsync/AsyncLipSyncer.cs
new file mode 100644 (file)
index 0000000..952c47c
--- /dev/null
@@ -0,0 +1,207 @@
+/*
+ * Copyright(c) 2024 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using Tizen.NUI;
+
+using static Tizen.AIAvatar.AIAvatar;
+
+namespace Tizen.AIAvatar
+{
+    [EditorBrowsable(EditorBrowsableState.Never)]
+    internal class AsyncLipSyncer
+    {
+        private readonly uint AsyncPlayTime = 160;
+        private Queue<Animation> lipAnimations;
+        private Queue<byte[]> lipAudios;
+        private Timer asyncVowelTimer;
+
+        private bool isAsyncInit = false;
+        private bool isFinishAsyncLip = false;
+
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        internal AsyncLipSyncer()
+        {
+
+        }
+
+        internal int SampleRate { get; set; }
+
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        internal bool IsAsyncInit { get=>isAsyncInit; set=>isAsyncInit = value; }
+
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        internal void SetFinishAsyncLip(bool finished)
+        {
+            isFinishAsyncLip = finished;
+        }
+
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        protected new void OnLipAnimationFinished(object sender, EventArgs e)
+        {
+            if (!isAsyncInit)
+            {
+                //TODO : State is Stop
+            }
+            else
+            {
+                Tizen.Log.Error(LogTag, "OnLipAnimationFinished---------------c");
+                //Async State
+                if (isFinishAsyncLip && lipAnimations.Count == 0)
+                {
+                    Tizen.Log.Error(LogTag, "Finish vowel lip sync");
+
+                    
+                    //Audio Player is Stop, AudioPlayer.Stop();
+                    //TODO : State is Stop
+                    DestroyVowelTimer();
+                    isAsyncInit = false;
+                }
+            }
+        }
+
+        internal void InitAsyncLipsync()
+        {
+            if (lipAnimations == null)
+            {
+                lipAnimations = new Queue<Animation>();
+            }
+            else
+            {
+                lipAnimations.Clear();
+            }
+
+            if (lipAudios == null)
+            {
+                lipAudios = new Queue<byte[]>();
+            }
+            else
+            {
+                lipAudios.Clear();
+            }
+        }
+
+        private void EnqueueVowels(byte[] buffer, bool deleteLast = false)
+        {
+            /*
+            var vowels = PredictVowels(buffer);
+            if (vowels != null)
+            {
+                vowelPools.Enqueue(vowels);
+                if (deleteLast)
+                {
+                    var vowelList = new List<string>(vowels);
+                    vowelList.RemoveAt(vowelList.Count - 1);
+                    vowels = vowelList.ToArray();
+                }
+            }*/
+        }
+
+        internal Animation CreateAsyncLipAnimation(byte[] buffer, int sampleRate)
+        {
+            EnqueueVowels(buffer, false);
+            return null;
+            //return CreateLipAnimationByVowelsQueue(sampleRate);
+        }
+
+        internal void EnqueueAnimation(byte[] recordBuffer, int sampleRate, int audioLength)
+        {
+            var createdAni = CreateAsyncLipAnimation(recordBuffer, sampleRate);
+            if (createdAni != null)
+            {
+                lipAnimations.Enqueue(createdAni);
+            }
+
+            //Use Audio Full File
+            ///var createdAni = avatarLipSyncer.CreateLipAnimation(recordBuffer, sampleRate);
+            //lipAnimations.Enqueue(createdAni);
+
+            var currentAudioBuffer = new byte[audioLength];
+            Buffer.BlockCopy(recordBuffer, 0, currentAudioBuffer, 0, audioLength);
+
+            lipAudios.Enqueue(currentAudioBuffer);
+        }
+
+        internal bool PlayAsyncLip(int sampleRate, bool isFinishAsyncLip)
+        {
+            try
+            {
+                if (lipAudios.Count <= 0 && lipAnimations.Count <= 0)
+                {
+                    Tizen.Log.Info(LogTag, "Return lipaudio 0");
+                    if (isFinishAsyncLip)
+                    {
+                        Tizen.Log.Info(LogTag, "Finish Async lipsync");
+                        return false;
+                    }
+                    return true;
+                }
+                Tizen.Log.Info(LogTag, "Async timer tick lipAudios : " + lipAudios.Count);
+                Tizen.Log.Info(LogTag, "Async timer tick lipAnimations : " + lipAnimations.Count);
+
+                var lipAnimation = lipAnimations.Dequeue();
+                lipAnimation.Finished += OnLipAnimationFinished;
+
+                //ResetLipAnimation(lipAnimation);
+                //PlayLipAnimation();
+                var audioBuffer = lipAudios.Dequeue();
+                
+                //Audio Playe rAsync Play
+                //AudioPlayer.PlayAsync(audioBuffer, sampleRate);
+                return true;
+
+            }
+            catch (Exception ex)
+            {
+                Log.Error(LogTag, $"---Log Tick : {ex.StackTrace}");
+
+                return false;
+            }
+        }
+
+        internal void StartAsyncLipPlayTimer()
+        {
+            if (asyncVowelTimer == null)
+            {
+                Tizen.Log.Info(LogTag, "Start Async");
+                asyncVowelTimer = new Timer(AsyncPlayTime);
+                asyncVowelTimer.Tick += OnAsyncVowelTick;
+                asyncVowelTimer.Start();
+            }
+            return;
+        }
+
+        private void DestroyVowelTimer()
+        {
+            if (asyncVowelTimer != null)
+            {
+
+                asyncVowelTimer.Tick -= OnAsyncVowelTick;
+                asyncVowelTimer.Stop();
+                asyncVowelTimer.Dispose();
+                asyncVowelTimer = null;
+            }
+        }
+
+        private bool OnAsyncVowelTick(object source, Tizen.NUI.Timer.TickEventArgs e)
+        {
+            return PlayAsyncLip(SampleRate, isFinishAsyncLip);
+        }
+    }
+}
diff --git a/src/Tizen.AIAvatar/src/Lipsync/LipSyncController.cs b/src/Tizen.AIAvatar/src/Lipsync/LipSyncController.cs
new file mode 100644 (file)
index 0000000..45349f8
--- /dev/null
@@ -0,0 +1,668 @@
+/*
+ * Copyright(c) 2024 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+using System.Collections.Generic;
+using System.ComponentModel;
+using System;
+using Tizen.Uix.Tts;
+
+using static Tizen.AIAvatar.AIAvatar;
+using Tizen.Multimedia;
+using Tizen.NUI.Scene3D;
+using Tizen.NUI;
+
+namespace Tizen.AIAvatar
+{
+     /// <summary>
+     /// A controller class used to manage lip sync functionality for avatars.
+     /// </summary>
+    [EditorBrowsable(EditorBrowsableState.Never)]
+    public class LipSyncController : IDisposable
+    {
+        private TTSController ttsController;
+        private AudioRecorder audioRecorder;
+        private LipSyncer lipSyncer;
+
+        private Avatar avatar;
+
+        private event EventHandler ttsReadyFinished;
+        private readonly Object ttsReadyFinishedLock = new Object();
+
+        /// <summary>  
+        /// Initializes a new instance of the <see cref="LipSyncController"/> class.  
+        /// </summary>  
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public LipSyncController(Avatar avatar)
+        {
+            this.avatar = avatar;
+
+            audioRecorder = new AudioRecorder();
+            lipSyncer = new LipSyncer();
+
+            lipSyncer.CreatedKeyFrameAnimation += OnCreatedKeyFrameAnimation;
+        }
+
+        private Animation CreateLipAnimation(AnimationKeyFrame animationKeyFrames, bool isMic = false)
+        {
+            var animationTime = (int)(animationKeyFrames.AnimationTime * 1000f);
+            var lipAnimation = new Animation(animationTime);
+
+            var motionData = new MotionData(animationTime);
+            for (var i = 0; i < animationKeyFrames.NodeNames.Length; i++)
+            {
+                var nodeName = animationKeyFrames.NodeNames[i];
+                for (var j = 0; j < animationKeyFrames.BlendShapeCounts[i]; j++)
+                {
+                    var blendShapeIndex = new BlendShapeIndex(new PropertyKey(nodeName), new PropertyKey(j));
+                    var keyFrameList = animationKeyFrames.GetKeyFrames(nodeName, j);
+                    if (keyFrameList.Count == 0)
+                    {
+                        continue;
+                    }
+
+                    var keyFrames = new KeyFrames();
+                    CreateKeyTimeFrames(ref keyFrames, keyFrameList, isMic);
+
+                    motionData.Add(blendShapeIndex, new MotionValue(keyFrames));
+                    lipAnimation = avatar.GenerateMotionDataAnimation(motionData);
+                }
+            }
+            return lipAnimation;
+        }
+
+        private KeyFrames CreateKeyTimeFrames(ref KeyFrames keyFrames, List<KeyFrame> keyFrameList, bool isMic = false)
+        {
+            foreach (var key in keyFrameList)
+            {
+                keyFrames.Add(key.time, key.value);
+            }
+            if (!isMic) keyFrames.Add(1.0f, 0.0f);
+
+            return keyFrames;
+        }
+
+        private Animation OnCreatedKeyFrameAnimation(AnimationKeyFrame animationKeyFrame, bool isMic)
+        {
+            if (animationKeyFrame == null)
+            {
+                Tizen.Log.Error(LogTag, "animtionKeyFrame is null");
+            }
+            var lipAnimation = CreateLipAnimation(animationKeyFrame, isMic);
+            return lipAnimation;
+        }
+
+        /// <summary>  
+        /// Occurs when text-to-speech synthesis has finished and the audio data is ready to play.  
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public event EventHandler TTSReadyFinished
+        {
+            add
+            {
+                lock (ttsReadyFinishedLock)
+                {
+                    ttsReadyFinished += value;
+                }
+
+            }
+
+            remove
+            {
+                lock (ttsReadyFinishedLock)
+                {
+                    if (ttsReadyFinished == null)
+                    {
+                        Log.Error(LogTag, "ttsReadyFinished is null");
+                        return;
+                    }
+                    ttsReadyFinished -= value;
+                }
+            }
+        }
+
+        /// <summary>  
+        /// Gets the current Text-To-Speech client associated with the Lip Sync Controller.  
+        /// </summary>  
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public TtsClient CurrentTTSClient => ttsController?.TtsHandle;
+
+        /// <summary>
+        /// Initializes the Text-To-Speech system for use with the Lip Sync Controller.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public void InitializeTTS()
+        {
+            if (ttsController == null)
+            {
+                try
+                {
+                    ttsController = new TTSController();
+                    //TODO : LipSync Event Connect
+                    ttsController.PreparedSyncText += OnPreparedSyncText;
+                    ttsController.StoppedTTS += OnStoppedTTS;
+                    ttsController.UpdatedBuffer += OnUpdatedBuffer;
+                }
+                catch (Exception e)
+                {
+                    Log.Error(LogTag, $"error :{e.Message}");
+                    Log.Error(LogTag, $"{e.StackTrace}");
+                }
+            }
+        }
+
+        private void OnUpdatedBuffer(object sender, TTSControllerEventArgs e)
+        {
+            throw new NotImplementedException();
+            if (lipSyncer != null)
+            {
+                Log.Error(LogTag, "OnTTSBufferChanged");
+                /*
+                lipSyncer.EnqueueAnimation(recordBuffer, sampleRate, audioLength);
+                if (!isAsyncLipStarting)
+                {
+                    lipSyncer.StartAsyncLipPlayTimer();
+                    isAsyncLipStarting = true;
+                }*/
+            }
+            else
+            {
+                Log.Error(LogTag, "avatarLipSyncer is null");
+            }
+        }
+
+        private void OnStoppedTTS(object sender, TTSControllerEventArgs e)
+        {
+            lipSyncer.Stop();
+        }
+
+        private void OnPreparedSyncText(object sender, TTSControllerEventArgs e)
+        {
+            var data = e.AudioData;
+            var sampleRate = e.SampleRate;
+            
+            // Play Lipsync Animation by Audio
+            lipSyncer.PlayAudio(data, sampleRate);
+        }
+
+        /// <summary>  
+        /// Deinitializes the Text-To-Speech system for use with the Lip Sync Controller. 
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public void DeInitializeTTS()
+        {
+            if (ttsController != null)
+            {
+                try
+                {
+                    ttsController.DeinitTts();
+                    ttsController = null;
+                }
+                catch (Exception e)
+                {
+                    Log.Error(LogTag, $"error :{e.Message}");
+                    Log.Error(LogTag, $"{e.StackTrace}");
+                }
+            }
+        }
+
+        /// <summary>  
+        /// Returns a list of supported voices for the Text-To-Speech system.  
+        /// </summary>  
+        /// <returns></returns>  
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public List<VoiceInfo> GetSupportedVoices()
+        {
+            return ttsController.GetSupportedVoices();
+        }
+
+        /// <summary>  
+        /// Plays the given audio with LipSync and returns whether it was successful or not. 
+        /// If the lip syncer is null, logs an error and returns false.
+        /// The lipSyncer plays the audio using the provided byte array and sample rate.  
+        /// </summary>  
+        /// <param name="audio">The audio data to be played in a byte array format.</param>  
+        /// <param name="sampleRate">The sampling rate of the audio data, default value is 24000 Hz.</param>
+        public bool PlayLipSync(byte[] audio, int sampleRate = 24000)
+        {
+            if (lipSyncer == null)
+            {
+                Log.Error(LogTag, "lipSyncer is null");
+                return false;
+            }
+            lipSyncer.PlayAudio(audio, sampleRate);
+
+            return true;
+        }
+
+        /// <summary>  
+        /// Plays the given audio with LipSync and returns whether it was successful or not. 
+        /// If the lip syncer is null, logs an error and returns false.
+        /// The lipSyncer plays the audio using the provided byte array and sample rate.  
+        /// </summary>  
+        /// <param name="audio">The audio data to be played in a byte array format.</param>  
+        /// <param name="sampleRate">The sampling rate of the audio data, default value is 16000 Hz.</param>
+        public bool PlayLipSync(string path, int sampleRate = 24000)
+        {
+            var audio = Utils.ReadAllBytes(path);
+            if (audio == null)
+            {
+                Log.Error(LogTag, "audio data is null");
+                return false;
+            }
+            lipSyncer.PlayAudio(audio, sampleRate);
+
+            return true;
+        }
+
+        /// <summary>  
+        /// Prepares the Text-To-Speech engine to synthesize speech from the provided text and voice info.  
+        /// </summary>  
+        /// <param name="text">The text to convert into speech.</param>  
+        /// <param name="voiceInfo">The voice info to use for converting the text into speech.</param>  
+        /// <param name="ttsReadyFinishedCallback">An optional callback that will be invoked when the TTS process is complete.</param>  
+        /// <returns><c>True</c> if preparation was successful, otherwise <c>False</c>.</returns> 
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public bool PrepareTTS(string text, VoiceInfo voiceInfo, EventHandler ttsReadyFinishedCallback = null)
+        {
+            if (ttsController == null || ttsController.TtsHandle == null)
+            {
+                Log.Error(LogTag, "tts is null");
+                return false;
+            }
+
+
+            if (!ttsController.IsSupportedVoice(voiceInfo))
+            {
+                Log.Info(LogTag, $"{voiceInfo.Language} & {voiceInfo.Type} is not supported");
+                return false;
+            }
+
+            Log.Info(LogTag, "Current TTS State :" + ttsController.TtsHandle.CurrentState);
+            if (ttsController.TtsHandle.CurrentState != Tizen.Uix.Tts.State.Ready)
+            {
+                Log.Info(LogTag, "TTS is not ready");
+                return false;
+            }
+
+            try
+            {
+                ttsController.AddText(text, voiceInfo);
+                ttsController.Prepare(ttsReadyFinishedCallback);
+            }
+            catch (Exception e)
+            {
+                Log.Error(LogTag, $"error :{e.Message}");
+                Log.Error(LogTag, $"{e.StackTrace}");
+                return false;
+            }
+            return true;
+        }
+
+        /// <summary>  
+        /// Prepares the Text-To-Speech engine to synthesize speech from the provided text and language code.  
+        /// </summary>  
+        /// <param name="text">The text to convert into speech.</param>  
+        /// <param name="lang">The two-letter ISO 639-1 language code to use for converting the text into speech (default is Korean - ko_KR).</param>  
+        /// <param name="ttsReadyFinishedCallback">An optional callback that will be invoked when the TTS process is complete.</param>  
+        /// <returns><c>True</c> if preparation was successful, otherwise <c>False</c>.</returns>  
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public bool PrepareTTS(string text, string lang = "ko_KR", EventHandler ttsReadyFinishedCallback = null)
+        {
+            if (ttsController == null || ttsController.TtsHandle == null)
+            {
+                Log.Error(LogTag, "tts is null");
+                return false;
+            }
+
+            if (!ttsController.IsSupportedVoice(lang))
+            {
+                Log.Error(LogTag, $"{lang} is not supported");
+                return false;
+            }
+
+            Log.Info(LogTag, "Current TTS State :" + ttsController.TtsHandle.CurrentState);
+            if (ttsController.TtsHandle.CurrentState != Tizen.Uix.Tts.State.Ready)
+            {
+                Log.Error(LogTag, "TTS is not ready");
+                return false;
+            }
+            try
+            {
+                ttsController.AddText(text, lang);
+                ttsController.Prepare(ttsReadyFinishedCallback);
+            }
+            catch (Exception e)
+            {
+                Log.Error(LogTag, $"error :{e.Message}");
+                Log.Error(LogTag, $"{e.StackTrace}");
+                return false;
+            }
+            return true;
+        }
+
+        /// <summary>  
+        /// Plays the previously prepared Text-To-Speech audio data.  
+        /// </summary>  
+        /// <returns><c>True</c> if playback started successfully, otherwise <c>False</c>.</returns>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public bool PlayPreparedTTS()
+        {
+            if (ttsController == null || ttsController.TtsHandle == null)
+            {
+                Log.Error(LogTag, "tts is null");
+                return false;
+            }
+
+            return ttsController.PlayPreparedText();
+        }
+
+        /// <summary>  
+        /// Converts the given text into speech using the specified voice info and plays the resulting audio immediately.  
+        /// </summary>  
+        /// <param name="text">The text to convert into speech.</param>  
+        /// <param name="voiceInfo">The voice info to use for converting the text into speech.</param>  
+        /// <returns><c>True</c> if playback started successfully, otherwise <c>False</c>.</returns>  
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public bool PlayTTS(string text, VoiceInfo voiceInfo)
+        {
+            if (ttsController == null || ttsController.TtsHandle == null)
+            {
+                Log.Error(LogTag, "tts is null");
+                return false;
+            }
+
+            if (!ttsController.IsSupportedVoice(voiceInfo))
+            {
+                Log.Info(LogTag, $"{voiceInfo.Language} & {voiceInfo.Type} is not supported");
+                return false;
+            }
+
+            Log.Info(LogTag, "Current TTS State :" + ttsController.TtsHandle.CurrentState);
+            if (ttsController.TtsHandle.CurrentState != Tizen.Uix.Tts.State.Ready)
+            {
+                Log.Info(LogTag, "TTS is not ready");
+                return false;
+            }
+
+            try
+            {
+                ttsController.AddText(text, voiceInfo);
+                ttsController.Play();
+            }
+            catch (Exception e)
+            {
+                Log.Error(LogTag, $"error :{e.Message}");
+                Log.Error(LogTag, $"{e.StackTrace}");
+                return false;
+            }
+            return true;
+        }
+
+        /// <summary>  
+        /// Converts the given text into speech using the specified language code and plays the resulting audio immediately.  
+        /// </summary>  
+        /// <param name="text">The text to convert into speech.</param>  
+        /// <param name="lang">The two-letter ISO 639-1 language code to use for converting the text into speech (default is Korean - ko_KR).</param>  
+        /// <returns><c>True</c> if playback started successfully, otherwise <c>False</c>.</returns>  
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public bool PlayTTS(string text, string lang = "ko_KR")
+        {
+            if (ttsController == null || ttsController.TtsHandle == null)
+            {
+                Log.Error(LogTag, "tts is null");
+                return false;
+            }
+
+            if (!ttsController.IsSupportedVoice(lang))
+            {
+                Log.Error(LogTag, $"{lang} is not supported");
+                return false;
+            }
+
+            Log.Info(LogTag, "Current TTS State :" + ttsController.TtsHandle.CurrentState);
+            if (ttsController.TtsHandle.CurrentState != Tizen.Uix.Tts.State.Ready)
+            {
+                Log.Error(LogTag, "TTS is not ready");
+                return false;
+            }
+            try
+            {
+                ttsController.AddText(text, lang);
+                ttsController.Play();
+            }
+            catch (Exception e)
+            {
+                Log.Error(LogTag, $"error :{e.Message}");
+                Log.Error(LogTag, $"{e.StackTrace}");
+                return false;
+            }
+            return true;
+        }
+
+        /// <summary>  
+        /// Asynchronously converts the given text into speech using the specified voice info and plays the resulting audio once it's ready.  
+        /// </summary>  
+        /// <param name="text">The text to convert into speech.</param>  
+        /// <param name="voiceInfo">The voice info to use for converting the text into speech.</param>  
+        /// <param name="ttsReadyFinishedCallback">An optional callback that will be invoked when the TTS process is complete.</param>  
+        /// <returns><c>True</c> if asynchronous conversion was initiated successfully, otherwise <c>False</c>.</returns>  
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public bool PlayTTSAsync(string text, VoiceInfo voiceInfo, EventHandler ttsReadyFinishedCallback = null)
+        {
+            if (ttsController == null || ttsController.TtsHandle == null)
+            {
+                Log.Error(LogTag, "tts is null");
+                return false;
+            }
+
+            if (!ttsController.IsSupportedVoice(voiceInfo))
+            {
+                Log.Info(LogTag, $"{voiceInfo.Language} & {voiceInfo.Type} is not supported");
+                return false;
+            }
+
+            Log.Info(LogTag, "Current TTS State :" + ttsController.TtsHandle.CurrentState);
+            if (ttsController.TtsHandle.CurrentState != Tizen.Uix.Tts.State.Ready)
+            {
+                Log.Info(LogTag, "TTS is not ready");
+                return false;
+            }
+
+            try
+            {
+                ttsController.AddText(text, voiceInfo);
+                ttsController.PlayAsync(ttsReadyFinishedCallback);
+            }
+            catch (Exception e)
+            {
+                Log.Error(LogTag, $"error :{e.Message}");
+                Log.Error(LogTag, $"{e.StackTrace}");
+                return false;
+            }
+            return true;
+        }
+
+        /// <summary>  
+        /// Asynchronously converts the given text into speech using the specified language code and plays the resulting audio once it's ready.  
+        /// </summary>  
+        /// <param name="text">The text to convert into speech.</param>  
+        /// <param name="lang">The two-letter ISO 639-1 language code to use for converting the text into speech (default is Korean - ko_KR).</param>  
+        /// <param name="ttsReadyFinishedCallback">An optional callback that will be invoked when the TTS process is complete.</param>  
+        /// <returns><c>True</c> if asynchronous conversion was initiated successfully, otherwise <c>False</c>.</returns>  
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public bool PlayTTS(string text, string lang = "ko_KR", EventHandler ttsReadyFinishedCallback = null)
+        {
+            if (ttsController == null || ttsController.TtsHandle == null)
+            {
+                Log.Error(LogTag, "tts is null");
+                return false;
+            }
+
+            if (!ttsController.IsSupportedVoice(lang))
+            {
+                Log.Error(LogTag, $"{lang} is not supported");
+                return false;
+            }
+
+            Log.Info(LogTag, "Current TTS State :" + ttsController.TtsHandle.CurrentState);
+            if (ttsController.TtsHandle.CurrentState != Tizen.Uix.Tts.State.Ready)
+            {
+                Log.Error(LogTag, "TTS is not ready");
+                return false;
+            }
+            try
+            {
+                ttsController.AddText(text, lang);
+                ttsController.PlayAsync(ttsReadyFinishedCallback);
+            }
+            catch (Exception e)
+            {
+                Log.Error(LogTag, $"error :{e.Message}");
+                Log.Error(LogTag, $"{e.StackTrace}");
+                return false;
+            }
+            return true;
+        }
+
+        /// <summary>  
+        /// Pauses the currently playing Text-To-Speech audio.  
+        /// </summary>  
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public void PauseTTS()
+        {
+            if (ttsController == null || ttsController.TtsHandle == null)
+            {
+                Log.Error(LogTag, "tts is null");
+                return;
+            }
+
+            try
+            {
+                Log.Info(LogTag, "Current TTS State :" + ttsController.TtsHandle.CurrentState);
+                ttsController?.Pause();
+            }
+            catch (Exception e)
+            {
+                Log.Error(LogTag, $"error :{e.Message}");
+                Log.Error(LogTag, $"{e.StackTrace}");
+            }
+        }
+
+        /// <summary>  
+        /// Stops the currently playing Text-To-Speech audio.  
+        /// </summary>  
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public void StopTTS()
+        {
+            if (ttsController == null || ttsController.TtsHandle == null)
+            {
+                Log.Error(LogTag, "tts is null");
+                return;
+            }
+
+            try
+            {
+                Log.Info(LogTag, "Current TTS State :" + ttsController.TtsHandle.CurrentState);
+                ttsController?.Stop();
+            }
+            catch (Exception e)
+            {
+                Log.Error(LogTag, $"error :{e.Message}");
+                Log.Error(LogTag, $"{e.StackTrace}");
+            }
+        }
+
+        public void InitializeMic()
+        {
+            if (audioRecorder == null)
+            {
+                Tizen.Log.Error(LogTag, "audio record is null");
+                return;
+            }
+            audioRecorder.InitializeMic(lipSyncer, 160);
+        }
+
+        public void DeinitializeMic()
+        {
+            if (audioRecorder == null)
+            {
+                Tizen.Log.Error(LogTag, "audio record is null");
+                return;
+            }
+            audioRecorder.StartRecording();
+        }
+
+        public void StartMic()
+        {
+            if (audioRecorder == null)
+            {
+                Tizen.Log.Error(LogTag, "audio record is null");
+                return;
+            }
+            audioRecorder.StartRecording();
+        }
+
+        public void StopMic()
+        {
+            if (audioRecorder == null)
+            {
+                Tizen.Log.Error(LogTag, "audio record is null");
+                return;
+            }
+            audioRecorder.StopRecording();
+        }
+
+        public void PauseMic()
+        {
+            if (audioRecorder == null)
+            {
+                Tizen.Log.Error(LogTag, "audio record is null");
+                return;
+            }
+            audioRecorder.PauseRecording();
+        }
+
+        public void ResumeMic()
+        {
+            if(audioRecorder == null)
+            {
+                Tizen.Log.Error(LogTag, "audio record is null");
+                return;
+            }
+            audioRecorder.ResumeRecording();
+        }
+
+        /// <summary>  
+        /// Releases unmanaged resources used by this instance.  
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public void Dispose()
+        {
+            if (ttsController != null)
+            {
+                ttsController.Dispose();
+                ttsController = null;
+            }
+
+            if (audioRecorder != null)
+            {
+                audioRecorder.Dispose();
+                audioRecorder = null;
+            }
+        }
+    }
+}
diff --git a/src/Tizen.AIAvatar/src/Lipsync/LipSyncer.cs b/src/Tizen.AIAvatar/src/Lipsync/LipSyncer.cs
new file mode 100644 (file)
index 0000000..8a5fc8f
--- /dev/null
@@ -0,0 +1,297 @@
+/*
+ * Copyright(c) 2024 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+using System;
+using System.Collections.Generic;
+using Tizen.NUI;
+using Tizen.NUI.Scene3D;
+using static Tizen.AIAvatar.AIAvatar;
+
+namespace Tizen.AIAvatar
+{
+    internal class LipSyncer
+    {
+        private Animation lipAnimation = null;
+
+        private VowelConverter vowelConverter;
+        private AudioPlayer audioPlayer;
+        private event Func<AnimationKeyFrame, bool, Animation> TheEvent;
+
+        internal Func<AnimationKeyFrame, bool, Animation> CreatedKeyFrameAnimation;
+
+        //Mic
+        private Queue<string[]> vowelPools = new Queue<string[]>();
+        private string prevVowel = "sil";
+
+        internal LipSyncer()
+        {
+            vowelConverter = new VowelConverter();
+            audioPlayer = new AudioPlayer();
+        }
+
+        internal AudioPlayer AudioPlayer { get { return audioPlayer; } }
+
+        public void SetLipAnimation(Animation lipAnimation)
+        {
+            this.lipAnimation = lipAnimation;
+        }
+
+        public void PlayAudio(byte[] audio, int sampleRate)
+        {
+            if (audio != null)
+            {
+                PlayLipSync(audio, sampleRate);
+            }
+        }
+
+        public void Stop()
+        {
+            StopLipSync();
+        }
+
+        public void Pause()
+        {
+            PauseLipSync();
+        }
+
+        public void Destroy()
+        {
+            DestroyLipAnimation();
+        }
+
+        //TODO : lipAnimation 자체를 Animator안에서 생성하고 관리될 수 있게 수정.
+        protected void ResetLipAnimation(Animation lipAnimation)
+        {
+            DestroyLipAnimation();
+            this.lipAnimation = lipAnimation;
+            if (this.lipAnimation != null)
+            {
+                this.lipAnimation.Finished += OnLipAnimationFinished;
+            }
+        }
+
+        protected void PlayLipAnimation()
+        {
+            if (lipAnimation == null)
+            {
+                Log.Error(LogTag, "Current Lip Animation is null");
+            }
+            lipAnimation?.Play();
+        }
+
+        protected void OnLipAnimationFinished(object sender, EventArgs e)
+        {
+        }
+
+        private void PlayLipSync(byte[] audio)
+        {
+            if (audio == null)
+            {
+                Tizen.Log.Error(LogTag, "audi data is null");
+                return;
+            }
+            DestroyLipAnimation();
+
+            var lipKeyframes = CreateKeyFrame(audio, CurrentAudioOptions.SampleRate);
+            if (lipKeyframes != null)
+            {
+                var lipAnimation = CreatedKeyFrameAnimation?.Invoke(lipKeyframes, false);
+
+                if (lipAnimation != null)
+                {
+                    ResetLipAnimation(lipAnimation);
+                    PlayLipAnimation();
+                    audioPlayer.Play(audio);
+                }
+                else
+                {
+                    Tizen.Log.Error(LogTag, "lipAnimation is null");
+                }
+            }
+            else
+            {
+                Tizen.Log.Error(LogTag, "lipKeyframes is null");
+            }
+        }
+
+        private void PlayLipSync(byte[] audio, int sampleRate)
+        {
+            DestroyLipAnimation();
+            var lipKeyFrames = CreateKeyFrame(audio, sampleRate);
+            var lipAnimation = CreatedKeyFrameAnimation?.Invoke(lipKeyFrames, false);
+            if (lipAnimation != null)
+            {
+                ResetLipAnimation(lipAnimation);
+                PlayLipAnimation();
+            }
+            audioPlayer.Play(audio, sampleRate);
+        }
+
+        private void PlayLipSync(string path)
+        {
+            var bytes = Utils.ReadAllBytes(path);
+            if (bytes != null)
+            {
+                PlayLipSync(bytes);
+            }
+            else
+            {
+                Log.Error(LogTag, "Failed to load audio file");
+            }
+        }
+
+        private void PauseLipSync()
+        {
+            PauseLipAnimation();
+            audioPlayer.Pause();
+        }
+
+        private void StopLipSync()
+        {
+            if (lipAnimation != null)
+            {
+                DestroyLipAnimation();
+
+                var lipAnimation = ResetLipAnimation();
+                if (lipAnimation != null)
+                {
+                    ResetLipAnimation(lipAnimation);
+                    PlayLipAnimation();
+                }
+                else
+                {
+                    Log.Error(LogTag, "Current Lip Animation is null");
+                }
+            }
+            else
+            {
+                Log.Error(LogTag, "Current Lip Animation is null");
+            }
+            audioPlayer.Stop();
+        }
+
+        private void PauseLipAnimation()
+        {
+            if (lipAnimation != null)
+            {
+                lipAnimation?.Pause();
+            }
+            else
+            {
+                Log.Error(LogTag, "Current Lip Animation is null");
+            }
+        }
+
+        private void DestroyLipAnimation()
+        {
+            if (lipAnimation != null)
+            {
+                lipAnimation.Stop();
+                lipAnimation.Dispose();
+                lipAnimation = null;
+            }
+        }
+
+        private void EnqueueVowels(byte[] buffer, bool deleteLast = false)
+        {
+            var vowels = PredictVowels(buffer);
+            if (vowels != null)
+            {
+                vowelPools.Enqueue(vowels);
+                if (deleteLast)
+                {
+                    var vowelList = new List<string>(vowels);
+                    vowelList.RemoveAt(vowelList.Count - 1);
+                    vowels = vowelList.ToArray();
+                }
+            }
+        }
+
+        private Animation CreateLipAnimationByVowelsQueue(int sampleRate = 0)
+        {
+            if (sampleRate == 0)
+            {
+                sampleRate = CurrentAudioOptions.SampleRate;
+            }
+            if (vowelPools.Count > 0)
+            {
+                AttachPreviousVowel(vowelPools.Dequeue(), out var newVowels);
+                Log.Info(LogTag, $"vowelRecognition: {String.Join(", ", newVowels)}");
+
+                var lipKeyFrames = vowelConverter?.CreateKeyFrames(newVowels, sampleRate, true);
+                var lipAnimation = CreatedKeyFrameAnimation?.Invoke(lipKeyFrames, true);
+
+                return lipAnimation;
+            }
+            return null;
+        }
+
+        private Animation ResetLipAnimation()
+        {
+            vowelPools.Clear();
+            var newVowels = new string[1];
+            newVowels[0] = prevVowel = "sil";
+            vowelPools.Enqueue(newVowels);
+            return CreateLipAnimationByVowelsQueue();
+        }
+
+        private string[] PredictVowels(byte[] audioData)
+        {
+            string[] vowels = vowelConverter?.PredictVowels(audioData);
+            return vowels;
+        }
+
+        private void AttachPreviousVowel(in string[] vowels, out string[] newVowels)
+        {
+            newVowels = new string[vowels.Length + 1];
+            newVowels[0] = prevVowel;
+            Array.Copy(vowels, 0, newVowels, 1, vowels.Length);
+            prevVowel = vowels[vowels.Length - 1];
+        }
+
+        private AnimationKeyFrame CreateKeyFrame(byte[] audio, int sampleRate)
+        {
+            var keyFrames = vowelConverter?.CreateKeyFrames(audio, sampleRate);
+            if (keyFrames == null)
+            {
+                Log.Error(LogTag, $"Failed to initialize KeyFrames");
+            }
+
+            return keyFrames;
+        }
+
+
+        internal void OnRecordBufferChanged(byte[] recordBuffer, int sampleRate)
+        {
+            EnqueueVowels(recordBuffer);
+        }
+
+        internal void OnRecodingTick()
+        {
+            var lipAnimation = CreateLipAnimationByVowelsQueue();
+            if (lipAnimation != null)
+            {
+                ResetLipAnimation(lipAnimation);
+                PlayLipAnimation();
+            }
+            else
+            {
+                Log.Error(LogTag, "Current Lip Animation is null");
+            }
+        }
+    }
+}
diff --git a/src/Tizen.AIAvatar/src/Lipsync/VowelConverter/Audio2Vowel/inMFCC/Algorithm/CustomMfccExtractor.cs b/src/Tizen.AIAvatar/src/Lipsync/VowelConverter/Audio2Vowel/inMFCC/Algorithm/CustomMfccExtractor.cs
new file mode 100644 (file)
index 0000000..ec9b754
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * Copyright(c) 2024 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+using System;
+using System.Collections.Generic;
+
+namespace Tizen.AIAvatar
+{
+    internal class CustomMfccExtractor : IMfccExtractor
+    {
+        private readonly int FilterBankSize = 24;
+
+        private int featureCount = 12;
+
+        private int blockSize;
+        private int frameSize;
+        private int hopSize;
+
+        private Window window;
+        private FFT fft;
+        private FilterBank filterBank;
+        private DCT dct;
+
+        private float[] block;
+        private float[] spectrum;
+        private float[] melSpectrum;
+
+        public CustomMfccExtractor(int samplingRate, float frameDuration, float hopDuration, int featureCount)
+        {
+            this.featureCount = featureCount;
+
+            frameSize = (int)Math.Round(samplingRate * frameDuration, 1);
+            hopSize = (int)Math.Round(samplingRate * hopDuration, 1);
+            blockSize = (int)Math.Pow(2, Math.Ceiling(Math.Log(frameSize, 2)));
+
+            window = new Window(frameSize);
+            fft = new FFT(blockSize);
+            filterBank = new FilterBank(FilterBankSize, samplingRate, blockSize);
+            dct = new DCT(FilterBankSize, this.featureCount);
+
+            block = new float[blockSize];
+            spectrum = new float[blockSize / 2 + 1];
+            melSpectrum = new float[FilterBankSize];
+        }
+
+        public List<float[]> ComputeFrom(float[] audio, int sampleRate)
+        {
+            int totalCount = (audio.Length - frameSize) / hopSize + 1;
+            List<float[]> mfccs = new List<float[]>(totalCount);
+
+            for (var i = 0; i < totalCount; i++)
+            {
+                mfccs.Add(new float[featureCount]);
+            }
+
+            var lastSample = audio.Length - frameSize;
+            for (int sample = 0, i = 0; sample <= lastSample; sample += hopSize, i++)
+            {
+                // 1. Framing
+                Buffer.BlockCopy(audio, sample * sizeof(float), block, 0, frameSize * sizeof(float));
+
+                for (var k = frameSize; k < blockSize; block[k++] = 0) { }
+
+                // 2. PreEmphasis
+                // PreEmphasis.PreEmphasize(ref block, 0.97f);
+
+                // 3. HammingWindow
+                window.Apply(block);
+
+                // 4. FFT
+                fft.Direct(block, spectrum);
+
+                // 5. MelFilterBank
+                filterBank.Apply(spectrum, melSpectrum);
+
+                // 6. DCT
+                dct.DirectNorm(melSpectrum, mfccs[i]);
+            }
+
+            return mfccs;
+        }
+    }
+
+    //DLL Interface
+    internal class Extractor
+    {
+        public static float[][] ComputeFrom(float[] audio, int samplingRate, float frameDuration, float hopDuration, int featureCount)
+        {
+            CustomMfccExtractor cme = new CustomMfccExtractor(samplingRate, frameDuration, hopDuration, featureCount);
+            List<float[]> mfccFeatures = cme.ComputeFrom(audio, samplingRate);
+
+            return mfccFeatures.ToArray();
+        }
+    }
+
+}
diff --git a/src/Tizen.AIAvatar/src/Lipsync/VowelConverter/Audio2Vowel/inMFCC/Algorithm/DCT.cs b/src/Tizen.AIAvatar/src/Lipsync/VowelConverter/Audio2Vowel/inMFCC/Algorithm/DCT.cs
new file mode 100644 (file)
index 0000000..9060f87
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * Copyright(c) 2024 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+using System;
+
+namespace Tizen.AIAvatar
+{
+    internal class DCT
+    {
+        private int dctSize;
+        private int featureCount;
+
+        private float[][] dctMatrix;
+
+        public DCT(int filterBankSize, int featureCount = 12)
+        {
+            dctSize = filterBankSize;
+            this.featureCount = featureCount;
+
+            dctMatrix = new float[dctSize][];
+
+            float m = MathF.PI / (dctSize << 1);
+
+            for (var k = 0; k < dctSize; k++)
+            {
+                dctMatrix[k] = new float[dctSize];
+
+                for (var n = 0; n < dctSize; n++)
+                {
+                    dctMatrix[k][n] = (float)(2 * Math.Cos(((n << 1) + 1) * k * m));
+                }
+            }
+        }
+
+        public void DirectNorm(float[] input, float[] output)
+        {
+
+            var norm0 = (float)Math.Sqrt(0.5f);
+            var norm = (float)Math.Sqrt(0.5f / dctSize);
+
+            for (var k = 0; k < featureCount; k++)
+            {
+                output[k] = 0.0f;
+                for (var n = 0; n < input.Length; n++)
+                {
+                    output[k] += input[n] * dctMatrix[k][n];
+                }
+                output[k] *= norm;
+            }
+            output[0] *= norm0;
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/Tizen.AIAvatar/src/Lipsync/VowelConverter/Audio2Vowel/inMFCC/Algorithm/FFT.cs b/src/Tizen.AIAvatar/src/Lipsync/VowelConverter/Audio2Vowel/inMFCC/Algorithm/FFT.cs
new file mode 100644 (file)
index 0000000..054f28f
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+ * Copyright(c) 2024 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+using System;
+
+namespace Tizen.AIAvatar
+{
+    internal class FFT
+    {
+        private int fftSize;
+
+        private float[] re, im;
+        private float[] realSpectrum, imagSpectrum;
+        private float[] cosTbl, sinTbl;
+        private float[] ar, br, ai, bi;
+
+        public FFT(int size)
+        {
+            fftSize = size / 2;
+
+            // Precalculate FFT Parameter
+            re = new float[fftSize];
+            im = new float[fftSize];
+            realSpectrum = new float[fftSize + 1];
+            imagSpectrum = new float[fftSize + 1];
+
+            var tblSize = (int)Math.Log(fftSize, 2);
+
+            cosTbl = new float[tblSize];
+            sinTbl = new float[tblSize];
+
+            for (int i = 1, pos = 0; i < fftSize; i *= 2, pos++)
+            {
+                cosTbl[pos] = (float)Math.Cos(2 * Math.PI * i / fftSize);
+                sinTbl[pos] = (float)Math.Sin(2 * Math.PI * i / fftSize);
+            }
+
+            ar = new float[fftSize];
+            br = new float[fftSize];
+            ai = new float[fftSize];
+            bi = new float[fftSize];
+
+            var f = MathF.PI / fftSize;
+
+            for (var i = 0; i < fftSize; i++)
+            {
+                ar[i] = (float)(0.5 * (1 - Math.Sin(f * i)));
+                ai[i] = (float)(-0.5 * Math.Cos(f * i));
+                br[i] = (float)(0.5 * (1 + Math.Sin(f * i)));
+                bi[i] = (float)(0.5 * Math.Cos(f * i));
+            }
+        }
+
+        public void Direct(float[] input, float[] output)
+        {
+            for (int i = 0, k = 0; i < fftSize; i++)
+            {
+                re[i] = input[k++];
+                im[i] = input[k++];
+            }
+
+            var L = fftSize;
+            var M = fftSize >> 1;
+            var S = fftSize - 1;
+            var ti = 0;
+            while (L >= 2)
+            {
+                var l = L >> 1;
+                var u1 = 1.0f;
+                var u2 = 0.0f;
+                var c = cosTbl[ti];
+                var s = -sinTbl[ti];
+                ti++;
+                for (var j = 0; j < l; j++)
+                {
+                    for (var i = j; i < fftSize; i += L)
+                    {
+                        var p = i + l;
+                        var t1 = re[i] + re[p];
+                        var t2 = im[i] + im[p];
+                        var t3 = re[i] - re[p];
+                        var t4 = im[i] - im[p];
+                        re[p] = t3 * u1 - t4 * u2;
+                        im[p] = t4 * u1 + t3 * u2;
+                        re[i] = t1;
+                        im[i] = t2;
+                    }
+                    var u3 = u1 * c - u2 * s;
+                    u2 = u2 * c + u1 * s;
+                    u1 = u3;
+                }
+                L >>= 1;
+            }
+            for (int i = 0, j = 0; i < S; i++)
+            {
+                if (i > j)
+                {
+                    var t1 = re[j];
+                    var t2 = im[j];
+                    re[j] = re[i];
+                    im[j] = im[i];
+                    re[i] = t1;
+                    im[i] = t2;
+                }
+                var k = M;
+                while (j >= k)
+                {
+                    j -= k;
+                    k >>= 1;
+                }
+                j += k;
+            }
+
+            realSpectrum[0] = re[0] * ar[0] - im[0] * ai[0] + re[0] * br[0] + im[0] * bi[0];
+            imagSpectrum[0] = im[0] * ar[0] + re[0] * ai[0] + re[0] * bi[0] - im[0] * br[0];
+
+            for (var k = 1; k < fftSize; k++)
+            {
+                realSpectrum[k] = re[k] * ar[k] - im[k] * ai[k] + re[fftSize - k] * br[k] + im[fftSize - k] * bi[k];
+                imagSpectrum[k] = im[k] * ar[k] + re[k] * ai[k] + re[fftSize - k] * bi[k] - im[fftSize - k] * br[k];
+            }
+
+            realSpectrum[fftSize] = re[0] - im[0];
+            imagSpectrum[fftSize] = 0;
+
+            for (int i = 0; i < fftSize; i++)
+            {
+                output[i] = realSpectrum[i] * realSpectrum[i] + imagSpectrum[i] * imagSpectrum[i];
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/Tizen.AIAvatar/src/Lipsync/VowelConverter/Audio2Vowel/inMFCC/Algorithm/FilterBank.cs b/src/Tizen.AIAvatar/src/Lipsync/VowelConverter/Audio2Vowel/inMFCC/Algorithm/FilterBank.cs
new file mode 100644 (file)
index 0000000..a5d178a
--- /dev/null
@@ -0,0 +1,184 @@
+/*
+ * Copyright(c) 2024 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+using System;
+using System.Linq;
+
+namespace Tizen.AIAvatar
+{
+    internal struct bangDouble
+    {
+        public double left;
+        public double center;
+        public double right;
+
+        public bangDouble(double l, double c, double r)
+        {
+            left = l;
+            center = c;
+            right = r;
+        }
+
+    }
+
+    internal class FilterBank
+    {
+        private float[][] _filterBank;
+        private int _filterBankSize;
+
+        public FilterBank(int filterBankSize, int samplingRate, int blockSize)
+        {
+            _filterBankSize = filterBankSize;
+            var melBands = MelBands(filterBankSize, samplingRate);
+            _filterBank = Triangular(blockSize, samplingRate, melBands, HerzToMel);
+        }
+
+        public void Apply(float[] input, float[] output)
+        {
+            for (var i = 0; i < _filterBankSize; i++)
+            {
+                var sum = 0.0f;
+
+                for (var j = 0; j < input.Length; j++)
+                {
+                    sum += _filterBank[i][j] * input[j];
+                }
+
+                output[i] = (float)Math.Log10(Math.Max(sum, float.Epsilon));
+            }
+        }
+
+        public static void Apply(float[][] filterBank, float[] spectrum, float[] filtered)
+        {
+            for (var i = 0; i < filterBank.Length; i++)
+            {
+                var en = 0.0f;
+
+                for (var j = 0; j < spectrum.Length; j++)
+                {
+                    en += filterBank[i][j] * spectrum[j];
+                }
+
+                filtered[i] = en;
+            }
+        }
+
+        public static bangDouble[] MelBands(
+            int melFilterCount, int samplingRate, float lowFreq = 0, float highFreq = 0, bool overlap = true)
+        {
+            return UniformBands(HerzToMel, MelToHerz, melFilterCount, samplingRate, lowFreq, highFreq, overlap);
+        }
+
+        public static float[][] Triangular(int fftSize,
+                                           int samplingRate,
+                                           bangDouble[] frequencies,
+                                           Func<double, double> mapper = null)
+        {
+            if (mapper is null) mapper = x => x;
+
+            var herzResolution = (float)samplingRate / fftSize;
+            var herzFrequencies = Enumerable.Range(0, fftSize / 2 + 1)
+                                            .Select(f => f * herzResolution)
+                                            .ToArray();
+
+            var filterCount = frequencies.Length;
+            var filterBank = new float[filterCount][];
+
+            for (var i = 0; i < filterCount; i++)
+            {
+                filterBank[i] = new float[fftSize / 2 + 1];
+
+                var left = frequencies[i].left;
+                var center = frequencies[i].center;
+                var right = frequencies[i].right;
+
+                left = mapper(left);
+                center = mapper(center);
+                right = mapper(right);
+
+                var j = 0;
+                for (; mapper(herzFrequencies[j]) <= left; j++) ;
+                for (; mapper(herzFrequencies[j]) <= center; j++)
+                {
+                    filterBank[i][j] = (float)((mapper(herzFrequencies[j]) - left) / (center - left));
+                }
+                for (; j < herzFrequencies.Length && mapper(herzFrequencies[j]) < right; j++)
+                {
+                    filterBank[i][j] = (float)((right - mapper(herzFrequencies[j])) / (right - center));
+                }
+            }
+
+            return filterBank;
+        }
+
+        private static bangDouble[] UniformBands(
+                                                    Func<double, double> scaleMapper,
+                                                    Func<double, double> inverseMapper,
+                                                    int filterCount,
+                                                    int samplingRate,
+                                                    float lowFreq = 0,
+                                                    float highFreq = 0,
+                                                    bool overlap = true)
+        {
+            if (lowFreq < 0) lowFreq = 0;
+            if (highFreq <= lowFreq) highFreq = samplingRate * 0.5f;
+
+            var startingFrequency = scaleMapper(lowFreq);
+            var frequencyTuples = new bangDouble[filterCount];
+
+            if (overlap)
+            {
+                var newResolution = (scaleMapper(highFreq) - scaleMapper(lowFreq)) / (filterCount + 1);
+                var frequencies = Enumerable.Range(0, filterCount + 2)
+                                            .Select(i => inverseMapper(startingFrequency + i * newResolution))
+                                            .ToArray();
+                for (var i = 0; i < filterCount; i++)
+                {
+                    frequencyTuples[i].left = frequencies[i];
+                    frequencyTuples[i].center = frequencies[i + 1];
+                    frequencyTuples[i].right = frequencies[i + 2];
+                }
+            }
+            else
+            {
+                var newResolution = (scaleMapper(highFreq) - scaleMapper(lowFreq)) / filterCount;
+                var frequencies = Enumerable.Range(0, filterCount + 1)
+                                            .Select(i => inverseMapper(startingFrequency + i * newResolution))
+                                            .ToArray();
+
+                for (var i = 0; i < filterCount; i++)
+                {
+                    frequencyTuples[i].left = frequencies[i];
+                    frequencyTuples[i].center = (frequencies[i] + frequencies[i + 1]) / 2;
+                    frequencyTuples[i].right = frequencies[i + 2];
+                }
+            }
+
+            return frequencyTuples;
+        }
+
+        public static double HerzToMel(double herz)
+        {
+            return 1127 * Math.Log(herz / 700 + 1);
+        }
+
+        public static double MelToHerz(double mel)
+        {
+            return (Math.Exp(mel / 1127) - 1) * 700;
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/Tizen.AIAvatar/src/Lipsync/VowelConverter/Audio2Vowel/inMFCC/Algorithm/IMFccExtractor.cs b/src/Tizen.AIAvatar/src/Lipsync/VowelConverter/Audio2Vowel/inMFCC/Algorithm/IMFccExtractor.cs
new file mode 100644 (file)
index 0000000..fcf5260
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * Copyright(c) 2024 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+using System.Collections.Generic;
+
+namespace Tizen.AIAvatar
+{
+    internal interface IMfccExtractor
+    {
+        List<float[]> ComputeFrom(float[] samples, int samplingRate);
+    }
+}
+
diff --git a/src/Tizen.AIAvatar/src/Lipsync/VowelConverter/Audio2Vowel/inMFCC/Algorithm/PreEmphasis.cs b/src/Tizen.AIAvatar/src/Lipsync/VowelConverter/Audio2Vowel/inMFCC/Algorithm/PreEmphasis.cs
new file mode 100644 (file)
index 0000000..2fedc33
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Copyright(c) 2024 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+namespace Tizen.AIAvatar
+{
+    internal class PreEmphasis
+    {
+        internal static void PreEmphasize(ref float[] block, float value)
+        {
+            float prevSample = block[0];
+
+            for (int i = 0; i < block.Length; i++)
+            {
+                var result = block[i] - prevSample * value;
+                prevSample = block[i];
+                block[i] = result;
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/Tizen.AIAvatar/src/Lipsync/VowelConverter/Audio2Vowel/inMFCC/Algorithm/Window.cs b/src/Tizen.AIAvatar/src/Lipsync/VowelConverter/Audio2Vowel/inMFCC/Algorithm/Window.cs
new file mode 100644 (file)
index 0000000..c319fd0
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright(c) 2024 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+using System;
+using System.Linq;
+
+namespace Tizen.AIAvatar
+{
+    internal class Window
+    {
+        private float[] _window;
+
+        public Window(int size)
+        {
+            _window = Hamming(size);
+        }
+
+        public void Apply(float[] block)
+        {
+            if (block.Length < _window.Length) return;
+
+            for (int i = 0; i < _window.Length; i++)
+            {
+                block[i] *= _window[i];
+            }
+        }
+
+        public static float[] Hamming(int length)
+        {
+            var n = 2 * Math.PI / (length - 1);
+            return Enumerable.Range(0, length)
+                             .Select(i => 0.54f - 0.46f * Math.Cos(i * n))
+                             .Select(v => (float)v)
+                             .ToArray();
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/Tizen.AIAvatar/src/Lipsync/VowelConverter/ISingleShotModel.cs b/src/Tizen.AIAvatar/src/Lipsync/VowelConverter/ISingleShotModel.cs
new file mode 100644 (file)
index 0000000..3ccade8
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Copyright(c) 2024 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+using System.ComponentModel;
+
+namespace Tizen.AIAvatar
+{
+    internal interface ISingleShotModel
+    {
+
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public void SetTensorData(int index, byte[] buffer);
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public byte[] GetTensorData(int index);
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public void Invoke();
+    }
+}
diff --git a/src/Tizen.AIAvatar/src/Lipsync/VowelConverter/SoftmaxLinqExtension.cs b/src/Tizen.AIAvatar/src/Lipsync/VowelConverter/SoftmaxLinqExtension.cs
new file mode 100644 (file)
index 0000000..bc88f8c
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * Copyright(c) 2024 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Tizen.AIAvatar
+{
+    internal static class SoftmaxLinqExtension
+    {
+        internal static IEnumerable<float> SoftMax(this IEnumerable<float> source)
+        {
+            var exp = source.Select(x => MathF.Exp(x)).ToArray();
+            var sum = exp.Sum();
+            return exp.Select(x => x / sum);
+        }
+    }
+}
diff --git a/src/Tizen.AIAvatar/src/Lipsync/VowelConverter/TFVowel6.cs b/src/Tizen.AIAvatar/src/Lipsync/VowelConverter/TFVowel6.cs
new file mode 100644 (file)
index 0000000..fcafa67
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * Copyright(c) 2024 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+using System;
+using System.ComponentModel;
+using Tizen.MachineLearning.Inference;
+using static Tizen.AIAvatar.AIAvatar;
+
+namespace Tizen.AIAvatar
+{
+    internal class TFVowel6 : ISingleShotModel
+    {
+        private SingleShot singleShot;
+        private TensorsInfo inputInfo;
+        private TensorsInfo outputInfo;
+        private TensorsData inputData;
+        private TensorsData outputData;
+
+        private readonly string modelPath = ApplicationResourcePath + "audio2vowel_7.tflite";
+
+        internal TFVowel6(int[] inputDimension, int[] outputDimension)
+        {
+            try
+            {
+                inputInfo = new TensorsInfo();
+                inputInfo.AddTensorInfo(TensorType.Float32, inputDimension);
+
+                outputInfo = new TensorsInfo();
+                outputInfo.AddTensorInfo(TensorType.Float32, outputDimension);
+
+                singleShot = new SingleShot(modelPath, inputInfo, outputInfo);
+            }
+            catch (Exception e)
+            {
+                if (e is NotSupportedException)
+                {
+                    Log.Info(LogTag, "NotSupportedException occurs");
+                }
+                else
+                {
+                    Log.Info(LogTag, e.Message);
+                }
+            }
+        }
+
+
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public void SetTensorData(int index, byte[] buffer)
+        {
+            try
+            {
+                inputData = inputInfo.GetTensorsData();
+                inputData.SetTensorData(index, buffer);
+            }
+            catch (Exception e)
+            {
+                Log.Info(LogTag, e.Message);
+            }
+        }
+
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public void Invoke()
+        {
+            try
+            {
+                outputData = singleShot.Invoke(inputData);
+            }
+            catch (Exception e)
+            {
+                Log.Info(LogTag, e.Message);
+            }
+
+        }
+
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public byte[] GetTensorData(int index)
+        {
+            return outputData.GetTensorData(index);
+        }
+
+
+    }
+}
diff --git a/src/Tizen.AIAvatar/src/Lipsync/VowelConverter/Vowel2Animation/AnimationConverter.cs b/src/Tizen.AIAvatar/src/Lipsync/VowelConverter/Vowel2Animation/AnimationConverter.cs
new file mode 100644 (file)
index 0000000..742368c
--- /dev/null
@@ -0,0 +1,165 @@
+/*
+ * Copyright(c) 2024 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+using Newtonsoft.Json;
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+
+namespace Tizen.AIAvatar
+{
+    internal enum Viseme
+    {
+        sil, AE, Ah, B_M_P, Ch_J, EE, Er, IH, Oh, W_OO, S_Z, F_V, TH,
+        T_L_D_N, K_G_H_NG, R
+    };
+
+    internal class AnimationConverter
+    {
+        private Dictionary<string, string> VowelToViseme
+            = new Dictionary<string, string> {
+            { "A", "Ah" },
+            { "E", "AE" },
+            { "I", "EE" },
+            { "O", "R" },
+            { "ER", "R" },
+            { "U", "W_OO" },
+            { "HM", "B_M_P" },
+            { "sil", "sil" }
+        };
+
+        private AnimationKeyFrame _animationKeyFrame;
+        private BlendShapeInfo _visemBlendShapeInfo;
+        private Dictionary<string, BlendShapeValue[]> _visemeMap;
+
+        private bool _isInitialized;
+
+        public AnimationConverter() { }
+
+        public void InitializeVisemeInfo(string info_path)
+        {
+            try
+            {
+                StreamReader v = new StreamReader(info_path);
+                var jsonString = v.ReadToEnd();
+
+                _visemBlendShapeInfo = JsonConvert.DeserializeObject<BlendShapeInfo>(jsonString);
+                _visemeMap = _visemBlendShapeInfo.GetVisemeMap();
+
+                var nodeNames = _visemBlendShapeInfo.GetNodeNames();
+                var blendShapeCounts = _visemBlendShapeInfo.GetBlendShapeCounts();
+                var blendShapeKeyFormat = _visemBlendShapeInfo.blendShape.keyFormat;
+
+                _animationKeyFrame = new AnimationKeyFrame(nodeNames,
+                                                           blendShapeCounts,
+                                                           blendShapeKeyFormat);
+                _isInitialized = true;
+            }
+            catch (Exception)
+            {
+                throw new FailedPersonalizeException(info_path);
+            }
+        }
+
+        public AnimationKeyFrame ConvertVowelsToAnimation(string[] vowels,
+                                                          float stepDuration)
+        {
+            if (!_isInitialized) throw new NotInitializedException();
+
+            _animationKeyFrame.ClearAnimation();
+            ConvertVowelsToVisemes(vowels, out var visemes);
+            ConvertVisemesToAnimationKeyFrame(visemes, stepDuration);
+
+            return _animationKeyFrame;
+        }
+
+        public AnimationKeyFrame ConvertVowelsToAnimationMic(string[] vowels,
+                                                             float stepDuration)
+        {
+            if (!_isInitialized) throw new NotInitializedException();
+
+            _animationKeyFrame.ClearAnimation();
+            ConvertVowelsToVisemes(vowels, out var visemes);
+            ConvertVisemesToAnimationKeyFrameMic(visemes, stepDuration);
+
+            return _animationKeyFrame;
+        }
+
+        private void ConvertVowelsToVisemes(in string[] vowels,
+                                            out string[] visemes)
+        {
+            visemes = new string[vowels.Length];
+
+            for (var i = 0; i < vowels.Length; i++)
+            {
+                if (!VowelToViseme.TryGetValue(vowels[i], out visemes[i]))
+                {
+                    throw new InvalidVowelTypeException(vowels[i]);
+                }
+            }
+        }
+
+        private void ConvertVisemesToAnimationKeyFrame(in string[] visemes,
+                                                       float stepDuration)
+        {
+            float animationTime = visemes.Length * stepDuration;
+            _animationKeyFrame.SetAnimationTime(animationTime);
+
+            for (int i = 0; i < visemes.Length; i++)
+            {
+                float timeStamp = GetTimeStamp(i, stepDuration) / animationTime;
+
+                foreach (var info in _visemeMap[visemes[i]])
+                {
+                    _animationKeyFrame.AddKeyFrame(info.nodeName,
+                                                   info.blendIndex,
+                                                   timeStamp,
+                                                   info.blendValue);
+                }
+            }
+        }
+
+        private void ConvertVisemesToAnimationKeyFrameMic(in string[] visemes,
+                                                          float stepDuration)
+        {
+            float animationTime = (visemes.Length - 1) * stepDuration;
+            _animationKeyFrame.SetAnimationTime(animationTime);
+
+            for (int i = 0; i < visemes.Length; i++)
+            {
+                float timeStamp = GetTimeStamp(i, stepDuration) / animationTime;
+
+                foreach (var info in _visemeMap[visemes[i]])
+                {
+                    _animationKeyFrame.AddKeyFrame(info.nodeName,
+                                                   info.blendIndex,
+                                                   timeStamp,
+                                                   info.blendValue);
+                }
+            }
+        }
+
+        private float GetTimeStamp(int idx, float stepDuration)
+        {
+            if (idx > 0)
+                return (idx * stepDuration) - (stepDuration / 2.0f);
+            else
+                return 0;
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/Tizen.AIAvatar/src/Lipsync/VowelConverter/Vowel2Animation/DTO/AnimationKeyFrame.cs b/src/Tizen.AIAvatar/src/Lipsync/VowelConverter/Vowel2Animation/DTO/AnimationKeyFrame.cs
new file mode 100644 (file)
index 0000000..04f2a6e
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * Copyright(c) 2024 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+using System.Collections.Generic;
+
+namespace Tizen.AIAvatar
+{
+    internal class KeyFrame
+    {
+        public KeyFrame(float t, float v)
+        {
+            time = t;
+            value = v;
+        }
+        public float time;
+        public float value;
+    }
+
+    internal class AnimationKeyFrame
+    {
+        private Dictionary<string, List<KeyFrame>[]> _animationKeyFrames;
+
+        public string[] NodeNames { get; private set; }
+        public int[] BlendShapeCounts { get; private set; }
+        public string BlendShapeKeyFormat { get; private set; }
+        public float AnimationTime { get; private set; }
+
+        public AnimationKeyFrame(string[] nodeNames,
+                                 int[] blendShapeCounts,
+                                 string blendShapeKeyFormat)
+        {
+            _animationKeyFrames = new Dictionary<string, List<KeyFrame>[]>();
+            NodeNames = nodeNames;
+            BlendShapeCounts = blendShapeCounts;
+            BlendShapeKeyFormat = blendShapeKeyFormat;
+
+            InitializeAnimation(nodeNames, blendShapeCounts);
+        }
+
+        public void SetAnimationTime(float animationTime)
+        {
+            AnimationTime = animationTime;
+        }
+
+        public List<KeyFrame> GetKeyFrames(string nodeName, int blendIndex)
+        {
+            return _animationKeyFrames[nodeName][blendIndex];
+        }
+
+        public void AddKeyFrame(string nodeName, int blendIndex, float time, float value)
+        {
+            _animationKeyFrames[nodeName][blendIndex].Add(new KeyFrame(time, value));
+        }
+
+        public void AddKeyFrame(string nodeName, int blendIndex, KeyFrame value)
+        {
+            _animationKeyFrames[nodeName][blendIndex].Add(value);
+        }
+
+        public void InitializeAnimation(string[] nodeNames, int[] blendShapeCounts)
+        {
+            ClearAnimation();
+
+            for (int i = 0; i < nodeNames.Length; i++)
+            {
+                var nodeName = nodeNames[i];
+                var blendShapeCount = blendShapeCounts[i];
+
+                _animationKeyFrames.Add(nodeName, new List<KeyFrame>[blendShapeCount]);
+
+                for (int j = 0; j < blendShapeCount; j++)
+                {
+                    _animationKeyFrames[nodeName][j] = new List<KeyFrame>();
+                }
+            }
+        }
+
+        public void ClearAnimation()
+        {
+            foreach (KeyValuePair<string, List<KeyFrame>[]> kvp in _animationKeyFrames)
+            {
+                foreach (List<KeyFrame> kf in kvp.Value)
+                {
+                    kf.Clear();
+                }
+            }
+        }
+    }
+}
diff --git a/src/Tizen.AIAvatar/src/Lipsync/VowelConverter/Vowel2Animation/DTO/BlendShapeInfo.cs b/src/Tizen.AIAvatar/src/Lipsync/VowelConverter/Vowel2Animation/DTO/BlendShapeInfo.cs
new file mode 100644 (file)
index 0000000..8fb8163
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * Copyright(c) 2024 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+using System.Collections.Generic;
+
+namespace Tizen.AIAvatar
+{
+    internal class BlendShapeInfo
+    {
+        public BlendShapeModelInfo blendShape;
+        public BlendShapeVisemeInfo[] visemes;
+
+        public BlendShapeInfo() { }
+
+        public string[] GetNodeNames()
+        {
+            return blendShape.nodeNames;
+        }
+
+        public int[] GetBlendShapeCounts()
+        {
+            return blendShape.blendShapeCount;
+        }
+
+        public Dictionary<string, BlendShapeValue[]> GetVisemeMap()
+        {
+            Dictionary<string, BlendShapeValue[]> visemeMap
+                = new Dictionary<string, BlendShapeValue[]>();
+
+            foreach (var visemeInfo in this.visemes)
+            {
+                visemeMap.Add(visemeInfo.name, visemeInfo.values);
+            }
+
+            return visemeMap;
+        }
+    }
+
+    internal class BlendShapeModelInfo
+    {
+        public string keyFormat;
+        public string[] nodeNames;
+        public int[] blendShapeCount;
+
+        public BlendShapeModelInfo(string keyFormat, string[] nodeNames, int[] blendShapeCount)
+        {
+            this.keyFormat = keyFormat;
+            this.nodeNames = nodeNames;
+            this.blendShapeCount = blendShapeCount;
+        }
+    }
+
+    internal class BlendShapeVisemeInfo
+    {
+        public string name;
+        public BlendShapeValue[] values;
+    }
+
+    internal class BlendShapeValue
+    {
+        public string nodeName;
+        public int blendIndex;
+        public float blendValue;
+    }
+}
diff --git a/src/Tizen.AIAvatar/src/Lipsync/VowelConverter/Vowel2Animation/Exception.cs b/src/Tizen.AIAvatar/src/Lipsync/VowelConverter/Vowel2Animation/Exception.cs
new file mode 100644 (file)
index 0000000..da7b089
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * Copyright(c) 2024 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+using System;
+
+namespace Tizen.AIAvatar
+{
+    internal class InvalidVowelTypeException : Exception
+    {
+        public InvalidVowelTypeException() { }
+
+        public InvalidVowelTypeException(string name)
+            : base($"Not supported vowel type, {name}") { }
+    }
+
+    internal class FailedPersonalizeException : Exception
+    {
+        public FailedPersonalizeException() { }
+
+        public FailedPersonalizeException(string name)
+            : base($"Failed to personalize, file_path : {name}") { }
+    }
+
+    internal class NotInitializedException : Exception
+    {
+        public NotInitializedException()
+            : base($"Animation Converter should be initialized with viseme_info") { }
+    }
+}
diff --git a/src/Tizen.AIAvatar/src/Lipsync/VowelConverter/VowelClassifier.cs b/src/Tizen.AIAvatar/src/Lipsync/VowelConverter/VowelClassifier.cs
new file mode 100644 (file)
index 0000000..958b6f1
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+ * Copyright(c) 2024 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Tizen.AIAvatar
+{
+    internal class VowelClassifier
+    {
+        private readonly int vowelForecastRange = 6;
+        private readonly string[] vowelName = { "A", "E", "I", "O", "U", "HM", "ER" };
+
+        private readonly int sampleRate;
+        private readonly int featureCount;
+
+        private float stepTime = 0.0f;
+        private const int DefaultFeatureMeanCount = 8;
+
+        private CustomMfccExtractor mfccExtractor;
+
+
+        internal VowelClassifier(int sampleRate, float frameDuration = 0.025f, float hopDuration = 0.01f, int featureCount = 12)
+        {
+            this.sampleRate = sampleRate;
+            this.featureCount = featureCount;
+            stepTime = (float)(hopDuration * DefaultFeatureMeanCount);
+            mfccExtractor = new CustomMfccExtractor(sampleRate, frameDuration, hopDuration, featureCount);
+        }
+
+        public float GetStepTime()
+        {
+            return stepTime;
+        }
+
+
+        public string[] Inference(byte[] audio, ISingleShotModel model)
+        {
+            int length = PreprocessInput(audio, out float[] features, out List<float> audioEnergy);
+            var outputData = InferenceModel(features, length, model);
+            var result = ProcessOutput(outputData, audioEnergy);
+
+            return result.ToArray();
+        }
+
+        public int PreprocessInput(byte[] audioByte, out float[] flattenedArray, out List<float> audioEnergy)
+        {
+            Utils.ConvertAudioToFloat(audioByte, out var audio);
+
+            var mfccFeatures = mfccExtractor.ComputeFrom(audio, sampleRate);
+
+            int featureLength = (int)Math.Ceiling((double)mfccFeatures.Count / DefaultFeatureMeanCount);
+            flattenedArray = new float[featureLength * featureCount];
+            audioEnergy = new List<float>();
+
+            for (int i = 0; i < featureLength; i++)
+            {
+                CalculateFeatureMean(mfccFeatures, out var featureMean, out var energy, i * DefaultFeatureMeanCount);
+                Array.Copy(featureMean, 0, flattenedArray, i * featureCount, featureCount);
+                audioEnergy.Add(energy);
+            }
+
+            return featureLength;
+        }
+
+        public List<float[]> InferenceModel(float[] input, int length, ISingleShotModel model)
+        {
+            byte[] inputBuffer = new byte[4 * 12 * 1 * 1];
+            byte[] outputBuffer;
+
+            int srcOffset = 0;
+            List<float[]> fullOutput = new List<float[]>();
+
+            for (int i = 0; i < length; i++)
+            {
+                float[] output = new float[7];
+
+                Buffer.BlockCopy(input, srcOffset, inputBuffer, 0, inputBuffer.Length);
+                srcOffset += inputBuffer.Length;
+
+                model.SetTensorData(0, inputBuffer);
+
+                model.Invoke();
+
+                outputBuffer = model.GetTensorData(0);
+
+                Buffer.BlockCopy(outputBuffer, 0, output, 0, outputBuffer.Length);
+
+                fullOutput.Add(output);
+
+            }
+
+            return fullOutput;
+        }
+
+        private List<string> ProcessOutput(List<float[]> outputData, List<float> audioEnergy)
+        {
+            var result = new List<string>();
+
+            for (int i = 0; i < outputData.Count; i++)
+            {
+                // Softmax 연산 수행
+                if (audioEnergy[i] > -1.0f)
+                {
+                    var scores = Enumerable.Range(0, vowelForecastRange).
+                       Select(j => outputData[i][j]).SoftMax().ToArray();
+                    int maxIndex = Array.IndexOf(scores, scores.Max());
+                    result.Add(vowelName[maxIndex]);
+                }
+                else
+                {
+                    result.Add("sil");
+                }
+
+            }
+
+            return result;
+        }
+
+        private void CalculateFeatureMean(in List<float[]> features,
+                                  out float[] featureMean,
+                                  out float energy,
+                                  int offset)
+        {
+            featureMean = new float[featureCount];
+            int featureLength = (DefaultFeatureMeanCount < features.Count - offset
+                                    ? DefaultFeatureMeanCount
+                                    : features.Count - offset);
+
+            float sum = 0f;
+            for (int fc = 0; fc < featureCount; fc++)
+            {
+                for (int dc = offset; dc < offset + DefaultFeatureMeanCount && dc < features.Count; dc++)
+                {
+                    featureMean[fc] += features[dc][fc];
+                }
+                featureMean[fc] /= featureLength;
+                sum += featureMean[fc];
+            }
+            energy = sum / featureCount;
+        }
+    }
+}
diff --git a/src/Tizen.AIAvatar/src/Lipsync/VowelConverter/VowelConverter.cs b/src/Tizen.AIAvatar/src/Lipsync/VowelConverter/VowelConverter.cs
new file mode 100644 (file)
index 0000000..0b65da2
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * Copyright(c) 2024 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+using System.Collections.Generic;
+
+using static Tizen.AIAvatar.AIAvatar;
+
+namespace Tizen.AIAvatar
+{
+    internal class VowelConverter
+    {
+        private TFVowel6 vowelClassfierModel = null;
+        private VowelClassifier vowelClassifier = null;
+        private Dictionary<int, VowelClassifier> vowelClassifiers;
+        private AnimationConverter animationConverter = new AnimationConverter();
+
+        internal VowelConverter()
+        {
+            vowelClassifiers = new Dictionary<int, VowelClassifier>();
+            vowelClassifier = GetVowelClassifier(CurrentAudioOptions.SampleRate);
+            vowelClassfierModel = new TFVowel6(new int[4] { 12, 1, 1, 1 }, new int[4] { 7, 1, 1, 1 });
+            animationConverter.InitializeVisemeInfo(VisemeInfo);
+        }
+
+        internal AnimationKeyFrame CreateKeyFrames(string[] vowels, int sampleRate, bool isMic = false)
+        {
+            vowelClassifier = GetVowelClassifier(sampleRate);
+
+            if (isMic)
+            {
+                return animationConverter.ConvertVowelsToAnimationMic(vowels, vowelClassifier.GetStepTime());
+            }
+            else
+            {
+                return animationConverter.ConvertVowelsToAnimation(vowels, vowelClassifier.GetStepTime());
+            }
+        }
+
+        internal AnimationKeyFrame CreateKeyFrames(byte[] audioData, int sampleRate, bool isMic = false)
+        {
+            vowelClassifier = GetVowelClassifier(sampleRate);
+
+            if (vowelClassifier == null)
+            {
+                Log.Error(LogTag, "Failed to play Buffer");
+                return null;
+            }
+            var vowels = PredictVowels(audioData);
+            Log.Info(LogTag, $"vowelRecognition: {string.Join(", ", vowels)}");
+
+            if (isMic) return animationConverter.ConvertVowelsToAnimationMic(vowels, vowelClassifier.GetStepTime());
+            else return animationConverter.ConvertVowelsToAnimation(vowels, vowelClassifier.GetStepTime());
+        }
+
+        internal string[] PredictVowels(byte[] audioData)
+        {
+            var vowels = vowelClassifier.Inference(audioData, vowelClassfierModel);
+            return vowels;
+        }
+
+        internal VowelClassifier GetVowelClassifier(int sampleRate)
+        {
+            if (vowelClassifiers.ContainsKey(sampleRate))
+            {
+                return vowelClassifiers[sampleRate];
+            }
+            else
+            {
+                vowelClassifiers[sampleRate] = new VowelClassifier(sampleRate);
+                return vowelClassifiers[sampleRate];
+            }
+        }
+    }
+}
diff --git a/src/Tizen.AIAvatar/src/Multimedia/Audio/AudioOptions.cs b/src/Tizen.AIAvatar/src/Multimedia/Audio/AudioOptions.cs
new file mode 100644 (file)
index 0000000..2ac9305
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * Copyright(c) 2024 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+using System.ComponentModel;
+using Tizen.Multimedia;
+
+namespace Tizen.AIAvatar
+{
+    /// <summary>
+    /// Provides the ability to audio 
+    /// </summary>
+    [EditorBrowsable(EditorBrowsableState.Never)]
+    internal class AudioOptions
+    {
+        private int sampleRate;
+        private AudioChannel channel;
+        private AudioSampleType sampleType;
+
+        /// <summary>
+        /// Initializes a new instance of the AudioOptions class with the specified sample rate, channel, and sampleType.
+        /// </summary>
+        /// <param name="sampleRate">the audio sample rate (8000 ~ 192000Hz)</param>
+        /// <param name="channel">the audio channel type.</param>
+        /// <param name="sampleType">the audio sample type.</param>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public AudioOptions(int sampleRate, AudioChannel channel, AudioSampleType sampleType)
+        {
+            this.sampleRate = sampleRate;
+            this.channel = channel;
+            this.sampleType = sampleType;
+        }
+
+        /// <summary>
+        /// The audio sample rate (8000 ~ 192000Hz)
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public int SampleRate { get => sampleRate; set => sampleRate = value; }
+
+        /// <summary>
+        /// The audio channel type
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public AudioChannel Channel { get => channel; set => channel = value; }
+
+        /// <summary>
+        /// The audio sample type
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public AudioSampleType SampleType { get => sampleType; set => sampleType = value; }
+    }
+}
diff --git a/src/Tizen.AIAvatar/src/Multimedia/Audio/AudioPlayer.cs b/src/Tizen.AIAvatar/src/Multimedia/Audio/AudioPlayer.cs
new file mode 100644 (file)
index 0000000..bd04ec0
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ * Copyright(c) 2024 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+using Tizen.Multimedia;
+using System.IO;
+using System;
+
+using static Tizen.AIAvatar.AIAvatar;
+
+namespace Tizen.AIAvatar
+{
+    internal class AudioPlayer : IDisposable
+    {
+        private AudioPlayback audioPlayback;
+        private MemoryStream audioStream;
+
+        internal AudioPlayer()
+        {
+        }
+
+        internal void PlayAsync(byte[] buffer, int sampleRate = 0)
+        {
+            if (audioPlayback == null)
+            {
+                Play(buffer, sampleRate);
+            }
+            else
+            {
+                audioPlayback.Write(buffer);
+            }
+        }
+
+        internal void Play(byte[] audioBytes, int sampleRate = 0)
+        {
+            if (audioBytes == null)
+            {
+                return;
+            }
+
+            try
+            {
+                if (audioPlayback != null)
+                {
+                    Destroy();
+                }
+                if (sampleRate == 0)
+                {
+                    sampleRate = CurrentAudioOptions.SampleRate;
+                }
+                audioPlayback = new AudioPlayback(sampleRate, CurrentAudioOptions.Channel, CurrentAudioOptions.SampleType);
+            }
+            catch (Exception e)
+            {
+                Log.Error(LogTag, $"Failed to create AudioPlayback. {e.Message}");
+            }
+
+            if (audioPlayback != null)
+            {
+                audioPlayback.Prepare();
+                audioPlayback.BufferAvailable += (sender, args) =>
+                {
+                    if (audioStream.Position == audioStream.Length)
+                    {
+                        return;
+                    }
+
+                    try
+                    {
+                        var buffer = new byte[args.Length];
+                        audioStream.Read(buffer, 0, args.Length);
+                        audioPlayback.Write(buffer);
+                    }
+                    catch (Exception e)
+                    {
+                        Log.Error(LogTag, $"Failed to write. {e.Message}");
+                    }
+                };
+
+                audioStream = new MemoryStream(audioBytes);
+            }
+        }
+
+        internal void Pause()
+        {
+            if (audioPlayback != null)
+            {
+                audioPlayback.Pause();
+            }
+            else
+            {
+                Log.Error(LogTag, $"audioPlayBack is null");
+            }
+        }
+
+        internal void Stop()
+        {
+            if (audioPlayback != null)
+            {
+                audioPlayback.Pause();
+                Destroy();
+            }
+            else
+            {
+                Log.Error(LogTag, $"audioPlayBack is null");
+            }
+        }
+
+        public void Dispose()
+        {
+            Destroy();
+
+            audioStream?.Flush();
+            audioStream?.Dispose();
+            audioStream = null;
+        }
+
+        private void Destroy()
+        {
+            audioPlayback?.Unprepare();
+            audioPlayback?.Dispose();
+            audioPlayback = null;
+        }
+    }
+}
diff --git a/src/Tizen.AIAvatar/src/Multimedia/Audio/AudioRecorder.cs b/src/Tizen.AIAvatar/src/Multimedia/Audio/AudioRecorder.cs
new file mode 100644 (file)
index 0000000..406ce6d
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+ * Copyright(c) 2023 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+using System;
+using System.Linq;
+using Tizen.Multimedia;
+using Tizen.NUI;
+using static Tizen.AIAvatar.AIAvatar;
+
+namespace Tizen.AIAvatar
+{
+    internal class AudioRecorder : IDisposable
+    {
+        private const string privilegeForRecording = "http://tizen.org/privilege/recorder";
+
+        private AsyncAudioCapture asyncAudioCapture;
+
+        private byte[] recordedBuffer;
+        private float desiredBufferDuration = 0.16f;
+        private int desiredBufferLength;
+
+        private Timer audioRecordingTimer;
+
+        private Action audioRecdingAction;
+        private Action<byte[], int> bufferAction;
+
+        private static AudioRecorder instance;
+
+        internal static AudioRecorder Instance
+        {
+            get
+            {
+                if (instance == null)
+                {
+                    instance = new AudioRecorder();
+                }
+                return instance;
+            }
+        }
+
+        internal event EventHandler<RecordBufferChangedEventArgs> BufferChanged;
+
+        internal AudioRecorder()
+        {
+            Utils.CheckPrivilege(privilegeForRecording);
+            desiredBufferLength = (int)(CurrentAudioOptions.SampleRate * desiredBufferDuration * 2);
+        }
+
+        internal void InitializeMic(LipSyncer lipSyncer, uint recordingTime = 160)
+        {
+            audioRecordingTimer = new Timer(recordingTime);
+            if (lipSyncer != null)
+            {
+                Tizen.Log.Error(LogTag, "LipSyncer of animator is null");
+                return;
+            }
+            this.audioRecdingAction = lipSyncer.OnRecodingTick;
+            this.bufferAction = lipSyncer.OnRecordBufferChanged;
+
+            BufferChanged += OnRecordBufferChanged;
+            audioRecordingTimer.Tick += AudioRecordingTimerTick;
+        }
+
+
+        internal void DeinitializeMic()
+        {
+            StopRecording();
+            BufferChanged -= OnRecordBufferChanged;
+
+            if (audioRecordingTimer != null)
+            {
+                audioRecordingTimer.Stop();
+                audioRecordingTimer.Tick -= AudioRecordingTimerTick;
+
+                audioRecordingTimer.Dispose();
+                audioRecordingTimer = null;
+            }
+            audioRecdingAction = null;
+        }
+
+        internal void StartRecording()
+        {
+            audioRecordingTimer?.Start();
+            asyncAudioCapture = new AsyncAudioCapture(CurrentAudioOptions.SampleRate, CurrentAudioOptions.Channel, CurrentAudioOptions.SampleType);
+
+            recordedBuffer = new byte[0];
+            asyncAudioCapture.DataAvailable += (s, e) =>
+            {
+                recordedBuffer = recordedBuffer.Concat(e.Data).ToArray();
+                if (recordedBuffer.Length >= desiredBufferLength)
+                {
+                    var recordedBuffer = this.recordedBuffer;
+                    this.recordedBuffer = Array.Empty<byte>();
+
+                    BufferChanged?.Invoke(this, new RecordBufferChangedEventArgs(recordedBuffer, CurrentAudioOptions.SampleRate));
+                }
+            };
+            asyncAudioCapture.Prepare();
+            Log.Info(LogTag, "Start Recording - Preapre AsyncAudioCapture");
+        }
+
+        internal void StopRecording()
+        {
+            audioRecordingTimer?.Stop();
+            asyncAudioCapture.Dispose();
+        }
+
+        internal void PauseRecording()
+        {
+            asyncAudioCapture.Pause();
+        }
+
+        internal void ResumeRecording()
+        {
+            asyncAudioCapture.Resume();
+        }
+
+        private void OnRecordBufferChanged(object sender, RecordBufferChangedEventArgs e)
+        {
+            bufferAction?.Invoke(e.RecordedBuffer, CurrentAudioOptions.SampleRate);
+        }
+
+        private bool AudioRecordingTimerTick(object source, Timer.TickEventArgs e)
+        {
+            Log.Info(LogTag, "TickTimer");
+            audioRecdingAction?.Invoke();
+            return true;
+        }
+
+        public void Dispose()
+        {
+            throw new NotImplementedException();
+        }
+    }
+}
diff --git a/src/Tizen.AIAvatar/src/Multimedia/Audio/RecordBufferChangedEventArgs.cs b/src/Tizen.AIAvatar/src/Multimedia/Audio/RecordBufferChangedEventArgs.cs
new file mode 100644 (file)
index 0000000..baf723d
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Copyright(c) 2024 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+using System;
+
+namespace Tizen.AIAvatar
+{
+    internal class RecordBufferChangedEventArgs : EventArgs
+    {
+        public byte[] RecordedBuffer { get; set; }
+        public int SampleRate { get; set; }
+
+        public RecordBufferChangedEventArgs(byte[] recordedBuffer, int SampleRate)
+        {
+            this.RecordedBuffer = recordedBuffer;
+            this.SampleRate = SampleRate;
+        }
+    }
+
+}
diff --git a/src/Tizen.AIAvatar/src/Multimedia/TTS/TTSController.cs b/src/Tizen.AIAvatar/src/Multimedia/TTS/TTSController.cs
new file mode 100644 (file)
index 0000000..f6cea3c
--- /dev/null
@@ -0,0 +1,532 @@
+/*
+ * Copyright(c) 2024 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Tizen.Uix.Tts;
+
+using static Tizen.AIAvatar.AIAvatar;
+
+namespace Tizen.AIAvatar
+{
+    internal class TTSControllerEventArgs : EventArgs
+    {
+        public TTSControllerEventArgs()
+        {
+        }
+
+        public TTSControllerEventArgs(byte[] audioData, int sampleRate)
+        {
+            //AudioData = audioData;
+            AudioData = new byte[audioData.Length];
+            Buffer.BlockCopy(audioData, 0, AudioData, 0, audioData.Length);
+            SampleRate = sampleRate;
+        }
+
+        public byte[] AudioData
+        {
+            get;
+            internal set;
+        }
+
+        public int SampleRate
+        {
+            get;
+            internal set;
+        }
+    }
+
+    internal class TTSController : IDisposable
+    {
+        private List<UtteranceText> textList;
+        private TtsClient ttsHandle;
+        private VoiceInfo voiceInfo;
+        private List<Byte> byteList;
+
+        private byte[] recordedBuffer;
+        private byte[] audioTailBuffer;
+
+        private int sampleRate;
+        private float desiredBufferDuration = 0.175f;
+        private float audioTailLengthFactor = 0.015f;
+        private float audioBufferMultiflier = 2f;
+
+        private int desiredBufferLength;
+        private int audioTailLength;
+
+        private bool isPrepared = false;
+        private bool isAsync = false;
+
+        private Action<byte[], int> bufferChangedAction;
+
+        private int audioLength;
+        private bool isAsyncLipStarting;
+
+        internal event EventHandler PlayReadyCallback;
+
+        internal event EventHandler<TTSControllerEventArgs> PreparedSyncText;
+        internal event EventHandler<TTSControllerEventArgs> StoppedTTS;
+        
+        
+        internal event EventHandler<TTSControllerEventArgs> UpdatedBuffer;
+
+        internal TTSController()
+        {
+            InitTts();
+        }
+
+        ~TTSController()
+        {
+            DeinitTts();
+        }
+
+        internal TtsClient TtsHandle
+        {
+            get { return ttsHandle; }
+        }
+
+        internal VoiceInfo VoiceInfo
+        {
+            get { return voiceInfo; }
+            set
+            {
+                voiceInfo = value;
+            }
+        }
+
+        internal List<VoiceInfo> GetSupportedVoices()
+        {
+            var voiceInfoList = new List<VoiceInfo>();
+
+            if (ttsHandle == null)
+            {
+                Log.Error(LogTag, $"ttsHandle is null");
+                return voiceInfoList;
+            }
+
+            var supportedVoices = ttsHandle.GetSupportedVoices();
+            foreach (var supportedVoice in supportedVoices)
+            {
+                Log.Info(LogTag, $"{supportedVoice.Language} & {supportedVoice.VoiceType} is supported");
+                voiceInfoList.Add(new VoiceInfo() { Language = supportedVoice.Language, Type = (VoiceType)supportedVoice.VoiceType });
+            }
+            return voiceInfoList;
+        }
+
+        internal bool IsSupportedVoice(string lang)
+        {
+            if (ttsHandle == null)
+            {
+                Log.Error(LogTag, $"ttsHandle is null");
+                return false;
+            }
+            var supportedVoices = ttsHandle.GetSupportedVoices();
+
+            foreach (var supportedVoice in supportedVoices)
+            {
+                if (supportedVoice.Language.Equals(lang))
+                {
+                    Log.Info(LogTag, $"{lang} is supported");
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        internal bool IsSupportedVoice(VoiceInfo voiceInfo)
+        {
+            if (ttsHandle == null)
+            {
+                Log.Error(LogTag, $"ttsHandle is null");
+                return false;
+            }
+            var supportedVoices = ttsHandle.GetSupportedVoices();
+            foreach (var supportedVoice in supportedVoices)
+            {
+                if (supportedVoice.Language.Equals(voiceInfo.Language) && ((VoiceType)supportedVoice.VoiceType == voiceInfo.Type))
+                {
+                    Log.Info(LogTag, $"{voiceInfo.Language} & {voiceInfo.Type} is supported");
+                    return true;
+                }
+            }
+            return false;
+        }
+
+
+        internal void AddText(string txt, VoiceInfo voiceInfo)
+        {
+            if (voiceInfo.Language == null)
+            {
+                Log.Error(LogTag, "VoiceInfo's value is null");
+            }
+            if (ttsHandle == null)
+            {
+                Log.Error(LogTag, $"ttsHandle is null");
+                return;
+            }
+            var temp = new UtteranceText();
+            temp.Text = txt;
+            temp.UttID = ttsHandle.AddText(txt, voiceInfo.Language, (int)voiceInfo.Type, 0);
+            try
+            {
+                textList.Add(temp);
+            }
+            catch (Exception e)
+            {
+                Log.Error(LogTag, $"Error AddText" + e.Message);
+            }
+        }
+
+        internal void AddText(string txt, string lang)
+        {
+            if (ttsHandle == null)
+            {
+                Log.Error(LogTag, $"ttsHandle is null");
+                return;
+            }
+            var temp = new UtteranceText();
+            temp.Text = txt;
+            temp.UttID = ttsHandle.AddText(txt, lang, (int)voiceInfo.Type, 0);
+            try
+            {
+                textList.Add(temp);
+            }
+            catch (Exception e)
+            {
+                Log.Error(LogTag, $"Error AddText" + e.Message);
+            }
+        }
+
+        internal void Prepare(EventHandler playReadyCallback)
+        {
+            if (ttsHandle == null)
+            {
+                Log.Error(LogTag, $"ttsHandle is null");
+                return;
+            }
+            Log.Info(LogTag, "Prepare TTS");
+            isPrepared = true;
+            isAsync = false;
+            PlayReadyCallback = playReadyCallback;
+            Play(true);
+        }
+
+
+        internal bool PlayPreparedText()
+        {
+            if (byteList != null && byteList.Count != 0)
+            {
+                Log.Info(LogTag, "PlayPreparedText TTS");
+
+                PreparedSyncText?.Invoke(this, new TTSControllerEventArgs(byteList.ToArray(), sampleRate));
+                return true;
+            }
+            return false;
+        }
+
+        internal void Play(bool isPrepared = false)
+        {
+            if (ttsHandle == null)
+            {
+                Log.Error(LogTag, $"ttsHandle is null");
+                return;
+            }
+
+            this.isPrepared = isPrepared;
+            isAsync = false;
+            ttsHandle.Play();
+        }
+
+        internal void PlayAsync(EventHandler playReadyCallback)
+        {
+            if (ttsHandle == null)
+            {
+                Log.Error(LogTag, $"ttsHandle is null");
+                return;
+            }
+
+            isPrepared = false;
+            isAsync = true;
+            PlayReadyCallback = playReadyCallback;
+            ttsHandle.Play();
+        }
+
+        public void Pause()
+        {
+            if (ttsHandle == null)
+            {
+                Log.Error(LogTag, $"ttsHandle is null");
+                return;
+            }
+            ttsHandle.Pause();
+        }
+
+        internal void Stop()
+        {
+            if (ttsHandle == null)
+            {
+                Log.Error(LogTag, $"ttsHandle is null");
+                return;
+            }
+            ttsHandle.Stop();
+            StoppedTTS?.Invoke(this, new TTSControllerEventArgs());
+        }
+
+        internal void DeinitTts()
+        {
+            try
+            {
+                if (ttsHandle != null)
+                {
+                    ttsHandle.Unprepare();
+
+                    // Unregister Callbacks
+                    ttsHandle.DefaultVoiceChanged -= TtsDefaultVoiceChangedCallback;
+                    ttsHandle.EngineChanged -= TtsEngineChangedCallback;
+                    ttsHandle.ErrorOccurred -= TtsErrorOccuredCallback;
+                    ttsHandle.StateChanged -= TtsStateChangedCallback;
+                    ttsHandle.UtteranceCompleted -= TtsUtteranceCompletedCallback;
+                    ttsHandle.UtteranceStarted -= TtsUtteranceStartedCallback;
+
+                    ttsHandle.Dispose();
+                    ttsHandle = null;
+                }
+
+                if (textList != null)
+                {
+                    textList.Clear();
+                    textList = null;
+                }
+
+                if (byteList != null)
+                {
+                    byteList.Clear();
+                    byteList = null;
+                }
+            }
+            catch (Exception e)
+            {
+                Log.Error(LogTag, "[ERROR] Fail to unprepare Tts");
+                Log.Error(LogTag, e.Message);
+            }
+        }
+
+        private void InitTts()
+        {
+            try
+            {
+                ttsHandle = new TtsClient();
+
+                // Register Callbacks
+                ttsHandle.DefaultVoiceChanged += TtsDefaultVoiceChangedCallback;
+                ttsHandle.EngineChanged += TtsEngineChangedCallback;
+                ttsHandle.ErrorOccurred += TtsErrorOccuredCallback;
+                ttsHandle.StateChanged += TtsStateChangedCallback;
+                ttsHandle.UtteranceCompleted += TtsUtteranceCompletedCallback;
+                ttsHandle.UtteranceStarted += TtsUtteranceStartedCallback;
+
+                ttsHandle.SynthesizedPcm += TtsSyntheiszedPCM;
+                ttsHandle.PlayingMode = PlayingMode.ByClient;
+
+                ttsHandle.Prepare();
+
+                voiceInfo = new VoiceInfo
+                {
+                    Language = ttsHandle.DefaultVoice.Language,
+                    Type = (VoiceType)ttsHandle.DefaultVoice.VoiceType
+                };
+
+                textList = new List<UtteranceText>();
+                Log.Info(LogTag, voiceInfo.Language + ", " + voiceInfo.Type.ToString());
+
+            }
+            catch (Exception e)
+            {
+                Log.Error(LogTag, "[ERROR] Fail to prepare Tts");
+                Log.Error(LogTag, e.Message);
+            }
+        }
+
+        private void TtsSyntheiszedPCM(object sender, SynthesizedPcmEventArgs e)
+        {
+            var dataSize = e.Data.Length;
+            var audio = new byte[dataSize];
+            sampleRate = e.SampleRate;
+
+            //Marshal.Copy(e.Data, audio, 0, dataSize);
+            switch (e.EventType) //START
+            {
+                case SynthesizedPcmEvent.Start://start
+                    Tizen.Log.Info(LogTag, "------------------Start : " + e.UtteranceId);
+                    Tizen.Log.Info(LogTag, "Output audio Size : " + dataSize);
+                    Tizen.Log.Info(LogTag, "SampleRate" + e.SampleRate);
+                    if (byteList == null)
+                    {
+                        byteList = new List<byte>();
+                    }
+                    if (recordedBuffer == null)
+                    {
+                        recordedBuffer = new byte[0];
+                    }
+                    byteList.Clear();
+
+                    if (isAsync)
+                    {
+                        recordedBuffer = Array.Empty<byte>();
+
+                        desiredBufferLength = (int)(e.SampleRate * desiredBufferDuration * audioBufferMultiflier);
+                        audioTailLength = (int)(sampleRate * audioTailLengthFactor * audioBufferMultiflier);
+                        audioTailBuffer = new byte[audioTailLength];
+                        PlayReadyCallback?.Invoke(null, EventArgs.Empty);
+                        //InitAsyncBuffer();
+                    }
+                    break;
+                case SynthesizedPcmEvent.Continue://continue
+                    if (isAsync)
+                    {
+                        recordedBuffer = recordedBuffer.Concat(e.Data).ToArray();
+                        //PlayAsync
+                        if (recordedBuffer.Length >= desiredBufferLength)
+                        {
+                            Tizen.Log.Error(LogTag, "Current recordbuffer length :" + recordedBuffer.Length);
+                            //UpdateBuffer(recordedBuffer, sampleRate);
+
+                            Buffer.BlockCopy(recordedBuffer, recordedBuffer.Length - audioTailLength, audioTailBuffer, 0, audioTailLength);
+
+                            recordedBuffer = Array.Empty<byte>();
+                            recordedBuffer = recordedBuffer.Concat(audioTailBuffer).ToArray();
+                            Array.Clear(audioTailBuffer, 0, audioTailLength);
+                        }
+                    }
+                    else
+                    {
+                        byteList.AddRange(e.Data);
+                    }
+                    break;
+                case SynthesizedPcmEvent.Finish://finish
+                    Tizen.Log.Info(LogTag, "------------------Finish : " + e.UtteranceId);
+                    if (!isAsync)
+                    {
+                        if (!isPrepared)
+                        {
+                            //Play voice immediately
+                            PlayPreparedText();
+                        }
+                        else
+                        {
+                            //Notify finished state
+                            Log.Info(LogTag, "Notify finished state");
+                            PlayReadyCallback?.Invoke(null, EventArgs.Empty);
+                        }
+                    }
+                    else
+                    {//async
+                        //FinishedSynthesizedPcm?.Invoke(null, EventArgs.Empty);
+                        //lipSyncer.SetFinishAsyncLip(true);
+                    }
+                    break;
+                case SynthesizedPcmEvent.Fail: //fail
+                    break;
+
+            }
+        }
+
+        private void TtsUtteranceStartedCallback(object sender, UtteranceEventArgs e)
+        {
+            Log.Debug(LogTag, "Utterance start now (" + e.UtteranceId + ")");
+        }
+
+        private void TtsUtteranceCompletedCallback(object sender, UtteranceEventArgs e)
+        {
+            Log.Debug(LogTag, "Utterance complete (" + e.UtteranceId + ")");
+
+            foreach (UtteranceText item in textList)
+            {
+                if (item.UttID == e.UtteranceId)
+                {
+                    textList.Remove(item);
+                    Log.Debug(LogTag, "TextList Count (" + textList.Count.ToString() + ")");
+                    break;
+                }
+            }
+        }
+
+        private void TtsStateChangedCallback(object sender, StateChangedEventArgs e)
+        {
+            Log.Debug(LogTag, "Current state is changed from (" + e.Previous + ") to (" + e.Current + ")");
+        }
+
+        private void TtsErrorOccuredCallback(object sender, ErrorOccurredEventArgs e)
+        {
+            Log.Error(LogTag, "Error is occured (" + e.ErrorMessage + ")");
+        }
+
+        private void TtsEngineChangedCallback(object sender, EngineChangedEventArgs e)
+        {
+            Log.Debug(LogTag, "Prefered engine is changed (" + e.EngineId + ") (" + e.VoiceType.Language + ")");
+        }
+
+        private void TtsDefaultVoiceChangedCallback(object sender, DefaultVoiceChangedEventArgs e)
+        {
+            Log.Debug(LogTag, "Default voice is changed from (" + e.Previous + ") to (" + e.Current + ")");
+        }
+
+        private void InitAsyncBuffer()
+        {
+            /*
+            InitedAsyncBuffer?.Invoke(null, EventArgs.Empty);
+            if (!lipSyncer.IsAsyncInit)
+            {
+                audioLength = (int)(sampleRate * 0.16f * 2f);
+
+                lipSyncer.InitAsyncLipsync();
+                lipSyncer.IsAsyncInit = true;
+
+                lipSyncer.SetFinishAsyncLip(false);
+                isAsyncLipStarting = false;
+            }*/
+        }
+
+        private void UpdateBuffer(byte[] recordBuffer, int sampleRate)
+        {
+            UpdatedBuffer?.Invoke(this, new TTSControllerEventArgs(recordBuffer, sampleRate));
+            /*
+            if (lipSyncer != null)
+            {
+                Log.Error(LogTag, "OnTTSBufferChanged");
+                lipSyncer.EnqueueAnimation(recordBuffer, sampleRate, audioLength);
+                if (!isAsyncLipStarting)
+                {
+                    lipSyncer.StartAsyncLipPlayTimer();
+                    isAsyncLipStarting = true;
+                }
+            }
+            else
+            {
+                Log.Error(LogTag, "avatarLipSyncer is null");
+            }*/
+        }
+
+        public void Dispose()
+        {
+            ttsHandle.Stop();
+            ttsHandle.Dispose();
+            ttsHandle = null;
+        }
+    }
+}
diff --git a/src/Tizen.AIAvatar/src/Multimedia/TTS/UtteranceText.cs b/src/Tizen.AIAvatar/src/Multimedia/TTS/UtteranceText.cs
new file mode 100644 (file)
index 0000000..2e69e1f
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Copyright(c) 2024 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+using System;
+
+namespace Tizen.AIAvatar
+{
+    internal struct UtteranceText : IEquatable<UtteranceText>
+    {
+        private string text;
+        private int uttID;
+
+        public string Text { get => text; set => text = value; }
+        public int UttID { get => uttID; set => uttID = value; }
+
+        public override bool Equals(object obj) => obj is VoiceInfo other && this.Equals(other);
+
+        public bool Equals(UtteranceText other) => Text == other.Text && UttID == other.UttID;
+
+        public static bool operator ==(UtteranceText lhsUtternaceText, UtteranceText rhsUtternaceText) => lhsUtternaceText.Equals(rhsUtternaceText);
+
+        public static bool operator !=(UtteranceText lhsUtternaceText, UtteranceText rhsVoiceInfo) => !lhsUtternaceText.Equals(rhsVoiceInfo);
+
+        public override int GetHashCode() => (Text, UttID).GetHashCode();
+    }
+}
diff --git a/src/Tizen.AIAvatar/src/Multimedia/TTS/VoiceInfo.cs b/src/Tizen.AIAvatar/src/Multimedia/TTS/VoiceInfo.cs
new file mode 100644 (file)
index 0000000..25e8e71
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * Copyright(c) 2024 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+using System;
+using System.ComponentModel;
+
+namespace Tizen.AIAvatar
+{
+    /// <summary>
+    /// VoiceInfo stores information about a voice. 
+    /// The 'Language' field stores the language of the voice
+    /// The 'Type' field stores the type of the voice. 
+    /// </summary>
+    [EditorBrowsable(EditorBrowsableState.Never)]
+    public struct VoiceInfo : IEquatable<VoiceInfo>
+    {
+        private string language;
+        private VoiceType type;
+
+        /// <summary>  
+        /// Gets or sets the language of the voice.  
+        /// </summary>  
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public string Language { get => language; set => language = value; }
+
+        /// <summary>  
+        /// Gets or sets the type of the voice.  
+        /// </summary>  
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public VoiceType Type { get => type; set => type = value; }
+
+        /// <summary>
+        /// Determines whether the specified object is equal to the current object.
+        /// </summary>
+        /// <param name="obj">The object to compare with the current object.</param>
+        /// <returns>true if equal VoiceInfo, else false.</returns>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public override bool Equals(object obj) => obj is VoiceInfo other && this.Equals(other);
+
+        /// <summary>
+        /// Determines whether the specified object is equal to the current object.
+        /// </summary>
+        /// <param name="other">The VoiceInfo to compare with the current VoiceInfo.</param>
+        /// <returns>true if equal VoiceInfo, else false.</returns>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public bool Equals(VoiceInfo other) => Language == other.Language && Type == other.Type;
+
+        /// <summary>
+        /// The == operator.
+        /// </summary>
+        /// <param name="lhsVoiceInfo">VoiceInfo to compare</param>
+        /// <param name="rhsVoiceInfo">VoiceInfo to be compared</param>
+        /// <returns>true if VoiceInfo are equal</returns>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public static bool operator ==(VoiceInfo lhsVoiceInfo, VoiceInfo rhsVoiceInfo) => lhsVoiceInfo.Equals(rhsVoiceInfo);
+
+        /// <summary>
+        /// The != operator.
+        /// </summary>
+        /// <param name="lhsVoiceInfo">VoiceInfo to compare</param>
+        /// <param name="rhsVoiceInfo">VoiceInfo to be compared</param>
+        /// <returns>true if VoiceInfo are not equal</returns>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public static bool operator !=(VoiceInfo lhsVoiceInfo, VoiceInfo rhsVoiceInfo) => !lhsVoiceInfo.Equals(rhsVoiceInfo);
+
+        /// <summary>
+        /// Gets the hash code of this VoiceInfo.
+        /// </summary>
+        /// <returns>The hash code.</returns>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public override int GetHashCode() => (Language, Type).GetHashCode();
+    }
+}
diff --git a/src/Tizen.AIAvatar/src/Multimedia/TTS/VoiceType.cs b/src/Tizen.AIAvatar/src/Multimedia/TTS/VoiceType.cs
new file mode 100644 (file)
index 0000000..dceb9a5
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Copyright(c) 2024 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+using System.ComponentModel;
+
+namespace Tizen.AIAvatar
+{
+    /// <summary>
+    /// VoiceType is an enum that represents various types of voices.  
+    /// </summary>
+    [EditorBrowsable(EditorBrowsableState.Never)]
+    public enum VoiceType
+    {
+        /// <summary>
+        /// Automatically determines the best voice to use based on available options.  
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        Auto = 0,
+        /// <summary>
+        /// Selects a male voice for speech synthesis.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        Male = 1,
+        /// <summary>
+        /// Selects a female voice for speech synthesis.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        Female = 2,
+        /// <summary>
+        /// Selects a child's voice for speech synthesis.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        Child = 3
+    }
+}
diff --git a/src/Tizen.AIAvatar/src/RestClient/IRestClient.cs b/src/Tizen.AIAvatar/src/RestClient/IRestClient.cs
new file mode 100644 (file)
index 0000000..9a593b1
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * Copyright(c) 2024 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+using System.Net.Http;
+using System.Threading.Tasks;
+
+namespace Tizen.AIAvatar
+{
+
+    internal interface IRestClient
+    {
+        Task<string> SendRequestAsync(HttpMethod method, string endpoint, string bearerToken = null, string jsonData = null);
+    }
+}
diff --git a/src/Tizen.AIAvatar/src/RestClient/RestClient.cs b/src/Tizen.AIAvatar/src/RestClient/RestClient.cs
new file mode 100644 (file)
index 0000000..0ee81eb
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * Copyright(c) 2024 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+using System;
+using System.Net.Http.Headers;
+using System.Net.Http;
+using System.Text;
+using System.Threading.Tasks;
+using System.ComponentModel;
+
+namespace Tizen.AIAvatar
+{
+    internal class RestClient : IRestClient, IDisposable
+    {
+        private readonly HttpClient client;
+
+        internal RestClient(HttpClient httpClient)
+        {
+            client = httpClient;
+        }
+
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public async Task<string> SendRequestAsync(HttpMethod method, string endpoint, string bearerToken = null, string jsonData = null)
+        {
+            AddBearerToken(bearerToken);
+
+            HttpRequestMessage request = new HttpRequestMessage(method, endpoint);
+
+            if (jsonData != null)
+            {
+                request.Content = new StringContent(jsonData, Encoding.UTF8, "application/json");
+            }
+
+            HttpResponseMessage response = await client.SendAsync(request);
+            request?.Dispose();
+            return await HandleResponse(response);
+        }
+
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public void Dispose()
+        {
+            client.Dispose();
+        }
+
+        private void AddBearerToken(string bearerToken)
+        {
+            if (!string.IsNullOrEmpty(bearerToken))
+            {
+                client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", bearerToken);
+            }
+        }
+
+        private async Task<string> HandleResponse(HttpResponseMessage response)
+        {
+            if (response.IsSuccessStatusCode)
+            {
+                return await response.Content.ReadAsStringAsync();
+            }
+            else
+            {
+                throw new HttpRequestException($"HTTP request failed with status code {response.StatusCode}");
+            }
+        }
+    }
+}
diff --git a/src/Tizen.AIAvatar/src/RestClient/RestClientFactory.cs b/src/Tizen.AIAvatar/src/RestClient/RestClientFactory.cs
new file mode 100644 (file)
index 0000000..07b7fa1
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * Copyright(c) 2024 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+using System.Net.Http;
+using System;
+
+namespace Tizen.AIAvatar
+{
+    internal class RestClientFactory
+    {
+        internal IRestClient CreateClient(string baseUrl)
+        {
+            return new RestClient(new HttpClient { BaseAddress = new Uri(baseUrl) });
+        }
+    }
+}
diff --git a/src/Tizen.AIAvatar/src/Tracking/TrackingController.cs b/src/Tizen.AIAvatar/src/Tracking/TrackingController.cs
new file mode 100644 (file)
index 0000000..4ca0fbf
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Copyright(c) 2024 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+namespace Tizen.AIAvatar
+{
+    internal class TrackingController
+    {
+        internal TrackingController()
+        {
+        }
+
+        internal void Initialize(TrackingOptions options)
+        {
+        }
+
+        internal void StartMotionTracking()
+        {
+
+        }
+
+        internal void StopMotionTracking()
+        {
+
+        }
+    }
+}
diff --git a/src/Tizen.AIAvatar/src/Tracking/TrackingOptions.cs b/src/Tizen.AIAvatar/src/Tracking/TrackingOptions.cs
new file mode 100644 (file)
index 0000000..a908e71
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * Copyright(c) 2024 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+namespace Tizen.AIAvatar
+{
+    internal class TrackingOptions
+    {
+    }
+}
diff --git a/src/Tizen.AIAvatar/src/internal/Avatar/AIAvatar.cs b/src/Tizen.AIAvatar/src/internal/Avatar/AIAvatar.cs
deleted file mode 100644 (file)
index 0002bc3..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright(c) 2023 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-using Tizen.Multimedia;
-
-namespace Tizen.AIAvatar
-{
-    internal static class AIAvatar
-    {
-        internal const string LogTag = "Tizen.AIAvatar";
-        internal static readonly string ApplicationResourcePath = "/usr/apps/org.tizen.default-avatar-resource/shared/res/";
-        internal static readonly string EmojiAvatarResourcePath = "/models/EmojiAvatar/";
-        internal static readonly string DefaultModelResourcePath = "/models/DefaultAvatar/";
-        internal static readonly string DefaultMotionResourcePath = "/animation/motion/";
-
-        internal static readonly string VisemeInfo = $"{ApplicationResourcePath}/viseme/emoji_viseme_info.json";
-        internal static readonly string DefaultModel = "DefaultAvatar.gltf";
-
-        internal static readonly string AREmojiDefaultAvatarPath = $"{ApplicationResourcePath}{DefaultModelResourcePath}{DefaultModel}";
-
-        internal static readonly string DefaultLowModelResourcePath = "/models/DefaultAvatar_Low/";
-        internal static readonly string ExternalModel = "model_external.gltf";
-        internal static readonly string AREmojiDefaultLowAvatarPath = $"{ApplicationResourcePath}{DefaultLowModelResourcePath}{ExternalModel}";
-
-        internal static AudioOptions DefaultAudioOptions = new AudioOptions(24000, AudioChannel.Mono, AudioSampleType.S16Le);
-        internal static AudioOptions CurrentAudioOptions = DefaultAudioOptions;
-    }
-}
diff --git a/src/Tizen.AIAvatar/src/internal/Avatar/Interop.SceneView.cs b/src/Tizen.AIAvatar/src/internal/Avatar/Interop.SceneView.cs
deleted file mode 100644 (file)
index 0e116ea..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright(c) 2023 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-namespace Tizen.AIAvatar
-{
-    internal class Interop
-    {
-        internal static partial class Libraries
-        {
-            public const string Scene3D = "libdali2-csharp-binder-scene3d.so";
-        }
-
-        [global::System.Runtime.InteropServices.DllImport(Libraries.Scene3D, EntryPoint = "CSharp_Dali_SceneView_Property_AlphaMaskURL_get")]
-        public static extern int AlphaMaskURLGet();
-
-        [global::System.Runtime.InteropServices.DllImport(Libraries.Scene3D, EntryPoint = "CSharp_Dali_SceneView_Property_MaskContentScale_get")]
-        public static extern int MaskContentScaleGet();
-
-        [global::System.Runtime.InteropServices.DllImport(Libraries.Scene3D, EntryPoint = "CSharp_Dali_SceneView_Property_CropToMask_get")]
-        public static extern int CropToMaskGet();
-
-    }
-}
diff --git a/src/Tizen.AIAvatar/src/internal/Avatar/Utils.cs b/src/Tizen.AIAvatar/src/internal/Avatar/Utils.cs
deleted file mode 100644 (file)
index 7f1acf9..0000000
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * Copyright(c) 2023 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-using System;
-using System.IO;
-using Tizen.Security;
-using Newtonsoft.Json;
-using System.Collections.Generic;
-using static Tizen.AIAvatar.AIAvatar;
-
-namespace Tizen.AIAvatar
-{
-    internal class Utils
-    {
-        internal static void ConvertAudioToFloat(in byte[] audioBytes, out float[] audioFloat)
-        {
-            audioFloat = new float[audioBytes.Length / 2];
-
-            for (int i = 0, j = 0; i < audioBytes.Length; i += 2, j++)
-            {
-                short sample = BitConverter.ToInt16(audioBytes, i);
-                audioFloat[j] = sample / 32768.0f;
-            }
-        }
-
-        internal static byte[] ReadAllBytes(string path)
-        {
-            try
-            {
-                var bytes = File.ReadAllBytes(path);
-                return bytes;
-            }
-            catch (Exception)
-            {
-                return null;
-            }
-        }
-
-        internal static void SaveFile(string path, string filename, byte[] array)
-        {
-            try
-            {
-                var file = new FileStream($"{path}/{filename}", FileMode.Create);
-                file.Write(array, 0, array.Length);
-                file.Close();
-            }
-            catch (Exception)
-            {
-                return;
-            }
-        }
-
-        internal static void CheckPrivilege(string privilege)
-        {
-            var result = PrivacyPrivilegeManager.CheckPermission(privilege);
-
-            switch (result)
-            {
-                case CheckResult.Allow:
-                    Log.Info(LogTag, $"Privilege \"{privilege}\" : allowed.");
-                    break;
-                case CheckResult.Deny:
-                    Log.Info(LogTag, $"Privilege \"{privilege}\" : denied.");
-                    /// Privilege can't be used
-                    break;
-                case CheckResult.Ask:
-                    /// Request permission to user
-                    PrivacyPrivilegeManager.RequestPermission(privilege);
-                    break;
-            }
-        }
-
-        internal static T ConvertJson<T>(string jsonString)
-        {
-            return JsonConvert.DeserializeObject<T>(jsonString);
-        }
-
-        internal int FindMaxValue<T>(List<T> list, Converter<T, int> projection)
-        {
-            if (list.Count == 0)
-            {
-                throw new InvalidOperationException("Empty list");
-            }
-            int maxValue = int.MinValue;
-            foreach (T item in list)
-            {
-                int value = projection(item);
-                if (value > maxValue)
-                {
-                    maxValue = value;
-                }
-            }
-            return maxValue;
-        }
-    }
-}
-
-internal class SystemUtils
-{
-    internal static void ST()
-    {
-        Tizen.Log.Error("MYLOG", System.Environment.StackTrace);
-    }
-
-    internal static string GetFileName(string path)
-    {
-        return System.IO.Path.GetFileName(path);
-    }
-    internal static string GetFileNameWithoutExtension(string path)
-    {
-        return System.IO.Path.GetFileNameWithoutExtension(path);
-    }
-}
diff --git a/src/Tizen.AIAvatar/src/internal/BlendShapeInfo/BlendShapeInfo.cs b/src/Tizen.AIAvatar/src/internal/BlendShapeInfo/BlendShapeInfo.cs
deleted file mode 100644 (file)
index 71e0ad1..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright(c) 2023 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-using System.Collections.Generic;
-using System.ComponentModel;
-using static Tizen.AIAvatar.AIAvatar;
-
-namespace Tizen.AIAvatar
-{
-    internal class BlendShapeInfo
-    {
-        internal BlendShapeModelInfo blendShape;
-        internal BlendShapeVisemeInfo[] visemes;
-
-        internal BlendShapeInfo() { }
-
-        internal string[] GetNodeNames()
-        {
-            if (blendShape == null)
-            {
-                Log.Error(LogTag, "blendShape is null");
-                return null;
-            }
-            return blendShape.nodeNames;
-        }
-
-        internal int[] GetBlendShapeCounts()
-        {
-            return blendShape.blendShapeCount;
-        }
-
-        internal Dictionary<Viseme, BlendShapeValue[]> GetVisemeMap()
-        {
-            Dictionary<Viseme, BlendShapeValue[]> visemeMap = new Dictionary<Viseme, BlendShapeValue[]>();
-
-            foreach (var visemeInfo in visemes)
-            {
-                visemeMap.Add(visemeInfo.name, visemeInfo.values);
-            }
-
-            return visemeMap;
-        }
-    }
-}
diff --git a/src/Tizen.AIAvatar/src/internal/BlendShapeInfo/BlendShapeModelInfo.cs b/src/Tizen.AIAvatar/src/internal/BlendShapeInfo/BlendShapeModelInfo.cs
deleted file mode 100644 (file)
index df8e125..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright(c) 2023 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-using System.ComponentModel;
-
-namespace Tizen.AIAvatar
-{
-    internal class BlendShapeModelInfo
-    {
-        internal string keyFormat;
-        internal string[] nodeNames;
-        internal int[] blendShapeCount;
-
-        internal BlendShapeModelInfo(string keyFormat, string[] nodeNames, int[] blendShapeCount)
-        {
-            this.keyFormat = keyFormat;
-            this.nodeNames = nodeNames;
-            this.blendShapeCount = blendShapeCount;
-        }
-    }
-}
diff --git a/src/Tizen.AIAvatar/src/internal/BlendShapeInfo/BlendShapeValue.cs b/src/Tizen.AIAvatar/src/internal/BlendShapeInfo/BlendShapeValue.cs
deleted file mode 100644 (file)
index 3ce5c01..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright(c) 2023 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-using System.ComponentModel;
-
-namespace Tizen.AIAvatar
-{
-    internal class BlendShapeValue
-    {
-        internal string nodeName;
-        internal BlendShapeType blendIndex;
-        internal float blendValue;
-    }
-}
diff --git a/src/Tizen.AIAvatar/src/internal/BlendShapeInfo/BlendShapeVisemeInfo.cs b/src/Tizen.AIAvatar/src/internal/BlendShapeInfo/BlendShapeVisemeInfo.cs
deleted file mode 100644 (file)
index cc11c6a..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright(c) 2023 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-using System.ComponentModel;
-
-namespace Tizen.AIAvatar
-{
-    internal class BlendShapeVisemeInfo
-    {
-        internal Viseme name;
-        internal BlendShapeValue[] values;
-    }
-}
diff --git a/src/Tizen.AIAvatar/src/internal/Common/IRestClient.cs b/src/Tizen.AIAvatar/src/internal/Common/IRestClient.cs
deleted file mode 100644 (file)
index 9a593b1..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright(c) 2024 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-using System.Net.Http;
-using System.Threading.Tasks;
-
-namespace Tizen.AIAvatar
-{
-
-    internal interface IRestClient
-    {
-        Task<string> SendRequestAsync(HttpMethod method, string endpoint, string bearerToken = null, string jsonData = null);
-    }
-}
diff --git a/src/Tizen.AIAvatar/src/internal/Common/RestClient.cs b/src/Tizen.AIAvatar/src/internal/Common/RestClient.cs
deleted file mode 100644 (file)
index 0ee81eb..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright(c) 2024 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-using System;
-using System.Net.Http.Headers;
-using System.Net.Http;
-using System.Text;
-using System.Threading.Tasks;
-using System.ComponentModel;
-
-namespace Tizen.AIAvatar
-{
-    internal class RestClient : IRestClient, IDisposable
-    {
-        private readonly HttpClient client;
-
-        internal RestClient(HttpClient httpClient)
-        {
-            client = httpClient;
-        }
-
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        public async Task<string> SendRequestAsync(HttpMethod method, string endpoint, string bearerToken = null, string jsonData = null)
-        {
-            AddBearerToken(bearerToken);
-
-            HttpRequestMessage request = new HttpRequestMessage(method, endpoint);
-
-            if (jsonData != null)
-            {
-                request.Content = new StringContent(jsonData, Encoding.UTF8, "application/json");
-            }
-
-            HttpResponseMessage response = await client.SendAsync(request);
-            request?.Dispose();
-            return await HandleResponse(response);
-        }
-
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        public void Dispose()
-        {
-            client.Dispose();
-        }
-
-        private void AddBearerToken(string bearerToken)
-        {
-            if (!string.IsNullOrEmpty(bearerToken))
-            {
-                client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", bearerToken);
-            }
-        }
-
-        private async Task<string> HandleResponse(HttpResponseMessage response)
-        {
-            if (response.IsSuccessStatusCode)
-            {
-                return await response.Content.ReadAsStringAsync();
-            }
-            else
-            {
-                throw new HttpRequestException($"HTTP request failed with status code {response.StatusCode}");
-            }
-        }
-    }
-}
diff --git a/src/Tizen.AIAvatar/src/internal/Common/RestClientFactory.cs b/src/Tizen.AIAvatar/src/internal/Common/RestClientFactory.cs
deleted file mode 100644 (file)
index 07b7fa1..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright(c) 2024 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-using System.Net.Http;
-using System;
-
-namespace Tizen.AIAvatar
-{
-    internal class RestClientFactory
-    {
-        internal IRestClient CreateClient(string baseUrl)
-        {
-            return new RestClient(new HttpClient { BaseAddress = new Uri(baseUrl) });
-        }
-    }
-}
diff --git a/src/Tizen.AIAvatar/src/internal/DefaultAvatar/DefaultAvatarProperties.cs b/src/Tizen.AIAvatar/src/internal/DefaultAvatar/DefaultAvatarProperties.cs
deleted file mode 100644 (file)
index d8e6ef3..0000000
+++ /dev/null
@@ -1,200 +0,0 @@
-/*
- * Copyright(c) 2023 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-using System;
-using System.Collections.Generic;
-using System.Text;
-using Tizen.NUI;
-using Tizen.NUI.Scene3D;
-
-namespace Tizen.AIAvatar
-{
-    internal class DefaultAvatarProperties : AvatarProperties
-    {
-        private static AvatarPropertyMapper defaultJointMapper = new AvatarPropertyMapper();
-        private static AvatarPropertyMapper defaultBlendShapeNameMapper = new AvatarPropertyMapper();
-        private static AvatarPropertyMapper defaultNodeMapper = new AvatarPropertyMapper();
-
-
-        internal DefaultAvatarProperties() : base(defaultJointMapper, defaultBlendShapeNameMapper, defaultNodeMapper)
-        {
-            foreach (var indexNamePair in blendShapeList)
-            {
-                defaultBlendShapeNameMapper.SetPropertyName((uint)indexNamePair.Item1, indexNamePair.Item2);
-            }
-
-            foreach (var indexNamePair in jointList)
-            {
-                defaultJointMapper.SetPropertyName((uint)indexNamePair.Item1, indexNamePair.Item2);
-            }
-
-            foreach (var indexNamePair in nodeList)
-            {
-                defaultNodeMapper.SetPropertyName((uint)indexNamePair.Item1, indexNamePair.Item2);
-            }
-        }
-
-        #region AR Emoji BlendShape name list
-        private static readonly List<(BlendShapeType, string)> blendShapeList = new List<(BlendShapeType, string)>()
-        {
-            (BlendShapeType.EyeBlinkLeft, "EyeBlink_Left"),
-            (BlendShapeType.EyeSquintLeft, "EyeSquint_Left"),
-            (BlendShapeType.EyeDownLeft, "EyeDown_Left"),
-            (BlendShapeType.EyeInLeft, "EyeIn_Left"),
-            (BlendShapeType.EyeOpenLeft, "EyeOpen_Left"),
-            (BlendShapeType.EyeOutLeft, "EyeOut_Left"),
-            (BlendShapeType.EyeUpLeft, "EyeUp_Left"),
-
-            (BlendShapeType.EyeBlinkRight, "EyeBlink_Right"),
-            (BlendShapeType.EyeSquintRight, "EyeSquint_Right"),
-            (BlendShapeType.EyeDownRight, "EyeDown_Right"),
-            (BlendShapeType.EyeInRight, "EyeIn_Right"),
-            (BlendShapeType.EyeOpenRight, "EyeOpen_Right"),
-            (BlendShapeType.EyeOutRight, "EyeOut_Right"),
-            (BlendShapeType.EyeUpRight, "EyeUp_Right"),
-
-            (BlendShapeType.JawForward, "JawFwd"),
-            (BlendShapeType.JawOpen, "JawOpen"),
-            (BlendShapeType.JawChew, "JawChew"),
-            (BlendShapeType.JawLeft, "JawLeft"),
-            (BlendShapeType.JawRight, "JawRight"),
-
-            (BlendShapeType.MouthLeft, "MouthLeft"),
-            (BlendShapeType.MouthFrownLeft, "MouthFrown_Left"),
-            (BlendShapeType.MouthSmileLeft, "MouthSmile_Left"),
-            (BlendShapeType.MouthDimpleLeft, "MouthDimple_Left"),
-
-            (BlendShapeType.MouthRight, "MouthRight"),
-            (BlendShapeType.MouthFrownRight, "MouthFrown_Right"),
-            (BlendShapeType.MouthSmileRight, "MouthSmile_Right"),
-            (BlendShapeType.MouthDimpleRight, "MouthDimple_Right"),
-
-            (BlendShapeType.LipsStretchLeft, "LipsStretch_Left"),
-            (BlendShapeType.LipsStretchRight, "LipsStretch_Right"),
-            (BlendShapeType.LipsUpperClose, "LipsUpperClose"),
-            (BlendShapeType.LipsLowerClose, "LipsLowerClose"),
-            (BlendShapeType.LipsUpperUp, "LipsUpperUp"),
-            (BlendShapeType.LipsLowerDown, "LipsLowerDown"),
-            (BlendShapeType.LipsUpperOpen, "LipsUpperOpen"),
-            (BlendShapeType.LipsLowerOpen, "LipsLowerOpen"),
-            (BlendShapeType.LipsFunnel, "LipsFunnel"),
-            (BlendShapeType.LipsPucker, "LipsPucker"),
-
-            (BlendShapeType.BrowDownLeft, "BrowsDown_Left"),
-            (BlendShapeType.BrowDownRight, "BrowsDown_Right"),
-            (BlendShapeType.BrowUpCenter, "BrowsUp_Center"),
-            (BlendShapeType.BrowUpLeft, "BrowsUp_Left"),
-            (BlendShapeType.BrowUpRight, "BrowsUp_Right"),
-            (BlendShapeType.CheekSquintLeft, "CheekSquint_Left"),
-            (BlendShapeType.CheekSquintRight, "CheekSquint_Right"),
-            (BlendShapeType.ChinLowerRaise, "ChinLowerRaise"),
-            (BlendShapeType.ChinUpperRaise, "ChinUpperRaise"),
-
-            (BlendShapeType.TongueOut, "Tongue_Out"),
-            (BlendShapeType.TongueUp, "Tongue_Up"),
-            (BlendShapeType.TongueDown, "Tongue_Down"),
-            (BlendShapeType.TongueLeft, "Tongue_Left"),
-            (BlendShapeType.TongueRight, "Tongue_Right"),
-
-            (BlendShapeType.Sneer, "Sneer"),
-            (BlendShapeType.Puff, "Puff"),
-            (BlendShapeType.PuffLeft, "Puff_Left"),
-            (BlendShapeType.PuffRight, "Puff_Right"),
-        };
-        #endregion
-
-        #region AR Emoji Joint name list
-        private static readonly List<(JointType, string)> jointList = new List<(JointType, string)>
-        {
-            (JointType.Head, "head_JNT"),
-            (JointType.Neck, "neck_JNT"),
-            (JointType.EyeLeft, "l_eye_JNT"),
-            (JointType.EyeRight, "r_eye_JNT"),
-
-            (JointType.ShoulderLeft, "l_arm_JNT"),
-            (JointType.ElbowLeft, "l_forearm_JNT"),
-            (JointType.WristLeft, "l_hand_JNT"),
-
-            (JointType.ShoulderRight, "r_arm_JNT"),
-            (JointType.ElbowRight, "r_forearm_JNT"),
-            (JointType.WristRight, "r_hand_JNT"),
-
-            (JointType.HipLeft, "l_upleg_JNT"),
-            (JointType.KneeLeft, "l_leg_JNT"),
-            (JointType.AnkleLeft, "l_foot_JNT"),
-            (JointType.ForeFootLeft, "l_toebase_JNT"),
-
-            (JointType.HipRight, "r_upleg_JNT"),
-            (JointType.KneeRight, "r_leg_JNT"),
-            (JointType.AnkleRight, "r_foot_JNT"),
-            (JointType.ForeFootRight, "r_toebase_JNT"),
-
-            (JointType.FingerThumb1Left, "l_handThumb1_JNT"),
-            (JointType.FingerThumb2Left, "l_handThumb2_JNT"),
-            (JointType.FingerThumb3Left, "l_handThumb3_JNT"),
-            (JointType.FingerThumb4Left, "l_handThumb4_JNT"),
-            (JointType.FingerIndex1Left, "l_handIndex1_JNT"),
-            (JointType.FingerIndex2Left, "l_handIndex2_JNT"),
-            (JointType.FingerIndex3Left, "l_handIndex3_JNT"),
-            (JointType.FingerIndex4Left, "l_handIndex4_JNT"),
-            (JointType.FingerMiddle1Left, "l_handMiddle1_JNT"),
-            (JointType.FingerMiddle2Left, "l_handMiddle2_JNT"),
-            (JointType.FingerMiddle3Left, "l_handMiddle3_JNT"),
-            (JointType.FingerMiddle4Left, "l_handMiddle4_JNT"),
-            (JointType.FingerRing1Left, "l_handRing1_JNT"),
-            (JointType.FingerRing2Left, "l_handRing2_JNT"),
-            (JointType.FingerRing3Left, "l_handRing3_JNT"),
-            (JointType.FingerRing4Left, "l_handRing4_JNT"),
-            (JointType.FingerPinky1Left, "l_handPinky1_JNT"),
-            (JointType.FingerPinky2Left, "l_handPinky2_JNT"),
-            (JointType.FingerPinky3Left, "l_handPinky3_JNT"),
-            (JointType.FingerPinky4Left, "l_handPinky4_JNT"),
-
-            (JointType.FingerThumb1Right, "r_handThumb1_JNT"),
-            (JointType.FingerThumb2Right, "r_handThumb2_JNT"),
-            (JointType.FingerThumb3Right, "r_handThumb3_JNT"),
-            (JointType.FingerThumb4Right, "r_handThumb4_JNT"),
-            (JointType.FingerIndex1Right, "r_handIndex1_JNT"),
-            (JointType.FingerIndex2Right, "r_handIndex2_JNT"),
-            (JointType.FingerIndex3Right, "r_handIndex3_JNT"),
-            (JointType.FingerIndex4Right, "r_handIndex4_JNT"),
-            (JointType.FingerMiddle1Right, "r_handMiddle1_JNT"),
-            (JointType.FingerMiddle2Right, "r_handMiddle2_JNT"),
-            (JointType.FingerMiddle3Right, "r_handMiddle3_JNT"),
-            (JointType.FingerMiddle4Right, "r_handMiddle4_JNT"),
-            (JointType.FingerRing1Right, "r_handRing1_JNT"),
-            (JointType.FingerRing2Right, "r_handRing2_JNT"),
-            (JointType.FingerRing3Right, "r_handRing3_JNT"),
-            (JointType.FingerRing4Right, "r_handRing4_JNT"),
-            (JointType.FingerPinky1Right, "r_handPinky1_JNT"),
-            (JointType.FingerPinky2Right, "r_handPinky2_JNT"),
-            (JointType.FingerPinky3Right, "r_handPinky3_JNT"),
-            (JointType.FingerPinky4Right, "r_handPinky4_JNT"),
-        };
-        #endregion
-
-        #region AR Emoji Joint name list
-        private static readonly List<(NodeType, string)> nodeList = new List<(NodeType, string)>
-        {
-            (NodeType.HeadGeo, "head_GEO"),
-            (NodeType.MouthGeo, "mouth_GEO"),
-            (NodeType.EyelashGeo, "eyelash_GEO"),
-        };
-        #endregion
-
-    }
-}
diff --git a/src/Tizen.AIAvatar/src/internal/LipSync/LipInfo.cs b/src/Tizen.AIAvatar/src/internal/LipSync/LipInfo.cs
deleted file mode 100644 (file)
index 8d785c9..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright(c) 2023 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-using Tizen.NUI;
-
-namespace Tizen.AIAvatar
-{
-    internal class LipInfo
-    {
-        private Animatable animatable;
-        private string nodeName;
-        private int blendShapeCount;
-
-        internal Animatable Animatable { get => animatable; set => animatable = value; }
-        internal string NodeName { get => nodeName; set => nodeName = value; }
-        internal int BlendShapeCount { get => blendShapeCount; set => blendShapeCount = value; }
-    }
-}
diff --git a/src/Tizen.AIAvatar/src/internal/LipSync/Models/ISingleShotModel.cs b/src/Tizen.AIAvatar/src/internal/LipSync/Models/ISingleShotModel.cs
deleted file mode 100644 (file)
index cf2cb8e..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-
-using System.ComponentModel;
-
-namespace Tizen.AIAvatar
-{
-    internal interface ISingleShotModel
-    {
-
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        public void SetTensorData(int index, byte[] buffer);
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        public byte[] GetTensorData(int index);
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        public void Invoke();
-    }
-}
diff --git a/src/Tizen.AIAvatar/src/internal/LipSync/Models/SoftmaxLinqExtension.cs b/src/Tizen.AIAvatar/src/internal/LipSync/Models/SoftmaxLinqExtension.cs
deleted file mode 100644 (file)
index de471a3..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-
-namespace Tizen.AIAvatar
-{
-    internal static class SoftmaxLinqExtension
-    {
-        internal static IEnumerable<float> SoftMax(this IEnumerable<float> source)
-        {
-            var exp = source.Select(x => MathF.Exp(x)).ToArray();
-            var sum = exp.Sum();
-            return exp.Select(x => x / sum);
-        }
-    }
-}
diff --git a/src/Tizen.AIAvatar/src/internal/LipSync/Models/TFVowel6.cs b/src/Tizen.AIAvatar/src/internal/LipSync/Models/TFVowel6.cs
deleted file mode 100644 (file)
index 1061a85..0000000
+++ /dev/null
@@ -1,82 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.ComponentModel;
-using System.Text;
-using Tizen.MachineLearning.Inference;
-using static Tizen.AIAvatar.AIAvatar;
-
-namespace Tizen.AIAvatar
-{
-    internal class TFVowel6 : ISingleShotModel
-    {
-        private SingleShot singleShot;
-        private TensorsInfo inputInfo;
-        private TensorsInfo outputInfo;
-        private TensorsData inputData;
-        private TensorsData outputData;
-
-        private readonly string modelPath = ApplicationResourcePath + "audio2vowel_7.tflite";
-
-        internal TFVowel6(int[] inputDimension, int[] outputDimension)
-        {
-            try
-            {
-                inputInfo = new TensorsInfo();
-                inputInfo.AddTensorInfo(TensorType.Float32, inputDimension);
-
-                outputInfo = new TensorsInfo();
-                outputInfo.AddTensorInfo(TensorType.Float32, outputDimension);
-
-                singleShot = new SingleShot(modelPath, inputInfo, outputInfo);
-            }
-            catch (Exception e)
-            {
-                if (e is NotSupportedException)
-                {
-                    Log.Info(LogTag, "NotSupportedException occurs");
-                }
-                else
-                {
-                    Log.Info(LogTag, e.Message);
-                }
-            }
-        }
-
-
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        public void SetTensorData(int index, byte[] buffer)
-        {
-            try
-            {
-                inputData = inputInfo.GetTensorsData();
-                inputData.SetTensorData(index, buffer);
-            }
-            catch (Exception e)
-            {
-                Log.Info(LogTag, e.Message);
-            }
-        }
-
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        public void Invoke()
-        {
-            try
-            {
-                outputData = singleShot.Invoke(inputData);
-            }
-            catch (Exception e)
-            {
-                Log.Info(LogTag, e.Message);
-            }
-
-        }
-
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        public byte[] GetTensorData(int index)
-        {
-            return outputData.GetTensorData(index);
-        }
-
-
-    }
-}
diff --git a/src/Tizen.AIAvatar/src/internal/LipSync/Viseme.cs b/src/Tizen.AIAvatar/src/internal/LipSync/Viseme.cs
deleted file mode 100644 (file)
index 431c500..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright(c) 2023 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-namespace Tizen.AIAvatar
-{
-    // Various visemes
-    internal enum Viseme
-    {
-        sil,
-        AE,
-        Ah,
-        B_M_P,
-        Ch_J,
-        EE,
-        Er,
-        IH,
-        Oh,
-        W_OO,
-        R,
-    };
-}
diff --git a/src/Tizen.AIAvatar/src/internal/Multimedia/AudioPlayer.cs b/src/Tizen.AIAvatar/src/internal/Multimedia/AudioPlayer.cs
deleted file mode 100644 (file)
index 0c631d7..0000000
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * Copyright(c) 2023 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-using Tizen.Multimedia;
-using System.IO;
-using System;
-
-using static Tizen.AIAvatar.AIAvatar;
-
-namespace Tizen.AIAvatar
-{
-    internal class AudioPlayer
-    {
-        private AudioPlayback audioPlayback;
-        private MemoryStream audioStream;
-
-        internal AudioPlayer()
-        {
-        }
-
-        internal void PlayAsync(byte[] buffer, int sampleRate = 0)
-        {
-            if (audioPlayback == null)
-            {
-                Play(buffer, sampleRate);
-            }
-            else
-            {
-                audioPlayback.Write(buffer);
-            }
-        }
-
-        internal void Play(byte[] audioBytes, int sampleRate = 0)
-        {
-            if (audioBytes == null)
-            {
-                return;
-            }
-
-            try
-            {
-                if (audioPlayback != null)
-                {
-                    DestroyAudioPlayback();
-                }
-                if (sampleRate == 0)
-                {
-                    sampleRate = CurrentAudioOptions.SampleRate;
-                }
-                audioPlayback = new AudioPlayback(sampleRate, CurrentAudioOptions.Channel, CurrentAudioOptions.SampleType);
-            }
-            catch (Exception e)
-            {
-                Log.Error(LogTag, $"Failed to create AudioPlayback. {e.Message}");
-                return;
-            }
-
-            if (audioPlayback != null)
-            {
-                audioPlayback.Prepare();
-                audioPlayback.BufferAvailable += (sender, args) =>
-                {
-                    if (audioStream.Position == audioStream.Length)
-                    {
-                        return;
-                    }
-
-                    try
-                    {
-                        var buffer = new byte[args.Length];
-                        audioStream.Read(buffer, 0, args.Length);
-                        audioPlayback.Write(buffer);
-                    }
-                    catch (Exception e)
-                    {
-                        Log.Error(LogTag, $"Failed to write. {e.Message}");
-                    }
-                };
-
-                audioStream = new MemoryStream(audioBytes);
-            }
-        }
-
-        internal void Pause()
-        {
-            if (audioPlayback != null)
-            {
-                audioPlayback.Pause();
-            }
-            else
-            {
-                Log.Error(LogTag, $"audioPlayBack is null");
-            }
-        }
-
-        internal void Stop()
-        {
-            if (audioPlayback != null)
-            {
-                audioPlayback.Pause();
-                DestroyAudioPlayback();
-            }
-            else
-            {
-                Log.Error(LogTag, $"audioPlayBack is null");
-            }
-        }
-
-        internal void Destroy()
-        {
-            DestroyAudioPlayback();
-        }
-
-        private void DestroyAudioPlayback()
-        {
-            audioPlayback?.Unprepare();
-            audioPlayback?.Dispose();
-            audioPlayback = null;
-        }
-    }
-}
diff --git a/src/Tizen.AIAvatar/src/internal/Multimedia/AudioRecorder.cs b/src/Tizen.AIAvatar/src/internal/Multimedia/AudioRecorder.cs
deleted file mode 100644 (file)
index e3e089a..0000000
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * Copyright(c) 2023 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-using System;
-using System.Linq;
-using System.Text;
-using Tizen.Multimedia;
-using Tizen.NUI;
-using static Tizen.AIAvatar.AIAvatar;
-
-namespace Tizen.AIAvatar
-{
-    internal class AudioRecorder
-    {
-        private const string privilegeForRecording = "http://tizen.org/privilege/recorder";
-
-        private AsyncAudioCapture asyncAudioCapture;
-
-        private byte[] recordedBuffer;
-        private float desiredBufferDuration = 0.16f;
-        private int desiredBufferLength;
-
-        private Timer audioRecordingTimer;
-
-        private Action audioRecdingAction;
-        private Action<byte[],int > bufferAction;
-
-        private static AudioRecorder instance;
-
-        internal static AudioRecorder Instance
-        {
-            get
-            {
-                if (instance == null)
-                {
-                    instance = new AudioRecorder();
-                }
-                return instance;
-            }
-        }
-
-        internal event EventHandler<RecordBufferChangedEventArgs> BufferChanged;
-
-        internal AudioRecorder()
-        {
-            Utils.CheckPrivilege(privilegeForRecording);
-            desiredBufferLength = (int)(CurrentAudioOptions.SampleRate * desiredBufferDuration * 2);
-        }
-
-
-        internal void InitMic(BlendShapePlayer animator, uint recordingTime = 160)
-        {
-            audioRecordingTimer = new Timer(recordingTime);
-            if (animator != null)
-            {
-                //TODO : Connection MIC
-                var lipSyncer = (animator.GetAnimationModule(AnimationModuleType.LipSyncer) as LipSyncer);
-                if(lipSyncer != null)
-                {
-                    Tizen.Log.Error(LogTag, "LipSyncer of animator is null");
-                    return;
-                }
-                this.audioRecdingAction = lipSyncer.OnRecodingTick;
-                this.bufferAction = lipSyncer.OnRecordBufferChanged;
-
-                BufferChanged += OnRecordBufferChanged;
-                audioRecordingTimer.Tick += AudioRecordingTimerTick;
-            }
-        }
-
-
-        internal void DeinitMic()
-        {
-            StopRecording();
-            BufferChanged -= OnRecordBufferChanged;
-
-            if (audioRecordingTimer != null)
-            {
-                audioRecordingTimer.Stop();
-                audioRecordingTimer.Tick -= AudioRecordingTimerTick;
-
-                audioRecordingTimer.Dispose();
-                audioRecordingTimer = null;
-            }
-            audioRecdingAction = null;
-        }
-
-        internal void StartRecording()
-        {
-            audioRecordingTimer?.Start();
-            asyncAudioCapture = new AsyncAudioCapture(CurrentAudioOptions.SampleRate, CurrentAudioOptions.Channel, CurrentAudioOptions.SampleType);
-
-            recordedBuffer = new byte[0];
-            asyncAudioCapture.DataAvailable += (s, e) =>
-            {
-                recordedBuffer = recordedBuffer.Concat(e.Data).ToArray();
-                if (recordedBuffer.Length >= desiredBufferLength)
-                {
-                    var recordedBuffer = this.recordedBuffer;
-                    this.recordedBuffer = Array.Empty<byte>();
-
-                    BufferChanged?.Invoke(this, new RecordBufferChangedEventArgs(recordedBuffer, CurrentAudioOptions.SampleRate));
-                }
-            };
-            asyncAudioCapture.Prepare();
-            Log.Info(LogTag, "Start Recording - Preapre AsyncAudioCapture");
-        }
-
-        internal void StopRecording()
-        {
-            audioRecordingTimer?.Stop();
-            asyncAudioCapture.Dispose();
-        }
-
-        internal void PauseRecording()
-        {
-            asyncAudioCapture.Pause();
-        }
-
-        internal void ResumeRecording()
-        {
-            asyncAudioCapture.Resume();
-        }
-
-        private void OnRecordBufferChanged(object sender, RecordBufferChangedEventArgs e)
-        {
-            bufferAction?.Invoke(e.RecordedBuffer, CurrentAudioOptions.SampleRate);
-        }
-
-        private bool AudioRecordingTimerTick(object source, Timer.TickEventArgs e)
-        {
-            Log.Info(LogTag, "TickTimer");
-            audioRecdingAction?.Invoke();
-            return true;
-        }
-    }
-}
diff --git a/src/Tizen.AIAvatar/src/internal/Multimedia/RecordBufferChangedEventArgs.cs b/src/Tizen.AIAvatar/src/internal/Multimedia/RecordBufferChangedEventArgs.cs
deleted file mode 100644 (file)
index 70bed45..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright(c) 2023 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-using System;
-
-namespace Tizen.AIAvatar
-{
-    internal class RecordBufferChangedEventArgs : EventArgs
-    {
-        public byte[] RecordedBuffer { get; set; }
-        public int SampleRate { get; set; }
-
-        public RecordBufferChangedEventArgs(byte[] recordedBuffer, int SampleRate)
-        {
-            this.RecordedBuffer = recordedBuffer;
-            this.SampleRate = SampleRate;
-        }
-    }
-
-}
diff --git a/src/Tizen.AIAvatar/src/internal/Uix/TTSLipSyncer.cs b/src/Tizen.AIAvatar/src/internal/Uix/TTSLipSyncer.cs
deleted file mode 100644 (file)
index 2c471a1..0000000
+++ /dev/null
@@ -1,497 +0,0 @@
-/*
- * Copyright(c) 2023 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-using System;
-using System.Collections.Generic;
-using Tizen.Uix.Tts;
-using System.Runtime.InteropServices;
-
-using static Tizen.AIAvatar.AIAvatar;
-using System.Linq;
-using Tizen.NUI;
-
-namespace Tizen.AIAvatar
-{
-    internal class TTSLipSyncer
-    {
-
-        private Avatar currentAvatar;
-
-        private List<UtteranceText> textList;
-        private TtsClient ttsHandle;
-        private VoiceInfo voiceInfo;
-        private List<Byte> byteList;
-
-        private byte[] recordedBuffer;
-        private byte[] audioTailBuffer;
-
-        private int sampleRate;
-        private float desiredBufferDuration = 0.175f;
-        private float audioTailLengthFactor = 0.015f;
-        private float audioBufferMultiflier = 2f;
-
-        private int desiredBufferLength;
-        private int audioTailLength;
-
-        private bool isPrepared = false;
-        private bool isAsync = false;
-
-        private Action<byte[], int> bufferChangedAction;
-
-        private int audioLength;
-        private bool isAsyncLipStarting;
-
-        private AsyncLipSyncer lipSyncer;
-
-
-        internal TTSLipSyncer(AsyncLipSyncer lipSyncer)
-        {
-            this.lipSyncer = lipSyncer;
-            InitTts();
-        }
-
-        ~TTSLipSyncer()
-        {
-            DeinitTts();
-        }
-
-        internal event EventHandler PlayReadyCallback;
-
-        internal TtsClient TtsHandle
-        {
-            get { return ttsHandle; }
-        }
-
-        internal VoiceInfo VoiceInfo
-        {
-            get { return voiceInfo; }
-            set
-            {
-                voiceInfo = value;
-            }
-        }
-
-        internal List<VoiceInfo> GetSupportedVoices()
-        {
-            var voiceInfoList = new List<VoiceInfo>();
-
-            if (ttsHandle == null)
-            {
-                Log.Error(LogTag, $"ttsHandle is null");
-                return voiceInfoList;
-            }
-
-            var supportedVoices = ttsHandle.GetSupportedVoices();
-            foreach (var supportedVoice in supportedVoices)
-            {
-                Log.Info(LogTag, $"{supportedVoice.Language} & {supportedVoice.VoiceType} is supported");
-                voiceInfoList.Add(new VoiceInfo() { Lang = supportedVoice.Language, Type = supportedVoice.VoiceType });
-            }
-            return voiceInfoList;
-        }
-
-        internal bool IsSupportedVoice(string lang)
-        {
-            if (ttsHandle == null)
-            {
-                Log.Error(LogTag, $"ttsHandle is null");
-                return false;
-            }
-            var supportedVoices = ttsHandle.GetSupportedVoices();
-
-            foreach (var supportedVoice in supportedVoices)
-            {
-                if (supportedVoice.Language.Equals(lang))
-                {
-                    Log.Info(LogTag, $"{lang} is supported");
-                    return true;
-                }
-            }
-            return false;
-        }
-
-        internal bool IsSupportedVoice(VoiceInfo voiceInfo)
-        {
-            if (ttsHandle == null)
-            {
-                Log.Error(LogTag, $"ttsHandle is null");
-                return false;
-            }
-            var supportedVoices = ttsHandle.GetSupportedVoices();
-            foreach (var supportedVoice in supportedVoices)
-            {
-                if (supportedVoice.Language.Equals(voiceInfo.Lang) && (supportedVoice.VoiceType == voiceInfo.Type))
-                {
-                    Log.Info(LogTag, $"{voiceInfo.Lang} & {voiceInfo.Type} is supported");
-                    return true;
-                }
-            }
-            return false;
-        }
-
-
-        internal void AddText(string txt, VoiceInfo voiceInfo)
-        {
-            if (voiceInfo.Lang == null || voiceInfo.Type == null)
-            {
-                Log.Error(LogTag, "VoiceInfo's value is null");
-            }
-            if (ttsHandle == null)
-            {
-                Log.Error(LogTag, $"ttsHandle is null");
-                return;
-            }
-            var temp = new UtteranceText();
-            temp.Text = txt;
-            temp.UttID = ttsHandle.AddText(txt, voiceInfo.Lang, (int)voiceInfo.Type, 0);
-            try
-            {
-                textList.Add(temp);
-            }
-            catch (Exception e)
-            {
-                Log.Error(LogTag, $"Error AddText" + e.Message);
-            }
-        }
-
-        internal void AddText(string txt, string lang)
-        {
-            if (ttsHandle == null)
-            {
-                Log.Error(LogTag, $"ttsHandle is null");
-                return;
-            }
-            var temp = new UtteranceText();
-            temp.Text = txt;
-            temp.UttID = ttsHandle.AddText(txt, lang, (int)voiceInfo.Type, 0);
-            try
-            {
-                textList.Add(temp);
-            }
-            catch (Exception e)
-            {
-                Log.Error(LogTag, $"Error AddText" + e.Message);
-            }
-        }
-
-        internal void Prepare(EventHandler playReadyCallback)
-        {
-            if (ttsHandle == null)
-            {
-                Log.Error(LogTag, $"ttsHandle is null");
-                return;
-            }
-            Log.Info(LogTag, "Prepare TTS");
-            isPrepared = true;
-            isAsync = false;
-            PlayReadyCallback = playReadyCallback;
-            Play(true);
-        }
-
-        internal bool PlayPreparedText()
-        {
-            if (byteList != null && byteList.Count != 0)
-            {
-                Log.Info(LogTag, "PlayPreparedText TTS");
-                currentAvatar?.AvatarAnimator?.PlayLipSync(byteList.ToArray(), sampleRate);
-                return true;
-            }
-            return false;
-        }
-
-        internal void Play(bool isPrepared = false)
-        {
-            if (ttsHandle == null)
-            {
-                Log.Error(LogTag, $"ttsHandle is null");
-                return;
-            }
-
-            this.isPrepared = isPrepared;
-            isAsync = false;
-            ttsHandle.Play();
-        }
-
-        internal void PlayAsync(EventHandler playReadyCallback)
-        {
-            if (ttsHandle == null)
-            {
-                Log.Error(LogTag, $"ttsHandle is null");
-                return;
-            }
-
-            isPrepared = false;
-            isAsync = true;
-            PlayReadyCallback = playReadyCallback;
-            ttsHandle.Play();
-        }
-
-        public void Pause()
-        {
-            if (ttsHandle == null)
-            {
-                Log.Error(LogTag, $"ttsHandle is null");
-                return;
-            }
-            ttsHandle.Pause();
-        }
-
-        internal void Stop()
-        {
-            if (ttsHandle == null)
-            {
-                Log.Error(LogTag, $"ttsHandle is null");
-                return;
-            }
-            ttsHandle.Stop();
-            currentAvatar?.AvatarAnimator?.StopLipSync();
-        }
-
-        private void InitTts()
-        {
-            try
-            {
-                ttsHandle = new TtsClient();
-
-                // Register Callbacks
-                ttsHandle.DefaultVoiceChanged += TtsDefaultVoiceChangedCallback;
-                ttsHandle.EngineChanged += TtsEngineChangedCallback;
-                ttsHandle.ErrorOccurred += TtsErrorOccuredCallback;
-                ttsHandle.StateChanged += TtsStateChangedCallback;
-                ttsHandle.UtteranceCompleted += TtsUtteranceCompletedCallback;
-                ttsHandle.UtteranceStarted += TtsUtteranceStartedCallback;
-
-                ttsHandle.SynthesizedPcm += TtsSyntheiszedPCM;
-                ttsHandle.PlayingMode = PlayingMode.ByClient;
-
-                ttsHandle.Prepare();
-
-                voiceInfo = new VoiceInfo
-                {
-                    Lang = ttsHandle.DefaultVoice.Language,
-                    Type = ttsHandle.DefaultVoice.VoiceType
-                };
-
-                textList = new List<UtteranceText>();
-                Log.Info(LogTag, voiceInfo.Lang + ", " + voiceInfo.Type.ToString());
-
-            }
-            catch (Exception e)
-            {
-                Log.Error(LogTag, "[ERROR] Fail to prepare Tts");
-                Log.Error(LogTag, e.Message);
-            }
-        }
-
-        internal void DeinitTts()
-        {
-            try
-            {
-                if (ttsHandle != null)
-                {
-                    ttsHandle.Unprepare();
-
-                    // Unregister Callbacks
-                    ttsHandle.DefaultVoiceChanged -= TtsDefaultVoiceChangedCallback;
-                    ttsHandle.EngineChanged -= TtsEngineChangedCallback;
-                    ttsHandle.ErrorOccurred -= TtsErrorOccuredCallback;
-                    ttsHandle.StateChanged -= TtsStateChangedCallback;
-                    ttsHandle.UtteranceCompleted -= TtsUtteranceCompletedCallback;
-                    ttsHandle.UtteranceStarted -= TtsUtteranceStartedCallback;
-
-                    ttsHandle.Dispose();
-                    ttsHandle = null;
-                }
-
-                if (textList != null)
-                {
-                    textList.Clear();
-                    textList = null;
-                }
-
-                if (byteList != null)
-                {
-                    byteList.Clear();
-                    byteList = null;
-                }
-                currentAvatar = null;
-            }
-            catch (Exception e)
-            {
-                Log.Error(LogTag, "[ERROR] Fail to unprepare Tts");
-                Log.Error(LogTag, e.Message);
-            }
-        }
-
-        private void TtsSyntheiszedPCM(object sender, SynthesizedPcmEventArgs e)
-        {
-
-            var dataSize = e.Data.Length;
-            var audio = new byte[dataSize];
-            sampleRate = e.SampleRate;
-
-            //Marshal.Copy(e.Data, audio, 0, dataSize);
-            switch (e.EventType) //START
-            {
-                case SynthesizedPcmEvent.Start://start
-                    Tizen.Log.Info(LogTag, "------------------Start : " + e.UtteranceId);
-                    Tizen.Log.Info(LogTag, "Output audio Size : " + dataSize);
-                    Tizen.Log.Info(LogTag, "SampleRate" + e.SampleRate);
-                    if (byteList == null)
-                    {
-                        byteList = new List<byte>();
-                    }
-                    if (recordedBuffer == null)
-                    {
-                        recordedBuffer = new byte[0];
-                    }
-                    byteList.Clear();
-
-                    if (isAsync)
-                    {
-                        recordedBuffer = Array.Empty<byte>();
-
-                        desiredBufferLength = (int)(e.SampleRate * desiredBufferDuration * audioBufferMultiflier);
-                        audioTailLength = (int)(sampleRate * audioTailLengthFactor * audioBufferMultiflier);
-                        audioTailBuffer = new byte[audioTailLength];
-                        PlayReadyCallback?.Invoke(null, EventArgs.Empty);
-                        InitAsyncBuffer();
-                        lipSyncer.SampleRate = sampleRate;
-                    }
-                    break;
-                case SynthesizedPcmEvent.Continue://continue
-                    if (isAsync)
-                    {
-                        recordedBuffer = recordedBuffer.Concat(e.Data).ToArray();
-                        //PlayAsync
-                        if (recordedBuffer.Length >= desiredBufferLength)
-                        {
-                            Tizen.Log.Error(LogTag, "Current recordbuffer length :" + recordedBuffer.Length);
-                            UpdateBuffer(recordedBuffer, sampleRate);
-                            
-                            Buffer.BlockCopy(recordedBuffer, recordedBuffer.Length - audioTailLength, audioTailBuffer, 0, audioTailLength);
-
-                            recordedBuffer = Array.Empty<byte>();
-                            recordedBuffer = recordedBuffer.Concat(audioTailBuffer).ToArray();
-                            Array.Clear(audioTailBuffer, 0, audioTailLength);
-                        }
-                    }
-                    else
-                    {
-                        byteList.AddRange(e.Data);
-                    }
-                    break;
-                case SynthesizedPcmEvent.Finish://finish
-                    Tizen.Log.Info(LogTag, "------------------Finish : " + e.UtteranceId);
-                    if (!isAsync)
-                    {
-                        if (!isPrepared)
-                        {
-                            //Play voice immediately
-                            //PlayPreparedText();
-                        }
-                        else
-                        {
-                            //Notify finished state
-                            Log.Info(LogTag, "Notify finished state");
-                            PlayReadyCallback?.Invoke(null, EventArgs.Empty);
-                        }
-                    }
-                    else
-                    {
-                        lipSyncer.SetFinishAsyncLip(true);
-                    }
-                    break;
-                case SynthesizedPcmEvent.Fail: //fail
-                    break;
-
-            }
-        }
-
-        private void TtsUtteranceStartedCallback(object sender, UtteranceEventArgs e)
-        {
-            Log.Debug(LogTag, "Utterance start now (" + e.UtteranceId + ")");
-        }
-
-        private void TtsUtteranceCompletedCallback(object sender, UtteranceEventArgs e)
-        {
-            Log.Debug(LogTag, "Utterance complete (" + e.UtteranceId + ")");
-
-            foreach (UtteranceText item in textList)
-            {
-                if (item.UttID == e.UtteranceId)
-                {
-                    textList.Remove(item);
-                    Log.Debug(LogTag, "TextList Count (" + textList.Count.ToString() + ")");
-                    break;
-                }
-            }
-        }
-
-        private void TtsStateChangedCallback(object sender, StateChangedEventArgs e)
-        {
-            Log.Debug(LogTag, "Current state is changed from (" + e.Previous + ") to (" + e.Current + ")");
-        }
-
-        private void TtsErrorOccuredCallback(object sender, ErrorOccurredEventArgs e)
-        {
-            Log.Error(LogTag, "Error is occured (" + e.ErrorMessage + ")");
-        }
-
-        private void TtsEngineChangedCallback(object sender, EngineChangedEventArgs e)
-        {
-            Log.Debug(LogTag, "Prefered engine is changed (" + e.EngineId + ") (" + e.VoiceType.Language + ")");
-        }
-
-        private void TtsDefaultVoiceChangedCallback(object sender, DefaultVoiceChangedEventArgs e)
-        {
-            Log.Debug(LogTag, "Default voice is changed from (" + e.Previous + ") to (" + e.Current + ")");
-        }
-
-        internal void InitAsyncBuffer()
-        {
-            if (!lipSyncer.IsAsyncInit)
-            {
-                audioLength = (int)(sampleRate * 0.16f * 2f);
-
-                lipSyncer.InitAsyncLipsync();
-                lipSyncer.IsAsyncInit = true;
-
-                lipSyncer.SetFinishAsyncLip(false);
-                isAsyncLipStarting = false;
-            }
-        }
-
-        internal void UpdateBuffer(byte[] recordBuffer, int sampleRate)
-        {
-            if (lipSyncer != null)
-            {
-                Log.Error(LogTag, "OnTTSBufferChanged");
-                lipSyncer.EnqueueAnimation(recordBuffer, sampleRate, audioLength);
-                if (!isAsyncLipStarting)
-                {
-                    lipSyncer.StartAsyncLipPlayTimer();
-                    isAsyncLipStarting = true;
-                }
-            }
-            else
-            {
-                Log.Error(LogTag, "avatarLipSyncer is null");
-            }
-        }
-    }
-}
diff --git a/src/Tizen.AIAvatar/src/internal/Uix/UtteranceText.cs b/src/Tizen.AIAvatar/src/internal/Uix/UtteranceText.cs
deleted file mode 100644 (file)
index 0254bf9..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright(c) 2023 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-namespace Tizen.AIAvatar
-{
-    internal struct UtteranceText
-    {
-        internal string Text;
-        internal int UttID;
-    }
-}
diff --git a/src/Tizen.AIAvatar/src/public/Avatar/Animations/AnimationModule/AnimationModule.cs b/src/Tizen.AIAvatar/src/public/Avatar/Animations/AnimationModule/AnimationModule.cs
deleted file mode 100644 (file)
index 42f49ad..0000000
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * Copyright(c) 2024 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-using System;
-using System.ComponentModel;
-using Tizen.NUI;
-using Tizen.NUI.Scene3D;
-
-using static Tizen.AIAvatar.AIAvatar;
-
-namespace Tizen.AIAvatar
-{
-    [EditorBrowsable(EditorBrowsableState.Never)]
-    public abstract class AnimationModule
-    {
-        private AvatarMotionState currentMotionState = AvatarMotionState.Unavailable;
-
-        private readonly Object motionChangedLock = new Object();
-        private event EventHandler<AvatarMotionChangedEventArgs> motionChanged;
-
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        public AnimationModule()
-        {
-
-        }
-
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        public AvatarMotionState CurrentMotionState
-        {
-            get
-            {
-                return currentMotionState;
-            }
-            set
-            {
-                if (currentMotionState == value)
-                {
-                    return;
-                }
-                var preState = currentMotionState;
-                currentMotionState = value;
-                if (motionChanged != null)
-                {
-                    motionChanged?.Invoke(this, new AvatarMotionChangedEventArgs(preState, currentMotionState));
-                }
-            }
-        }
-
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        public abstract void Init(Animation animation);
-
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        public abstract void Play(IAnimationModuleData data);
-
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        public abstract void Stop();
-
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        public abstract void Pause();
-
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        public abstract void Destroy();
-
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        protected void SetCurrentState(AvatarMotionState state)
-        {
-            CurrentMotionState = state;
-        }
-
-
-        /// <summary>
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        public event EventHandler<AvatarMotionChangedEventArgs> MotionStateChanged
-        {
-            add
-            {
-                lock (motionChangedLock)
-                {
-                    motionChanged += value;
-                }
-
-            }
-
-            remove
-            {
-                lock (motionChangedLock)
-                {
-                    if (motionChanged == null)
-                    {
-                        Log.Error(LogTag, "Remove StateChanged Failed : motionChanged is null");
-                        return;
-                    }
-                    motionChanged -= value;
-                }
-            }
-        }
-    }
-
-    [EditorBrowsable(EditorBrowsableState.Never)]
-    public enum AnimationModuleType
-    {
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        EyeBlinker,
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        LipSyncer,
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        MotionBehavior,
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        JointTransformer,
-    }
-}
diff --git a/src/Tizen.AIAvatar/src/public/Avatar/Animations/AnimationModule/AsyncLipSyncer.cs b/src/Tizen.AIAvatar/src/public/Avatar/Animations/AnimationModule/AsyncLipSyncer.cs
deleted file mode 100644 (file)
index 7bab580..0000000
+++ /dev/null
@@ -1,181 +0,0 @@
-/*
- * Copyright(c) 2024 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-using System;
-using System.Collections.Generic;
-using System.ComponentModel;
-using Tizen.NUI;
-
-using static Tizen.AIAvatar.AIAvatar;
-
-namespace Tizen.AIAvatar
-{
-    [EditorBrowsable(EditorBrowsableState.Never)]
-    internal class AsyncLipSyncer : LipSyncer
-    {
-        private readonly uint AsyncPlayTime = 160;
-        private Queue<Animation> lipAnimations;
-        private Queue<byte[]> lipAudios;
-        private Timer asyncVowelTimer;
-
-        private bool isAsyncInit = false;
-        private bool isFinishAsyncLip = false;
-
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        internal AsyncLipSyncer()
-        {
-
-        }
-
-        internal int SampleRate { get; set; }
-
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        internal bool IsAsyncInit { get=>isAsyncInit; set=>isAsyncInit = value; }
-
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        internal void SetFinishAsyncLip(bool finished)
-        {
-            isFinishAsyncLip = finished;
-        }
-
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        protected new void OnLipAnimationFinished(object sender, EventArgs e)
-        {
-            if (!isAsyncInit)
-            {
-                CurrentMotionState = AvatarMotionState.Stopped;
-            }
-            else
-            {
-                Tizen.Log.Error(LogTag, "OnLipAnimationFinished---------------c");
-                //Async State
-                if (isFinishAsyncLip && lipAnimations.Count == 0)
-                {
-                    Tizen.Log.Error(LogTag, "Finish vowel lip sync");
-
-                    AudioPlayer.Stop();
-                    CurrentMotionState = AvatarMotionState.Stopped;
-                    DestroyVowelTimer();
-                    isAsyncInit = false;
-                }
-            }
-        }
-
-        internal void InitAsyncLipsync()
-        {
-            if (lipAnimations == null)
-            {
-                lipAnimations = new Queue<Animation>();
-            }
-            else
-            {
-                lipAnimations.Clear();
-            }
-
-            if (lipAudios == null)
-            {
-                lipAudios = new Queue<byte[]>();
-            }
-            else
-            {
-                lipAudios.Clear();
-            }
-        }
-
-        internal void EnqueueAnimation(byte[] recordBuffer, int sampleRate, int audioLength)
-        {
-            var createdAni = CreateAsyncLipAnimation(recordBuffer, sampleRate);
-            if (createdAni != null)
-            {
-                lipAnimations.Enqueue(createdAni);
-            }
-
-            //Use Audio Full File
-            ///var createdAni = avatarLipSyncer.CreateLipAnimation(recordBuffer, sampleRate);
-            //lipAnimations.Enqueue(createdAni);
-
-            var currentAudioBuffer = new byte[audioLength];
-            Buffer.BlockCopy(recordBuffer, 0, currentAudioBuffer, 0, audioLength);
-
-            lipAudios.Enqueue(currentAudioBuffer);
-        }
-
-        internal bool PlayAsyncLip(int sampleRate, bool isFinishAsyncLip)
-        {
-            try
-            {
-                if (lipAudios.Count <= 0 && lipAnimations.Count <= 0)
-                {
-                    Tizen.Log.Info(LogTag, "Return lipaudio 0");
-                    if (isFinishAsyncLip)
-                    {
-                        Tizen.Log.Info(LogTag, "Finish Async lipsync");
-                        return false;
-                    }
-                    return true;
-                }
-                Tizen.Log.Info(LogTag, "Async timer tick lipAudios : " + lipAudios.Count);
-                Tizen.Log.Info(LogTag, "Async timer tick lipAnimations : " + lipAnimations.Count);
-
-                var lipAnimation = lipAnimations.Dequeue();
-                lipAnimation.Finished += OnLipAnimationFinished;
-
-                ResetLipAnimation(lipAnimation);
-                PlayLipAnimation();
-                var audioBuffer = lipAudios.Dequeue();
-                AudioPlayer.PlayAsync(audioBuffer, sampleRate);
-                return true;
-
-            }
-            catch (Exception ex)
-            {
-                Log.Error(LogTag, $"---Log Tick : {ex.StackTrace}");
-
-                return false;
-            }
-        }
-
-        internal void StartAsyncLipPlayTimer()
-        {
-            if (asyncVowelTimer == null)
-            {
-                Tizen.Log.Info(LogTag, "Start Async");
-                asyncVowelTimer = new Timer(AsyncPlayTime);
-                asyncVowelTimer.Tick += OnAsyncVowelTick;
-                asyncVowelTimer.Start();
-            }
-            return;
-        }
-
-        private void DestroyVowelTimer()
-        {
-            if (asyncVowelTimer != null)
-            {
-
-                asyncVowelTimer.Tick -= OnAsyncVowelTick;
-                asyncVowelTimer.Stop();
-                asyncVowelTimer.Dispose();
-                asyncVowelTimer = null;
-            }
-        }
-
-        private bool OnAsyncVowelTick(object source, Tizen.NUI.Timer.TickEventArgs e)
-        {
-            return PlayAsyncLip(SampleRate, isFinishAsyncLip);
-        }
-    }
-}
diff --git a/src/Tizen.AIAvatar/src/public/Avatar/Animations/AnimationModule/AvatarMotions.cs b/src/Tizen.AIAvatar/src/public/Avatar/Animations/AnimationModule/AvatarMotions.cs
deleted file mode 100644 (file)
index 364cd3a..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright(c) 2024 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-using Tizen.NUI;
-using Tizen.NUI.Scene3D;
-
-namespace Tizen.AIAvatar
-{
-    internal class AvatarMotions
-    {
-        private MotionData eyeMotionData;
-        private const int blinkDuration = 200;
-
-        internal AvatarMotions(AvatarProperties properties)
-        {
-            CreateEyeBlinkMotionData(properties);
-        }
-
-        internal MotionData EyeMotionData { get { return eyeMotionData; } }
-
-        private void CreateEyeBlinkMotionData(AvatarProperties avatarProperties)
-        {
-            var keyFrames = new KeyFrames();
-            keyFrames.Add(0.1f, 0.0f);
-            keyFrames.Add(0.5f, 1.0f);
-            keyFrames.Add(0.9f, 0.0f);
-
-            var headBlendShapeEyeLeft = new AvatarBlendShapeIndex(avatarProperties.NodeMapper, NodeType.HeadGeo, avatarProperties.BlendShapeMapper, BlendShapeType.EyeBlinkLeft);
-            var headBlendShapeEyeRight = new AvatarBlendShapeIndex(avatarProperties.NodeMapper, NodeType.HeadGeo, avatarProperties.BlendShapeMapper, BlendShapeType.EyeBlinkRight);
-            var eyelashBlendShapeEyeLeft = new AvatarBlendShapeIndex(avatarProperties.NodeMapper, NodeType.EyelashGeo, avatarProperties.BlendShapeMapper, BlendShapeType.EyeBlinkLeft);
-            var eyelashBlendShapeEyeRight = new AvatarBlendShapeIndex(avatarProperties.NodeMapper, NodeType.EyelashGeo, avatarProperties.BlendShapeMapper, BlendShapeType.EyeBlinkRight);
-
-            eyeMotionData = new MotionData(blinkDuration);
-            if (headBlendShapeEyeLeft != null)
-            {
-                eyeMotionData.Add(headBlendShapeEyeLeft, new MotionValue(keyFrames));
-            }
-            if (headBlendShapeEyeRight != null)
-            {
-                eyeMotionData.Add(headBlendShapeEyeRight, new MotionValue(keyFrames));
-            }
-            if (eyelashBlendShapeEyeLeft != null)
-            {
-                eyeMotionData.Add(eyelashBlendShapeEyeLeft, new MotionValue(keyFrames));
-            }
-            if (eyelashBlendShapeEyeRight != null)
-            {
-                eyeMotionData.Add(eyelashBlendShapeEyeRight, new MotionValue(keyFrames));
-            }
-        }
-    }
-}
diff --git a/src/Tizen.AIAvatar/src/public/Avatar/Animations/AnimationModule/BlendShapePlayer.cs b/src/Tizen.AIAvatar/src/public/Avatar/Animations/AnimationModule/BlendShapePlayer.cs
deleted file mode 100644 (file)
index e2beca4..0000000
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
- * Copyright(c) 2023 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-using System;
-using System.Collections.Generic;
-using System.ComponentModel;
-using System.Reflection;
-using Tizen.NUI.Scene3D;
-using Tizen.NUI;
-
-using static Tizen.AIAvatar.AIAvatar;
-
-namespace Tizen.AIAvatar
-{
-    internal class BlendShapePlayer
-    {
-        private Dictionary<AnimationModuleType, AnimationModule> animationModules = new Dictionary<AnimationModuleType, AnimationModule>();
-
-        private EyeBlinker blinker;
-        private AsyncLipSyncer lipSyncer;
-
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        public BlendShapePlayer()
-        {
-            blinker = new EyeBlinker();
-            lipSyncer = new AsyncLipSyncer();
-
-            animationModules.Add(AnimationModuleType.EyeBlinker, blinker);
-            animationModules.Add(AnimationModuleType.LipSyncer, lipSyncer);
-        }
-
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        public AsyncLipSyncer LipSyncer => lipSyncer;
-
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        public void SetBlinkAnimation(Animation blinkerAnimation)
-        {
-            animationModules[AnimationModuleType.EyeBlinker].Init(blinkerAnimation);
-        }
-
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        public void SetLipSyncAnimation(Animation lipsyncAnimation)
-        {
-            animationModules[AnimationModuleType.LipSyncer].Init(lipsyncAnimation);
-        }
-
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        public AnimationModule GetAnimationModule(AnimationModuleType type)
-        {
-            return animationModules[type];
-        }
-
-        /// <summary>
-        /// Start eye blink animation
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        public void StartEyeBlink()
-        {
-            animationModules[AnimationModuleType.EyeBlinker]?.Play(null);
-        }
-
-        /// <summary>
-        /// Stop eye blink animation
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        public void StopEyeBlink()
-        {
-            animationModules[AnimationModuleType.EyeBlinker]?.Stop();
-        }
-
-        /// <summary>
-        /// Play synchronization avatar lip based on the voice file(byte[])
-        /// </summary>
-        /// <param name="audio">byte array of voice</param>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        public void PlayLipSync(byte[] audio)
-        {
-            if (animationModules[AnimationModuleType.LipSyncer] == null)
-            {
-                Log.Error(LogTag, $"error : avatarLipSync is null");
-                return;
-            }
-            var lipData = new LipSyncData();
-
-            lipData.AudioFile = new byte[audio.Length];
-            Buffer.BlockCopy(audio, 0, lipData.AudioFile, 0, audio.Length);
-            animationModules[AnimationModuleType.LipSyncer].Play(lipData);
-        }
-
-        /// <summary>
-        /// Play synchronization avatar lip based on the voice file(byte[])
-        /// </summary>
-        /// <param name="audio">byte array of voice</param>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        public void PlayLipSync(byte[] audio, int sampleRate)
-        {
-            if (animationModules[AnimationModuleType.LipSyncer] == null)
-            {
-                Log.Error(LogTag, $"error : avatarLipSync is null");
-                return;
-            }
-            var lipData = new LipSyncData();
-
-            lipData.AudioFile = new byte[audio.Length];
-            Buffer.BlockCopy(audio, 0, lipData.AudioFile, 0, audio.Length);
-            lipData.SampleRate = sampleRate;
-            animationModules[AnimationModuleType.LipSyncer].Play(lipData);
-        }
-
-        /// <summary>
-        /// Pause lip synchronization
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        public void PauseLipSync()
-        {
-            if (animationModules[AnimationModuleType.LipSyncer] == null)
-            {
-                Log.Error(LogTag, $"error : avatarLipSync is null");
-                return;
-            }
-            animationModules[AnimationModuleType.LipSyncer].Pause();
-        }
-
-        /// <summary>
-        /// Stop lip synchronization
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        public void StopLipSync()
-        {
-            if (animationModules[AnimationModuleType.LipSyncer] == null)
-            {
-                Log.Error(LogTag, $"error : avatarLipSync is null");
-                return;
-            }
-            animationModules[AnimationModuleType.LipSyncer].Stop();
-        }
-
-        internal void DestroyAnimations()
-        {
-            foreach ( var animationModule in animationModules.Values )
-            {
-                animationModule.Destroy();
-            }
-        }
-    }
-}
diff --git a/src/Tizen.AIAvatar/src/public/Avatar/Animations/AnimationModule/EyeBlinker.cs b/src/Tizen.AIAvatar/src/public/Avatar/Animations/AnimationModule/EyeBlinker.cs
deleted file mode 100644 (file)
index c246732..0000000
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * Copyright(c) 2023 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-using System;
-using System.ComponentModel;
-using Tizen.NUI;
-using Tizen.NUI.Scene3D;
-
-using static Tizen.AIAvatar.AIAvatar;
-
-namespace Tizen.AIAvatar
-{
-    [EditorBrowsable(EditorBrowsableState.Never)]
-    internal class EyeBlinker : AnimationModule
-    {
-        private const int blinkIntervalMinimum = 800;
-        private const int blinkIntervalMaximum = 3000;
-        private Animation eyeAnimation;
-
-        private Timer blinkTimer;
-
-        private bool isPlaying = false;
-        private const int blinkDuration = 200;
-
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        internal EyeBlinker()
-        {
-
-        }
-
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        public override void Init(Animation eyeAnimation)
-        {
-            this.eyeAnimation = eyeAnimation;
-        }
-
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        public override void Play(IAnimationModuleData data)
-        {
-            //data
-            StartEyeBlink();
-        }
-
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        public override void Stop()
-        {
-            StopEyeBlink();
-        }
-
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        public override void Pause()
-        {
-            eyeAnimation?.Pause();
-        }
-
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        public override void Destroy()
-        {
-            DestroyAnimation();
-        }
-
-        private void StartEyeBlink()
-        {
-            DestroyBlinkTimer();
-
-            blinkTimer = new Timer(blinkDuration);
-            if (blinkTimer != null)
-            {
-                blinkTimer.Tick += OnBlinkTimer;
-                blinkTimer?.Start();
-                isPlaying = true;
-            }
-        }
-
-        private void PauseEyeBlink()
-        {
-            blinkTimer?.Stop();
-            isPlaying = false;
-        }
-
-        private void StopEyeBlink()
-        {
-            blinkTimer?.Stop();
-            isPlaying = false;
-        }
-
-        private void DestroyAnimation()
-        {
-            DestroyBlinkTimer();
-            if (eyeAnimation != null)
-            {
-                eyeAnimation.Stop();
-                eyeAnimation.Dispose();
-                eyeAnimation = null;
-            }
-            isPlaying = false;
-        }
-
-        private bool OnBlinkTimer(object source, Timer.TickEventArgs e)
-        {
-            if (eyeAnimation == null)
-            {
-                Log.Error(LogTag, "eye animation is not ready");
-                return false;
-            }
-            eyeAnimation?.Play();
-
-            var random = new Random();
-            var fortimerinterval = (uint)random.Next(blinkIntervalMinimum, blinkIntervalMaximum);
-            blinkTimer.Interval = fortimerinterval;
-            return true;
-        }
-
-        private void DestroyBlinkTimer()
-        {
-            if (blinkTimer != null)
-            {
-                blinkTimer.Tick -= OnBlinkTimer;
-                blinkTimer.Stop();
-                blinkTimer.Dispose();
-                blinkTimer = null;
-            }
-        }
-    }
-}
diff --git a/src/Tizen.AIAvatar/src/public/Avatar/Animations/AnimationModule/JointTransformer.cs b/src/Tizen.AIAvatar/src/public/Avatar/Animations/AnimationModule/JointTransformer.cs
deleted file mode 100644 (file)
index 4ff5e96..0000000
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Copyright(c) 2023 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-using System.ComponentModel;
-using Tizen.NUI;
-using Tizen.NUI.Scene3D;
-
-namespace Tizen.AIAvatar
-{
-    [EditorBrowsable(EditorBrowsableState.Never)]
-    internal class JointTransformer
-    {
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        public JointTransformer() 
-        {
-        }
-
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        public void Init(Animation animation)
-        {
-        }
-
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        public void Play(IAnimationModuleData data)
-        {
-        }
-
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        public void Pause()
-        {
-        }
-
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        public void Stop()
-        {
-        }
-
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        public void Destroy()
-        {
-        }
-
-        private void SetJointMotion(AvatarProperties properties, JointType jointType, MotionTransformIndex.TransformTypes type, Rotation rotation)
-        {
-            var motionTransform = new AvatarJointTransformIndex(properties.JointMapper, jointType, type);
-            var motionData = new MotionData();
-            motionData.Add(
-                motionTransform,
-                new MotionValue()
-                {
-                    //TODO : Tizen_7.0에 pitch, yaw, roll patch 추가하기
-                    //PropertyValue = new PropertyValue(new Rotation(new Radian(pitch), new Radian(yaw), new Radian(roll))),
-                }
-            );
-            //avatar.SetMotionData(motionData);
-        }
-
-        private void SetJointMotion(string keyValue, float pitch, float yaw, float roll)
-        {
-            var motionData = new MotionData();
-            motionData.Add(
-                new MotionTransformIndex()
-                {
-                    ModelNodeId = new PropertyKey(keyValue),
-                    TransformType = MotionTransformIndex.TransformTypes.Orientation,
-                },
-                new MotionValue()
-                {
-                    //TODO : Tizen_7.0에 pitch, yaw, roll patch 추가하기
-                    //PropertyValue = new PropertyValue(new Rotation(new Radian(pitch), new Radian(yaw), new Radian(roll))),
-                }
-            );
-            //avatar.SetMotionData(motionData);
-        }
-
-        private void SetJointMotion(string keyValue, MotionTransformIndex.TransformTypes type, Rotation rotation)
-        {
-            var motionData = new MotionData();
-            motionData.Add(
-                new MotionTransformIndex()
-                {
-                    ModelNodeId = new PropertyKey(keyValue),
-                    TransformType = type,
-                },
-                new MotionValue()
-                {
-                    PropertyValue = new PropertyValue(rotation),
-                }
-            );
-            //avatar.SetMotionData(motionData);
-        }
-    }
-}
diff --git a/src/Tizen.AIAvatar/src/public/Avatar/Animations/AnimationModule/LipSyncer.cs b/src/Tizen.AIAvatar/src/public/Avatar/Animations/AnimationModule/LipSyncer.cs
deleted file mode 100644 (file)
index d8b4121..0000000
+++ /dev/null
@@ -1,369 +0,0 @@
-/*
- * Copyright(c) 2023 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-using System;
-using System.Collections.Generic;
-using System.ComponentModel;
-using Tizen.NUI;
-using Tizen.NUI.Scene3D;
-
-using static Tizen.AIAvatar.AIAvatar;
-
-namespace Tizen.AIAvatar
-{
-    [EditorBrowsable(EditorBrowsableState.Never)]
-    internal class LipSyncer : AnimationModule
-    {
-        private Avatar avatar;
-        private Animation lipAnimation = null;
-
-        //private VowelConverter vowelConverter;
-        private AudioPlayer audioPlayer;
-
-        //Mic
-        private Queue<string[]> vowelPools = new Queue<string[]>();
-        private string prevVowel = "sil";
-
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        internal LipSyncer()
-        {
-        }
-
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        internal AudioPlayer AudioPlayer { get { return audioPlayer; } }
-
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        public override void Init(Animation lipAnimation)
-        {
-            this.lipAnimation = lipAnimation;
-            //vowelConverter = new VowelConverter();
-            audioPlayer = new AudioPlayer();
-
-            CurrentMotionState = AvatarMotionState.Ready;
-        }
-
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        public override void Play(IAnimationModuleData data)
-        {
-            if (data is LipSyncData lipSyncData)
-            {
-                if (lipSyncData.AudioFile != null)
-                {
-                    PlayLipSync(lipSyncData.AudioFile, lipSyncData.SampleRate);
-                }
-            }
-        }
-
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        public override void Stop()
-        {
-            StopLipSync();
-        }
-
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        public override void Pause()
-        {
-            PauseLipSync();
-        }
-
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        public override void Destroy()
-        {
-            DestroyLipAnimation();
-        }
-
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        protected Animation CreateAsyncLipAnimation(byte[] buffer, int sampleRate)
-        {
-            EnqueueVowels(buffer, false);
-            return CreateLipAnimationByVowelsQueue(sampleRate);
-        }
-
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        //TODO : lipAnimation 자체를 Animator안에서 생성하고 관리될 수 있게 수정.
-        protected void ResetLipAnimation(Animation lipAnimation)
-        {
-            DestroyLipAnimation();
-            this.lipAnimation = lipAnimation;
-            if (this.lipAnimation != null)
-            {
-                this.lipAnimation.Finished += OnLipAnimationFinished;
-            }
-        }
-
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        protected void PlayLipAnimation()
-        {
-            if (lipAnimation == null)
-            {
-                Log.Error(LogTag, "Current Lip Animation is null");
-            }
-            lipAnimation?.Play();
-        }
-
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        protected void OnLipAnimationFinished(object sender, EventArgs e)
-        {
-            CurrentMotionState = AvatarMotionState.Stopped;
-        }
-
-        private void PlayLipSync(byte[] audio)
-        {
-            if (audio == null)
-            {
-                Tizen.Log.Error(LogTag, "audi data is null");
-                return;
-            }
-
-            DestroyLipAnimation();
-            var lipAnimation = CreateLipAnimation(audio, CurrentAudioOptions.SampleRate);
-            if (lipAnimation != null)
-            {
-                ResetLipAnimation(lipAnimation);
-                PlayLipAnimation();
-            }
-            else
-            {
-
-                Tizen.Log.Error(LogTag, "lipAnimation is null");
-            }
-            audioPlayer.Play(audio);
-            CurrentMotionState = AvatarMotionState.Playing;
-        }
-
-        private void PlayLipSync(byte[] audio, int sampleRate)
-        {
-            DestroyLipAnimation();
-            var lipAnimation = CreateLipAnimation(audio, sampleRate);
-            if (lipAnimation != null)
-            {
-                ResetLipAnimation(lipAnimation);
-                PlayLipAnimation();
-            }
-            audioPlayer.Play(audio, sampleRate);
-            CurrentMotionState = AvatarMotionState.Playing;
-        }
-
-        private void PlayLipSync(string path)
-        {
-            var bytes = Utils.ReadAllBytes(path);
-            if (bytes != null)
-            {
-                PlayLipSync(bytes);
-            }
-            else
-            {
-                Log.Error(LogTag, "Failed to load audio file");
-            }
-        }
-
-        private void PauseLipSync()
-        {
-            PauseLipAnimation();
-            audioPlayer.Pause();
-            CurrentMotionState = AvatarMotionState.Paused;
-        }
-
-        private void StopLipSync()
-        {
-            StopLipAnimation();
-            audioPlayer.Stop();
-            CurrentMotionState = AvatarMotionState.Stopped;
-        }
-
-        private void PauseLipAnimation()
-        {
-            if (lipAnimation != null)
-            {
-                lipAnimation?.Pause();
-            }
-            else
-            {
-                Log.Error(LogTag, "Current Lip Animation is null");
-            }
-        }
-
-        private void StopLipAnimation()
-        {
-            if (lipAnimation != null)
-            {
-                DestroyLipAnimation();
-
-                var lipAnimation = ResetLipAnimation();
-                if (lipAnimation != null)
-                {
-                    ResetLipAnimation(lipAnimation);
-                    PlayLipAnimation();
-                }
-                else
-                {
-                    Log.Error(LogTag, "Current Lip Animation is null");
-                }
-            }
-            else
-            {
-                Log.Error(LogTag, "Current Lip Animation is null");
-            }
-        }
-
-        private void DestroyLipAnimation()
-        {
-            if (lipAnimation != null)
-            {
-                lipAnimation.Stop();
-                lipAnimation.Dispose();
-                lipAnimation = null;
-            }
-        }
-
-        private Animation CreateLipAnimation(byte[] array, int sampleRate)
-        {
-            Animation lipKeyframes = null;// CreateKeyFrame(array, sampleRate);
-            if (lipKeyframes != null)
-            {
-
-                return null;// CreateLipAnimation(lipKeyframes);
-            }
-            return null;
-        }
-
-        private void EnqueueVowels(byte[] buffer, bool deleteLast = false)
-        {
-            var vowels = PredictVowels(buffer);
-            if (vowels != null)
-            {
-                vowelPools.Enqueue(vowels);
-                if (deleteLast)
-                {
-                    var vowelList = new List<string>(vowels);
-                    vowelList.RemoveAt(vowelList.Count - 1);
-                    vowels = vowelList.ToArray();
-                }
-            }
-        }
-
-        private Animation CreateLipAnimationByVowelsQueue(int sampleRate = 0)
-        {
-            if (sampleRate == 0)
-            {
-                sampleRate = CurrentAudioOptions.SampleRate;
-            }
-            if (vowelPools.Count > 0)
-            {
-                AttachPreviousVowel(vowelPools.Dequeue(), out var newVowels);
-                Log.Info(LogTag, $"vowelRecognition: {String.Join(", ", newVowels)}");
-
-                //var lipKeyFrames = vowelConverter?.CreateKeyFrames(newVowels, sampleRate, true);
-                return null;// CreateLipAnimation(lipKeyFrames, true);
-            }
-            return null;
-        }
-
-        private Animation ResetLipAnimation()
-        {
-            vowelPools.Clear();
-            var newVowels = new string[1];
-            newVowels[0] = prevVowel = "sil";
-            vowelPools.Enqueue(newVowels);
-            return CreateLipAnimationByVowelsQueue();
-        }
-
-        private string[] PredictVowels(byte[] audioData)
-        {
-            string[] vowels = null;// vowelConverter?.PredictVowels(audioData);
-            return vowels;
-        }
-
-        private void AttachPreviousVowel(in string[] vowels, out string[] newVowels)
-        {
-            newVowels = new string[vowels.Length + 1];
-            newVowels[0] = prevVowel;
-            Array.Copy(vowels, 0, newVowels, 1, vowels.Length);
-            prevVowel = vowels[vowels.Length - 1];
-        }
-
-        /*
-        private AnimationKeyFrame CreateKeyFrame(byte[] audio, int sampleRate)
-        {
-            var keyFrames = vowelConverter?.CreateKeyFrames(audio, sampleRate);
-            if (keyFrames == null)
-            {
-                Log.Error(LogTag, $"Failed to initialize KeyFrames");
-            }
-
-            return keyFrames;
-        }
-
-        private Animation CreateLipAnimation(AnimationKeyFrame animationKeyFrames, bool isMic = false)
-        {
-            var animationTime = (int)(animationKeyFrames.AnimationTime * 1000f);
-            var lipAnimation = new Animation(animationTime);
-
-            var motionData = new MotionData(animationTime);
-            for (var i = 0; i < animationKeyFrames.NodeNames.Length; i++)
-            {
-                var nodeName = animationKeyFrames.NodeNames[i];
-                for (var j = 0; j < animationKeyFrames.BlendShapeCounts[i]; j++)
-                {
-                    var blendShapeIndex = new BlendShapeIndex(new PropertyKey(nodeName), new PropertyKey(j));
-                    var keyFrameList = animationKeyFrames.GetKeyFrames(nodeName, j);
-                    if (keyFrameList.Count == 0)
-                    {
-                        continue;
-                    }
-
-                    var keyFrames = new KeyFrames();
-                    CreateKeyTimeFrames(ref keyFrames, keyFrameList, isMic);
-
-                    motionData.Add(blendShapeIndex, new MotionValue(keyFrames));
-                    lipAnimation = avatar.GenerateMotionDataAnimation(motionData);
-                }
-            }
-            return lipAnimation;
-        }
-        private KeyFrames CreateKeyTimeFrames(ref KeyFrames keyFrames, List<KeyFrame> keyFrameList, bool isMic = false)
-        {
-            foreach (var key in keyFrameList)
-            {
-                keyFrames.Add(key.time, key.value);
-            }
-            if (!isMic) keyFrames.Add(1.0f, 0.0f);
-
-            return keyFrames;
-        }
-        */
-
-        internal void OnRecordBufferChanged(byte[] recordBuffer, int sampleRate)
-        {
-            EnqueueVowels(recordBuffer);
-        }
-
-        internal void OnRecodingTick()
-        {
-            var lipAnimation = CreateLipAnimationByVowelsQueue();
-            if (lipAnimation != null)
-            {
-                ResetLipAnimation(lipAnimation);
-                PlayLipAnimation();
-            }
-            else
-            {
-                Log.Error(LogTag, "Current Lip Animation is null");
-            }
-        }
-    }
-}
diff --git a/src/Tizen.AIAvatar/src/public/Avatar/Animations/AnimationModule/MotionPlayer.cs b/src/Tizen.AIAvatar/src/public/Avatar/Animations/AnimationModule/MotionPlayer.cs
deleted file mode 100644 (file)
index ce101c4..0000000
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright(c) 2024 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-using System.ComponentModel;
-using Tizen.NUI;
-using Tizen.NUI.Scene3D;
-
-using static Tizen.AIAvatar.AIAvatar;
-
-namespace Tizen.AIAvatar
-{
-    internal class MotionPlayer
-    {
-        private Animation motionAnimation;
-        internal Animation MotionAnimation { get => motionAnimation; private set => motionAnimation = value; }
-
-        internal MotionPlayer()
-        {
-
-        }
-
-        /// <summary>
-        /// Play avatar animation by AnimationInfo
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        internal void PlayAnimation(Animation motionAnimation, int duration = 3000, bool isLooping = false, int loopCount = 1)
-        {
-            ResetAnimations();
-            if (motionAnimation != null)
-            {
-                MotionAnimation = motionAnimation;
-                MotionAnimation?.Play();
-            }
-            else
-            {
-                Tizen.Log.Error(LogTag, "motionAnimation is null");
-            }
-        }
-
-        /// <summary>
-        /// Pause avatar animation
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        internal void PauseMotionAnimation()
-        {
-            MotionAnimation?.Pause();
-        }
-
-        /// <summary>
-        /// Stop avatar animation
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        internal void StopMotionAnimation()
-        {
-            MotionAnimation?.Stop();
-        }
-
-        private void ResetAnimations()
-        {
-            if (MotionAnimation != null)
-            {
-                MotionAnimation.Stop();
-                MotionAnimation.Dispose();
-                MotionAnimation = null;
-            }
-        }
-    }
-}
diff --git a/src/Tizen.AIAvatar/src/public/Avatar/Animations/AnimationModuleData/IAnimationModuleData.cs b/src/Tizen.AIAvatar/src/public/Avatar/Animations/AnimationModuleData/IAnimationModuleData.cs
deleted file mode 100644 (file)
index 9b6110d..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright(c) 2024 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-using System.ComponentModel;
-
-namespace Tizen.AIAvatar
-{
-    [EditorBrowsable(EditorBrowsableState.Never)]
-    public interface IAnimationModuleData
-    {
-    }
-
-    [EditorBrowsable(EditorBrowsableState.Never)]
-    public enum MotionDataType
-    {
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        AnimationInfo,
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        MotionData
-    }
-}
diff --git a/src/Tizen.AIAvatar/src/public/Avatar/Animations/AnimationModuleData/LipSyncData.cs b/src/Tizen.AIAvatar/src/public/Avatar/Animations/AnimationModuleData/LipSyncData.cs
deleted file mode 100644 (file)
index 88b57cf..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright(c) 2024 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-using System;
-using System.Collections.Generic;
-using System.ComponentModel;
-using System.Text;
-using Tizen.AIAvatar;
-
-namespace Tizen.AIAvatar
-{
-    [EditorBrowsable(EditorBrowsableState.Never)]
-    public class LipSyncData : IAnimationModuleData
-    {
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        public byte[] AudioFile { get; set; }
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        public int SampleRate { get; set; }
-    }
-}
diff --git a/src/Tizen.AIAvatar/src/public/Avatar/Animations/AnimationModuleData/MotionBehaviorData.cs b/src/Tizen.AIAvatar/src/public/Avatar/Animations/AnimationModuleData/MotionBehaviorData.cs
deleted file mode 100644 (file)
index a4bd49f..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright(c) 2024 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-using System.ComponentModel;
-using Tizen.NUI.Scene3D;
-
-namespace Tizen.AIAvatar
-{
-    [EditorBrowsable(EditorBrowsableState.Never)]
-    public class MotionBehaviorData : IAnimationModuleData
-    {
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        public MotionDataType Type { get; set; } = MotionDataType.AnimationInfo;
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        public AnimationInfo AnimationInfo { get; set; }
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        public MotionData MotionData { get; set; }
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        public int Duration { get; set; } = 3000;
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        public bool IsLooping { get; set; } = false;
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        public int LoopCount { get; set; } = 1;
-    }
-}
diff --git a/src/Tizen.AIAvatar/src/public/Avatar/Animations/AvatarMotionChangedEventArgs.cs b/src/Tizen.AIAvatar/src/public/Avatar/Animations/AvatarMotionChangedEventArgs.cs
deleted file mode 100644 (file)
index 77c497a..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright(c) 2023 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-using System;
-using System.ComponentModel;
-
-namespace Tizen.AIAvatar
-{
-    /// <summary>
-    /// 
-    /// </summary>
-    [EditorBrowsable(EditorBrowsableState.Never)]
-    public class AvatarMotionChangedEventArgs : EventArgs
-    {
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        public AvatarMotionChangedEventArgs(AvatarMotionState previous, AvatarMotionState current)
-        {
-            Previous = previous;
-            Current = current;
-        }
-
-        /// <summary>
-        /// The previous state.
-        /// </summary>
-        /// <since_tizen> 3 </since_tizen>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        public AvatarMotionState Previous
-        {
-            get;
-            internal set;
-        }
-
-        /// <summary>
-        /// The current state.
-        /// </summary>
-        /// <since_tizen> 3 </since_tizen>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        public AvatarMotionState Current
-        {
-            get;
-            internal set;
-        }
-    }
-}
diff --git a/src/Tizen.AIAvatar/src/public/Avatar/Animations/AvatarMotionState.cs b/src/Tizen.AIAvatar/src/public/Avatar/Animations/AvatarMotionState.cs
deleted file mode 100644 (file)
index 4ad5692..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright(c) 2023 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-using System.ComponentModel;
-
-namespace Tizen.AIAvatar
-{
-    /// <summary>
-    /// Enumeration for the states.
-    /// </summary>
-    /// <since_tizen> 3 </since_tizen>
-    [EditorBrowsable(EditorBrowsableState.Never)]
-    public enum AvatarMotionState
-    {
-        /// <summary>
-        ///  Created state.
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        Failed = -1,
-
-        /// <summary>
-        /// Ready state.
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        Ready = 0,
-
-        /// <summary>
-        /// Playing state.
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        Playing = 3,
-
-        /// <summary>
-        /// Paused state.
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        Paused = 4,
-
-        /// <summary>
-        /// Stopped state.
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        Stopped = 5,
-
-        /// <summary>
-        /// Unavailable state.
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        Unavailable
-    };
-}
diff --git a/src/Tizen.AIAvatar/src/public/Avatar/AudioOptions.cs b/src/Tizen.AIAvatar/src/public/Avatar/AudioOptions.cs
deleted file mode 100644 (file)
index f7587a6..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright(c) 2023 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-using System.ComponentModel;
-using Tizen.Multimedia;
-
-namespace Tizen.AIAvatar
-{
-    /// <summary>
-    /// Provides the ability to audio 
-    /// </summary>
-    // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
-    [EditorBrowsable(EditorBrowsableState.Never)]
-    public class AudioOptions
-    {
-        private int sampleRate;
-        private AudioChannel channel;
-        private AudioSampleType sampleType;
-
-        /// <summary>
-        /// Initializes a new instance of the AudioOptions class with the specified sample rate, channel, and sampleType.
-        /// </summary>
-        /// <param name="sampleRate">the audio sample rate (8000 ~ 192000Hz)</param>
-        /// <param name="channel">the audio channel type.</param>
-        /// <param name="sampleType">the audio sample type.</param>
-        // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        public AudioOptions(int sampleRate, AudioChannel channel, AudioSampleType sampleType)
-        {
-            this.sampleRate = sampleRate;
-            this.channel = channel;
-            this.sampleType = sampleType;
-        }
-
-        /// <summary>
-        /// The audio sample rate (8000 ~ 192000Hz)
-        /// </summary>
-        // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        public int SampleRate { get => sampleRate; set => sampleRate = value; }
-
-        /// <summary>
-        /// The audio channel type
-        /// </summary>
-        // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        public AudioChannel Channel { get => channel; set => channel = value; }
-
-        /// <summary>
-        /// The audio sample type
-        /// </summary>
-        // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        public AudioSampleType SampleType { get => sampleType; set => sampleType = value; }
-    }
-}
diff --git a/src/Tizen.AIAvatar/src/public/Avatar/Avatar.cs b/src/Tizen.AIAvatar/src/public/Avatar/Avatar.cs
deleted file mode 100644 (file)
index f1ffab8..0000000
+++ /dev/null
@@ -1,227 +0,0 @@
-/*
- * Copyright(c) 2023 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-using System.ComponentModel;
-using Tizen.NUI.Scene3D;
-using Tizen.NUI;
-
-using static Tizen.AIAvatar.AIAvatar;
-
-namespace Tizen.AIAvatar
-{
-    /// <summary>
-    /// Avatar is a Class to show 3D avatar objects.
-    /// It is subclass of Model s.t. we can control Avatar like models animation easly.
-    /// For example, 
-    /// 
-    /// Avatar supports AR Emoji.
-    /// </summary>
-    [EditorBrowsable(EditorBrowsableState.Never)]
-    public class Avatar : Model
-    {
-        private AvatarProperties avatarProperties = new DefaultAvatarProperties();
-        private AvatarMotions avatarMotions;
-
-        private BlendShapePlayer avatarAnimator;
-        private MotionPlayer motionPlayer;
-        private JointTransformer jointTransformer;
-
-        /// <summary>
-        /// Create an initialized AvatarModel.
-        /// </summary>
-        // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        public Avatar() : base()
-        {
-            InitAvatar();
-        }
-
-        /// <summary>
-        /// Create an initialized AREmojiDefaultAvatar.
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        public Avatar(AvatarInfo avatarInfo) : base(avatarInfo.ResourcePath)
-        {
-            InitAvatar();
-        }
-
-        /// <summary>
-        /// Create an initialized Avatar.
-        /// </summary>
-        /// <param name="avatarlUrl">avatar file url.(e.g. glTF, and DLI).</param>
-        /// <param name="resourceDirectoryUrl"> The url to derectory containing resources: binary, image etc.</param>
-        /// <remarks>
-        /// If resourceDirectoryUrl is empty, the parent directory url of avatarUrl is used for resource url.
-        ///
-        /// http://tizen.org/privilege/mediastorage for local files in media storage.
-        /// http://tizen.org/privilege/externalstorage for local files in external storage.
-        /// </remarks>
-        // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        public Avatar(string avatarUrl, string resourceDirectoryUrl = "") : base(avatarUrl, resourceDirectoryUrl)
-        {
-            InitAvatar();
-        }
-
-        /// <summary>
-        /// Copy constructor.
-        /// </summary>
-        /// <param name="avatar">Source object to copy.</param>
-        // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        public Avatar(Avatar avatar) : base(avatar)
-        {
-            InitAvatar();
-        }
-
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        public AvatarProperties AvatarProperties
-        {
-            get => avatarProperties;
-            set => avatarProperties = value;
-        }
-
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        internal BlendShapePlayer AvatarAnimator
-        {
-            get => avatarAnimator; 
-            set => avatarAnimator = value;
-        }
-
-
-        /// <summary>
-        /// Play avatar animation by AnimationInfo
-        /// </summary>
-        /// <param name="index">index of default avatar animations</param>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        private void PlayAnimation(AnimationInfo animationInfo, int duration = 3000, bool isLooping = false, int loopCount = 1)
-        {
-            if (animationInfo == null)
-            {
-                Tizen.Log.Error(LogTag, "animationInfo is null");
-                return;
-            }
-            if (animationInfo.MotionData == null)
-            {
-                Tizen.Log.Error(LogTag, "animationInfo.MotionData is null");
-                return;
-            }
-            var motionAnimation = GenerateMotionDataAnimation(animationInfo.MotionData);
-            if (motionAnimation != null)
-            {
-                motionAnimation.Duration = duration;
-                motionAnimation.Looping = isLooping;
-                motionAnimation.LoopCount = loopCount;
-                motionAnimation.BlendPoint = 0.2f;
-                motionPlayer.PlayAnimation(motionAnimation);
-            }
-            else
-            {
-                Tizen.Log.Error(LogTag, "motionAnimation is null");
-            }
-        }
-
-        /// <summary>
-        /// Play avatar animation by MotionData
-        /// </summary>
-        /// <param name="index">index of default avatar animations</param>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        private void PlayAnimation(MotionData motionData, int duration = 3000, bool isLooping = false, int loopCount = 1)
-        {
-
-            if (motionData == null)
-            {
-                Tizen.Log.Error(LogTag, "motionData is null");
-                return;
-            }
-            var motionAnimation = GenerateMotionDataAnimation(motionData);
-            if (motionAnimation != null)
-            {
-                motionAnimation.Duration = duration;
-                motionAnimation.Looping = isLooping;
-                motionAnimation.LoopCount = loopCount;
-                motionAnimation.BlendPoint = 0.2f;
-                motionPlayer.PlayAnimation(motionAnimation);
-            }
-            else
-            {
-                Tizen.Log.Error(LogTag, "motionAnimation is null");
-            }
-        }
-
-        private void PlayAnimation(int index, int duration = 3000, bool isLooping = false, int loopCount = 1)
-        {
-            //TODO by index
-            //var motionAnimation = GenerateMotionDataAnimation(animationInfoList[index].MotionData);
-            /*motionAnimation.Duration = duration;
-            motionAnimation.Looping = isLooping;
-            motionAnimation.LoopCount = loopCount;
-            motionAnimation.BlendPoint = 0.2f;
-
-            motionPlayer.PlayAnimation(motionAnimation);*/
-        }
-
-        /// <summary>
-        /// Pause avatar animation
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        private void PauseMotionAnimation()
-        {
-            motionPlayer.PauseMotionAnimation();
-        }
-
-        /// <summary>
-        /// Stop avatar animation
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        private void StopMotionAnimation()
-        {
-            motionPlayer?.StopMotionAnimation();
-        }
-
-
-        private void InitAvatar()
-        {
-            avatarMotions = new AvatarMotions(avatarProperties);
-
-            AvatarAnimator = new BlendShapePlayer();
-
-            avatarProperties.AvatarPropertiesChanged += (s, e) =>
-            {
-                var eyeAnimation = CreateMotionAnimation(avatarMotions.EyeMotionData);
-                if (eyeAnimation != null)
-                {
-                    avatarAnimator.SetBlinkAnimation(eyeAnimation);
-                }
-            };
-
-            ResourcesLoaded += (s, e) =>
-            {
-                var eyeAnimation = CreateMotionAnimation(avatarMotions.EyeMotionData);
-                if (eyeAnimation != null)
-                {
-                    avatarAnimator.SetBlinkAnimation(eyeAnimation);
-                }
-            };
-        }
-
-        private Animation CreateMotionAnimation(MotionData data)
-        {
-            return GenerateMotionDataAnimation(data);
-        }
-    }
-}
diff --git a/src/Tizen.AIAvatar/src/public/Avatar/Common/BlendShapeType.cs b/src/Tizen.AIAvatar/src/public/Avatar/Common/BlendShapeType.cs
deleted file mode 100644 (file)
index 3b55de0..0000000
+++ /dev/null
@@ -1,380 +0,0 @@
-/*
- * Copyright(c) 2023 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-using System.ComponentModel;
-
-namespace Tizen.AIAvatar
-{
-    /// <summary>
-    /// The type of predefined blendshape. We can customize each type name by "TODO_mapper"
-    /// TODO : Explain me
-    /// TODO : Need to check each joint exist in AR Emoji
-    /// Note : This is temperal name of joints.
-    /// </summary>
-    [EditorBrowsable(EditorBrowsableState.Never)]
-    internal enum BlendShapeType
-    {
-        #region Left Eyes
-        /// <summary>
-        /// EyeBlinkLeft blendshape
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        EyeBlinkLeft = 0,
-
-        /// <summary>
-        /// EyeSquintLeft blendshape
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        EyeSquintLeft,
-
-        /// <summary>
-        /// EyeDownLeft blendshape
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        EyeDownLeft,
-
-        /// <summary>
-        /// EyeInLeft blendshape
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        EyeInLeft,
-
-        /// <summary>
-        /// EyeOpenLeft blendshape
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        EyeOpenLeft,
-
-        /// <summary>
-        /// EyeOutLeft blendshape
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        EyeOutLeft,
-
-        /// <summary>
-        /// EyeUpLeft blendshape
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        EyeUpLeft,
-        #endregion
-
-        #region Right Eyes
-        /// <summary>
-        /// EyeBlinkRight blendshape
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        EyeBlinkRight,
-
-        /// <summary>
-        /// EyeSquintRight blendshape
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        EyeSquintRight,
-
-        /// <summary>
-        /// EyeDownRight blendshape
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        EyeDownRight,
-
-        /// <summary>
-        /// EyeInRight blendshape
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        EyeInRight,
-
-        /// <summary>
-        /// EyeOpenRight blendshape
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        EyeOpenRight,
-
-        /// <summary>
-        /// EyeOutRight blendshape
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        EyeOutRight,
-
-        /// <summary>
-        /// EyeUpRight blendshape
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        EyeUpRight,
-        #endregion
-
-        #region Mouth and Jaw
-        /// <summary>
-        /// JawForward blendshape
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        JawForward,
-
-        /// <summary>
-        /// JawOpen blendshape
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        JawOpen,
-
-        /// <summary>
-        /// JawChew blendshape
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        JawChew,
-
-        /// <summary>
-        /// JawLeft blendshape
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        JawLeft,
-
-        /// <summary>
-        /// JawRight blendshape
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        JawRight,
-
-        /// <summary>
-        /// MouthLeft blendshape
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        MouthLeft,
-
-        /// <summary>
-        /// MouthFrownLeft blendshape
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        MouthFrownLeft,
-
-        /// <summary>
-        /// MouthSmileLeft blendshape
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        MouthSmileLeft,
-
-        /// <summary>
-        /// MouthDimpleLeft blendshape
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        MouthDimpleLeft,
-
-        /// <summary>
-        /// MouthRight blendshape
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        MouthRight,
-
-        /// <summary>
-        /// MouthFrownRight blendshape
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        MouthFrownRight,
-
-        /// <summary>
-        /// MouthSmileRight blendshape
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        MouthSmileRight,
-
-        /// <summary>
-        /// MouthDimpleRight blendshape
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        MouthDimpleRight,
-        #endregion
-
-        #region Lips
-        /// <summary>
-        /// LipsStretchLeft blendshape
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        LipsStretchLeft,
-
-        /// <summary>
-        /// LipsStretchRight blendshape
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        LipsStretchRight,
-
-        /// <summary>
-        /// LipsUpperClose blendshape
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        LipsUpperClose,
-
-        /// <summary>
-        /// LipsLowerClose blendshape
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        LipsLowerClose,
-
-        /// <summary>
-        /// LipsUpperUp blendshape
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        LipsUpperUp,
-
-        /// <summary>
-        /// LipsLowerDown blendshape
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        LipsLowerDown,
-
-        /// <summary>
-        /// LipsUpperOpen blendshape
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        LipsUpperOpen,
-
-        /// <summary>
-        /// LipsLowerOpen blendshape
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        LipsLowerOpen,
-
-        /// <summary>
-        /// LipsFunnel blendshape
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        LipsFunnel,
-
-        /// <summary>
-        /// LipsPucker blendshape
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        LipsPucker,
-        #endregion
-
-        #region Eyebrows, Cheeks, and Chin
-        /// <summary>
-        /// BrowDownLeft blendshape
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        BrowDownLeft,
-
-        /// <summary>
-        /// BrowDownRight blendshape
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        BrowDownRight,
-
-        /// <summary>
-        /// BrowUpCenter blendshape
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        BrowUpCenter,
-
-        /// <summary>
-        /// BrowUpLeft blendshape
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        BrowUpLeft,
-
-        /// <summary>
-        /// BrowUpRight blendshape
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        BrowUpRight,
-
-        /// <summary>
-        /// CheekSquintLeft blendshape
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        CheekSquintLeft,
-
-        /// <summary>
-        /// CheekSquintRight blendshape
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        CheekSquintRight,
-
-        /// <summary>
-        /// ChinLowerRaise blendshape
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        ChinLowerRaise,
-
-        /// <summary>
-        /// ChinUpperRaise blendshape
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        ChinUpperRaise,
-        #endregion
-
-        #region Tongue
-        /// <summary>
-        /// TongueOut blendshape
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        TongueOut,
-
-        /// <summary>
-        /// TongueUp blendshape
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        TongueUp,
-
-        /// <summary>
-        /// TongueDown blendshape
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        TongueDown,
-
-        /// <summary>
-        /// TongueLeft blendshape
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        TongueLeft,
-
-        /// <summary>
-        /// TongueRight blendshape
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        TongueRight,
-        #endregion
-
-        #region ETC
-        /// <summary>
-        /// Sneer blendshape
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        Sneer,
-
-        /// <summary>
-        /// Puff blendshape
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        Puff,
-
-        /// <summary>
-        /// PuffLeft blendshape
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        PuffLeft,
-
-        /// <summary>
-        /// PuffRight blendshape
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        PuffRight,
-        #endregion
-        /// <summary>
-        /// Max value of default blendshape. It will be used when we determine the motion index is default or custom.
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        DefaultBlendShapeMax,
-    }
-}
diff --git a/src/Tizen.AIAvatar/src/public/Avatar/Common/JointType.cs b/src/Tizen.AIAvatar/src/public/Avatar/Common/JointType.cs
deleted file mode 100644 (file)
index d8a87f4..0000000
+++ /dev/null
@@ -1,400 +0,0 @@
-/*
- * Copyright(c) 2023 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-using System.ComponentModel;
-
-namespace Tizen.AIAvatar
-{
-    /// <summary>
-    /// The type of predefined skeletal joint. We can customize each type name by "TODO_mapper"
-    /// TODO : Explain me
-    /// TODO : Need to check each joint exist in AR Emoji
-    /// Note : This is temperal name of joints.
-    /// </summary>
-    [EditorBrowsable(EditorBrowsableState.Never)]
-    internal enum JointType
-    {
-        #region Head
-        /// <summary>
-        /// Head joint
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        Head = 0,
-
-        /// <summary>
-        /// Neck joint
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        Neck,
-
-        /// <summary>
-        /// EyeLeft joint
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        EyeLeft,
-
-        /// <summary>
-        /// EyeRight joint
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        EyeRight,
-        #endregion
-
-        #region Left Upper Body
-        /// <summary>
-        /// ShoulderLeft joint
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        ShoulderLeft,
-
-        /// <summary>
-        /// ElbowLeft joint
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        ElbowLeft,
-
-        /// <summary>
-        /// WristLeft joint
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        WristLeft,
-        #endregion
-
-        #region Right Upper Body
-        /// <summary>
-        /// ShoulderRight joint
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        ShoulderRight,
-
-        /// <summary>
-        /// ElbowRight joint
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        ElbowRight,
-
-        /// <summary>
-        /// WristRight joint
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        WristRight,
-        #endregion
-
-        #region Left Lower Body
-        /// <summary>
-        /// HipLeft joint
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        HipLeft,
-
-        /// <summary>
-        /// KneeLeft joint
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        KneeLeft,
-
-        /// <summary>
-        /// AnkleLeft joint
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        AnkleLeft,
-
-        /// <summary>
-        /// ForeFootLeft joint
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        ForeFootLeft,
-        #endregion
-
-        #region Right Lower Body
-        /// <summary>
-        /// HipRight joint
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        HipRight,
-
-        /// <summary>
-        /// KneeRight joint
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        KneeRight,
-
-        /// <summary>
-        /// AnkleRight joint
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        AnkleRight,
-
-        /// <summary>
-        /// ForeFootRight joint
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        ForeFootRight,
-        #endregion
-
-        #region Left Hand Finger
-        /// <summary>
-        /// FingerThumb1Left joint
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        FingerThumb1Left,
-
-        /// <summary>
-        /// FingerThumb2Left joint
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        FingerThumb2Left,
-
-        /// <summary>
-        /// FingerThumb3Left joint
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        FingerThumb3Left,
-
-        /// <summary>
-        /// FingerThumb4Left joint
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        FingerThumb4Left,
-
-        /// <summary>
-        /// FingerIndex1Left joint
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        FingerIndex1Left,
-
-        /// <summary>
-        /// FingerIndex2Left joint
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        FingerIndex2Left,
-
-        /// <summary>
-        /// FingerIndex3Left joint
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        FingerIndex3Left,
-
-        /// <summary>
-        /// FingerIndex4Left joint
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        FingerIndex4Left,
-
-        /// <summary>
-        /// FingerMiddle1Left joint
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        FingerMiddle1Left,
-
-        /// <summary>
-        /// FingerMiddle2Left joint
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        FingerMiddle2Left,
-
-        /// <summary>
-        /// FingerMiddle3Left joint
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        FingerMiddle3Left,
-
-        /// <summary>
-        /// FingerMiddle4Left joint
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        FingerMiddle4Left,
-
-        /// <summary>
-        /// FingerRing1Left joint
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        FingerRing1Left,
-
-        /// <summary>
-        /// FingerRing2Left joint
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        FingerRing2Left,
-
-        /// <summary>
-        /// FingerRing3Left joint
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        FingerRing3Left,
-
-        /// <summary>
-        /// FingerRing4Left joint
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        FingerRing4Left,
-
-        /// <summary>
-        /// FingerPinky1Left joint
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        FingerPinky1Left,
-
-        /// <summary>
-        /// FingerPinky2Left joint
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        FingerPinky2Left,
-
-        /// <summary>
-        /// FingerPinky3Left joint
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        FingerPinky3Left,
-
-        /// <summary>
-        /// FingerPinky4Left joint
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        FingerPinky4Left,
-        #endregion
-
-        #region Right Hand Finger
-        /// <summary>
-        /// FingerThumb1Right joint
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        FingerThumb1Right,
-
-        /// <summary>
-        /// FingerThumb2Right joint
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        FingerThumb2Right,
-
-        /// <summary>
-        /// FingerThumb3Right joint
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        FingerThumb3Right,
-
-        /// <summary>
-        /// FingerThumb4Right joint
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        FingerThumb4Right,
-
-        /// <summary>
-        /// FingerIndex1Right joint
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        FingerIndex1Right,
-
-        /// <summary>
-        /// FingerIndex2Right joint
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        FingerIndex2Right,
-
-        /// <summary>
-        /// FingerIndex3Right joint
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        FingerIndex3Right,
-
-        /// <summary>
-        /// FingerIndex4Right joint
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        FingerIndex4Right,
-
-        /// <summary>
-        /// FingerMiddle1Right joint
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        FingerMiddle1Right,
-
-        /// <summary>
-        /// FingerMiddle2Right joint
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        FingerMiddle2Right,
-
-        /// <summary>
-        /// FingerMiddle3Right joint
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        FingerMiddle3Right,
-
-        /// <summary>
-        /// FingerMiddle4Right joint
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        FingerMiddle4Right,
-
-        /// <summary>
-        /// FingerRing1Right joint
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        FingerRing1Right,
-
-        /// <summary>
-        /// FingerRing2Right joint
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        FingerRing2Right,
-
-        /// <summary>
-        /// FingerRing3Right joint
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        FingerRing3Right,
-
-        /// <summary>
-        /// FingerRing4Right joint
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        FingerRing4Right,
-
-        /// <summary>
-        /// FingerPinky1Right joint
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        FingerPinky1Right,
-
-        /// <summary>
-        /// FingerPinky2Right joint
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        FingerPinky2Right,
-
-        /// <summary>
-        /// FingerPinky3Right joint
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        FingerPinky3Right,
-
-        /// <summary>
-        /// FingerPinky4Right joint
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        FingerPinky4Right,
-        #endregion
-
-        /// <summary>
-        /// Max value of default joint. It will be used when we determine the motion index is default or custom.
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        DefaultJointMax,
-    }
-
-}
diff --git a/src/Tizen.AIAvatar/src/public/Avatar/Common/NodeType.cs b/src/Tizen.AIAvatar/src/public/Avatar/Common/NodeType.cs
deleted file mode 100644 (file)
index e23c076..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright(c) 2023 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-using System.ComponentModel;
-
-namespace Tizen.AIAvatar
-{
-    [EditorBrowsable(EditorBrowsableState.Never)]
-    internal enum NodeType
-    {
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        HeadGeo,
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        MouthGeo,
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        EyelashGeo
-    }
-}
diff --git a/src/Tizen.AIAvatar/src/public/Avatar/Controller/AvatarLLM.cs b/src/Tizen.AIAvatar/src/public/Avatar/Controller/AvatarLLM.cs
deleted file mode 100644 (file)
index 5bfed20..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright(c) 2024 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-using Newtonsoft.Json;
-using System.Net.Http;
-using System;
-using System.Threading.Tasks;
-using Tizen.Uix.Tts;
-using System.ComponentModel;
-
-namespace Tizen.AIAvatar
-{
-    [EditorBrowsable(EditorBrowsableState.Never)]
-    internal class AvatarLLM
-    {
-        private AvatarTTS avatarTTS;
-        private IRestClient restClient;
-        private const string playgroundURL = "https://playground-api.sec.samsung.net";
-
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        internal AvatarLLM()
-        {
-        }
-
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        internal void InitAvatarLLM(AvatarTTS avatarTTS)
-        {
-            this.avatarTTS = avatarTTS;
-            // Setup RestClinet
-            var restClientFactory = new RestClientFactory();
-            restClient = restClientFactory.CreateClient(playgroundURL);
-        }
-
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        internal async Task StartTTSWithLLMAsync(string text, string token)
-        {
-            var bearerToken = token;
-            var jsonData = "{\"messages\": [{\"role\": \"user\", \"content\": \"" + text + "\"}]}";
-
-            try
-            {
-                var postResponse = await restClient.SendRequestAsync(HttpMethod.Post, "/api/v1/chat/completions", bearerToken, jsonData);
-                var responseData = JsonConvert.DeserializeObject<dynamic>(postResponse);
-                string content = responseData["response"]["content"];
-                Log.Info("Tizen.AIAvatar", content);
-
-                //TTS 호출
-                var voiceInfo = new VoiceInfo()
-                {
-                    Lang = "en_US",
-                    Type = Voice.Female,
-                };
-
-                avatarTTS.PlayTTSAsync(content, voiceInfo, (o, e) => {
-                    
-                });
-
-            }
-            catch (Exception ex)
-            {
-                Log.Error("Tizen.AIAvatar", "에러 발생: " + ex.Message);
-            }
-        }
-    }
-}
diff --git a/src/Tizen.AIAvatar/src/public/Avatar/Controller/AvatarMic.cs b/src/Tizen.AIAvatar/src/public/Avatar/Controller/AvatarMic.cs
deleted file mode 100644 (file)
index 8c8e8ba..0000000
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright(c) 2023 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-using System.ComponentModel;
-
-using static Tizen.AIAvatar.AIAvatar;
-
-namespace Tizen.AIAvatar
-{
-    [EditorBrowsable(EditorBrowsableState.Never)]
-    internal class AvatarMic
-    {
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        internal AvatarMic()
-        {
-        }
-
-        /// <summary>
-        /// Initialize Microphone for using live lip sync
-        /// </summary>
-        /// <privilege>http://tizen.org/privilege/recorder</privilege>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        internal bool InitAvatarMic(Avatar avatar)
-        {
-            if (AudioRecorder.Instance == null)
-            {
-                Log.Error(LogTag, $"Failed to initialize AudioRecorder");
-                return false;
-            }
-            AudioRecorder.Instance?.InitMic(avatar?.AvatarAnimator);
-
-            return true;
-        }
-
-        /// <summary>
-        /// Deinitialize Microphone
-        /// </summary>
-        /// <privilege>http://tizen.org/privilege/recorder</privilege>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        internal bool DeinitAvatarMIC()
-        {
-            AudioRecorder.Instance?.DeinitMic();
-
-            return true;
-        }
-
-        /// <summary>
-        /// Start synchronization avatar lip based on the microphone's voice
-        /// </summary>
-        /// <privilege>http://tizen.org/privilege/recorder</privilege>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        internal void StartMic()
-        {
-            AudioRecorder.Instance?.StartRecording();
-        }
-
-        /// <summary>
-        /// Stop microphone
-        /// </summary>
-        /// <privilege>http://tizen.org/privilege/recorder</privilege>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        internal void StopMic()
-        {
-            AudioRecorder.Instance?.StopRecording();
-        }
-    }
-}
diff --git a/src/Tizen.AIAvatar/src/public/Avatar/Controller/AvatarTTS.cs b/src/Tizen.AIAvatar/src/public/Avatar/Controller/AvatarTTS.cs
deleted file mode 100644 (file)
index 6c5954d..0000000
+++ /dev/null
@@ -1,421 +0,0 @@
-/*
- * Copyright(c) 2023 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-using System.Collections.Generic;
-using System.ComponentModel;
-using System;
-using Tizen.Uix.Tts;
-
-using static Tizen.AIAvatar.AIAvatar;
-
-namespace Tizen.AIAvatar
-{
-    [EditorBrowsable(EditorBrowsableState.Never)]
-    internal class AvatarTTS
-    {
-        private TTSLipSyncer ttsLipSyncer;
-
-        private event EventHandler ttsReadyFinished;
-        private readonly Object ttsReadyFinishedLock = new Object();
-
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        internal AvatarTTS()
-        {
-        }
-
-        /// <summary>
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        internal event EventHandler TTSReadyFinished
-        {
-            add
-            {
-                lock (ttsReadyFinishedLock)
-                {
-                    ttsReadyFinished += value;
-                }
-
-            }
-
-            remove
-            {
-                lock (ttsReadyFinishedLock)
-                {
-                    if (ttsReadyFinished == null)
-                    {
-                        Log.Error(LogTag, "ttsReadyFinished is null");
-                        return;
-                    }
-                    ttsReadyFinished -= value;
-                }
-            }
-        }
-
-        /// <summary>
-        /// <param name=""></param>
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        internal TtsClient CurrentTTSClient => ttsLipSyncer?.TtsHandle;
-
-        /// <summary>
-        /// <param name=""></param>
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        internal void InitTTS(Avatar avatar)
-        {
-            if (ttsLipSyncer == null)
-            {
-                try
-                {
-                    ttsLipSyncer = new TTSLipSyncer(avatar?.AvatarAnimator?.LipSyncer);
-                }
-                catch (Exception e)
-                {
-                    Log.Error(LogTag, $"error :{e.Message}");
-                    Log.Error(LogTag, $"{e.StackTrace}");
-                }
-            }
-        }
-
-        /// <summary>
-        /// <param name=""></param>
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        internal void DeinitTTS()
-        {
-            if (ttsLipSyncer != null)
-            {
-                try
-                {
-                    ttsLipSyncer.DeinitTts();
-                    ttsLipSyncer = null;
-                }
-                catch (Exception e)
-                {
-                    Log.Error(LogTag, $"error :{e.Message}");
-                    Log.Error(LogTag, $"{e.StackTrace}");
-                }
-            }
-        }
-
-        /// <summary>
-        /// <param name=""></param>
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        internal List<VoiceInfo> GetSupportedVoices()
-        {
-            return ttsLipSyncer.GetSupportedVoices();
-        }
-
-        /// <summary>
-        /// <param name=""></param>
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        internal bool PrepareTTS(string text, VoiceInfo voiceInfo, EventHandler ttsReadyFinishedCallback = null)
-        {
-            if (ttsLipSyncer == null || ttsLipSyncer.TtsHandle == null)
-            {
-                Log.Error(LogTag, "tts is null");
-                return false;
-            }
-
-
-            if (!ttsLipSyncer.IsSupportedVoice(voiceInfo))
-            {
-                Log.Info(LogTag, $"{voiceInfo.Lang} & {voiceInfo.Type} is not supported");
-                return false;
-            }
-
-            Log.Info(LogTag, "Current TTS State :" + ttsLipSyncer.TtsHandle.CurrentState);
-            if (ttsLipSyncer.TtsHandle.CurrentState != Tizen.Uix.Tts.State.Ready)
-            {
-                Log.Info(LogTag, "TTS is not ready");
-                return false;
-            }
-
-            try
-            {
-                ttsLipSyncer.AddText(text, voiceInfo);
-                ttsLipSyncer.Prepare(ttsReadyFinishedCallback);
-            }
-            catch (Exception e)
-            {
-                Log.Error(LogTag, $"error :{e.Message}");
-                Log.Error(LogTag, $"{e.StackTrace}");
-                return false;
-            }
-            return true;
-        }
-
-        /// <summary>
-        /// <param name=""></param>
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        internal bool PrepareTTS(string text, string lang = "ko_KR", EventHandler ttsReadyFinishedCallback = null)
-        {
-            if (ttsLipSyncer == null || ttsLipSyncer.TtsHandle == null)
-            {
-                Log.Error(LogTag, "tts is null");
-                return false;
-            }
-
-            if (!ttsLipSyncer.IsSupportedVoice(lang))
-            {
-                Log.Error(LogTag, $"{lang} is not supported");
-                return false;
-            }
-
-            Log.Info(LogTag, "Current TTS State :" + ttsLipSyncer.TtsHandle.CurrentState);
-            if (ttsLipSyncer.TtsHandle.CurrentState != Tizen.Uix.Tts.State.Ready)
-            {
-                Log.Error(LogTag, "TTS is not ready");
-                return false;
-            }
-            try
-            {
-                ttsLipSyncer.AddText(text, lang);
-                ttsLipSyncer.Prepare(ttsReadyFinishedCallback);
-            }
-            catch (Exception e)
-            {
-                Log.Error(LogTag, $"error :{e.Message}");
-                Log.Error(LogTag, $"{e.StackTrace}");
-                return false;
-            }
-            return true;
-        }
-
-        /// <summary>
-        /// <param name=""></param>
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        internal bool PlayPreparedTTS()
-        {
-            if (ttsLipSyncer == null || ttsLipSyncer.TtsHandle == null)
-            {
-                Log.Error(LogTag, "tts is null");
-                return false;
-            }
-
-            return ttsLipSyncer.PlayPreparedText();
-        }
-
-        /// <summary>
-        /// <param name=""></param>
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        internal bool PlayTTS(string text, VoiceInfo voiceInfo)
-        {
-            if (ttsLipSyncer == null || ttsLipSyncer.TtsHandle == null)
-            {
-                Log.Error(LogTag, "tts is null");
-                return false;
-            }
-
-
-            if (!ttsLipSyncer.IsSupportedVoice(voiceInfo))
-            {
-                Log.Info(LogTag, $"{voiceInfo.Lang} & {voiceInfo.Type} is not supported");
-                return false;
-            }
-
-            Log.Info(LogTag, "Current TTS State :" + ttsLipSyncer.TtsHandle.CurrentState);
-            if (ttsLipSyncer.TtsHandle.CurrentState != Tizen.Uix.Tts.State.Ready)
-            {
-                Log.Info(LogTag, "TTS is not ready");
-                return false;
-            }
-
-            try
-            {
-                ttsLipSyncer.AddText(text, voiceInfo);
-                ttsLipSyncer.Play();
-            }
-            catch (Exception e)
-            {
-                Log.Error(LogTag, $"error :{e.Message}");
-                Log.Error(LogTag, $"{e.StackTrace}");
-                return false;
-            }
-            return true;
-        }
-
-        /// <summary>
-        /// <param name=""></param>
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        internal bool PlayTTS(string text, string lang = "ko_KR")
-        {
-            if (ttsLipSyncer == null || ttsLipSyncer.TtsHandle == null)
-            {
-                Log.Error(LogTag, "tts is null");
-                return false;
-            }
-
-            if (!ttsLipSyncer.IsSupportedVoice(lang))
-            {
-                Log.Error(LogTag, $"{lang} is not supported");
-                return false;
-            }
-
-            Log.Info(LogTag, "Current TTS State :" + ttsLipSyncer.TtsHandle.CurrentState);
-            if (ttsLipSyncer.TtsHandle.CurrentState != Tizen.Uix.Tts.State.Ready)
-            {
-                Log.Error(LogTag, "TTS is not ready");
-                return false;
-            }
-            try
-            {
-                ttsLipSyncer.AddText(text, lang);
-                ttsLipSyncer.Play();
-            }
-            catch (Exception e)
-            {
-                Log.Error(LogTag, $"error :{e.Message}");
-                Log.Error(LogTag, $"{e.StackTrace}");
-                return false;
-            }
-            return true;
-        }
-        
-        /// <summary>
-        /// <param name=""></param>
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        internal bool PlayTTSAsync(string text, VoiceInfo voiceInfo, EventHandler ttsReadyFinishedCallback = null)
-        {
-            if (ttsLipSyncer == null || ttsLipSyncer.TtsHandle == null)
-            {
-                Log.Error(LogTag, "tts is null");
-                return false;
-            }
-
-
-            if (!ttsLipSyncer.IsSupportedVoice(voiceInfo))
-            {
-                Log.Info(LogTag, $"{voiceInfo.Lang} & {voiceInfo.Type} is not supported");
-                return false;
-            }
-
-            Log.Info(LogTag, "Current TTS State :" + ttsLipSyncer.TtsHandle.CurrentState);
-            if (ttsLipSyncer.TtsHandle.CurrentState != Tizen.Uix.Tts.State.Ready)
-            {
-                Log.Info(LogTag, "TTS is not ready");
-                return false;
-            }
-
-            try
-            {
-                ttsLipSyncer.AddText(text, voiceInfo);
-                ttsLipSyncer.PlayAsync(ttsReadyFinishedCallback);
-            }
-            catch (Exception e)
-            {
-                Log.Error(LogTag, $"error :{e.Message}");
-                Log.Error(LogTag, $"{e.StackTrace}");
-                return false;
-            }
-            return true;
-        }
-
-        /// <summary>
-        /// <param name=""></param>
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        internal bool PlayTTS(string text, string lang = "ko_KR", EventHandler ttsReadyFinishedCallback = null)
-        {
-            if (ttsLipSyncer == null || ttsLipSyncer.TtsHandle == null)
-            {
-                Log.Error(LogTag, "tts is null");
-                return false;
-            }
-
-            if (!ttsLipSyncer.IsSupportedVoice(lang))
-            {
-                Log.Error(LogTag, $"{lang} is not supported");
-                return false;
-            }
-
-            Log.Info(LogTag, "Current TTS State :" + ttsLipSyncer.TtsHandle.CurrentState);
-            if (ttsLipSyncer.TtsHandle.CurrentState != Tizen.Uix.Tts.State.Ready)
-            {
-                Log.Error(LogTag, "TTS is not ready");
-                return false;
-            }
-            try
-            {
-                ttsLipSyncer.AddText(text, lang);
-                ttsLipSyncer.PlayAsync(ttsReadyFinishedCallback);
-            }
-            catch (Exception e)
-            {
-                Log.Error(LogTag, $"error :{e.Message}");
-                Log.Error(LogTag, $"{e.StackTrace}");
-                return false;
-            }
-            return true;
-        }
-
-        /// <summary>
-        /// <param name=""></param>
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        internal void PauseTTS()
-        {
-            if (ttsLipSyncer == null || ttsLipSyncer.TtsHandle == null)
-            {
-                Log.Error(LogTag, "tts is null");
-                return;
-            }
-
-            try
-            {
-                Log.Info(LogTag, "Current TTS State :" + ttsLipSyncer.TtsHandle.CurrentState);
-                ttsLipSyncer?.Pause();
-            }
-            catch (Exception e)
-            {
-                Log.Error(LogTag, $"error :{e.Message}");
-                Log.Error(LogTag, $"{e.StackTrace}");
-            }
-        }
-
-        /// <summary>
-        /// <param name=""></param>
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        internal void StopTTS()
-        {
-            if (ttsLipSyncer == null || ttsLipSyncer.TtsHandle == null)
-            {
-                Log.Error(LogTag, "tts is null");
-                return;
-            }
-
-            try
-            {
-                Log.Info(LogTag, "Current TTS State :" + ttsLipSyncer.TtsHandle.CurrentState);
-                ttsLipSyncer?.Stop();
-            }
-            catch (Exception e)
-            {
-                Log.Error(LogTag, $"error :{e.Message}");
-                Log.Error(LogTag, $"{e.StackTrace}");
-            }
-        }
-    }
-}
diff --git a/src/Tizen.AIAvatar/src/public/Avatar/Info/AnimationInfo.cs b/src/Tizen.AIAvatar/src/public/Avatar/Info/AnimationInfo.cs
deleted file mode 100644 (file)
index 17c7998..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright(c) 2023 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-using System.ComponentModel;
-using Tizen.NUI.Scene3D;
-
-namespace Tizen.AIAvatar
-{
-    [EditorBrowsable(EditorBrowsableState.Never)]
-    public class AnimationInfo
-    {
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        public MotionData MotionData { get; internal set; }
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        public string MotionName { get; internal set; }
-
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        public AnimationInfo(MotionData motionData, string motionName)
-        {
-            MotionData = motionData;
-            MotionName = motionName;
-        }
-    }
-}
diff --git a/src/Tizen.AIAvatar/src/public/Avatar/Info/AvatarInfo.cs b/src/Tizen.AIAvatar/src/public/Avatar/Info/AvatarInfo.cs
deleted file mode 100644 (file)
index 7f7b95e..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright(c) 2023 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-using System;
-using System.ComponentModel;
-using static Tizen.AIAvatar.AIAvatar;
-
-namespace Tizen.AIAvatar
-{
-    [EditorBrowsable(EditorBrowsableState.Never)]
-    public class AvatarInfo
-    {
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        public string Name { get; private set; }
-
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        public string ThumbnailPath { get; private set; }
-        
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        internal string ResourcePath { get; private set; }
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        internal AvatarInfoOption avatarInfoOption { get; private set; }
-
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        public AvatarInfo(string path, string Name, AvatarInfoOption info = AvatarInfoOption.Thumbnail)
-        {
-            this.Name = Name;
-            this.avatarInfoOption = info;
-
-            if (info == AvatarInfoOption.Thumbnail)
-            {
-                ThumbnailPath = path;
-            }
-            else
-            {
-                ResourcePath = path;
-            }
-        }
-
-        internal AvatarInfo(string directoryPath)
-        {
-            string path = ApplicationResourcePath + EmojiAvatarResourcePath;
-            Name = directoryPath.Substring(path.Length, directoryPath.Length - path.Length);
-            ResourcePath = $"{directoryPath}/{AIAvatar.ExternalModel}";
-        }
-    }
-
-    [EditorBrowsable(EditorBrowsableState.Never)]
-    public enum AvatarInfoOption
-    {
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        Thumbnail = 0,
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        Resource = 1,
-    }
-}
diff --git a/src/Tizen.AIAvatar/src/public/Avatar/Info/VoiceInfo.cs b/src/Tizen.AIAvatar/src/public/Avatar/Info/VoiceInfo.cs
deleted file mode 100644 (file)
index 7757da1..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright(c) 2023 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-using System.ComponentModel;
-using Tizen.Uix.Tts;
-
-namespace Tizen.AIAvatar
-{
-    [EditorBrowsable(EditorBrowsableState.Never)]
-    public struct VoiceInfo
-    {
-        private string lang;
-        private Voice type;
-
-        /// <summary>
-        /// 
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        public string Lang { get => lang; set => lang = value; }
-
-        /// <summary>
-        /// 
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        public Voice Type { get => type; set => type = value; }
-    }
-}
diff --git a/src/Tizen.AIAvatar/src/public/Avatar/Properties/AvatarBlendShapeIndex.cs b/src/Tizen.AIAvatar/src/public/Avatar/Properties/AvatarBlendShapeIndex.cs
deleted file mode 100644 (file)
index 0264b9b..0000000
+++ /dev/null
@@ -1,193 +0,0 @@
-/*
- * Copyright(c) 2023 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-using System.ComponentModel;
-using Tizen.NUI;
-using Tizen.NUI.Scene3D;
-
-namespace Tizen.AIAvatar
-{
-    /// <summary>
-    /// Specialized <see cref="BlendShapeIndex"/> to control avatar blend shape.
-    /// </summary>
-    /// <example>
-    /// <code>
-    /// AvatarBlendShapeIndex leftEyeBlink = new AvatarBlendShapeIndex(avatar.BlendShapeMapper, BlendShapeType.EyeBlinkLeft);
-    ///
-    /// // We can change the property later.
-    /// AVatarBlendShapeIndex rightEyeBlink = new AvatarJointTransformIndex(avatar.BlendShapeMapper);
-    /// rightEyeBlink.AvatarBlendShapeType = (uint)BlendShapeType.EyeBlinkRight;
-    /// </code>
-    /// </example>
-    [EditorBrowsable(EditorBrowsableState.Never)]
-    public class AvatarBlendShapeIndex : BlendShapeIndex
-    {
-        internal AvatarPropertyMapper nameMapper = null;
-        internal uint blendShapeType;
-
-        /// <summary>
-        /// Create an initialized avatar blend shape index.
-        /// </summary>
-        /// <param name="mapper">Name mapper for this index</param>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        public AvatarBlendShapeIndex(AvatarPropertyMapper mapper) : base()
-        {
-            nameMapper = mapper;
-        }
-
-        /// <summary>
-        /// Create an initialized avatar blend shape index with input blend shape ID.
-        /// </summary>
-        /// <param name="mapper">Name mapper for this index</param>
-        /// <param name="blendShapeId">Blend shape ID for this motion index</param>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        public AvatarBlendShapeIndex(AvatarPropertyMapper mapper, PropertyKey blendShapeId) : base(new PropertyKey(GetPropertyNameFromMapper(mapper, blendShapeId)))
-        {
-            nameMapper = mapper;
-        }
-
-        /// <summary>
-        /// Create an initialized avatar blend shape index with blend shape type.
-        /// </summary>
-        /// <param name="mapper">Name mapper for this index</param>
-        /// <param name="blendShapeType">Type of blend shape for this motion index</param>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        internal AvatarBlendShapeIndex(AvatarPropertyMapper blendShapeMapper, BlendShapeType blendShapeType) : this(blendShapeMapper, (uint)blendShapeType)
-        {
-        }
-
-        /// <summary>
-        /// 
-        /// </summary>
-        /// <param name="mapper">Name mapper for this index</param>
-        /// <param name="blendShapeType">Type of blend shape for this motion index</param>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        public AvatarBlendShapeIndex(AvatarPropertyMapper mapper, uint blendShapeType) : base(new PropertyKey(GetPropertyNameFromMapper(mapper, blendShapeType)))
-        {
-            nameMapper = mapper;
-            this.blendShapeType = blendShapeType;
-        }
-
-        /// <summary>
-        /// 
-        /// </summary>
-        /// <param name="mapper">Name mapper for this index</param>
-        /// <param name="blendShapeType">Type of blend shape for this motion index</param>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        internal AvatarBlendShapeIndex(AvatarPropertyMapper nodeMapper, NodeType nodeType, AvatarPropertyMapper blendShapeMapper, BlendShapeType blendShapeType) : base(new PropertyKey(GetPropertyNameFromMapper(nodeMapper, (uint)nodeType)), new PropertyKey(GetPropertyNameFromMapper(blendShapeMapper, (uint)blendShapeType)))
-        {
-            nameMapper = blendShapeMapper;
-            this.blendShapeType = (uint)blendShapeType;
-        }
-
-        /// <summary>
-        /// Get the name of given index.
-        /// </summary>
-        /// <param name="mapper">Name mapper for given index</param>
-        /// <param name="id">Target ID what we want to get name</param>
-        /// <returns>Name, or null if invalid</returns>
-        private static string GetPropertyNameFromMapper(AvatarPropertyMapper mapper, PropertyKey id)
-        {
-            if (id == null)
-            {
-                return "";
-            }
-            if (id.Type == PropertyKey.KeyType.String)
-            {
-                return id.StringKey;
-            }
-            return mapper?.GetPropertyName((uint)id.IndexKey) ?? "";
-        }
-
-        /// <summary>
-        /// Get the name of given JointType.
-        /// </summary>
-        /// <param name="mapper">Name mapper for given index</param>
-        /// <param name="blendShapeType">Type of joint what we want to get name</param>
-        /// <returns>Name, or null if invalid</returns>
-        private static string GetPropertyNameFromMapper(AvatarPropertyMapper mapper, uint blendShapeType)
-        {
-            return mapper?.GetPropertyName(blendShapeType) ?? "";
-        }
-
-        /// <summary>
-        /// TODO : Explain me
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        public AvatarPropertyMapper NameMapper
-        {
-            get
-            {
-                return nameMapper;
-            }
-            set
-            {
-                nameMapper = value;
-
-                using PropertyKey blendShapeId = new(GetPropertyNameFromMapper(nameMapper, blendShapeType));
-                base.BlendShapeId = blendShapeId;
-            }
-        }
-
-        /// <summary>
-        /// TODO : Explain me
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        public uint AvatarBlendShapeType
-        {
-            get
-            {
-                return blendShapeType;
-            }
-            set
-            {
-                blendShapeType = value;
-
-                using PropertyKey blendShapeId = new(GetPropertyNameFromMapper(nameMapper, blendShapeType));
-                base.BlendShapeId = blendShapeId;
-            }
-        }
-
-        /// <summary>
-        /// Hijack property to control Avatar specified logic.
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        public new PropertyKey BlendShapeId
-        {
-            get
-            {
-                return base.BlendShapeId;
-            }
-            set
-            {
-                if (value != null)
-                {
-                    if (value.Type == PropertyKey.KeyType.Index)
-                    {
-                        blendShapeType = (uint)value.IndexKey;
-                    }
-                    using PropertyKey blendShapeId = new(GetPropertyNameFromMapper(nameMapper, value));
-                    base.BlendShapeId = blendShapeId;
-                }
-                else
-                {
-                    base.BlendShapeId = value;
-                }
-            }
-        }
-    }
-}
diff --git a/src/Tizen.AIAvatar/src/public/Avatar/Properties/AvatarJointTransformIndex.cs b/src/Tizen.AIAvatar/src/public/Avatar/Properties/AvatarJointTransformIndex.cs
deleted file mode 100644 (file)
index 6163e22..0000000
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- * Copyright(c) 2023 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-using System.ComponentModel;
-using Tizen.NUI;
-using Tizen.NUI.Scene3D;
-
-namespace Tizen.AIAvatar
-{
-    /// <summary>
-    /// Specialized <see cref="MotionTransformIndex"/> to control avatar joint transform.
-    /// </summary>
-    /// <example>
-    /// <code>
-    /// AvatarJointTransformIndex position = new AvatarJointTransformIndex(avatar.JointMapper, JointType.Head, MotionTransformIndex.TransformTypes.Position);
-    ///
-    /// // We can change the property later.
-    /// AvatarJointTransformIndex orientation = new AvatarJointTransformIndex(avatar.JointMapper);
-    /// orientation.AvatarJointType = (uint)JointType.Neck;
-    /// orientation.TransformType = MotionTransformIndex.TransformTypes.Orientation;
-    /// </code>
-    /// </example>
-    [EditorBrowsable(EditorBrowsableState.Never)]
-    public class AvatarJointTransformIndex : MotionTransformIndex
-    {
-        internal AvatarPropertyMapper nameMapper = null;
-        internal uint jointType;
-
-        /// <summary>
-        /// Create an initialized avatar joint transform index.
-        /// </summary>
-        /// <param name="mapper">Name mapper for this index</param>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        public AvatarJointTransformIndex(AvatarPropertyMapper mapper) : base()
-        {
-            nameMapper = mapper;
-        }
-
-        /// <summary>
-        /// Create an initialized avatar joint transform index with input node id, and transform type.
-        /// </summary>
-        /// <param name="mapper">Name mapper for this index</param>
-        /// <param name="modelNodeId">Node ID for this motion index</param>
-        /// <param name="transformType">Transform property type for this motion index</param>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        public AvatarJointTransformIndex(AvatarPropertyMapper mapper, PropertyKey modelNodeId, TransformTypes transformType) : base(new PropertyKey(GetPropertyNameFromMapper(mapper, modelNodeId)), transformType)
-        {
-            nameMapper = mapper;
-        }
-
-        /// <summary>
-        /// Create an initialized avatar joint transform index with input node id, and transform type.
-        /// </summary>
-        /// <param name="mapper">Name mapper for this index</param>
-        /// <param name="jointType">Type of joint for this motion index</param>
-        /// <param name="transformType">Transform property type for this motion index</param>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        internal AvatarJointTransformIndex(AvatarPropertyMapper mapper, JointType jointType, TransformTypes transformType) : this(mapper, (uint)jointType, transformType)
-        {
-        }
-
-        /// <summary>
-        /// Create an initialized avatar joint transform index with input node id, and transform type.
-        /// </summary>
-        /// <param name="mapper">Name mapper for this index</param>
-        /// <param name="jointType">Type of joint for this motion index</param>
-        /// <param name="transformType">Transform property type for this motion index</param>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        public AvatarJointTransformIndex(AvatarPropertyMapper mapper, uint jointType, TransformTypes transformType) : base(new PropertyKey(GetPropertyNameFromMapper(mapper, jointType)), transformType)
-        {
-            nameMapper = mapper;
-            this.jointType = jointType;
-        }
-
-        private static string GetPropertyNameFromMapper(AvatarPropertyMapper mapper, PropertyKey id)
-        {
-            if (id == null)
-            {
-                return "";
-            }
-            if (id.Type == PropertyKey.KeyType.String)
-            {
-                return id.StringKey;
-            }
-            return mapper?.GetPropertyName((uint)id.IndexKey) ?? "";
-        }
-
-        private static string GetPropertyNameFromMapper(AvatarPropertyMapper mapper, uint jointType)
-        {
-            return mapper?.GetPropertyName(jointType) ?? "";
-        }
-
-        /// <summary>
-        /// TODO : Explain me
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        public AvatarPropertyMapper NameMapper
-        {
-            get
-            {
-                return nameMapper;
-            }
-            set
-            {
-                nameMapper = value;
-
-                using PropertyKey nodeId = new(GetPropertyNameFromMapper(nameMapper, jointType));
-                base.ModelNodeId = nodeId;
-            }
-        }
-
-        /// <summary>
-        /// TODO : Explain me
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        public uint AvatarJointType
-        {
-            get
-            {
-                return jointType;
-            }
-            set
-            {
-                jointType = value;
-
-                using PropertyKey nodeId = new(GetPropertyNameFromMapper(nameMapper, jointType));
-                base.ModelNodeId = nodeId;
-            }
-        }
-
-        /// <summary>
-        /// Hijack property to control Avatar specified logic.
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        public new PropertyKey ModelNodeId
-        {
-            get
-            {
-                return base.ModelNodeId;
-            }
-            set
-            {
-                if (value != null)
-                {
-                    if (value.Type == PropertyKey.KeyType.Index)
-                    {
-                        jointType = (uint)value.IndexKey;
-                    }
-                    using PropertyKey nodeId = new(GetPropertyNameFromMapper(nameMapper, value));
-                    base.ModelNodeId = nodeId;
-                }
-                else
-                {
-                    base.ModelNodeId = value;
-                }
-            }
-        }
-    }
-}
diff --git a/src/Tizen.AIAvatar/src/public/Avatar/Properties/AvatarProperties.cs b/src/Tizen.AIAvatar/src/public/Avatar/Properties/AvatarProperties.cs
deleted file mode 100644 (file)
index a6b8612..0000000
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright(c) 2023 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-using System;
-using System.ComponentModel;
-
-namespace Tizen.AIAvatar
-{
-    [EditorBrowsable(EditorBrowsableState.Never)]
-    public class AvatarProperties
-    {
-        private AvatarPropertyMapper jointMapper;
-        private AvatarPropertyMapper blendShapeMapper;
-        private AvatarPropertyMapper nodeMapper;
-
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        public AvatarProperties(AvatarPropertyMapper jointMapper, AvatarPropertyMapper blendShapeMapper, AvatarPropertyMapper nodeMapper)
-        {
-            JointMapper = new AvatarPropertyMapper(jointMapper);
-            BlendShapeMapper = new AvatarPropertyMapper(blendShapeMapper);
-            NodeMapper = new AvatarPropertyMapper(nodeMapper);
-        }
-
-        internal event EventHandler<AvatarProperties> AvatarPropertiesChanged;
-
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        public AvatarPropertyMapper JointMapper
-        {
-            get
-            {
-                return jointMapper;
-            }
-            set
-            {
-                jointMapper = value;
-                AvatarPropertiesChanged?.Invoke(jointMapper, this);
-            }
-        }
-
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        public AvatarPropertyMapper BlendShapeMapper
-        {
-            get
-            {
-                return blendShapeMapper;
-            }
-            set
-            {
-                blendShapeMapper = value;
-                AvatarPropertiesChanged?.Invoke(blendShapeMapper, this);
-            }
-        }
-
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        public AvatarPropertyMapper NodeMapper
-        {
-            get
-            {
-                return nodeMapper;
-            }
-            set
-            {
-                nodeMapper = value;
-                AvatarPropertiesChanged?.Invoke(nodeMapper, this);
-            }
-        }
-    }
-}
diff --git a/src/Tizen.AIAvatar/src/public/Avatar/Properties/AvatarPropertyMapper.cs b/src/Tizen.AIAvatar/src/public/Avatar/Properties/AvatarPropertyMapper.cs
deleted file mode 100644 (file)
index bcd7115..0000000
+++ /dev/null
@@ -1,176 +0,0 @@
-/*
- * Copyright(c) 2023 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-using System.Collections.Generic;
-using System.ComponentModel;
-
-namespace Tizen.AIAvatar
-{
-    /// <summary>
-    /// TODO : Explain more detail
-    /// </summary>
-    [EditorBrowsable(EditorBrowsableState.Never)]
-    public class AvatarPropertyMapper
-    {
-        /// <summary>
-        /// Mapper between index and property name
-        /// </summary>
-        private Dictionary<uint, string> mapper = null;
-
-        /// <summary>
-        /// The counter of index. It will be increased one when we register custom index.
-        /// </summary>
-        private uint customIndexCounter = 0;
-
-        /// <summary>
-        /// Create an initialized AvatarPropertyNameMapper.
-        /// </summary>
-        // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        public AvatarPropertyMapper()
-        {
-            mapper = new Dictionary<uint, string>();
-            customIndexCounter = 0u;
-        }
-
-        /// <summary>
-        /// Copy constructor.
-        /// </summary>
-        // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        public AvatarPropertyMapper(AvatarPropertyMapper rhs)
-        {
-            if (rhs != null)
-            {
-                mapper = new Dictionary<uint, string>(rhs.Mapper);
-                customIndexCounter = rhs.customIndexCounter;
-            }
-            else
-            {
-                mapper = new Dictionary<uint, string>();
-                customIndexCounter = 0u;
-            }
-        }
-
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        protected uint CustomIndexCounter
-        {
-            get
-            {
-                return customIndexCounter;
-            }
-            set
-            {
-                customIndexCounter = value;
-            }
-        }
-
-        /// <summary>
-        /// Get current mapper information.
-        /// </summary>
-        // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        public Dictionary<uint, string> Mapper
-        {
-            get
-            {
-                return mapper;
-            }
-        }
-
-        /// <summary>
-        /// TODO : Explain me.
-        /// </summary>
-        /// <param name="index">The index of property what we want to set</param>
-        /// <returns>The index of property, or uint.MaxValue if not exist</returns>
-        // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        public string this[uint index]
-        {
-            set
-            {
-                SetPropertyName(index, value);
-            }
-            get
-            {
-                return GetPropertyName(index);
-            }
-        }
-
-        /// <summary>
-        /// TODO : Explain me.
-        /// </summary>
-        /// <param name="name">The name of custom property</param>
-        /// <returns>The index of property matched with name.</returns>
-        // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        public uint RegisterCustomProperty(string name)
-        {
-            uint ret = GetPropertyIndexByName(name);
-            if (ret >= customIndexCounter)
-            {
-                ret = customIndexCounter++;
-                SetPropertyName(ret, name);
-            }
-            return ret;
-        }
-
-        /// <summary>
-        /// TODO : Explain me.
-        /// </summary>
-        /// <param name="name">The name of property what we want to get index</param>
-        /// <returns>The index of property, or uint.MaxValue if not exist</returns>
-        // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        public uint GetPropertyIndexByName(string name)
-        {
-            // TODO : Do this without iteration
-            foreach (var pair in mapper)
-            {
-                if (pair.Value == name)
-                {
-                    return pair.Key;
-                }
-            }
-            return uint.MaxValue;
-        }
-
-        /// <summary>
-        /// TODO : Explain me.
-        /// </summary>
-        /// <param name="index">The index of property what we want to set</param>
-        /// <param name="name">The name of property what we want to set</param>
-        /// <remark>
-        /// New property will be added if we use index that not exist in mapper.
-        /// </remark>
-        internal void SetPropertyName(uint index, string name)
-        {
-            mapper.TryAdd(index, name);
-        }
-
-        /// <summary>
-        /// TODO : Explain me.
-        /// </summary>
-        /// <param name="index">The index of property what we want to set</param>
-        /// <returns>The name of property, or null if not exist</returns>
-        internal string GetPropertyName(uint index)
-        {
-            string ret = null;
-            mapper.TryGetValue(index, out ret);
-            return ret;
-        }
-    }
-}
diff --git a/src/Tizen.AIAvatar/test/Test.cs b/src/Tizen.AIAvatar/test/Test.cs
new file mode 100644 (file)
index 0000000..e8f0e11
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Copyright(c) 2024 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+namespace Tizen.AIAvatar
+{
+    internal class Test
+    {
+        public void CreateTest()
+        {
+            var avatar1 = new Avatar();
+
+            var avatarInfo = new AvatarInfo("avatarName", "resourcePath");
+            var avatar2 = new Avatar(avatarInfo);
+
+            var avatar3 = new Avatar("resourcePath");
+
+            var avatar4 = new Avatar(avatar1);
+
+            avatar1.Dispose();
+            avatar2.Dispose();
+            avatar3.Dispose();
+            avatar4.Dispose();
+        }
+    }
+}
diff --git a/test/Tizen.AIAvatar.Example/Tizen.AIAvatar.Sample.csproj b/test/Tizen.AIAvatar.Example/Tizen.AIAvatar.Sample.csproj
new file mode 100644 (file)
index 0000000..b74ab56
--- /dev/null
@@ -0,0 +1,19 @@
+<Project Sdk="Tizen.NET.Sdk/1.1.9">
+  <PropertyGroup>
+    <OutputType>Exe</OutputType>
+    <TargetFramework>net6.0</TargetFramework>
+    <AssemblyName>AIAvatarSample</AssemblyName>
+  </PropertyGroup>
+
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugType>portable</DebugType>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>None</DebugType>
+  </PropertyGroup>
+
+  <ItemGroup>
+     <ProjectReference Include="..\..\src\Tizen.AIAvatar\Tizen.AIAvatar.csproj" />
+     <ProjectReference Include="../../src/Tizen.NUI.Components/Tizen.NUI.Components.csproj" />
+  </ItemGroup>
+</Project>
diff --git a/test/Tizen.AIAvatar.Example/Tizen.AIAvatar.Sample.sln b/test/Tizen.AIAvatar.Example/Tizen.AIAvatar.Sample.sln
new file mode 100644 (file)
index 0000000..0e2ce1b
--- /dev/null
@@ -0,0 +1,28 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.7.34009.444
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tizen.AIAvatar.Sample", "Tizen.AIAvatar.Sample.csproj", "{0176A159-FCC2-45B8-ABEE-63FEBFEA5079}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tizen.AIAvatar", "..\..\src\Tizen.AIAvatar\Tizen.AIAvatar.csproj", "{D1971AA8-5B1D-467A-9E86-292B01C4DDB8}"
+EndProject
+Global
+       GlobalSection(SolutionConfigurationPlatforms) = preSolution
+               Debug|Any CPU = Debug|Any CPU
+               Release|Any CPU = Release|Any CPU
+       EndGlobalSection
+       GlobalSection(ProjectConfigurationPlatforms) = postSolution
+               {0176A159-FCC2-45B8-ABEE-63FEBFEA5079}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+               {0176A159-FCC2-45B8-ABEE-63FEBFEA5079}.Debug|Any CPU.Build.0 = Debug|Any CPU
+               {0176A159-FCC2-45B8-ABEE-63FEBFEA5079}.Release|Any CPU.ActiveCfg = Release|Any CPU
+               {0176A159-FCC2-45B8-ABEE-63FEBFEA5079}.Release|Any CPU.Build.0 = Release|Any CPU
+               {D1971AA8-5B1D-467A-9E86-292B01C4DDB8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+               {D1971AA8-5B1D-467A-9E86-292B01C4DDB8}.Debug|Any CPU.Build.0 = Debug|Any CPU
+               {D1971AA8-5B1D-467A-9E86-292B01C4DDB8}.Release|Any CPU.ActiveCfg = Release|Any CPU
+               {D1971AA8-5B1D-467A-9E86-292B01C4DDB8}.Release|Any CPU.Build.0 = Release|Any CPU
+       EndGlobalSection
+       GlobalSection(SolutionProperties) = preSolution
+               HideSolutionNode = FALSE
+       EndGlobalSection
+EndGlobal
diff --git a/test/Tizen.AIAvatar.Example/res/audio2vowel_7.tflite b/test/Tizen.AIAvatar.Example/res/audio2vowel_7.tflite
new file mode 100644 (file)
index 0000000..95bd359
Binary files /dev/null and b/test/Tizen.AIAvatar.Example/res/audio2vowel_7.tflite differ
diff --git a/test/Tizen.AIAvatar.Example/res/images/Irradiance.ktx b/test/Tizen.AIAvatar.Example/res/images/Irradiance.ktx
new file mode 100644 (file)
index 0000000..df24c05
Binary files /dev/null and b/test/Tizen.AIAvatar.Example/res/images/Irradiance.ktx differ
diff --git a/test/Tizen.AIAvatar.Example/res/images/Radiance.ktx b/test/Tizen.AIAvatar.Example/res/images/Radiance.ktx
new file mode 100644 (file)
index 0000000..51aa681
Binary files /dev/null and b/test/Tizen.AIAvatar.Example/res/images/Radiance.ktx differ
diff --git a/test/Tizen.AIAvatar.Example/res/images/UI_BG.png b/test/Tizen.AIAvatar.Example/res/images/UI_BG.png
new file mode 100644 (file)
index 0000000..aba41d7
Binary files /dev/null and b/test/Tizen.AIAvatar.Example/res/images/UI_BG.png differ
diff --git a/test/Tizen.AIAvatar.Example/res/voice/cs-CZ-Wavenet-A.wav b/test/Tizen.AIAvatar.Example/res/voice/cs-CZ-Wavenet-A.wav
new file mode 100644 (file)
index 0000000..98d72c6
Binary files /dev/null and b/test/Tizen.AIAvatar.Example/res/voice/cs-CZ-Wavenet-A.wav differ
diff --git a/test/Tizen.AIAvatar.Example/res/voice/da-DK-Wavenet-A.wav b/test/Tizen.AIAvatar.Example/res/voice/da-DK-Wavenet-A.wav
new file mode 100644 (file)
index 0000000..9bae76d
Binary files /dev/null and b/test/Tizen.AIAvatar.Example/res/voice/da-DK-Wavenet-A.wav differ
diff --git a/test/Tizen.AIAvatar.Example/res/voice/el-GR-Wavenet-A.wav b/test/Tizen.AIAvatar.Example/res/voice/el-GR-Wavenet-A.wav
new file mode 100644 (file)
index 0000000..43388f0
Binary files /dev/null and b/test/Tizen.AIAvatar.Example/res/voice/el-GR-Wavenet-A.wav differ
diff --git a/test/Tizen.AIAvatar.Example/res/voice/voice_0.bin b/test/Tizen.AIAvatar.Example/res/voice/voice_0.bin
new file mode 100644 (file)
index 0000000..743e789
Binary files /dev/null and b/test/Tizen.AIAvatar.Example/res/voice/voice_0.bin differ
diff --git a/test/Tizen.AIAvatar.Example/res/voice/voice_1.bin b/test/Tizen.AIAvatar.Example/res/voice/voice_1.bin
new file mode 100644 (file)
index 0000000..8ce3aa0
Binary files /dev/null and b/test/Tizen.AIAvatar.Example/res/voice/voice_1.bin differ
diff --git a/test/Tizen.AIAvatar.Example/shared/res/Tizen.AIAvatar.Example.png b/test/Tizen.AIAvatar.Example/shared/res/Tizen.AIAvatar.Example.png
new file mode 100644 (file)
index 0000000..9f3cb98
Binary files /dev/null and b/test/Tizen.AIAvatar.Example/shared/res/Tizen.AIAvatar.Example.png differ
diff --git a/test/Tizen.AIAvatar.Example/src/AvatarScene.cs b/test/Tizen.AIAvatar.Example/src/AvatarScene.cs
new file mode 100644 (file)
index 0000000..e35263a
--- /dev/null
@@ -0,0 +1,387 @@
+/*
+ * Copyright(c) 2023 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+using global::System;
+using System.IO;
+using System.Collections.Generic;
+using Tizen.NUI;
+using Tizen.NUI.BaseComponents;
+using Tizen.NUI.Scene3D;
+using Tizen.AIAvatar;
+using Tizen;
+using Tizen.Uix.Tts;
+
+namespace AIAvatar
+{
+    public class AvatarScene : SceneView
+    {
+        private static readonly string ApplicationResourcePath = "/usr/apps/org.tizen.default-avatar-resource/shared/res/";
+        private static readonly string EmojiAvatarResourcePath = "/models/EmojiAvatar/";
+        private static readonly string DefaultMotionResourcePath = "/animation/motion/";
+        private static string resourcePath = Utils.ResourcePath;
+
+        private const int cameraAnimationDurationMilliSeconds = 2000;
+        private const int sceneTransitionDurationMilliSeconds = 1500;
+
+        private Avatar defaultAIAvatar;
+        private List<AvatarInfo> avatarList;
+        private List<AnimationInfo> animationInfoList;
+        private LipSyncController lipSyncController;
+
+        private bool isBlink = false;
+        private bool isShowing = true;
+
+        private int avatarIndex = 0;
+        private float iblFactor = 0.3f;
+
+        public float IBLFactor
+        {
+            get
+            {
+                return iblFactor;
+            }
+            set
+            {
+                iblFactor = value;
+                ImageBasedLightScaleFactor = value;
+            }
+        }
+
+        public AvatarScene()
+        {
+            PivotPoint = Tizen.NUI.PivotPoint.TopLeft;
+            ParentOrigin = Tizen.NUI.ParentOrigin.TopLeft;
+            PositionUsesPivotPoint = true;
+
+            // Setup Image Based Light
+            SetupSceneViewIBL();
+
+            // Setup camera preset
+            SetupDefaultCamera();
+
+            // Setup Default Avatar Position & Orientation
+            SetupDefaultAvatar();
+
+            // Load Default Animations
+            LoadDefaultAnimations();
+        }
+
+        private void LoadDefaultAnimations()
+        {
+            var motionAnimations = Directory.GetFiles(ApplicationResourcePath + DefaultMotionResourcePath, "*.bvh");
+            animationInfoList = new List<AnimationInfo>();
+
+            foreach (var path in motionAnimations)
+            {
+                var motionData = new MotionData();
+                motionData.LoadMotionCaptureAnimation(path, true, new Vector3(0.01f, 0.01f, 0.01f), false);
+
+                var animationInfo = new AnimationInfo(motionData, GetFileNameWithoutExtension(path));
+                animationInfoList.Add(animationInfo);
+            }
+        }
+
+        public void SetupSceneViewIBLFactor(float value)
+        {
+            IBLFactor = value;
+        }
+
+        public void StartAvatarTalk_1()
+        {
+            PlayLip("cs-CZ-Wavenet-A.wav");
+        }
+
+        public void StartAvatarTalk_2()
+        {
+            PlayLip("da-DK-Wavenet-A.wav");
+        }
+
+        public void StartAvatarTalk_3()
+        {
+            PlayLip("el-GR-Wavenet-A.wav");
+        }
+
+        public void StartAvatarTalkByPath()
+        {
+            PlayLip($"{resourcePath}/voice/voice_0.bin");
+        }
+
+        private void PlayLip(string source)
+        {
+            var path = $"{resourcePath}/voice/{source}";
+            var bytes = ReadAllBytes(path);
+
+            Tizen.Log.Error("AIAvatar", "audio path : " + path);
+            if (lipSyncController == null)
+            {
+                lipSyncController = new LipSyncController(defaultAIAvatar);
+            }
+
+            if (bytes != null)
+            {
+                lipSyncController.PlayLipSync(bytes);
+            }
+            else
+            {
+                Tizen.Log.Error("AIAvatar", "Fail to load bytes");
+            }
+        }
+
+        public void StartRandomAnimation()
+        {
+            var randomIdx = new Random().Next(0, animationInfoList.Count);
+            defaultAIAvatar.PlayAnimation(animationInfoList[randomIdx].MotionData);
+        }
+
+        public void StartMic()
+        {
+            InitMic();
+            lipSyncController?.StartMic();
+        }
+
+        public void StopMic()
+        {
+            InitMic();
+            lipSyncController?.StopMic();
+        }
+
+        public void EyeBlink()
+        {
+            if (!isBlink)
+            {
+                defaultAIAvatar.StartEyeBlink();
+            }
+            else
+            {
+                defaultAIAvatar.StopEyeBlink();
+            }
+            isBlink = !isBlink;
+        }
+
+        public void ShowHide()
+        {
+            if (!isShowing)
+            {
+                defaultAIAvatar.Show();
+            }
+            else
+            {
+                defaultAIAvatar.Hide();
+            }
+            isShowing = !isShowing;
+        }
+
+        public void InintTTsTest()
+        {
+            InitTTS();
+        }
+
+        public void StartTTSTest()
+        {
+            lipSyncController.StopTTS();
+            VoiceInfo voiceInfo = new VoiceInfo()
+            {
+                Language = "en_US",
+                Type = VoiceType.Female,
+            };
+
+            lipSyncController.PrepareTTS(Utils.TTSText, voiceInfo, (o, e) =>
+            {
+                lipSyncController.PlayPreparedTTS();
+            });
+        }
+
+        public void StopTTSTest()
+        {
+            if (lipSyncController == null)
+            {
+                Tizen.Log.Error("AIAvatar", "lipSyncController is null");
+                return;
+            }
+            lipSyncController.StopTTS();
+        }
+
+        public void SwitchCamera()
+        {
+            CameraTransition(1, cameraAnimationDurationMilliSeconds);
+        }
+
+        public void SetupSceneViewCameraFov(float value)
+        {
+            var camera = GetSelectedCamera();
+            camera.FieldOfView = new Radian(value);
+        }
+
+        public void ChangeAvatar()
+        {
+            DestroyAvatar();
+            if (avatarIndex + 1 <= avatarList.Count - 1)
+            {
+                avatarIndex++;
+            }
+            else
+            {
+                avatarIndex = 0;
+            }
+            CreateAvatar();
+
+        }
+
+        internal static string GetFileNameWithoutExtension(string path)
+        {
+            return System.IO.Path.GetFileNameWithoutExtension(path);
+        }
+
+        private void InitTTS()
+        {
+            if (lipSyncController == null)
+            {
+                lipSyncController = new LipSyncController(defaultAIAvatar);
+            }
+            lipSyncController.InitializeTTS();
+        }
+
+        private void InitMic()
+        {
+            if (lipSyncController == null)
+            {
+                lipSyncController = new LipSyncController(defaultAIAvatar);
+            }
+            lipSyncController.InitializeMic();
+        }
+
+        private byte[] ReadAllBytes(string path)
+        {
+            try
+            {
+                var bytes = File.ReadAllBytes(path);
+                return bytes;
+            }
+            catch (Exception)
+            {
+                return null;
+            }
+        }
+
+        private void SetupDefaultAvatar()
+        {
+            avatarList = AvatarExtension.GetDefaultAvatarList();
+            foreach (var info in avatarList)
+            {
+                Tizen.Log.Info("AvatarSample", $"Avatar Name :{info.Name}\n");
+                Tizen.Log.Info("AvatarSample", $"Avatar Thumbnail :{info.ThumbnailPath}\n");
+            }
+
+            CreateAvatar();
+        }
+
+        private void CreateAvatar()
+        {
+            defaultAIAvatar = new Avatar(avatarList[avatarIndex])
+            {
+                Position = new Position(0.0f, -1.70f, -2.0f),
+                Size = new Size(1.0f, 1.0f, 1.0f),
+                Orientation = new Rotation(new Radian(new Degree(0.0f)), Vector3.YAxis)
+            };
+            //var animator = defaultAIAvatar.CurrentAnimator;
+            //animator.MotionStateChanged += OnMotionStateChanged;
+            //animator.LipStateChanged += OnLipStateChanged;
+            Add(defaultAIAvatar);
+        }
+
+        private void DestroyAvatar()
+        {
+            if (defaultAIAvatar != null)
+            {
+                Remove(defaultAIAvatar);
+                /*
+                var animator = defaultAIAvatar.CurrentAnimator;
+                animator.MotionStateChanged -= OnMotionStateChanged;
+                animator.LipStateChanged -= OnLipStateChanged;
+*/
+                defaultAIAvatar.Dispose();
+                defaultAIAvatar = null;
+            }
+
+        }
+
+        private void OnMotionStateChanged(object sender, AvatarMotionChangedEventArgs e)
+        {
+            var avatar = sender as Avatar;//Avatar changed state
+
+            switch (e.Current)
+            {
+                case AvatarMotionState.Ready:
+                    Log.Error(Utils.LogTag, "Current Avatar State is Ready");
+                    break;
+
+                case AvatarMotionState.Playing:
+                    Log.Error(Utils.LogTag, "Current Avatar State is Playing");
+                    break;
+
+                case AvatarMotionState.Paused:
+                    Log.Error(Utils.LogTag, "Current Avatar State is Paused");
+                    break;
+
+                case AvatarMotionState.Stopped:
+                    Log.Error(Utils.LogTag, "Current Avatar State is Stopped");
+                    break;
+            }
+        }
+
+        private void OnLipStateChanged(object sender, AvatarMotionChangedEventArgs e)
+        {
+            var avatar = sender as Avatar;//Avatar changed state
+
+            switch (e.Current)
+            {
+                case AvatarMotionState.Ready:
+                    Log.Error(Utils.LogTag, "Current Avatar Lip is Ready");
+                    break;
+
+                case AvatarMotionState.Playing:
+                    Log.Error(Utils.LogTag, "Current Avatar Lip is Playing");
+                    break;
+
+                case AvatarMotionState.Paused:
+                    Log.Error(Utils.LogTag, "Current Avatar Lip is Paused");
+                    break;
+
+                case AvatarMotionState.Stopped:
+                    Log.Error(Utils.LogTag, "Current Avatar Lip is Stopped");
+                    break;
+            }
+        }
+
+        private void SetupSceneViewIBL()
+        {
+            SetImageBasedLightSource(resourcePath + "images/" + "Irradiance.ktx", resourcePath + "images/" + "Radiance.ktx", IBLFactor);
+        }
+
+        private void SetupDefaultCamera()
+        {
+            // Default camera setting
+            // Note : SceneView always have 1 default camera.
+            var defaultCamera = GetCamera(0u);
+
+            defaultCamera.PositionX = 0.0f;
+            defaultCamera.PositionY = -2.3f;
+            defaultCamera.PositionZ = 0.0f;
+            defaultCamera.FieldOfView = new Radian(new Degree(45.0f));
+        }
+    }
+}
diff --git a/test/Tizen.AIAvatar.Example/src/ControlPannelComponent.cs b/test/Tizen.AIAvatar.Example/src/ControlPannelComponent.cs
new file mode 100644 (file)
index 0000000..fc33ede
--- /dev/null
@@ -0,0 +1,332 @@
+/*
+ * Copyright(c) 2023 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+using global::System;
+using Tizen.NUI;
+using Tizen.NUI.BaseComponents;
+using Tizen.NUI.Scene3D;
+using Tizen.NUI.Components;
+
+namespace AIAvatar
+{
+    public class UIControlPanel
+    {
+        private readonly Vector2 SceneViewPadding = new Vector2(0.0f, 0.0f);
+        private ButtonStyle buttonStyle;
+        private SliderStyle sliderStyle;
+
+        private Window uiWindow;
+        private AvatarScene mainScene;
+        private View controlPannel;
+
+        private TextField editor;
+
+        private readonly float ControlPannelWidthScale = 0.25f;// Relative size of window width. windowSize.Width * 0.5f
+
+        public event EventHandler OnExitButtonClicked;
+
+        public void MakeControlPannel(Window uiWindow, AvatarScene mainScene)
+        {
+            this.uiWindow = uiWindow;
+            this.mainScene = mainScene;
+
+            if (controlPannel != null)
+            {
+                return;
+            }
+
+            InitializeButtonStyle();
+            InitializeSliderStyle();
+
+            controlPannel = new ScrollableBase()
+            {
+                BackgroundColor = new Color(0.85f, 0.85f, 0.85f, 0.25f),
+
+                PivotPoint = PivotPoint.TopLeft,
+                ParentOrigin = ParentOrigin.TopLeft,
+                PositionUsesPivotPoint = true,
+                //CornerRadius = 30.0f,
+                Padding = new Extents(30, 30, 30, 30),
+
+                Layout = new LinearLayout()
+                {
+                    LinearOrientation = LinearLayout.Orientation.Vertical,
+                    HorizontalAlignment = HorizontalAlignment.Begin,
+                    VerticalAlignment = VerticalAlignment.Top,
+                    CellPadding = new Size2D(10, 20),
+                },
+                HideScrollbar = false,
+            };
+            uiWindow.Add(controlPannel);
+
+            // Make control buttons
+            MakeControlPannelComponents();
+        }
+
+        public void ReizeUIPanel(View avatarScene, View circleView)
+        {
+            var windowSize = uiWindow.Size;
+            var layoutLTR = (windowSize.Width >= windowSize.Height);
+
+            var sceneViewSize = new Vector2(0, 0);
+            var sceneViewPosition = new Vector2(0, 0);
+            var controlPannelSize = new Vector2(0, 0);
+            var controlPannelPosition = new Vector2(0, 0);
+            if (layoutLTR) // layout Left to Right
+            {
+                sceneViewSize = new Vector2(windowSize.Width - SceneViewPadding.X * 3.0f - ControlPannelWidthScale * windowSize.Width,
+                                            windowSize.Height - SceneViewPadding.Y * 2.0f);
+                sceneViewPosition = new Vector2(SceneViewPadding.X * 2.0f + ControlPannelWidthScale * windowSize.Width, SceneViewPadding.Y);
+                controlPannelSize = new Vector2(ControlPannelWidthScale * windowSize.Width, windowSize.Height - SceneViewPadding.Y * 2.0f);
+                controlPannelPosition = new Vector2(SceneViewPadding.X, SceneViewPadding.Y);
+            }
+            else // layout Top to Bottom
+            {
+                sceneViewSize = new Vector2(windowSize.Width - SceneViewPadding.X * 2.0f,
+                                        windowSize.Height - SceneViewPadding.Y * 3.0f - ControlPannelWidthScale * windowSize.Height);
+                sceneViewPosition = new Vector2(SceneViewPadding.X, SceneViewPadding.Y * 2.0f + ControlPannelWidthScale * windowSize.Height);
+                controlPannelSize = new Vector2(windowSize.Width - SceneViewPadding.X * 2.0f, ControlPannelWidthScale * windowSize.Height);
+                controlPannelPosition = new Vector2(SceneViewPadding.X, SceneViewPadding.Y);
+            }
+
+            // Update SceneView and ControlPannel size/position if we has.
+            if (avatarScene != null && circleView != null)
+            {
+                avatarScene.SizeWidth = sceneViewSize.Width;
+                avatarScene.SizeHeight = sceneViewSize.Height;
+                avatarScene.PositionX = 0;//sceneViewPosition.X;
+                avatarScene.PositionY = 0;//sceneViewPosition.Y;
+
+                circleView.SizeWidth = sceneViewSize.Width;
+                circleView.SizeHeight = sceneViewSize.Width;
+                circleView.PositionX = sceneViewPosition.X;
+                circleView.PositionY = sceneViewPosition.Y;
+            }
+
+            if (controlPannel != null)
+            {
+                controlPannel.SizeWidth = controlPannelSize.Width;
+                controlPannel.SizeHeight = controlPannelSize.Height;
+                controlPannel.PositionX = controlPannelPosition.X;
+                controlPannel.PositionY = controlPannelPosition.Y;
+            }
+        }
+
+        private void InitializeButtonStyle()
+        {
+            buttonStyle = new ButtonStyle()
+            {
+                Size = new Size(252, 48),
+                ItemSpacing = new Size2D(8, 8),
+                CornerRadius = 12.0f,
+                ItemHorizontalAlignment = HorizontalAlignment.Center,
+                ItemVerticalAlignment = VerticalAlignment.Center,
+                BorderlineWidth = 5.0f,
+                BackgroundColor = new Selector<Color>()
+                {
+                    Normal = Styles.BIG_TAG_FOCUS_BACKGROUND_COLOR1,
+                    Pressed = Styles.BIG_TAG_NORMAL_BACKGROUND_COLOR1,
+                    Focused = Styles.BIG_TAG_FOCUS_BACKGROUND_COLOR2,
+                    Selected = Styles.BIG_TAG_NORMAL_BACKGROUND_COLOR1,
+                    Disabled = new Color(0.792f, 0.792f, 0.792f, 1),
+                },
+                BorderlineColorSelector = new Selector<Color>()
+                {
+                    Normal = Styles.BIG_TAG_FOCUS_BACKGROUND_COLOR2,
+                    Pressed = Styles.BIG_TAG_NORMAL_BACKGROUND_COLOR2,
+                    Focused = Styles.BIG_TAG_FOCUS_BACKGROUND_COLOR1,
+                    Selected = Styles.BIG_TAG_NORMAL_BACKGROUND_COLOR2,
+                    Disabled = new Color(0.94f, 0.95f, 0.93f, 1.0f),
+                },
+                Text = new TextLabelStyle()
+                {
+                    TextColor = new Color("#0D0D0D"),
+                    PixelSize = 24,
+                },
+            };
+        }
+
+        private void InitializeSliderStyle()
+        {
+            sliderStyle = new SliderStyle()
+            {
+                Size = new Size(850, 50),
+                TrackThickness = 8,
+                Track = new ImageViewStyle()
+                {
+                    Size = new Size(800, 8),
+                    CornerRadius = 4.0f,
+                    BackgroundColor = new Selector<Color>()
+                    {
+                        Normal = new Color(1.0f, 0.37f, 0.0f, 0.1f),
+                        Disabled = new Color(1.0f, 0.37f, 0.0f, 0.1f),
+                    },
+                },
+                Progress = new ImageViewStyle()
+                {
+                    Size = new Size(800, 8),
+                    CornerRadius = 4.0f,
+                    BackgroundColor = new Selector<Color>()
+                    {
+                        //Normal = new Color("#FF6200"),
+                        Normal = Styles.BIG_TAG_FOCUS_BACKGROUND_COLOR2,
+                        Disabled = new Color("#CACACA"),
+                    },
+                },
+                Thumb = new ImageViewStyle()
+                {
+                    Size = new Size(24, 24),
+                    BackgroundColor = new Selector<Color>()
+                    {
+                        Normal = Styles.BIG_TAG_FOCUS_BACKGROUND_COLOR1,
+                        Pressed = Styles.BIG_TAG_NORMAL_BACKGROUND_COLOR1,
+                        Focused = Styles.BIG_TAG_FOCUS_BACKGROUND_COLOR2,
+                        Disabled = new Color(0.94f, 0.95f, 0.93f, 1.0f),
+                    },
+                    BorderlineWidth = 5.0f,
+                    BorderlineColorSelector = new Selector<Color>()
+                    {
+                        Normal = Styles.BIG_TAG_FOCUS_BACKGROUND_COLOR2,
+                        Pressed = Styles.BIG_TAG_NORMAL_BACKGROUND_COLOR2,
+                        Focused = Styles.BIG_TAG_FOCUS_BACKGROUND_COLOR1,
+                        Disabled = new Color(0.94f, 0.95f, 0.93f, 1.0f),
+                    },
+                    CornerRadius = new Vector4(0.5f, 0.5f, 0.5f, 0.5f),
+                    CornerRadiusPolicy = VisualTransformPolicyType.Relative,
+                },
+                ValueIndicatorImage = new ImageViewStyle()
+                {
+                    Size = new Size(43, 40),
+                    BorderlineWidth = 1.0f,
+                    BorderlineColor = new Color("#FF6200"),
+                    BackgroundColor = new Color(1.0f, 1.0f, 1.0f, 0.0f),
+                    CornerRadius = 12.0f,
+                },
+                ValueIndicatorText = new TextLabelStyle()
+                {
+                    SizeHeight = 24,
+                    PixelSize = 16,
+                    TextColor = new Color("#FF6200"),
+                }
+            };
+        }
+
+        private void MakeControlPannelComponents()
+        {
+            AddControlEditor();
+            AddControlButton("ChangeAvatar", "button_avatar", mainScene.ChangeAvatar);
+            AddControlButton("Random Animation", "button_bvh", mainScene.StartRandomAnimation);
+            AddControlButton("EyeBlink", "button_bvh", mainScene.EyeBlink);
+
+            AddControlButton("TTS Init", "button_avatar", mainScene.InintTTsTest);
+            AddControlButton("TTS Start", "button_avatar", mainScene.StartTTSTest);
+            AddControlButton("TTS Stop", "button_avatar", mainScene.StopTTSTest);
+            AddControlButton("CZ", "button_avatar", mainScene.StartAvatarTalk_1);
+            AddControlButton("DK", "button_avatar", mainScene.StartAvatarTalk_2);
+            AddControlButton("GR", "button_avatar", mainScene.StartAvatarTalk_3);
+            AddControlButton("Start Mic", "button_bvh", mainScene.StartMic);
+            AddControlButton("Stop Mic", "button_bvh", mainScene.StopMic);
+            AddControlButton("Show/Hide", "button_bvh", mainScene.ShowHide);
+            AddControlSlider("Camera FOV", "slider_camera_fov", 0.1f, 1.3f, mainScene.GetSelectedCamera().FieldOfView.ConvertToFloat(), mainScene.SetupSceneViewCameraFov);
+            AddControlSlider("IBL intensity", "slider_ibl_factor", 0.1f, 0.8f, mainScene.IBLFactor, mainScene.SetupSceneViewIBLFactor);
+            AddControlButton("Quit", "button_quit", Exit);
+        }
+
+        private void AddControlEditor()
+        {
+            editor = new TextField()
+            {
+                Text = Utils.TTSText,
+                PlaceholderText = "Input Your Message",
+                Name = "InputText",
+                BackgroundColor = Color.White,
+                WidthSpecification = LayoutParamPolicies.MatchParent,
+            };
+            editor.TextChanged += (obj, e) => {
+                Utils.TTSText = e.TextField.Text;
+            };
+
+            controlPannel.Add(editor);
+        }
+
+        private void AddControlButton(string buttonText, string buttonName, Action func)
+        {
+            var button = new Button(buttonStyle)
+            {
+                Text = buttonText,
+                Name = buttonName,
+                WidthSpecification = LayoutParamPolicies.MatchParent,
+            };
+            button.Clicked += (o, e) =>
+            {
+                Button me = o as Button;
+                if (me == null) return;
+
+                func();
+            };
+
+            controlPannel.Add(button);
+        }
+
+        private Slider AddControlSlider(string sliderText, string sliderName, float minValue, float maxValue, float currentValue, Action<float> func)
+        {
+            var dummy = new View()
+            {
+                WidthSpecification = LayoutParamPolicies.MatchParent,
+                Layout = new LinearLayout()
+                {
+                    LinearOrientation = LinearLayout.Orientation.Horizontal,
+                    HorizontalAlignment = HorizontalAlignment.Begin,
+                    VerticalAlignment = VerticalAlignment.Center,
+                    CellPadding = new Size2D(5, 0),
+                },
+            };
+            var label = new TextLabel()
+            {
+                WidthSpecification = LayoutParamPolicies.MatchParent,
+                Text = sliderText,
+                FontSizeScale = 0.5f,
+                Focusable = false,
+                Weight = 0.2f,
+                MultiLine = true,
+            };
+            dummy.Add(label);
+            var slider = new Slider(sliderStyle)
+            {
+                WidthSpecification = LayoutParamPolicies.MatchParent,
+                MinValue = minValue,
+                MaxValue = maxValue,
+                CurrentValue = currentValue,
+                Name = sliderName,
+                Weight = 0.8f,
+            };
+            slider.ValueChanged += (o, e) =>
+            {
+                func(e.CurrentValue);
+            };
+            dummy.Add(slider);
+            controlPannel.Add(dummy);
+
+            return slider;
+        }
+
+        private void Exit()
+        {
+            OnExitButtonClicked?.Invoke(null, null);
+        }
+    }
+}
diff --git a/test/Tizen.AIAvatar.Example/src/SampleMain.cs b/test/Tizen.AIAvatar.Example/src/SampleMain.cs
new file mode 100644 (file)
index 0000000..31dc70a
--- /dev/null
@@ -0,0 +1,156 @@
+/*
+ * Copyright(c) 2023 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+using System;
+using Tizen.AIAvatar;
+using Tizen.NUI;
+using Tizen.NUI.BaseComponents;
+using Tizen.Security;
+
+using Tizen;
+using Tizen.Multimedia;
+
+namespace AIAvatar
+{
+    partial class Program : NUIApplication
+    {
+        private Window window;
+        private Tizen.NUI.Size windowSize;
+        private AvatarScene avatarScene;
+        private View circleMaskView;
+
+        private UIControlPanel uiControlPanel;
+
+        protected override void OnCreate()
+        {
+            base.OnCreate();
+            Initialize();
+        }
+
+        private void Initialize()
+        {
+            //var asyncAudioCapture = new AsyncAudioCapture(24000, AudioChannel.Mono, AudioSampleType.S16Le);
+
+            window = NUIApplication.GetDefaultWindow();
+            window.BackgroundColor = new Color(0.85f, 0.85f, 0.85f, 1.0f); ;
+
+            window.AddAvailableOrientation(Window.WindowOrientation.Landscape);
+            window.AddAvailableOrientation(Window.WindowOrientation.Portrait);
+            window.AddAvailableOrientation(Window.WindowOrientation.LandscapeInverse);
+            window.AddAvailableOrientation(Window.WindowOrientation.PortraitInverse);
+
+            window.Resized += OnResizedEvent;
+            window.KeyEvent += OnKeyEvent;
+
+            MakeBackground();
+            MakeAvatarScene();
+            MakeUIPanel();
+
+            RecalculatePositionSizeFromWindowSize();
+        }
+
+        private void OnResizedEvent(object sender, Window.ResizedEventArgs e)
+        {
+            RecalculatePositionSizeFromWindowSize();
+        }
+
+        private void MakeBackground()
+        {
+            var backgroundView = new View()
+            {
+                WidthResizePolicy = ResizePolicyType.FillToParent,
+                HeightResizePolicy = ResizePolicyType.FillToParent,
+                BackgroundImage = Tizen.Applications.Application.Current.DirectoryInfo.Resource + "images/UI_BG.png",
+            };
+            backgroundView.TouchEvent += (o, e) =>
+            {
+                if (e.Touch.GetState(0) == PointStateType.Down)
+                {
+                    Tizen.Log.Error("NUI", $"Background touched.\n");
+                }
+                return true;
+            };
+            window.Add(backgroundView);
+        }
+
+        private void MakeAvatarScene()
+        {
+            avatarScene = new AvatarScene();
+            avatarScene.UseFramebuffer = true;
+
+            avatarScene.SetAlphaMaskUrl(Tizen.Applications.Application.Current.DirectoryInfo.Resource + "images/contact-cards-mask.png");
+            avatarScene.EnableCropToMask(false);
+            //window.Add(avatarScene);
+            
+            circleMaskView = new View()
+            {
+                Size = new Tizen.NUI.Size(),
+                Position = new Position(0, 0),
+                BackgroundColor = new Tizen.NUI.Color(0.0f, 0.0f, 0.0f, 0.0f),//new Tizen.NUI.Color("#221F1F"),
+            };
+            window.Add(circleMaskView);
+            circleMaskView.Add(avatarScene);
+
+            //circleMaskView.ClippingMode = ClippingModeType.ClipChildren;
+            //circleMaskView.CornerRadius = new Vector4(0.5f,0.5f,0.5f,0.5f);
+            circleMaskView.CornerRadiusPolicy = VisualTransformPolicyType.Relative;
+        }
+
+        private void MakeUIPanel()
+        {
+            uiControlPanel = new UIControlPanel();
+            uiControlPanel.OnExitButtonClicked += OnExitButtonClicked;
+            uiControlPanel.MakeControlPannel(window, avatarScene);
+        }
+
+        private void OnExitButtonClicked(object sender, EventArgs e)
+        {
+            ExitApplication();
+        }
+
+        private void RecalculatePositionSizeFromWindowSize()
+        {
+            uiControlPanel.ReizeUIPanel(avatarScene, circleMaskView);
+        }
+
+        private void OnKeyEvent(object sender, Window.KeyEventArgs e)
+        {
+            
+            if (e.Key.State != Key.StateType.Down)
+            {
+                return;
+            }
+
+            if (e.Key.KeyPressedName == "Escape" || e.Key.KeyPressedName == "XF86Back" || e.Key.KeyPressedName == "BackSpace")
+            {
+                ExitApplication();
+            }
+        }
+
+        private void ExitApplication()
+        {
+            Utils.FullGC();
+            Exit();
+        }
+
+        static void Main(string[] args)
+        {
+            var app = new Program();
+            app.Run(args);
+        }
+    }
+}
diff --git a/test/Tizen.AIAvatar.Example/src/Styles.cs b/test/Tizen.AIAvatar.Example/src/Styles.cs
new file mode 100644 (file)
index 0000000..ca0e7e3
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * Copyright(c) 2023 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+using Tizen.NUI;
+
+namespace AIAvatar
+{
+    public static class Styles
+    {
+        public static readonly Color BIG_TAG_NORMAL_BACKGROUND_COLOR1 = new Color(0xFF / 255.0f, 0xFE / 255.0f, 0xFE / 255.0f, 0.8f);
+        public static readonly Color BIG_TAG_NORMAL_BACKGROUND_COLOR2 = new Color(0xDB / 255.0f, 0xE3 / 255.0f, 0xFF / 255.0f, 0.8f);
+        public static readonly Color BIG_TAG_FOCUS_BACKGROUND_COLOR1 = new Color(0xD9 / 255.0f, 0xE1 / 255.0f, 0xFF / 255.0f, 0.8f);
+        public static readonly Color BIG_TAG_FOCUS_BACKGROUND_COLOR2 = new Color(0xB2 / 255.0f, 0xC4 / 255.0f, 0xFF / 255.0f, 0.8f);
+        public static readonly Color BIG_TAG_NORMAL_SHADOW_COLOR = new Color(62.0f / 255.0f, 62.0f / 255.0f, 62.0f / 255.0f, 0.8f);
+    }
+}
diff --git a/test/Tizen.AIAvatar.Example/src/Utils.cs b/test/Tizen.AIAvatar.Example/src/Utils.cs
new file mode 100644 (file)
index 0000000..4eff516
--- /dev/null
@@ -0,0 +1,19 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace AIAvatar
+{
+    public static class Utils
+    {
+        static public string LogTag = "AvatarSample";
+        static public string TTSText = "Select an avatar that will guide you through the functions of your age.";
+        static public string ResourcePath = Tizen.Applications.Application.Current.DirectoryInfo.Resource;
+        static public void FullGC()
+        {
+            global::System.GC.Collect();
+            global::System.GC.WaitForPendingFinalizers();
+            global::System.GC.Collect();
+        }
+    }
+}
diff --git a/test/Tizen.AIAvatar.Example/tizen-manifest.xml b/test/Tizen.AIAvatar.Example/tizen-manifest.xml
new file mode 100644 (file)
index 0000000..106b7a3
--- /dev/null
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns="http://tizen.org/ns/packages" api-version="7.0" package="AIAvatarSample" version="1.0.0">
+  <profile name="common" />
+  <ui-application appid="AIAvatar.Sample"
+                                        exec="AIAvatarSample.dll"
+                                        type="dotnet"
+                                        multiple="false"
+                                        taskmanage="true"
+                                        nodisplay="false"
+                                        launch_mode="single"
+                    api-version="10">
+    <label>Tizen.AIAvatar</label>
+    <icon>Tizen.AIAvatar.png</icon>
+    <metadata key="http://tizen.org/metadata/prefer_dotnet_aot" value="true" />
+  </ui-application>
+  <privileges>
+      <privilege>http://tizen.org/privilege/internet</privilege>
+      <privilege>http://tizen.org/privilege/window.priority.set</privilege>
+      <privilege>http://tizen.org/privilege/filesystem.read</privilege>
+      <privilege>http://tizen.org/privilege/recorder</privilege>
+  </privileges>
+</manifest>