TizenRefApp-8394 Implement playing of audio files in conversation 41/125741/1
authorDenis Dolzhenko <d.dolzhenko@samsung.com>
Tue, 18 Apr 2017 13:06:36 +0000 (16:06 +0300)
committerDenis Dolzhenko <d.dolzhenko@samsung.com>
Tue, 18 Apr 2017 13:06:36 +0000 (16:06 +0300)
Change-Id: I7988bd772b8634ad3a16e61bc0d88051d44cf4f7
Signed-off-by: Denis Dolzhenko <d.dolzhenko@samsung.com>
21 files changed:
.cproject
res/dummy_res/1.mp3 [new file with mode: 0644]
res/dummy_res/2.mp3 [new file with mode: 0644]
res/edje/conv_list_bubble.edc
src/Common/MsgEngine/src/dummy/MsgConvMediaDummy.cpp
src/Common/Utils/inc/MediaPlayer.h [new file with mode: 0644]
src/Common/Utils/inc/MediaPlayerProvider.h [new file with mode: 0644]
src/Common/Utils/src/MediaPlayer.cpp [new file with mode: 0644]
src/Common/Utils/src/MediaPlayerProvider.cpp [new file with mode: 0644]
src/Common/Utils/src/MediaUtils.cpp
src/Conversation/Controller/inc/BubbleAudioEntity.h [new file with mode: 0644]
src/Conversation/Controller/inc/BubbleEntity.h
src/Conversation/Controller/inc/BubbleEntityFactory.h
src/Conversation/Controller/inc/BubbleVoiceEntity.h [deleted file]
src/Conversation/Controller/src/BubbleAudioEntity.cpp [new file with mode: 0644]
src/Conversation/Controller/src/BubbleEntityFactory.cpp
src/Conversation/Controller/src/ConvListItem.cpp
src/Conversation/View/inc/BubbleAudioViewItem.h [new file with mode: 0644]
src/Conversation/View/inc/BubbleVoiceViewItem.h [deleted file]
src/Conversation/View/src/BubbleAudioViewItem.cpp [new file with mode: 0644]
src/Conversation/View/src/BubbleVoiceViewItem.cpp [deleted file]

index 2ed3781a00afd7b7c4ae91031b122544fd2644e3..61d61eb2fe75ee8ee1236f1a1d541f76281fd909 100644 (file)
--- a/.cproject
+++ b/.cproject
                                                                        <listOptionValue builtIn="false" value="Native_API"/>
                                                                </option>
                                                                <option id="gnu.cpp.compiler.option.dialect.std.1756711526" name="Language standard" superClass="gnu.cpp.compiler.option.dialect.std" useByScannerDiscovery="true" value="gnu.cpp.compiler.dialect.c++11" valueType="enumerated"/>
-                                                               <option id="gnu.cpp.compiler.option.preprocessor.def.1776859471" name="Defined symbols (-D)" superClass="gnu.cpp.compiler.option.preprocessor.def" useByScannerDiscovery="false" valueType="definedSymbols">
-                                                                       <listOptionValue builtIn="false" value="MSG_PRIVATE_API"/>
-                                                               </option>
+                                                               <option id="gnu.cpp.compiler.option.preprocessor.def.1776859471" name="Defined symbols (-D)" superClass="gnu.cpp.compiler.option.preprocessor.def" useByScannerDiscovery="false" valueType="definedSymbols"/>
                                                                <option id="gnu.cpp.compiler.option.other.other.1256197611" name="Other flags" superClass="gnu.cpp.compiler.option.other.other" value="-c -fmessage-length=0 -Wno-extern-c-compat" valueType="string"/>
                                                                <inputType id="cdt.managedbuild.tool.gnu.cpp.compiler.input.1529131313" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.input"/>
                                                        </tool>
                                                                        <listOptionValue builtIn="false" value="Native_API"/>
                                                                </option>
                                                                <option id="gnu.cpp.compiler.option.dialect.std.177145679" name="Language standard" superClass="gnu.cpp.compiler.option.dialect.std" value="gnu.cpp.compiler.dialect.c++11" valueType="enumerated"/>
-                                                               <option id="gnu.cpp.compiler.option.preprocessor.def.889877088" name="Defined symbols (-D)" superClass="gnu.cpp.compiler.option.preprocessor.def" valueType="definedSymbols">
-                                                                       <listOptionValue builtIn="false" value="MSG_PRIVATE_API"/>
-                                                               </option>
+                                                               <option id="gnu.cpp.compiler.option.preprocessor.def.889877088" name="Defined symbols (-D)" superClass="gnu.cpp.compiler.option.preprocessor.def" valueType="definedSymbols"/>
                                                                <option id="gnu.cpp.compiler.option.other.other.645149247" name="Other flags" superClass="gnu.cpp.compiler.option.other.other" value="-c -fmessage-length=0 -Wno-extern-c-compat" valueType="string"/>
                                                                <inputType id="cdt.managedbuild.tool.gnu.cpp.compiler.input.1209285457" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.input"/>
                                                        </tool>
