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 690c03069c69859fc51003da6bf8dc4a8053cc51..c2a71ca4b1b1fe5f793f179d44f50a4331a96242 100755 (executable)
@@ -36,6 +36,16 @@ extern "C" {
 #define FEEDBACK_SUCCEEDED(n)                ((n) == FEEDBACK_ERROR_NONE)
 #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.
@@ -245,6 +255,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 7e64a446c66b61fb33a295d79af166295e34bdf8..b477deae27740ea25ac487ecb8fb70b6fa3dea78 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 0e1e59e86b19d5fe115d560b77c2ff41cbb7ca12..e329a060de192435372efbfa1eb73bf7dbc57986 100644 (file)
@@ -673,5 +673,60 @@ API int feedback_get_theme_ids_internal(feedback_type_e feedback_type, unsigned
        if (ret < 0)
                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 9cf540235c704f48fe1fc11c34c696cf3e2fd23c..486d0a835e0b61578fee2f29e59a1e321ba0947e 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 002bcdce502645e3190ae66ba685414e1834cd11..b90b7d87b02aa07c334b33cb9a6022a9eda2f428 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 95f348ea0b83abe0c214813146a7230eef396b7c..46586f56396b0144828f32fe185ca7ac17f9104c 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 976fa6d073183b7c0ecc6d9ecb47173a18752c81..5447c8302ce9571cef7931ef58a3edb9a14a0c7f 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 7521a18d0cb336f509d0a09bef046398e03ae18e..1b93d8e441301f997b06c5ff732ee88b6b3a3f45 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);