[TV Audio] Implementation of playSound()
authorMarcin Wasowski <m.wasowski2@samsung.com>
Thu, 18 Dec 2014 20:57:50 +0000 (21:57 +0100)
committerLukasz Foniok <l.foniok@samsung.com>
Wed, 7 Jan 2015 13:24:34 +0000 (14:24 +0100)
- audio files added to res/tvsounds/
- audio files still need to be added to packaging

Change-Id: I9f1a6852f28b4b2f7e4ea6de58a8065207a3269f
Signed-off-by: Marcin Wasowski <m.wasowski2@samsung.com>
14 files changed:
res/tvsounds/back.pcm [new file with mode: 0644]
res/tvsounds/cancel.pcm [new file with mode: 0644]
res/tvsounds/del.pcm [new file with mode: 0644]
res/tvsounds/enter.pcm [new file with mode: 0644]
res/tvsounds/keypad.pcm [new file with mode: 0644]
res/tvsounds/move.pcm [new file with mode: 0644]
res/tvsounds/preparing.pcm [new file with mode: 0644]
res/tvsounds/select.pcm [new file with mode: 0644]
res/tvsounds/warning.pcm [new file with mode: 0644]
src/tvaudio/tvaudio_api.js
src/tvaudio/tvaudio_instance.cc
src/tvaudio/tvaudio_instance.h
src/tvaudio/tvaudio_manager.cc
src/tvaudio/tvaudio_manager.h

diff --git a/res/tvsounds/back.pcm b/res/tvsounds/back.pcm
new file mode 100644 (file)
index 0000000..ee41b2a
Binary files /dev/null and b/res/tvsounds/back.pcm differ
diff --git a/res/tvsounds/cancel.pcm b/res/tvsounds/cancel.pcm
new file mode 100644 (file)
index 0000000..1707745
Binary files /dev/null and b/res/tvsounds/cancel.pcm differ
diff --git a/res/tvsounds/del.pcm b/res/tvsounds/del.pcm
new file mode 100644 (file)
index 0000000..7ace3f4
Binary files /dev/null and b/res/tvsounds/del.pcm differ
diff --git a/res/tvsounds/enter.pcm b/res/tvsounds/enter.pcm
new file mode 100644 (file)
index 0000000..405233d
Binary files /dev/null and b/res/tvsounds/enter.pcm differ
diff --git a/res/tvsounds/keypad.pcm b/res/tvsounds/keypad.pcm
new file mode 100644 (file)
index 0000000..c6c7dcb
Binary files /dev/null and b/res/tvsounds/keypad.pcm differ
diff --git a/res/tvsounds/move.pcm b/res/tvsounds/move.pcm
new file mode 100644 (file)
index 0000000..c72792b
Binary files /dev/null and b/res/tvsounds/move.pcm differ
diff --git a/res/tvsounds/preparing.pcm b/res/tvsounds/preparing.pcm
new file mode 100644 (file)
index 0000000..f2f808e
Binary files /dev/null and b/res/tvsounds/preparing.pcm differ
diff --git a/res/tvsounds/select.pcm b/res/tvsounds/select.pcm
new file mode 100644 (file)
index 0000000..db86f0d
Binary files /dev/null and b/res/tvsounds/select.pcm differ
diff --git a/res/tvsounds/warning.pcm b/res/tvsounds/warning.pcm
new file mode 100644 (file)
index 0000000..d4ca5ea
Binary files /dev/null and b/res/tvsounds/warning.pcm differ
index 5e226ab9478246b588b1ff4b6d2b8bb932d54c72..8613d67c3c570dd49e314ca660cb9fd555438b94 100644 (file)
@@ -30,6 +30,7 @@ function AudioControlManager() {
 }
 
 
+
 /**
  * Turns on or off the silent mode.
  * @param {!boolean} mute  The mute state
@@ -181,12 +182,47 @@ AudioControlManager.prototype.getOutputMode = function() {
 
 
 /**
- * Plays the sound of a specific beep.
+ * Allowed types of sound
+ * They should correspond to values in native layer and .pcm files
+ */
+var AudioBeepType = [
+  'MOVE', // indented use the same sound
+    'UP',
+    'DOWN',
+    'LEFT',
+    'RIGHT',
+    'PAGE_LEFT',
+    'PAGE_RIGHT',
+  'BACK',
+  'SELECT',
+  'CANCEL',
+  'WARNING',
+  'KEYPAD',
+  'KEYPAD_ENTER',
+  'KEYPAD_DEL',
+  'PREPARING'
+];
+Object.freeze(AudioBeepType);
+
+
+/**
+ * Plays one of specific sounds.
+ * @param {!AudioBeepType} beep The Sound to play.
  */
