/* * libfeedback * Copyright (c) 2012 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. */ #include #include #include #include #include #include "feedback.h" #include "feedback-internal.h" #include "profiles.h" #include "devices.h" #include "log.h" #ifndef API #define API __attribute__ ((visibility("default"))) #endif static unsigned int init_cnt; static pthread_mutex_t fmutex = PTHREAD_MUTEX_INITIALIZER; static guint signal_id = 0; #define SIGNAL_VIBRATOR_INITIATED "InitiateVibrator" //LCOV_EXCL_START Not called Callback static void restart_callback(GDBusConnection *conn, const gchar *sender, const gchar *path, const gchar *iface, const gchar *name, GVariant *params, gpointer user_data) { const struct device_ops *dev; dev = find_device(FEEDBACK_TYPE_VIBRATION); if (!dev) { _E("Not supported device : type(FEEDBACK_TYPE_VIBRATION)"); //LCOV_EXCL_LINE return; } if (dev->init) dev->init(); } //LCOV_EXCL_STOP API int feedback_initialize(void) { int ret; pthread_mutex_lock(&fmutex); if (!profile) { _E("there is no valid profile module."); //LCOV_EXCL_LINE pthread_mutex_unlock(&fmutex); //LCOV_EXCL_LINE System Error return FEEDBACK_ERROR_NOT_SUPPORTED; //LCOV_EXCL_LINE System Error } if (init_cnt++ > 0) { pthread_mutex_unlock(&fmutex); return FEEDBACK_ERROR_NONE; } ret = subscribe_dbus_signal(NULL, NULL, VIBRATOR_INTERFACE_HAPTIC, SIGNAL_VIBRATOR_INITIATED, restart_callback, NULL, NULL); if (ret <= 0) _E("Failed to register signal handler. ret=%d", ret); //LCOV_EXCL_LINE System Error else signal_id = ret; /* initialize device */ devices_init(); /* initialize profile feature */ if (profile->init) profile->init(); pthread_mutex_unlock(&fmutex); return FEEDBACK_ERROR_NONE; } API int feedback_deinitialize(void) { pthread_mutex_lock(&fmutex); if (!init_cnt) { pthread_mutex_unlock(&fmutex); return FEEDBACK_ERROR_NOT_INITIALIZED; } if (init_cnt-- > 1) { pthread_mutex_unlock(&fmutex); return FEEDBACK_ERROR_NONE; } if (signal_id > 0) unsubscribe_dbus_signal(NULL, signal_id); /* deinitialize device */ devices_exit(); /* deinitialize profile feature */ if (profile->exit) profile->exit(); pthread_mutex_unlock(&fmutex); return FEEDBACK_ERROR_NONE; } static feedback_pattern_e check_pattern(feedback_type_e type, feedback_pattern_e pattern, const char *func) { feedback_pattern_e switched = pattern; bool result = false; if (type < FEEDBACK_TYPE_NONE || type >= FEEDBACK_TYPE_END) type = FEEDBACK_TYPE_NONE; //LCOV_EXCL_LINE /* if you need to switch pattern */ if (profile->get_switched_pattern) result = profile->get_switched_pattern(pattern, &switched); if (pattern != switched && result) _W("pattern is changed : %s %s(%d) -> %s(%d) by %s", //LCOV_EXCL_LINE profile->str_type[type], profile->str_pattern(pattern), pattern , profile->str_pattern(switched), switched, func); else _W("pattern is : %s %s(%d) by %s", //LCOV_EXCL_LINE profile->str_type[type], profile->str_pattern(pattern), pattern, func); return switched; } API int feedback_play(feedback_pattern_e pattern) { int err; /* check initialize */ pthread_mutex_lock(&fmutex); if (!init_cnt) { _E("Not initialized"); //LCOV_EXCL_LINE pthread_mutex_unlock(&fmutex); return FEEDBACK_ERROR_NOT_INITIALIZED; } pthread_mutex_unlock(&fmutex); if (pattern <= FEEDBACK_PATTERN_NONE || pattern >= profile->max_pattern) { _E("Invalid parameter : pattern(%d)", pattern); return FEEDBACK_ERROR_INVALID_PARAMETER; } _D("request all type with pattern %s(%d)", profile->str_pattern(pattern), pattern); /* play all device */ err = devices_play(check_pattern(FEEDBACK_TYPE_NONE, pattern, __func__), false); /** * devices_play() returns error even if all devices are failed. * It means if to play anything is successful, * this function regards as success. */ if (err == -ENOTSUP) return FEEDBACK_ERROR_NOT_SUPPORTED; //LCOV_EXCL_LINE else if (err < 0) return FEEDBACK_ERROR_OPERATION_FAILED; //LCOV_EXCL_LINE return FEEDBACK_ERROR_NONE; } API int feedback_play_type(feedback_type_e type, feedback_pattern_e pattern) { const struct device_ops *dev; int err; /* check initialize */ pthread_mutex_lock(&fmutex); if (!init_cnt) { _E("Not initialized"); pthread_mutex_unlock(&fmutex); return FEEDBACK_ERROR_NOT_INITIALIZED; } pthread_mutex_unlock(&fmutex); if (type <= FEEDBACK_TYPE_NONE || type >= profile->max_type) { _E("Invalid parameter : type(%d)", type); //LCOV_EXCL_LINE return FEEDBACK_ERROR_INVALID_PARAMETER; //LCOV_EXCL_LINE } if (pattern <= FEEDBACK_PATTERN_NONE || pattern >= profile->max_pattern) { _E("Invalid parameter : pattern(%d)", pattern); //LCOV_EXCL_LINE return FEEDBACK_ERROR_INVALID_PARAMETER; //LCOV_EXCL_LINE } /* play proper device */ dev = find_device(type); if (!dev) { _E("Not supported device : type(%s)", profile->str_type[type]); //LCOV_EXCL_LINE return FEEDBACK_ERROR_NOT_SUPPORTED; //LCOV_EXCL_LINE } err = dev->play(check_pattern(type, pattern, __func__), false); if (err == -ENOTSUP) return FEEDBACK_ERROR_NOT_SUPPORTED; //LCOV_EXCL_LINE else if (err == -ECOMM || err == -EACCES) return FEEDBACK_ERROR_PERMISSION_DENIED; //LCOV_EXCL_LINE else if (err < 0) return FEEDBACK_ERROR_OPERATION_FAILED; //LCOV_EXCL_LINE return FEEDBACK_ERROR_NONE; } API int feedback_stop(void) { int err; /* check initialize */ pthread_mutex_lock(&fmutex); if (!init_cnt) { _E("Not initialized"); //LCOV_EXCL_LINE pthread_mutex_unlock(&fmutex); return FEEDBACK_ERROR_NOT_INITIALIZED; } pthread_mutex_unlock(&fmutex); /* stop all device */ err = devices_stop(); if (err == -ENOTSUP) return FEEDBACK_ERROR_NOT_SUPPORTED; //LCOV_EXCL_LINE else if (err == -ECOMM || err == -EACCES) return FEEDBACK_ERROR_PERMISSION_DENIED; //LCOV_EXCL_LINE else if (err < 0) return FEEDBACK_ERROR_OPERATION_FAILED; //LCOV_EXCL_LINE return FEEDBACK_ERROR_NONE; } API int feedback_is_supported_pattern(feedback_type_e type, feedback_pattern_e pattern, bool *status) { const struct device_ops *dev; bool supported; int err; /* check initialize */ pthread_mutex_lock(&fmutex); if (!init_cnt) { _E("Not initialized"); //LCOV_EXCL_LINE pthread_mutex_unlock(&fmutex); return FEEDBACK_ERROR_NOT_INITIALIZED; } pthread_mutex_unlock(&fmutex); if (!status) { _E("Invalid parameter : status(NULL)"); return FEEDBACK_ERROR_INVALID_PARAMETER; } if (type <= FEEDBACK_TYPE_NONE || type >= profile->max_type) { _E("Invalid parameter : type(%d)", type); return FEEDBACK_ERROR_INVALID_PARAMETER; } if (pattern <= FEEDBACK_PATTERN_NONE || pattern >= profile->max_pattern) { _E("Invalid parameter : pattern(%d)", pattern); return FEEDBACK_ERROR_INVALID_PARAMETER; } /* play proper device */ dev = find_device(type); if (!dev) { _E("Not supported device : type(%s)", profile->str_type[type]); //LCOV_EXCL_LINE return FEEDBACK_ERROR_NOT_SUPPORTED; //LCOV_EXCL_LINE } err = dev->is_supported(check_pattern(type, pattern, __func__), &supported); if (err == -ENOTSUP) return FEEDBACK_ERROR_NOT_SUPPORTED; //LCOV_EXCL_LINE System Error else if (err == -ECOMM || err == -EACCES) return FEEDBACK_ERROR_PERMISSION_DENIED; //LCOV_EXCL_LINE System Error else if (err < 0) { _E("fail to invoke is_supported() : pattern(%d)", pattern); //LCOV_EXCL_LINE return FEEDBACK_ERROR_OPERATION_FAILED; //LCOV_EXCL_LINE } *status = supported; return FEEDBACK_ERROR_NONE; } /* Internal APIs */ API int feedback_play_type_by_name(char *type, char *pattern) { feedback_type_e etype; feedback_pattern_e epattern; int type_max; int pattern_max; if (!type || !pattern) { _E("Invalid parameter : type(%s), pattern(%s)", type, pattern); return FEEDBACK_ERROR_INVALID_PARAMETER; } type_max = profile->max_type; for (etype = 0; etype < type_max; ++etype) { if (!strncmp(type, profile->str_type[etype], strlen(type))) break; } if (etype == type_max) { _E("Invalid parameter : type(%s)", type); return FEEDBACK_ERROR_INVALID_PARAMETER; } pattern_max = profile->max_pattern; for (epattern = 0; epattern < pattern_max; ++epattern) { if (!strncmp(pattern, profile->str_pattern(epattern), strlen(pattern))) break; } if (epattern == pattern_max) { _E("Invalid parameter : pattern(%s)", pattern); return FEEDBACK_ERROR_INVALID_PARAMETER; } return feedback_play_type(etype, epattern); } API int feedback_play_internal(feedback_pattern_internal_e internal_pattern) { int err; feedback_pattern_e pattern = (feedback_pattern_e)internal_pattern; /* check initialize */ pthread_mutex_lock(&fmutex); if (!init_cnt) { _E("Not initialized"); //LCOV_EXCL_LINE pthread_mutex_unlock(&fmutex); return FEEDBACK_ERROR_NOT_INITIALIZED; } pthread_mutex_unlock(&fmutex); if (pattern <= FEEDBACK_PATTERN_NONE || pattern >= profile->max_pattern) { _E("Invalid parameter : pattern(%d)", pattern); return FEEDBACK_ERROR_INVALID_PARAMETER; } _D("request all type with pattern %s(%d)", profile->str_pattern(pattern), pattern); /* play all device */ err = devices_play(check_pattern(FEEDBACK_TYPE_NONE, pattern, __func__), true); /** * devices_play() returns error even if all devices are failed. * It means if to play anything is successful, * this function regards as success. */ if (err == -ENOTSUP) return FEEDBACK_ERROR_NOT_SUPPORTED; else if (err < 0) return FEEDBACK_ERROR_OPERATION_FAILED; //LCOV_EXCL_LINE return FEEDBACK_ERROR_NONE; } API int feedback_play_type_internal(feedback_type_e type, feedback_pattern_internal_e internal_pattern) { const struct device_ops *dev; int err; feedback_pattern_e pattern = (feedback_pattern_e)internal_pattern; /* check initialize */ pthread_mutex_lock(&fmutex); if (!init_cnt) { _E("Not initialized"); //LCOV_EXCL_LINE pthread_mutex_unlock(&fmutex); return FEEDBACK_ERROR_NOT_INITIALIZED; } pthread_mutex_unlock(&fmutex); if (type <= FEEDBACK_TYPE_NONE || type >= profile->max_type) { _E("Invalid parameter : type(%d)", type); return FEEDBACK_ERROR_INVALID_PARAMETER; } if (pattern <= FEEDBACK_PATTERN_NONE || pattern >= profile->max_pattern) { _E("Invalid parameter : pattern(%d)", pattern); return FEEDBACK_ERROR_INVALID_PARAMETER; } /* play proper device */ dev = find_device(type); if (!dev) { _E("Not supported device : type(%s)", profile->str_type[type]); //LCOV_EXCL_LINE return FEEDBACK_ERROR_NOT_SUPPORTED; //LCOV_EXCL_LINE } _D("request type %s with pattern %s(%d)", profile->str_type[type], profile->str_pattern(pattern), pattern); err = dev->play(check_pattern(type, pattern, __func__), true); if (err == -ENOTSUP) return FEEDBACK_ERROR_NOT_SUPPORTED; //LCOV_EXCL_LINE else if (err == -ECOMM || err == -EACCES) return FEEDBACK_ERROR_PERMISSION_DENIED; //LCOV_EXCL_LINE else if (err < 0) return FEEDBACK_ERROR_OPERATION_FAILED; //LCOV_EXCL_LINE return FEEDBACK_ERROR_NONE; } API int feedback_play_soundpath_internal(feedback_pattern_internal_e internal_pattern, const char *soundpath) { int err; feedback_pattern_e pattern = (feedback_pattern_e)internal_pattern; /* check initialize */ pthread_mutex_lock(&fmutex); if (!init_cnt) { _E("Not initialized"); //LCOV_EXCL_LINE pthread_mutex_unlock(&fmutex); return FEEDBACK_ERROR_NOT_INITIALIZED; } pthread_mutex_unlock(&fmutex); if (pattern <= FEEDBACK_PATTERN_NONE || pattern >= profile->max_pattern) { _E("Invalid parameter : pattern(%d)", pattern); return FEEDBACK_ERROR_INVALID_PARAMETER; } if (!soundpath) { _E("Invalid parameter : pattern path(NULL)"); return FEEDBACK_ERROR_INVALID_PARAMETER; } _D("request all type with pattern %s(%d), soundpath %s", profile->str_pattern(pattern), pattern, soundpath); /* play all device */ err = devices_play_soundpath(check_pattern(FEEDBACK_TYPE_NONE, pattern, __func__), soundpath, true); /** * devices_play() returns error even if all devices are failed. * It means if to play anything is successful, * this function regards as success. */ if (err == -ENOTSUP) return FEEDBACK_ERROR_NOT_SUPPORTED; else if (err < 0) return FEEDBACK_ERROR_OPERATION_FAILED; //LCOV_EXCL_LINE return FEEDBACK_ERROR_NONE; } API int feedback_play_type_soundpath_internal(feedback_type_e type, feedback_pattern_internal_e internal_pattern, const char *soundpath) { const struct device_ops *dev; int err; feedback_pattern_e pattern = (feedback_pattern_e)internal_pattern; /* check initialize */ pthread_mutex_lock(&fmutex); if (!init_cnt) { _E("Not initialized"); //LCOV_EXCL_LINE pthread_mutex_unlock(&fmutex); return FEEDBACK_ERROR_NOT_INITIALIZED; } pthread_mutex_unlock(&fmutex); if (type <= FEEDBACK_TYPE_NONE || type >= profile->max_type) { _E("Invalid parameter : type(%d)", type); return FEEDBACK_ERROR_INVALID_PARAMETER; } if (pattern <= FEEDBACK_PATTERN_NONE || pattern >= profile->max_pattern) { _E("Invalid parameter : pattern(%d)", pattern); return FEEDBACK_ERROR_INVALID_PARAMETER; } if ((type == FEEDBACK_TYPE_SOUND) && (soundpath == NULL)) { _E("Invalid parameter : sound path(NULL)"); return FEEDBACK_ERROR_INVALID_PARAMETER; } /* play proper device */ dev = find_device(type); if (!dev) { _E("Not supported device : type(%s)", profile->str_type[type]); //LCOV_EXCL_LINE return FEEDBACK_ERROR_NOT_SUPPORTED; //LCOV_EXCL_LINE } _D("request type %s with pattern(%s), soundpath(%s)", profile->str_type[type], profile->str_pattern(pattern), soundpath?soundpath:"NULL"); if (type == FEEDBACK_TYPE_SOUND) { if (dev->play_path) err = dev->play_path(check_pattern(type, pattern, __func__), soundpath, true); else err = -ENOTSUP; //LCOV_EXCL_LINE } else { if (dev->play) err = dev->play(check_pattern(type, pattern, __func__), true); else err = -ENOTSUP; //LCOV_EXCL_LINE } if (err == -ENOTSUP) return FEEDBACK_ERROR_NOT_SUPPORTED; //LCOV_EXCL_LINE else if (err == -ECOMM || err == -EACCES) return FEEDBACK_ERROR_PERMISSION_DENIED; //LCOV_EXCL_LINE else if (err < 0) return FEEDBACK_ERROR_OPERATION_FAILED; //LCOV_EXCL_LINE return FEEDBACK_ERROR_NONE; }