feedback: Add feedback_play_type_with_flags_internal() 03/302903/5
authorYunhee Seo <yuni.seo@samsung.com>
Fri, 15 Dec 2023 05:00:40 +0000 (14:00 +0900)
committerYunhee Seo <yuni.seo@samsung.com>
Tue, 19 Dec 2023 04:22:54 +0000 (13:22 +0900)
To support sound play with priority, new api is added.

This function is added to feedback.
- int feedback_play_type_with_flags_internal(feedback_type_e type, feedback_pattern_internal_e internal_pattern,
feedback_flag_e flag);
- This function plays feedback pattern by pre-defined feedback_flag_e.

Sound play behavior varies depending on feedback_flag_e.
- FEEDBACK_FLAG_NONE
- This flag works the same as feedback_play_type_internal().
- FEEDBACK_FLAG_PRIORITY_BASED_PLAY
- This flag will only work in sound play. Sound pattern will be played with priority.

The sound pattern priority value will be used as defined in the sound conf file.

Change-Id: Idba5314030d393af82d155cd8e4a258a9e6ab82f
Signed-off-by: Yunhee Seo <yuni.seo@samsung.com>
include/feedback-internal.h
src/devices.h
src/feedback.c
src/sound.c
src/vibrator.c
tests/main.c
tests/test-feedback-internal.c
tests/test-feedback-internal.h