diff --git a/res/dummy_res/1.mp3 b/res/dummy_res/1.mp3
new file mode 100644 (file)
index 0000000..e1c0445
Binary files /dev/null and b/res/dummy_res/1.mp3 differ
diff --git a/res/dummy_res/2.mp3 b/res/dummy_res/2.mp3
new file mode 100644 (file)
index 0000000..5c1a40b
Binary files /dev/null and b/res/dummy_res/2.mp3 differ
index 23ff55c981cd025fcbfba31fadcc7ff78b082a4c..b43e98ee5cda1721db7461babfdfb669bcd390a3 100644 (file)
@@ -221,7 +221,7 @@ collections {
       }
    }
    group {
-      name: "conv/list/voice_item";
+      name: "conv/list/audio_item";
       images {
          image: "msg_received.#.png" COMP;
          image: "msg_received_play.png" COMP;
@@ -372,7 +372,7 @@ collections {
                color: 0 0 0 255;
             }
             description {
-               state: "play" 0.0;
+               state: "pause" 0.0;
                inherit: "default" 0.0;
                image.normal: "msg_received_pause.png";
             }
@@ -435,14 +435,14 @@ collections {
             name: "play";
             signal: "sound,play";
             source: "";
-            action: STATE_SET "play" 0.0;
+            action: STATE_SET "default" 0.0;
             target: "icon";
          }
          program {
             name: "pause";
             signal: "sound,pause";
             source: "";
-            action: STATE_SET "default" 0.0;
+            action: STATE_SET "pause" 0.0;
             target: "icon";
          }
       }
index 8f84a65a8039d817f09c09e4df05204915e4672b..d2a4217411ff8190d8f0f56adccce0e63168da1f 100644 (file)
@@ -21,7 +21,8 @@
 using namespace Msg;
 
 const std::vector<std::string> fileNames = {"cat.png", "Calendar1.vcs", "Contact.vcf",
-                                            "big.txt", "call.csv", "phone.jpg", "table.3gp", "Voice.m4a"};
+                                            "big.txt", "call.csv", "phone.jpg", "table.3gp",
+                                            "Voice.m4a", "1.mp3", "2.mp3"};
 
 MsgConvMediaDummy::MsgConvMediaDummy(bool release)
     : MsgStructDummy(release)