-AudioControlManager.prototype.playSound = function() {
+AudioControlManager.prototype.playSound = function(beep) {
+  var args = validator.validateArgs(arguments, [{
+    name: 'type',
+    type: validator.Types.ENUM,
+    values: AudioBeepType // AudioBeepType
+  }]);
+
+  var ret = native.callSync('AudioControlManager_playSound',
+                            {type: args.type});
+  if (native.isFailure(ret)) {
+    throw native.getErrorObject(ret);
+  }
   return;
 };
 
-
 // Exports
 exports = new AudioControlManager();
index 05e8af59e1e8eec56f5e9f56393c4fbb94ecba1c..55e9a1c1df3a704874628409e830fb227d3b2f02 100644 (file)
@@ -40,6 +40,7 @@ TVAudioInstance::TVAudioInstance() {
     REGISTER_SYNC("AudioControlManager_getOutputMode", getOutputMode);
     REGISTER_SYNC("AudioControlManager_setVolumeChangeListener", setVolumeChangeListener);
     REGISTER_SYNC("AudioControlManager_unsetVolumeChangeListener", unsetVolumeChangeListener);
+    REGISTER_SYNC("AudioControlManager_playSound", playSound);
     #undef REGISTER_SYNC
 }
 
@@ -125,5 +126,12 @@ void TVAudioInstance::onVolumeChangeCallback(u_int16_t volume) {
   }
 }
 
+void TVAudioInstance::playSound(const picojson::value& args,
+        picojson::object& out) {
+    const std::string& type = args.get("type").to_str();
+    AudioControlManager::getInstance().playSound(type);
+    ReportSuccess(picojson::value(true), out);
+}
+
 }  // namespace tvaudio
 }  // namespace extension
index f10b7eeac8e69fedb7e16d02c2c0c531501bbc21..a1f23f6a57307b891b6d6b73bc417fdde2290ac8 100644 (file)
@@ -29,8 +29,8 @@ class TVAudioInstance :
     void getOutputMode(const picojson::value& args, picojson::object& out);
     void setVolumeChangeListener(const picojson::value& args, picojson::object& out);
     void unsetVolumeChangeListener(const picojson::value& args, picojson::object& out);
-
     virtual void onVolumeChangeCallback(u_int16_t volume);
+    void playSound(const picojson::value& args, picojson::object& out);
 };
 
 }  // namespace tvaudio
index c8cbe6ebc818f3ea7bb112f91478e50f255d0258..63764ef293e1ab92f753b30012d6a192f235e213 100755 (executable)
@@ -2,15 +2,25 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include <avoc_defs.h>
+#include "tvaudio/tvaudio_manager.h"
+
 #include <avoc.h>
+#include <avoc_defs.h>
+#include <audio_io.h>
 #include <sound_manager.h>
 #include <sound_manager_product.h>
 
+#include <glib.h>
+
+#include <fstream> // NOLINT (readability/streams)
+// this flag is no longer enforced in the newest cpplint.py
+
+#include <string>
+#include <vector>
+
 #include "common/logger.h"
 #include "common/platform_exception.h"
 
