From: Marcin Wasowski Date: Thu, 18 Dec 2014 20:57:50 +0000 (+0100) Subject: [TV Audio] Implementation of playSound() X-Git-Tag: submit/tizen_tv/20150603.064601~1^2~670^2~1 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=70c5801ce9e45ebf9dcab77243a0df623c4204d0;p=platform%2Fcore%2Fapi%2Fwebapi-plugins.git [TV Audio] Implementation of playSound() - audio files added to res/tvsounds/ - audio files still need to be added to packaging Change-Id: I9f1a6852f28b4b2f7e4ea6de58a8065207a3269f Signed-off-by: Marcin Wasowski --- diff --git a/res/tvsounds/back.pcm b/res/tvsounds/back.pcm new file mode 100644 index 00000000..ee41b2a5 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 index 00000000..17077458 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 index 00000000..7ace3f4a 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 index 00000000..405233dc 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 index 00000000..c6c7dcb0 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 index 00000000..c72792bf 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 index 00000000..f2f808e5 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 index 00000000..db86f0dc 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 index 00000000..d4ca5ea0 Binary files /dev/null and b/res/tvsounds/warning.pcm differ diff --git a/src/tvaudio/tvaudio_api.js b/src/tvaudio/tvaudio_api.js index 5e226ab9..8613d67c 100644 --- a/src/tvaudio/tvaudio_api.js +++ b/src/tvaudio/tvaudio_api.js @@ -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(); diff --git a/src/tvaudio/tvaudio_instance.cc b/src/tvaudio/tvaudio_instance.cc index 05e8af59..55e9a1c1 100644 --- a/src/tvaudio/tvaudio_instance.cc +++ b/src/tvaudio/tvaudio_instance.cc @@ -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 diff --git a/src/tvaudio/tvaudio_instance.h b/src/tvaudio/tvaudio_instance.h index f10b7eea..a1f23f6a 100644 --- a/src/tvaudio/tvaudio_instance.h +++ b/src/tvaudio/tvaudio_instance.h @@ -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 diff --git a/src/tvaudio/tvaudio_manager.cc b/src/tvaudio/tvaudio_manager.cc index c8cbe6eb..63764ef2 100755 --- a/src/tvaudio/tvaudio_manager.cc +++ b/src/tvaudio/tvaudio_manager.cc @@ -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 +#include "tvaudio/tvaudio_manager.h" + #include +#include +#include #include #include +#include + +#include // NOLINT (readability/streams) +// this flag is no longer enforced in the newest cpplint.py + +#include +#include + #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(play_data); + + LOGD("Beep type: %d", pData->beep_type.c_str()); + + const std::string& filename = pData->filename; + std::unique_ptr > 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 > +AudioControlManager::loadFile(const std::string& filename) { + LOGD("Enter"); + std::unique_ptr> pBuffer(new std::vector()); + 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>(); + } + + 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>(); + } + + 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 >(); + } + file.close(); + + LOGD("Got buffer"); + return pBuffer; +} + } // namespace tvaudio } // namespace extension diff --git a/src/tvaudio/tvaudio_manager.h b/src/tvaudio/tvaudio_manager.h index 1cae31ab..fa093200 100755 --- a/src/tvaudio/tvaudio_manager.h +++ b/src/tvaudio/tvaudio_manager.h @@ -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 +#include +#include +#include +#include + #ifndef SRC_TVAUDIO_TVAUDIO_MANAGER_H_ #define SRC_TVAUDIO_TVAUDIO_MANAGER_H_ + #include 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> + loadFile(const std::string& filename); + + // key : sound file path + const std::map 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 stopSound; + std::string beep_type; + std::string filename; + }; + PlayData m_playData; }; } // namespace tvaudio