}
+
/**
* Turns on or off the silent mode.
* @param {!boolean} mute The mute state
/**
- * 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();
REGISTER_SYNC("AudioControlManager_getOutputMode", getOutputMode);
REGISTER_SYNC("AudioControlManager_setVolumeChangeListener", setVolumeChangeListener);
REGISTER_SYNC("AudioControlManager_unsetVolumeChangeListener", unsetVolumeChangeListener);
+ REGISTER_SYNC("AudioControlManager_playSound", playSound);
#undef REGISTER_SYNC
}
}
}
+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
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
// 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 {
}
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() {
}
}
+/**
+ * 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
// 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 {
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