-#include "tvaudio/tvaudio_manager.h"
 
 namespace extension {
 namespace tvaudio {
@@ -28,9 +38,11 @@ VolumeChangeListener::~VolumeChangeListener() {
 }
 
 AudioControlManager::AudioControlManager() :
-        m_volume_step(VOLUME_STEP),
-        m_volume_change_listener(NULL) {
+    m_volume_step(VOLUME_STEP),
+    m_volume_change_listener(NULL),
+    m_playThreadIdInit(false) {
     LOGD("Enter");
+    m_playData.stopSound = false;
 }
 
 AudioControlManager::~AudioControlManager() {
@@ -180,6 +192,134 @@ void AudioControlManager::volumeChangeCallback(
     }
 }
 
+/**
+ * Play one of predefined sounds
+ *
+ * If sound is already played it is replaced by the new sound
+ *
+ * @return {bool} true if successful, false otherwise
+ */
+bool AudioControlManager::playSound(const std::string &type) {
+    LOGD("Enter");
+    const auto beep = SoundMap.find(type);
+    if (beep == SoundMap.end()) {
+        throw UnknownException("Unknown beep type: " + type);
+    }
+
+    void *status;
+    if (m_playThreadIdInit) {
+        m_playData.stopSound = true;
+        pthread_join(m_playThreadId, &status);
+        m_playData.stopSound = false;
+    }
+    pthread_attr_t attr;
+    pthread_attr_init(&attr);
+    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
+
+    m_playData.beep_type = beep->first;
+    m_playData.filename = beep->second;
+
+    if (0 == pthread_create(&m_playThreadId, &attr, play, &m_playData )) {
+        m_playThreadIdInit = true;
+    } else {
+        LOGE("Failed to create pthread");
+        throw UnknownException("Failed to create pthread to play sound");
+    }
+    return true;
+}
+
+void* AudioControlManager::play(void* play_data) {
+    LOGD("Enter");
+    PlayData* pData = static_cast<PlayData*>(play_data);
+
+    LOGD("Beep type: %d", pData->beep_type.c_str());
+
+    const std::string& filename = pData->filename;
+    std::unique_ptr <std::vector <char>> pBuffer =
+            AudioControlManager::loadFile(filename);
+
+    audio_out_h handle;
+    int error = audio_out_create(SAMPLING_FREQ,
+                                AUDIO_CHANNEL_STEREO,
+                                AUDIO_SAMPLE_TYPE_S16_LE,
+                                SOUND_TYPE_NOTIFICATION,
+                                &handle);
+    if (AUDIO_IO_ERROR_NONE != error) {
+        LOGE("Failed to open audio output: %d", error);
+        return NULL;
+    }
+
+    error = audio_out_prepare(handle);
+    if (AUDIO_IO_ERROR_NONE != error) {
+        LOGE("Failed to open audio output: %d", error);
+        audio_out_destroy(handle);
+        return NULL;
+    }
+
+    int counter = 0;
+    int dataLeftSize = pBuffer->size();
+    while ((!pData->stopSound) && (dataLeftSize > 0)) {
+        if ((dataLeftSize - AudioControlManager::CHUNK) < 0) {
+            dataLeftSize = dataLeftSize;
+            error = audio_out_write(handle,
+                                    &(*pBuffer)[counter],
+                                    dataLeftSize);
+            if (dataLeftSize != error) {
+                LOGE("Failed to write to audio output: %d", error);
+                audio_out_destroy(handle);
+                return NULL;
+            }
+            break;
+        } else {
+            dataLeftSize = dataLeftSize - AudioControlManager::CHUNK;
+            error = audio_out_write(handle,
+                                    &(*pBuffer)[counter],
+                                    AudioControlManager::CHUNK);
+            if (AudioControlManager::CHUNK != error) {
+                LOGE("Failed to write to audio output: %d", error);
+                audio_out_destroy(handle);
+                return NULL;
+            }
+        }
+        counter += AudioControlManager::CHUNK;
+    }  // while
+    audio_out_destroy(handle);
+    return NULL;
+}
+
+std::unique_ptr <std::vector<char>>
+AudioControlManager::loadFile(const std::string& filename) {
+    LOGD("Enter");
+    std::unique_ptr<std::vector<char>> pBuffer(new std::vector<char>());
+    std::ifstream file(filename.c_str(),
+                    (std::ios::binary | std::ios::in | std::ios::ate));
+    if (!file.is_open()) {
+        LOGE("Could not open file %s", filename.c_str());
+        return std::unique_ptr< std::vector<char>>();
+    }
+
+    std::ifstream::pos_type size = file.tellg();
+    if (size < 0) {
+        file.close();
+        LOGE("Failed to open file %s - incorrect size", filename.c_str());
+        return std::unique_ptr<std::vector<char>>();
+    }
+
+    LOGD("resizing");
+    pBuffer->resize(size);
+    LOGD("resized");
+    file.seekg(0, std::ios::beg);
+    if (!file.read(&(*pBuffer)[0], size)) {
+        file.close();
+        LOGE("Failed to read audio file %s", filename.c_str());
+        return std::unique_ptr <std::vector <char>>();
+    }
+    file.close();
+
+    LOGD("Got buffer");
+    return pBuffer;
+}
+
 }  // namespace tvaudio
 }  // namespace extension
 
index 1cae31ab423fe34499e1368e6dc557e70e74a785..fa09320055bc846dfddfb5b9881c807fe8c7d69b 100755 (executable)
@@ -2,19 +2,26 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <atomic>
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
 #ifndef SRC_TVAUDIO_TVAUDIO_MANAGER_H_
 #define SRC_TVAUDIO_TVAUDIO_MANAGER_H_
 
+
 #include <sys/types.h>
 
 namespace extension {
 namespace tvaudio {
 
 enum AudioOutputMode {
-  PCM = 0,
-  DOLBY,
-  DTS,
-  AAC
+    PCM = 0,
+    DOLBY,
+    DTS,
+    AAC
 };
 
 class VolumeChangeListener {
@@ -30,25 +37,63 @@ class AudioControlManager {
     void setVolume(u_int16_t volume);
     void setVolumeUp();
     void setVolumeDown();
+    bool playSound(const std::string &type);
     u_int16_t getVolume();
     AudioOutputMode getOutputMode();
     void registerVolumeChangeListener(VolumeChangeListener* listener);
     void unregisterVolumeChangeListener();
     static void volumeChangeCallback(unsigned int volume, void* user_data);
 
-    // Not copyable, assignable, movable
-    AudioControlManager(AudioControlManager const&) = delete;
-    void operator=(AudioControlManager const&) = delete;
+    // Non-copyable, -assignable, -movable
+    AudioControlManager(const AudioControlManager &) = delete;
     AudioControlManager(AudioControlManager &&) = delete;
+    AudioControlManager& operator=(const AudioControlManager &) & = delete;
+    AudioControlManager& operator=(AudioControlManager &&) & = delete;
 
     static AudioControlManager& getInstance();
 
  private:
     u_int16_t m_volume_step;
     VolumeChangeListener* m_volume_change_listener;
-
     AudioControlManager();
     virtual ~AudioControlManager();
+
+    static const int CHUNK = 768;
+    static const int SAMPLING_FREQ = 44100;
+
+    static void* play(void* _args);
+
+    bool m_playThreadIdInit;
+    pthread_t m_playThreadId;
+
+    static std::unique_ptr<std::vector<char>>
+        loadFile(const std::string& filename);
+
+    //  key : sound file path
+    const std::map<const std::string, const std::string> SoundMap = {
+        {"MOVE",          "/opt/usr/share/settings/Ringtones/move.pcm"},
+        {"UP",            "/opt/usr/share/settings/Ringtones/move.pcm"},
+        {"DOWN",          "/opt/usr/share/settings/Ringtones/move.pcm"},
+        {"LEFT",          "/opt/usr/share/settings/Ringtones/move.pcm"},
+        {"RIGHT",         "/opt/usr/share/settings/Ringtones/move.pcm"},
+        {"PAGE_LEFT",     "/opt/usr/share/settings/Ringtones/move.pcm"},
+        {"PAGE_RIGHT",    "/opt/usr/share/settings/Ringtones/move.pcm"},
+
+        {"BACK",          "/opt/usr/share/settings/Ringtones/back.pcm"},
+        {"SELECT",        "/opt/usr/share/settings/Ringtones/select.pcm"},
+        {"CANCEL",        "/opt/usr/share/settings/Ringtones/cancel.pcm"},
+        {"WARNING",       "/opt/usr/share/settings/Ringtones/enter.pcm"},
+        {"KEYPAD",        "/opt/usr/share/settings/Ringtones/keypad.pcm"},
+        {"KEYPAD_ENTER",  "/opt/usr/share/settings/Ringtones/enter.pcm"},
+        {"KEYPAD_DEL",    "/opt/usr/share/settings/Ringtones/del.pcm"},
+        {"PREPARING",     "/opt/usr/share/settings/Ringtones/preparing.pcm"},
+    };
+    struct PlayData {
+        std::atomic<bool> stopSound;
+        std::string beep_type;
+        std::string filename;
+    };
+    PlayData m_playData;
 };
 
 }  // namespace tvaudio