diff --git a/src/Common/Utils/inc/MediaPlayer.h b/src/Common/Utils/inc/MediaPlayer.h
new file mode 100644 (file)
index 0000000..27662bc
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2016  Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://floralicense.org/license/
+ *
+ * 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.
+ */
+
+#ifndef MediaPlayer_h_
+#define MediaPlayer_h_
+
+#include <player.h>
+#include <sound_manager.h>
+#include <string>
+#include <Evas.h>
+
+namespace Msg {
+    class IMediaPlayerListener;
+
+    class MediaPlayer {
+        public:
+            MediaPlayer();
+            ~MediaPlayer();
+            MediaPlayer(const MediaPlayer&) = delete;
+            MediaPlayer& operator=(const MediaPlayer&) = delete;
+
+            void setDisplay(Evas_Object *obj);
+            bool start();
+            void stop();
+            void pause();
+            bool isPlaying() const;
+            void setUri(const std::string &uri);
+            void setListener(IMediaPlayerListener *l);
+            int getDuration() const; // msec
+            static int getDuration(const std::string &uri);
+            void setPosition(int msec);
+            int getPosition() const; // msec
+            bool getFocus() const;
+
+        private:
+            void onCompleted();
+            void onSeek();
+
+            // Call from media internal thread:
+            void onSoundStreamFocusStateChanged(sound_stream_info_h stream_info,
+                                                sound_stream_focus_mask_e focus_mask,
+                                                sound_stream_focus_state_e focus_state,
+                                                sound_stream_focus_change_reason_e reason,
+                                                int sound_behavior,
+                                                const char *extra_info);
+            player_state_e getState() const;
+            static bool isCallReason(sound_stream_focus_change_reason_e reason);
+
+        private:
+            player_h m_Player;
+            IMediaPlayerListener *m_pListener;
+            sound_stream_info_h m_StreamInfo;
+    };
+
+    class IMediaPlayerListener {
+        public:
+            virtual ~IMediaPlayerListener() {}
+            virtual void onCompleted(MediaPlayer &player) {};
+            virtual void onSoundFocusChanged(MediaPlayer &player) {};
+    };
+}
+
+#endif // MediaPlayer_h_
diff --git a/src/Common/Utils/inc/MediaPlayerProvider.h b/src/Common/Utils/inc/MediaPlayerProvider.h
new file mode 100644 (file)
index 0000000..583db2e
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2016  Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://floralicense.org/license/
+ *
+ * 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.
+ */
+
+#ifndef MediaPlayerProvider_h_
+#define MediaPlayerProvider_h_
+
+#include "MediaPlayer.h"
+#include <memory>
+
+namespace Msg {
+    class IMediaPlayerProviderClient;
+    class MediaPlayerProvider;
+    typedef std::shared_ptr<MediaPlayerProvider> MediaPlayerProviderRef;
+
+    class MediaPlayerProvider {
+        public:
+            MediaPlayerProvider();
+            ~MediaPlayerProvider();
+            MediaPlayerProvider(const MediaPlayerProvider&) = delete;
+            MediaPlayerProvider& operator=(const MediaPlayerProvider&) = delete;
+
+            MediaPlayer &acquire(IMediaPlayerProviderClient *client);
+            void release(IMediaPlayerProviderClient *client);
+            IMediaPlayerProviderClient *getClient() const;
+
+        private:
+            IMediaPlayerProviderClient *m_pClient;
+            std::unique_ptr<MediaPlayer> m_Player;
+    };
+
+    class IMediaPlayerProviderClient {
+        public:
+            virtual ~IMediaPlayerProviderClient() {}
+            virtual void onAcquire(MediaPlayerProvider &provider) {};
+            virtual void onRelease(MediaPlayerProvider &provider) {};
+    };
+}
+
+#endif // MediaPlayerProvider_h_
diff --git a/src/Common/Utils/src/MediaPlayer.cpp b/src/Common/Utils/src/MediaPlayer.cpp
new file mode 100644 (file)
index 0000000..deba347
--- /dev/null
@@ -0,0 +1,211 @@
+/*
+ * Copyright 2016  Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://floralicense.org/license/
+ *
+ * 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.
+ */
+
+#include "MediaPlayer.h"
+#include "Logger.h"
+#include "Callback.h"
+
+#include <Ecore.h>
+
+using namespace Msg;
+
+MediaPlayer::MediaPlayer()
+    : m_Player()
+    , m_pListener(nullptr)
+    , m_StreamInfo()
+{
+    sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA,
+            makeCbLast(&MediaPlayer::onSoundStreamFocusStateChanged), this, &m_StreamInfo);
+    if (m_StreamInfo) {
+        player_create(&m_Player);
+        if (m_Player) {
+            player_set_sound_type(m_Player, SOUND_TYPE_MEDIA);
+            player_set_volume(m_Player, 1.0, 1.0);
+            player_set_looping(m_Player, false);
+            player_set_sound_stream_info(m_Player, m_StreamInfo);
+            player_set_completed_cb(m_Player, makeCbLast(&MediaPlayer::onCompleted), this);
+        }
+    }
+}
+
+MediaPlayer::~MediaPlayer()
+{
+    m_pListener = nullptr;
+    stop();
+
+    if (m_StreamInfo)
+        sound_manager_destroy_stream_information(m_StreamInfo);
+
+    if (m_Player) {
+        player_unprepare(m_Player);
+        player_destroy(m_Player);
+    }
+}
+
+void MediaPlayer::setDisplay(Evas_Object *obj)
+{
+    player_set_display_mode(m_Player, PLAYER_DISPLAY_MODE_LETTER_BOX);
+    player_set_display(m_Player, PLAYER_DISPLAY_TYPE_EVAS, GET_DISPLAY(obj));
+    player_set_display_visible(m_Player, obj != nullptr);
+}
+
+player_state_e MediaPlayer::getState() const
+{
+    player_state_e state = PLAYER_STATE_NONE;
+    player_get_state(m_Player, &state);
+    return state;
+}
+
+bool MediaPlayer::isCallReason(sound_stream_focus_change_reason_e reason)
+{
+    return reason == SOUND_STREAM_FOCUS_CHANGED_BY_RINGTONE ||
+           reason == SOUND_STREAM_FOCUS_CHANGED_BY_VOIP ||
+           reason == SOUND_STREAM_FOCUS_CHANGED_BY_CALL;
+}
+
+bool MediaPlayer::getFocus() const
+{
+    sound_stream_focus_change_reason_e acquiredBy = SOUND_STREAM_FOCUS_CHANGED_BY_MEDIA;
+    int flags = 0;
+    char *extraInfo = nullptr;
+
+    if (sound_manager_get_current_playback_focus(&acquiredBy, &flags, &extraInfo) == SOUND_MANAGER_ERROR_NONE) {
+        free(extraInfo);
+        return !isCallReason(acquiredBy);
+    }
+
+    return true;
+}
+
+bool MediaPlayer::start()
+{
+    sound_manager_acquire_focus(m_StreamInfo, SOUND_STREAM_FOCUS_FOR_PLAYBACK, SOUND_BEHAVIOR_NONE, nullptr);
+    if (getState() == PLAYER_STATE_IDLE)
+        player_prepare(m_Player);
+
+    if (getState() != PLAYER_STATE_PLAYING) {
+        int err = player_start(m_Player);
+    }
+
+    return getState() == PLAYER_STATE_PLAYING;
+}
+
+void MediaPlayer::stop()
+{
+    sound_manager_release_focus(m_StreamInfo, SOUND_STREAM_FOCUS_FOR_PLAYBACK, SOUND_BEHAVIOR_NONE, nullptr);
+    player_state_e state = getState();
+    if (state == PLAYER_STATE_PLAYING || state == PLAYER_STATE_PAUSED)
+        player_stop(m_Player);
+}
+
+void MediaPlayer::pause()
+{
+    if (getState() == PLAYER_STATE_PLAYING)
+        player_pause(m_Player);
+}
+
+bool MediaPlayer::isPlaying() const
+{
+    return getState() == PLAYER_STATE_PLAYING;
+}
+
+void MediaPlayer::setUri(const std::string &uri)
+{
+    stop();
+    player_unprepare(m_Player);
+    player_set_uri(m_Player, uri.c_str());
+}
+
+void MediaPlayer::setListener(IMediaPlayerListener *l)
+{
+    m_pListener = l;
+}
+
+int MediaPlayer::getDuration() const
+{
+    int msec = 0;
+    player_get_duration(m_Player, &msec);
+    return msec;
+}
+
+void MediaPlayer::setPosition(int msec)
+{
+    if (getState() == PLAYER_STATE_IDLE)
+        player_prepare(m_Player);
+
+    player_state_e state = getState();
+    if (state == PLAYER_STATE_PLAYING || state == PLAYER_STATE_PAUSED || state == PLAYER_STATE_READY) {
+        int res = player_set_play_position(m_Player, msec, true, makeCbLast(&MediaPlayer::onSeek), this);
+    }
+}
+
+int MediaPlayer::getPosition() const
+{
+    int msec = 0;
+    player_state_e state = getState();
+    if (state == PLAYER_STATE_PLAYING || state == PLAYER_STATE_PAUSED || state == PLAYER_STATE_READY)
+        player_get_play_position(m_Player, &msec);
+
+    return msec;
+}
+
+int MediaPlayer::getDuration(const std::string &uri)
+{
+    int msec = 0;
+    if (!uri.empty()) {
+        player_h player = {};
+        player_create(&player);
+        if (player_set_uri(player, uri.c_str()) == PLAYER_ERROR_NONE) {
+            player_prepare(player);
+            player_get_duration(player, &msec);
+            player_unprepare(player);
+        }
+        player_destroy(player);
+    }
+    return msec;
+}
+
+void MediaPlayer::onCompleted()
+{
+    stop();
+    if (m_pListener)
+        m_pListener->onCompleted(*this);
+}
+
+void MediaPlayer::onSeek()
+{
+    MSG_LOG("");
+}
+
+void MediaPlayer::onSoundStreamFocusStateChanged(sound_stream_info_h stream_info,
+                                                 sound_stream_focus_mask_e focus_mask,
+                                                 sound_stream_focus_state_e focus_state,
+                                                 sound_stream_focus_change_reason_e reason,
+                                                 int sound_behavior,
+                                                 const char *extra_info)
+{
+    MSG_LOG("Interrupted focus change reason = ", reason);
+    if (isCallReason(reason)) {
+        ecore_main_loop_thread_safe_call_async(
+        [](void *data)
+        {
+            auto *self = (MediaPlayer*)data;
+            if (self->m_pListener)
+                self->m_pListener->onSoundFocusChanged(*self);
+        },
+        this);
+    }
+}
diff --git a/src/Common/Utils/src/MediaPlayerProvider.cpp b/src/Common/Utils/src/MediaPlayerProvider.cpp
new file mode 100644 (file)
index 0000000..d9cf321
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2016  Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://floralicense.org/license/
+ *
+ * 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.
+ */
+
+#include "MediaPlayerProvider.h"
+
+using namespace Msg;
+
+MediaPlayerProvider::MediaPlayerProvider()
+    : m_pClient(nullptr)
+{
+}
+
+MediaPlayerProvider::~MediaPlayerProvider()
+{
+}
+
+MediaPlayer &MediaPlayerProvider::acquire(IMediaPlayerProviderClient *client)
+{
+    if (!m_Player)
+        m_Player.reset(new MediaPlayer);
+
+    if (m_pClient != client) {
+        release(m_pClient);
+
+        m_pClient = client;
+
+        if (m_pClient)
+            m_pClient->onAcquire(*this);
+    }
+
+    return *m_Player;
+}
+
+void MediaPlayerProvider::release(IMediaPlayerProviderClient *client)
+{
+    if (m_pClient == client && m_Player) {
+
+        IMediaPlayerProviderClient *client = m_pClient;
+        m_pClient = nullptr;
+
+        if (client)
+            client->onRelease(*this);
+
+        m_Player->stop();
+        m_Player->setListener(nullptr);
+    }
+}
+
+IMediaPlayerProviderClient *MediaPlayerProvider::getClient() const
+{
+    return m_pClient;
+}
index ff0d65d3c7128e95383f2a01dda359dad7f25957..6bc29c4a58385cb5664475cc7c8dd990863ac5fc 100644 (file)
@@ -111,8 +111,7 @@ int getDuration(const std::string &uri)
 {
     MetadataExtractor extractor(uri);
     int duration = 0;
-    if (extractor.isValid())
-    {
+    if (extractor.isValid()) {
         duration = extractor.getInt(METADATA_DURATION);
         MSG_LOG("Duration msec: ", duration);
     }
diff --git a/src/Conversation/Controller/inc/BubbleAudioEntity.h b/src/Conversation/Controller/inc/BubbleAudioEntity.h
new file mode 100644 (file)
index 0000000..457e1ba
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2016 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://floralicense.org/license/
+ *
+ * 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.
+ */
+
+#ifndef BubbleAudioEntity_h_
+#define BubbleAudioEntity_h_
+
+#include "BubbleAudioViewItem.h"
+#include "BubbleEntity.h"
+#include "MediaPlayerProvider.h"
+
+#include <Ecore.h>
+
+namespace Msg {
+    class BubbleAudioEntity
+        : public BubbleEntity
+        , private IMediaPlayerProviderClient
+        , private IMediaPlayerListener {
+
+        public:
+            BubbleAudioEntity(MediaPlayerProviderRef mediaPlayerProvider,
+                             std::string filePath,
+                             std::string fileName,
+                             Message::Direction direction);
+
+            virtual ~BubbleAudioEntity();
+
+            void clickHandler();
+            BubbleAudioViewItem *createView(Evas_Object *parent) override;
+
+        private:
+            // View:
+            void onViewDel(Evas *e, Evas_Object *obj, void *event_info);
+
+            // IMediaPlayerProviderClient:
+            void onAcquire(MediaPlayerProvider &provider) override;
+            void onRelease(MediaPlayerProvider &provider) override;
+
+            // IMediaPlayerListener:
+            void onCompleted(MediaPlayer &player) override;
+            void onSoundFocusChanged(MediaPlayer &player) override;
+
+            // Timer:
+            Eina_Bool onTick();
+
+            struct PlayInfo {
+                std::string uri;
+                int duration; // msec
+                int playPos;  // msec
+                bool isPlaying;
+            };
+
+            void play();
+            void stop();
+            void stopHandler();
+            void stopTimer();
+            void startTimer();
+            void updateProgress();
+            void updatePlayState();
+
+        private:
+            MediaPlayerProviderRef m_MediaPlayerProvider;
+            BubbleAudioViewItem *m_pView;
+            Ecore_Timer *m_pTimer;
+            MediaPlayer *m_pPlayer;
+            PlayInfo m_PlayInfo;
+            std::string m_FileName;
+            std::string m_DurationStr;
+    };
+}
+
+#endif /* BubbleAudioEntity_h_ */
index ea66ce1320976fe5549384c67d0a562e02a3cd26..97e0ab2255b500ab95dbaaf0fc98f096741f752f 100644 (file)
@@ -36,7 +36,6 @@ namespace Msg {
                 SubjectItem,
                 TextItem,
                 ImageItem,
-                VoiceItem,
                 AudioItem,
                 VideoItem,
                 ContactItem,
@@ -47,7 +46,7 @@ namespace Msg {
             };
 
         public:
-            BubbleEntity(Type type, Message::Direction direction, const std::string &filePath = "");
+            BubbleEntity(Type type, Message::Direction direction, std::string filePath = "");
             virtual ~BubbleEntity();
 
             Type getType() const;
@@ -64,10 +63,10 @@ namespace Msg {
             long long m_FileSize;
     };
 
-    inline BubbleEntity::BubbleEntity(Type type, Message::Direction direction, const std::string &filePath)
+    inline BubbleEntity::BubbleEntity(Type type, Message::Direction direction, std::string filePath)
         : m_Type(type)
         , m_Direction(direction)
-        , m_FilePath(filePath)
+        , m_FilePath(std::move(filePath))
         , m_FileSize(!filePath.empty() ? FileUtils::getFileSize(filePath) : 0)
     {
     }
index 137378a6cb03a4cff1323ea1af0caf5032acab0b..1c3628cab534c9b6e9ed6b34f8cbed4acabd6bf0 100644 (file)
@@ -21,6 +21,7 @@
 #include "MsgConversationItem.h"
 #include "WorkingDir.h"
 #include "BubbleEntity.h"
+#include "MediaPlayerProvider.h"
 
 #include <string>
 #include <list>
@@ -35,6 +36,7 @@ namespace Msg {
     class BubbleCalEventEntity;
     class BubbleContactEntity;
     class BubbleNoContentEntity;
+    class MediaPlayer;
 
     class BubbleEntityFactory {
         public:
@@ -51,12 +53,13 @@ namespace Msg {
             BubbleEntity *createTextEntityFromFile(std::string filePath, Message::Direction direction);
             BubbleEntity *createSubjectEntity(const std::string subject, Message::Direction direction);
             BubbleEntity *createVideoEntity(std::string filePath, std::string fileName, Message::Direction direction);
-            BubbleEntity *createVoiceEntity(std::string filePath, std::string fileName, Message::Direction direction);
+            BubbleEntity *createAudioEntity(std::string filePath, std::string fileName, Message::Direction direction);
             BubbleEntityFactory(BubbleEntityFactory&) = delete;
             BubbleEntityFactory& operator=(const BubbleEntityFactory&) = delete;
 
         private:
             WorkingDirRef m_WorkingDir;
+            MediaPlayerProviderRef m_MediaPlayerProvider;
     };
 }
 
diff --git a/src/Conversation/Controller/inc/BubbleVoiceEntity.h b/src/Conversation/Controller/inc/BubbleVoiceEntity.h
deleted file mode 100644 (file)
index 66acb37..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright 2016 Samsung Electronics Co., Ltd
- *
- * Licensed under the Flora License, Version 1.1 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://floralicense.org/license/
- *
- * 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.
- */
-
-#ifndef BubbleVoiceEntity_h_
-#define BubbleVoiceEntity_h_
-
-#include "BubbleEntity.h"
-#include "BubbleVoiceViewItem.h"
-
-namespace Msg {
-    class BubbleVoiceEntity
-        : public BubbleEntity {
-        public:
-            BubbleVoiceEntity(const std::string &filePath, const std::string fileName, Message::Direction direction);
-            virtual ~BubbleVoiceEntity();
-
-            BubbleVoiceViewItem *createView(Evas_Object *parent) override;
-
-        private:
-            std::string m_FileName;
-    };
-    inline BubbleVoiceEntity::BubbleVoiceEntity(const std::string &filePath, const std::string fileName, Message::Direction direction)
-        : BubbleEntity(VoiceItem, direction, filePath)
-        , m_FileName(std::move(fileName))
-    {
-    }
-
-    inline BubbleVoiceEntity::~BubbleVoiceEntity()
-    {
-    }
-
-    inline BubbleVoiceViewItem *BubbleVoiceEntity::createView(Evas_Object *parent)
-    {
-        auto *item = new BubbleVoiceViewItem(parent, *this);
-        item->setMainText(m_FileName);
-        return item;
-    }
-}
-
-#endif /* BubbleVoiceEntity_h_ */
diff --git a/src/Conversation/Controller/src/BubbleAudioEntity.cpp b/src/Conversation/Controller/src/BubbleAudioEntity.cpp
new file mode 100644 (file)
index 0000000..a6561e5
--- /dev/null
@@ -0,0 +1,186 @@
+/*
+ * Copyright 2016 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://floralicense.org/license/
+ *
+ * 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.
+ */
+
+#include "BubbleAudioEntity.h"
+#include "MediaUtils.h"
+#include "Logger.h"
+
+#include <sstream>
+#include <iomanip>
+#include <math.h>
+
+using namespace Msg;
+
+namespace {
+    std::string makeDurationStr(int msec)
+    {
+        std::stringstream ss;
+        int sec = ceil(msec / 1000.0);
+        int h = sec / 60;
+        int m = sec % 60;
+        ss << std::setfill('0') << std::setw(2) << h << ':'
+           << std::setfill('0') << std::setw(2) << m;
+        return ss.str();
+    }
+}
+
+BubbleAudioEntity::BubbleAudioEntity(MediaPlayerProviderRef mediaPlayerProvider,
+                                    std::string filePath,
+                                    std::string fileName,
+                                    Message::Direction direction)
+    : BubbleEntity(AudioItem, direction, filePath)
+    , m_MediaPlayerProvider(mediaPlayerProvider)
+    , m_pView(nullptr)
+    , m_pTimer(nullptr)
+    , m_pPlayer(nullptr)
+    , m_PlayInfo {}
+    , m_FileName(std::move(fileName))
+    , m_DurationStr()
+{
+    m_PlayInfo.uri = std::move(filePath);
+    m_PlayInfo.duration = MediaUtils::getDuration(m_PlayInfo.uri);
+    m_PlayInfo.isPlaying = false;
+    m_PlayInfo.playPos = 0;
+
+    m_DurationStr = makeDurationStr(m_PlayInfo.duration);
+}
+
+BubbleAudioEntity::~BubbleAudioEntity()
+{
+    stop();
+}
+
+void BubbleAudioEntity::clickHandler()
+{
+    if (m_pPlayer && m_pPlayer->isPlaying())
+        stop();
+    else
+        play();
+}
+
+void BubbleAudioEntity::play()
+{
+    m_pPlayer = &m_MediaPlayerProvider->acquire(this);
+    m_pPlayer->setListener(this);
+    m_pPlayer->setUri(getFilePath());
+
+    if (m_pPlayer->start()) {
+        m_PlayInfo.isPlaying = true;
+        // Warning setPosition() works only after start();
+        if (m_PlayInfo.playPos > 0)
+            m_pPlayer->setPosition(m_PlayInfo.playPos);
+        startTimer();
+        updateProgress();
+        updatePlayState();
+    }
+}
+
+void BubbleAudioEntity::stop()
+{
+    m_MediaPlayerProvider->release(this);
+}
+
+void BubbleAudioEntity::stopHandler()
+{
+    m_PlayInfo.isPlaying = false;
+    m_PlayInfo.playPos = m_pPlayer ?  m_pPlayer->getPosition() : 0;
+    stopTimer();
+    updatePlayState();
+    updateProgress();
+}
+
+BubbleAudioViewItem *BubbleAudioEntity::createView(Evas_Object *parent)
+{
+    m_pView = new BubbleAudioViewItem(parent, *this);
+    m_pView->addEventCb(EVAS_CALLBACK_DEL, makeCbFirst(&BubbleAudioEntity::onViewDel), this);
+    m_pView->setMainText(m_FileName);
+    m_pView->setTimeText(m_DurationStr);
+    updateProgress();
+    updatePlayState();
+    return m_pView;
+}
+
+void BubbleAudioEntity::startTimer()
+{
+    static const double timeInterval = 0.01;
+    if (!m_pTimer)
+        m_pTimer = ecore_timer_add(timeInterval, makeCbFirst(&BubbleAudioEntity::onTick), this);
+}
+
+void BubbleAudioEntity::stopTimer()
+{
+    if (m_pTimer) {
+        ecore_timer_del(m_pTimer);
+        m_pTimer = nullptr;
+    }
+}
+
+void BubbleAudioEntity::updateProgress()
+{
+    if (m_pView) {
+        double pos = m_PlayInfo.playPos;
+        double dur = m_PlayInfo.duration;
+        double relPos = dur > 0.0 ?  pos / dur : 0.0;
+        m_pView->setProgress(relPos);
+    }
+}
+
+void BubbleAudioEntity::updatePlayState()
+{
+    if (m_pView) {
+        auto state = m_PlayInfo.isPlaying ? BubbleAudioViewItem::PauseState :
+                                            BubbleAudioViewItem::PlayState;
+        m_pView->setState(state);
+    }
+}
+
+Eina_Bool BubbleAudioEntity::onTick()
+{
+    m_PlayInfo.playPos = m_pPlayer ? m_pPlayer->getPosition() : 0;
+    updateProgress();
+    return true;
+}
+
+void BubbleAudioEntity::onViewDel(Evas *e, Evas_Object *obj, void *event_info)
+{
+    if (m_pView && obj == *m_pView)
+        m_pView = nullptr;
+}
+
+void BubbleAudioEntity::onAcquire(MediaPlayerProvider &provider)
+{
+    MSG_LOG(this);
+}
+
+void BubbleAudioEntity::onRelease(MediaPlayerProvider &provider)
+{
+    MSG_LOG(this);
+    stopHandler();
+    m_pPlayer = nullptr;
+}
+
+void BubbleAudioEntity::onCompleted(MediaPlayer &player)
+{
+    MSG_LOG(this);
+    stopHandler();
+}
+
+void BubbleAudioEntity::onSoundFocusChanged(MediaPlayer &player)
+{
+    MSG_LOG(this);
+    stopHandler();
+}
+
index 675684587962173744d90ba24fb5927aed8e47d2..e0611c6b11fd2205dded8f22c708ec535dc1a520 100644 (file)
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include <BubbleAudioEntity.h>
 #include "BubbleEntityFactory.h"
 #include "FileUtils.h"
 #include "MediaType.h"
@@ -28,7 +29,6 @@
 #include "BubbleCalEventEntity.h"
 #include "BubbleContactEntity.h"
 #include "BubbleNoContentEntity.h"
-#include "BubbleVoiceEntity.h"
 #include "BubbleUnknownFileEntity.h"
 #include "BubbleSubjectEntity.h"
 
@@ -38,6 +38,7 @@ using namespace Msg;
 
 BubbleEntityFactory::BubbleEntityFactory(WorkingDirRef &workingDir)
     : m_WorkingDir(workingDir)
+    , m_MediaPlayerProvider(std::make_shared<MediaPlayerProvider>())
 {
 }
 
@@ -111,7 +112,7 @@ BubbleEntity *BubbleEntityFactory::createEntity(const MsgConvMedia &msgMedia, Me
         case MsgMedia::ImageType:
             return new BubbleImageEntity(std::move(filePath), direction);
         case MsgMedia::AudioType:
-            return createVoiceEntity(std::move(filePath), std::move(fileName), direction);
+            return createAudioEntity(std::move(filePath), std::move(fileName), direction);
         case MsgMedia::VideoType:
             return createVideoEntity(std::move(filePath), std::move(fileName), direction);
         default:
@@ -145,13 +146,13 @@ BubbleNoContentEntity *BubbleEntityFactory::createNoContentEntity(Message::Direc
     return new BubbleNoContentEntity(direction);
 }
 
-BubbleEntity *BubbleEntityFactory::createVoiceEntity(std::string filePath, std::string fileName, Message::Direction direction)
+BubbleEntity *BubbleEntityFactory::createAudioEntity(std::string filePath, std::string fileName, Message::Direction direction)
 {
     if (MediaUtils::hasAudio(filePath))
-        return new BubbleVoiceEntity(filePath, fileName, direction);
+        return new BubbleAudioEntity(m_MediaPlayerProvider, std::move(filePath), std::move(fileName), direction);
 
     // File does not contain audio or broken:
-    return new BubbleUnknownFileEntity(filePath, fileName, direction);
+    return new BubbleUnknownFileEntity(std::move(filePath), std::move(fileName), direction);
 }
 
 BubbleEntity *BubbleEntityFactory::createVideoEntity(std::string filePath, std::string fileName, Message::Direction direction)
@@ -160,7 +161,7 @@ BubbleEntity *BubbleEntityFactory::createVideoEntity(std::string filePath, std::
            return new BubbleVideoEntity(m_WorkingDir, std::move(filePath), direction);
 
     // Try to create Audio entity.
-    return createVoiceEntity(std::move(filePath), std::move(fileName), direction);
+    return createAudioEntity(std::move(filePath), std::move(fileName), direction);
 }
 
 BubbleEntity *BubbleEntityFactory::createTextEntityFromFile(std::string filePath, Message::Direction direction)
index e8c33a9d581f4106e692ffea66a82328b30efabd..03f14dc083ae78adfbc0b9a7166b24f9c2b84872 100644 (file)
@@ -29,6 +29,7 @@
 #include "ToastPopup.h"
 #include "IconTextPopup.h"
 #include "Callback.h"
+#include "BubbleAudioEntity.h"
 
 #include <algorithm>
 
@@ -176,7 +177,11 @@ std::string ConvListItem::getMsgType()
 void ConvListItem::onAction(BubbleViewItem &item)
 {
     MSG_LOG("");
-    // TODO: iml.
+    if (auto *audio = dynamic_cast<BubbleAudioEntity*>(&item.getEntity())) {
+        audio->clickHandler();
+    } else {
+        // TODO: impl.
+    }
 }
 
 
diff --git a/src/Conversation/View/inc/BubbleAudioViewItem.h b/src/Conversation/View/inc/BubbleAudioViewItem.h
new file mode 100644 (file)
index 0000000..d88a526
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2016 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://floralicense.org/license/
+ *
+ * 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.
+ */
+
+#ifndef BubbleAudioViewItem_h_
+#define BubbleAudioViewItem_h_
+
+#include "BubbleViewItem.h"
+
+namespace Msg {
+    class BubbleAudioViewItem
+        : public BubbleViewItem {
+
+        public:
+            enum State {
+                PlayState,
+                PauseState
+            };
+
+        public:
+            BubbleAudioViewItem(Evas_Object *parent, BubbleEntity &entity);
+            virtual ~BubbleAudioViewItem();
+
+            void setMainText(const std::string &text);
+            void setTimeText(const std::string &text);
+            void setProgress(double progress);
+            void setState(State state);
+
+            void calculate() override;
+
+        private:
+            Evas_Object *m_pItemLayout;
+    };
+}
+
+#endif /* BubbleAudioViewItem_h_ */
diff --git a/src/Conversation/View/inc/BubbleVoiceViewItem.h b/src/Conversation/View/inc/BubbleVoiceViewItem.h
deleted file mode 100644 (file)
index a54f817..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright 2016 Samsung Electronics Co., Ltd
- *
- * Licensed under the Flora License, Version 1.1 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://floralicense.org/license/
- *
- * 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.
- */
-
-#ifndef BubbleVoiceViewItem_h_
-#define BubbleVoiceViewItem_h_
-
-#include "BubbleViewItem.h"
-
-namespace Msg {
-    class BubbleVoiceViewItem
-        : public BubbleViewItem {
-        public:
-            BubbleVoiceViewItem(Evas_Object *parent, BubbleEntity &entity);
-            virtual ~BubbleVoiceViewItem();
-
-            void setMainText(const std::string &text);
-            void setTimeText(const std::string &text);
-            void setProgress(const double progress);
-            void calculate() override;
-
-        private:
-            Evas_Object *m_pVoiceItemLayout;
-    };
-}
-
-#endif /* BubbleVoiceViewItem_h_ */
diff --git a/src/Conversation/View/src/BubbleAudioViewItem.cpp b/src/Conversation/View/src/BubbleAudioViewItem.cpp
new file mode 100644 (file)
index 0000000..bfed2ed
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2016  Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://floralicense.org/license/
+ *
+ * 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.
+ */
+
+#include "BubbleAudioViewItem.h"
+#include "Resource.h"
+#include "TextDecorator.h"
+#include "PathUtils.h"
+
+using namespace Msg;
+
+BubbleAudioViewItem::BubbleAudioViewItem(Evas_Object *parent, BubbleEntity &entity)
+    : BubbleViewItem(parent, entity)
+    , m_pItemLayout(nullptr)
+{
+    m_pItemLayout = addLayout(getEo(), CONV_LIST_BUBBLE_EDJ_PATH, "conv/list/audio_item");
+    setContent(m_pItemLayout);
+}
+
+BubbleAudioViewItem::~BubbleAudioViewItem()
+{
+}
+
+void BubbleAudioViewItem::setMainText(const std::string &text)
+{
+    elm_object_part_text_set(m_pItemLayout, "text.filename", text.c_str());
+}
+
+void BubbleAudioViewItem::setTimeText(const std::string &text)
+{
+    elm_object_part_text_set(m_pItemLayout, "text.time", text.c_str());
+}
+
+void BubbleAudioViewItem::setProgress(const double progress)
+{
+    edje_object_part_drag_value_set(elm_layout_edje_get(m_pItemLayout), "rect.progress", progress, 0.0);
+}
+
+void BubbleAudioViewItem::setState(State state)
+{
+    const char *sig = state == PlayState ? "sound,play" : "sound,pause";
+    emitSignal(m_pItemLayout, sig, "");
+}
+
+void BubbleAudioViewItem::calculate()
+{
+    evas_object_smart_calculate(m_pItemLayout);
+    BubbleViewItem::calculate();
+}
diff --git a/src/Conversation/View/src/BubbleVoiceViewItem.cpp b/src/Conversation/View/src/BubbleVoiceViewItem.cpp
deleted file mode 100644 (file)
index e69e60b..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright 2016  Samsung Electronics Co., Ltd
- *
- * Licensed under the Flora License, Version 1.1 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://floralicense.org/license/
- *
- * 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.
- */
-
-#include "BubbleVoiceViewItem.h"
-#include "Resource.h"
-#include "TextDecorator.h"
-#include "PathUtils.h"
-
-using namespace Msg;
-
-BubbleVoiceViewItem::BubbleVoiceViewItem(Evas_Object *parent, BubbleEntity &entity)
-    : BubbleViewItem(parent, entity)
-    , m_pVoiceItemLayout(nullptr)
-{
-    m_pVoiceItemLayout = addLayout(getEo(), CONV_LIST_BUBBLE_EDJ_PATH, "conv/list/voice_item");
-    setContent(m_pVoiceItemLayout);
-}
-
-BubbleVoiceViewItem::~BubbleVoiceViewItem()
-{
-}
-
-void BubbleVoiceViewItem::setMainText(const std::string &text)
-{
-    elm_object_part_text_set(m_pVoiceItemLayout, "text.filename", text.c_str());
-}
-
-void BubbleVoiceViewItem::setTimeText(const std::string &text)
-{
-    elm_object_part_text_set(m_pVoiceItemLayout, "text.time", text.c_str());
-}
-
-void BubbleVoiceViewItem::setProgress(const double progress)
-{
-    edje_object_part_drag_value_set(elm_layout_edje_get(m_pVoiceItemLayout), "rect.progress", progress, 0.0);
-}
-
-void BubbleVoiceViewItem::calculate()
-{
-    evas_object_smart_calculate(m_pVoiceItemLayout);
-    BubbleViewItem::calculate();
-}