index 690c030..c2a71ca 100755 (executable)
@@ -37,6 +37,16 @@ extern "C" {
 #define FEEDBACK_FAILED(n)                   ((n) != FEEDBACK_ERROR_NONE)
 
 /**
+ * @brief Enumeration for feedback sound play method.
+ * @details Currently, it is used only in the sound play.
+ * @since_tizen 7.0
+ */
+typedef enum {
+       FEEDBACK_FLAG_NONE = 0,                     /**< Feedback flag none */
+       FEEDBACK_FLAG_PRIORITY_BASED_PLAY = (1<<0), /**< Feedback flag for priority-based play */
+} feedback_flag_e;
+
+/**
  *
  * @brief Plays specific type of reactions that are pre-defined.
  * @details
@@ -246,6 +256,34 @@ int feedback_stop_type_internal(feedback_type_e feedback_type);
 int feedback_get_theme_ids_internal(feedback_type_e feedback_type, unsigned int *count_of_theme, unsigned int **theme_ids);
 
 /**
+ * @brief Plays specific type of reactions that are pre-defined with priority.
+ * @details This function can be used to react to pre-defined actions. \n
+ *          It play specific type of system pre-defined pattern with priority.
+ * @since_tizen 7.0
+ * @remarks Currently, there are two types of reactions: sound and vibration. \n
+ *          Depending on the settings, some types cannot be operated.
+ *          FEEDBACK_FLAG_PRIORITY_BASED_PLAY is for playing sound with priority.
+ *          FEEDBACK_FLAG_NONE works the same as feedback_play_type_internal().
+ *          And for controlling haptic device, the privilege should be set to, %http://tizen.org/privilege/haptic.
+ *          If you don't have the haptic privilege, it returns FEEDBACK_ERROR_PERMISSION_DENIED error.
+ *          The above-mentioned haptic device rule is only for FEEDBACK_FLAG_NONE.
+ *          Priority playing is not supported in vibrator.
+ * @param[in] type The pattern type
+ * @param[in] pattern The pre-defined internal pattern
+ * @param[in] flag The sound play method flag
+ * @return @c 0 on success,
+ *         otherwise a negative error value
+ * @retval #FEEDBACK_ERROR_NONE Successful
+ * @retval #FEEDBACK_ERROR_OPERATION_FAILED Operation not permitted
+ * @retval #FEEDBACK_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #FEEDBACK_ERROR_NOT_SUPPORTED Not supported device
+ * @retval #FEEDBACK_ERROR_PERMISSION_DENIED Permission denied
+ * @retval #FEEDBACK_ERROR_NOT_INITIALIZED Not initialized
+ * @pre feedback_initialize()
+ * @see feedback_play_type_internal()
+ */
+int feedback_play_type_with_flags_internal(feedback_type_e type, feedback_pattern_internal_e internal_pattern, feedback_flag_e flag);
+/**
  * @}
  */
 
index 7e64a44..b477dea 100644 (file)
@@ -30,6 +30,7 @@ struct device_ops {
        void (*exit) (void);
        int (*play) (int, bool);
        int (*play_path) (int, const char *, bool);
+       int (*play_with_priority) (int, bool);
        int (*stop) (void);
        int (*is_supported) (int, bool *);
        int (*get_path) (int, char *, unsigned int);
index 0e1e59e..e329a06 100644 (file)
@@ -674,4 +674,59 @@ API int feedback_get_theme_ids_internal(feedback_type_e feedback_type, unsigned
                return FEEDBACK_ERROR_OPERATION_FAILED;
 
        return FEEDBACK_ERROR_NONE;
+}
+
+API int feedback_play_type_with_flags_internal(feedback_type_e type, feedback_pattern_internal_e internal_pattern, feedback_flag_e flag)
+{
+       const struct device_ops *dev;
+       int err;
+       feedback_pattern_e pattern = (feedback_pattern_e)internal_pattern;
+
+       if (flag < FEEDBACK_FLAG_NONE || flag > FEEDBACK_FLAG_PRIORITY_BASED_PLAY) {
+               _E("Invalid parameter : feedback_flag_e(%d)", flag);
+               return FEEDBACK_ERROR_INVALID_PARAMETER;
+       }
+
+       if (flag == FEEDBACK_FLAG_NONE)
+               return feedback_play_type_internal(type, 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);
+       if (flag == FEEDBACK_FLAG_PRIORITY_BASED_PLAY) {
+               if (!dev->play_with_priority)
+                       return FEEDBACK_ERROR_OPERATION_FAILED;
+               err = dev->play_with_priority(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;
 }
\ No newline at end of file
index 9cf5402..486d0a8 100644 (file)
@@ -76,6 +76,32 @@ static const char *get_data(feedback_pattern_e pattern)
        return sound_data->path;
 }
 
+static int get_sound_pattern_data(feedback_pattern_e pattern, const char **path, int *priority)
+{
+       struct sound_pattern_data *sound_data = NULL;
+       int ret = 0;
+
+       if (pattern <= FEEDBACK_PATTERN_NONE || pattern >= profile->max_pattern)
+               return -EINVAL;
+
+       ret = sound_thememan_get_pattern_data(current_theme_id, pattern, &sound_data);
+       if (ret < 0)
+               return -EPERM;
+
+       if (!sound_data) {
+               _E("Not supported pattern : %d", pattern);
+               return -EPERM;
+       }
+
+       if (sound_data->path && path)
+               *path = sound_data->path;
+
+       if (priority)
+               *priority = sound_data->priority;
+
+       return 0;
+}
+
 inline int is_sound_mode(void)
 {
        return sndstatus;
@@ -466,6 +492,78 @@ static int sound_get_theme_ids(unsigned int *count_of_theme, unsigned int **them
        return 0;
 }
 
+static int sound_play_with_priority(feedback_pattern_e pattern, bool always)
+{
+       struct stat buf;
+       int retry = FEEDBACK_RETRY_CNT;
+       int ret = 0;
+       sound_stream_info_h stream_info;
+       const char *path = NULL;
+       int level;
+       int priority = -1;
+
+       if (vconf_get_bool(VCONFKEY_SETAPPL_SOUND_STATUS_BOOL, &sndstatus) < 0) {
+               _D("fail to get sound status, will work as turning off"); //LCOV_EXCL_LINE
+               sndstatus = 0; //LCOV_EXCL_LINE
+       }
+
+       if (always) {
+               _W("Always on condition(pattern %s)", profile->str_pattern(pattern)); //LCOV_EXCL_LINE
+               goto check_pattern;
+       }
+
+       if (sndstatus == 0 && profile->get_always_alert_case && !profile->get_always_alert_case(FEEDBACK_TYPE_SOUND, pattern)) {
+               _D("Sound condition is OFF (sndstatus : %d)", sndstatus); //LCOV_EXCL_LINE
+               return 0;
+       }
+
+       if (sndstatus && profile->get_always_off_case && profile->get_always_off_case(FEEDBACK_TYPE_SOUND, pattern)) {
+               _D("Sound always off condition(pattern %s)", profile->str_pattern(pattern)); //LCOV_EXCL_LINE
+               return 0;
+       }
+
+check_pattern:
+       /* get sound file path */
+       ret = get_sound_pattern_data(pattern, &path, &priority);
+       if (ret < 0 || stat(path, &buf)) {
+               _E("Not supported sound pattern(pattern %d)", pattern); //LCOV_EXCL_LINE
+               return -ENOTSUP;
+       }
+
+       /* play sound file */
+       if (profile->is_notification_type && profile->is_notification_type(pattern)) {
+               ret = sound_manager_create_stream_information(SOUND_STREAM_TYPE_NOTIFICATION,
+                NULL, NULL, &stream_info);
+               if (ret != SOUND_MANAGER_ERROR_NONE) {
+                       _E("Failed to set session to play sound(%d)", ret); //LCOV_EXCL_LINE
+                       return -ENOENT; //LCOV_EXCL_LINE
+               }
+               do {
+               ret = wav_player_start_new(path, stream_info, play_completed, stream_info, NULL);
+                       if (ret == WAV_PLAYER_ERROR_NONE) {
+                               _D("Wav Play success! SND filename is %s", path); //LCOV_EXCL_LINE
+                               return 0;
+                       }
+                       _E("Failed to play sound file (%d, %s)", ret, path); //LCOV_EXCL_LINE
+               } while (retry--); //LCOV_EXCL_LINE
+       } else {
+               do {
+                       if (profile->get_strength_type)
+                               level = profile->get_strength_type(FEEDBACK_TYPE_SOUND, pattern);
+                       else
+                               level = VOLUME_TYPE_SYSTEM;
+
+                       ret = mm_sound_play_keysound_ex(path, level, priority);
+                       if (ret == MM_ERROR_NONE) {
+                               _D("Play success! %s(%s) priority %d", profile->str_pattern(pattern), path, priority);
+                               return 0;
+                       }
+                       _E("mm_sound_play_keysound_ex() returned error(%d)", ret); //LCOV_EXCL_LINE
+               } while (retry--); //LCOV_EXCL_LINE
+       }
+       return -EPERM;
+}
+
 static const struct device_ops sound_device_ops = {
        .type = FEEDBACK_TYPE_SOUND,
        .name = "Sound",
@@ -473,6 +571,7 @@ static const struct device_ops sound_device_ops = {
        .exit = sound_exit,
        .play = sound_play,
        .play_path = sound_play_path,
+       .play_with_priority = sound_play_with_priority,
        .stop = sound_stop,
        .is_supported = sound_is_supported,
        .get_path = sound_get_path,
index 002bcdc..b90b7d8 100644 (file)
@@ -394,6 +394,7 @@ static const struct device_ops vibrator_device_ops = {
        .set_theme_id = NULL,
        .get_theme_id = NULL,
        .get_theme_ids = NULL,
+       .play_with_priority = NULL,
 };
 
 DEVICE_OPS_REGISTER(&vibrator_device_ops);
index 95f348e..46586f5 100644 (file)
@@ -31,6 +31,7 @@ void test_all()
        LOG_RESULT(TEST_FEEDBACK_GET_SOUND_THEME_ID_INTERNAL(), "TEST_FEEDBACK_GET_SOUND_THEME_ID_INTERNAL");
        LOG_RESULT(TEST_FEEDBACK_SET_SOUND_THEME_ID_INTERNAL(), "TEST_FEEDBACK_SET_SOUND_THEME_ID_INTERNAL");
        LOG_RESULT(TEST_FEEDBACK_GET_SOUND_THEME_IDS_INTERNAL(), "TEST_FEEDBACK_GET_SOUND_THEME_IDS_INTERNAL");
+       LOG_RESULT(TEST_FEEDBACK_PLAY_TYPE_WITH_FLAGS_INTERNAL(), "TEST_FEEDBACK_PLAY_TYPE_WITH_FLAGS_INTERNAL");
 }
 
 void show_usage()
index 976fa6d..5447c83 100644 (file)
@@ -441,6 +441,23 @@ bool TEST_FEEDBACK_GET_SOUND_THEME_IDS_INTERNAL(void)
        REPORT_AND_RETURN();
 }
 
+static void test_feedback_play_type_with_flags_internal(void)
+{
+       feedback_initialize();
+       RESULT(feedback_play_type_with_flags_internal(FEEDBACK_TYPE_SOUND, FEEDBACK_PATTERN_TAP, -1), FEEDBACK_ERROR_INVALID_PARAMETER, "invalid parameter");
+       RESULT(feedback_play_type_with_flags_internal(FEEDBACK_TYPE_VIBRATION, FEEDBACK_PATTERN_TAP, FEEDBACK_FLAG_PRIORITY_BASED_PLAY), FEEDBACK_ERROR_OPERATION_FAILED, "operation failed");
+       RESULT(feedback_play_type_with_flags_internal(FEEDBACK_TYPE_SOUND, FEEDBACK_PATTERN_TAP, FEEDBACK_FLAG_PRIORITY_BASED_PLAY), FEEDBACK_ERROR_NONE, "error none");
+       RESULT(feedback_play_type_with_flags_internal(FEEDBACK_TYPE_SOUND, FEEDBACK_PATTERN_TAP, FEEDBACK_FLAG_NONE), FEEDBACK_ERROR_NONE, "error none");
+       feedback_deinitialize();
+}
+
+bool TEST_FEEDBACK_PLAY_TYPE_WITH_FLAGS_INTERNAL(void)
+{
+       INIT();
+       test_feedback_play_type_with_flags_internal();
+       REPORT_AND_RETURN();
+}
+
 void TEST_INTERNAL_INIT()
 {
        init_supported_pattern(FEEDBACK_TYPE_SOUND, pattern_s);
index 7521a18..1b93d8e 100644 (file)
@@ -124,6 +124,7 @@ bool TEST_FEEDBACK_GET_COUNT_OF_SOUND_THEME_INTERNAL(void);
 bool TEST_FEEDBACK_GET_SOUND_THEME_ID_INTERNAL(void);
 bool TEST_FEEDBACK_SET_SOUND_THEME_ID_INTERNAL(void);
 bool TEST_FEEDBACK_GET_SOUND_THEME_IDS_INTERNAL(void);
+bool TEST_FEEDBACK_PLAY_TYPE_WITH_FLAGS_INTERNAL(void);
 
 void TEST_INTERNAL_INIT(void);