|
12 | 12 | #include <sof/compiler_attributes.h> |
13 | 13 | #include <rtos/panic.h> |
14 | 14 | #include <sof/ipc/msg.h> |
| 15 | +#include <sof/ipc/notification_pool.h> |
15 | 16 | #include <rtos/alloc.h> |
16 | 17 | #include <rtos/init.h> |
17 | 18 | #include <sof/lib/uuid.h> |
|
24 | 25 | #include <ipc/stream.h> |
25 | 26 | #include <ipc/topology.h> |
26 | 27 | #include <ipc4/base-config.h> |
| 28 | +#include <ipc4/notification.h> |
27 | 29 | #include <user/trace.h> |
28 | 30 | #include <stddef.h> |
29 | 31 | #include <stdint.h> |
@@ -74,6 +76,10 @@ struct mixin_data { |
74 | 76 | mix_func mix; |
75 | 77 | mix_func gain_mix; |
76 | 78 | struct mixin_sink_config sink_config[MIXIN_MAX_SINKS]; |
| 79 | +#if CONFIG_XRUN_NOTIFICATIONS_ENABLE |
| 80 | + uint32_t last_reported_underrun; |
| 81 | + uint32_t underrun_notification_period; |
| 82 | +#endif |
77 | 83 | }; |
78 | 84 |
|
79 | 85 | /* |
@@ -138,6 +144,9 @@ static int mixin_init(struct processing_module *mod) |
138 | 144 | return -ENOMEM; |
139 | 145 |
|
140 | 146 | mod_data->private = md; |
| 147 | +#if CONFIG_XRUN_NOTIFICATIONS_ENABLE |
| 148 | + md->underrun_notification_period = MIXIN_MODULE_DEFAULT_UNDERRUN_NOTIFICATION_PERIOD; |
| 149 | +#endif |
141 | 150 |
|
142 | 151 | for (i = 0; i < MIXIN_MAX_SINKS; i++) { |
143 | 152 | md->sink_config[i].mixer_mode = IPC4_MIXER_NORMAL_MODE; |
@@ -237,6 +246,26 @@ static void silence(struct cir_buf_ptr *stream, uint32_t start_offset, |
237 | 246 | } |
238 | 247 | } |
239 | 248 |
|
| 249 | +#if CONFIG_XRUN_NOTIFICATIONS_ENABLE |
| 250 | +static void mixin_check_notify_underrun(struct comp_dev *dev, struct mixin_data *mixin_data, |
| 251 | + size_t source_avail, size_t sinks_free) |
| 252 | +{ |
| 253 | + mixin_data->last_reported_underrun++; |
| 254 | + |
| 255 | + if (!source_avail && mixin_data->last_reported_underrun >= |
| 256 | + mixin_data->underrun_notification_period) { |
| 257 | + mixin_data->last_reported_underrun = 0; |
| 258 | + |
| 259 | + struct ipc_msg *notify = ipc_notification_pool_get(IPC4_RESOURCE_EVENT_SIZE); |
| 260 | + if (!notify) |
| 261 | + return; |
| 262 | + mixer_underrun_notif_msg_init(notify, dev->ipc_config.id, false, |
| 263 | + source_avail, sinks_free); |
| 264 | + ipc_msg_send(notify, notify->tx_data, false); |
| 265 | + } |
| 266 | +} |
| 267 | +#endif |
| 268 | + |
240 | 269 | /* Most of the mixing is done here on mixin side. mixin mixes its source data |
241 | 270 | * into each connected mixout sink buffer. Basically, if mixout sink buffer has |
242 | 271 | * no data, mixin copies its source data into mixout sink buffer. If mixout sink |
@@ -356,6 +385,14 @@ static int mixin_process(struct processing_module *mod, |
356 | 385 | if (sinks_free_frames == 0 || sinks_free_frames == INT32_MAX) |
357 | 386 | return 0; |
358 | 387 |
|
| 388 | +#if CONFIG_XRUN_NOTIFICATIONS_ENABLE |
| 389 | + size_t frame_bytes = source_get_frame_bytes(sources[0]); |
| 390 | + size_t min_frames = MIN(dev->frames, sinks_free_frames); |
| 391 | + mixin_check_notify_underrun(dev, mixin_data, |
| 392 | + source_avail_frames * frame_bytes, |
| 393 | + min_frames * frame_bytes); |
| 394 | +#endif |
| 395 | + |
359 | 396 | if (source_avail_frames > 0) { |
360 | 397 | size_t buf_size; |
361 | 398 |
|
@@ -917,11 +954,49 @@ static int mixin_set_config(struct processing_module *mod, uint32_t config_id, |
917 | 954 | return 0; |
918 | 955 | } |
919 | 956 |
|
| 957 | +#if CONFIG_XRUN_NOTIFICATIONS_ENABLE |
| 958 | +static int mixin_set_config_param(struct processing_module *mod, uint32_t param_id_data) |
| 959 | +{ |
| 960 | + struct mixin_data *mixin_data = module_get_private_data(mod); |
| 961 | + union config_param_id_data cfg; |
| 962 | + cfg.dw = param_id_data; |
| 963 | + |
| 964 | + if (cfg.f.id == IPC4_MIXER_UNDERRUN_NOTIF_PERIOD) |
| 965 | + { |
| 966 | + if (cfg.f.data16 < MIXIN_MODULE_MIN_UNDERRUN_NOTIFICATION_PERIOD) |
| 967 | + return -EINVAL; |
| 968 | + |
| 969 | + mixin_data->underrun_notification_period = cfg.f.data16; |
| 970 | + return 0; |
| 971 | + } |
| 972 | + return -EINVAL; |
| 973 | +} |
| 974 | + |
| 975 | +static int mixin_get_config_param(struct processing_module *mod, uint32_t *param_id_data) |
| 976 | +{ |
| 977 | + struct mixin_data *mixin_data = module_get_private_data(mod); |
| 978 | + union config_param_id_data cfg; |
| 979 | + cfg.dw = *param_id_data; |
| 980 | + |
| 981 | + if (cfg.f.id == IPC4_MIXER_UNDERRUN_NOTIF_PERIOD) |
| 982 | + { |
| 983 | + cfg.f.data16 = mixin_data->underrun_notification_period; |
| 984 | + *param_id_data = cfg.dw; |
| 985 | + return 0; |
| 986 | + } |
| 987 | + return -EINVAL; |
| 988 | +} |
| 989 | +#endif |
| 990 | + |
920 | 991 | static const struct module_interface mixin_interface = { |
921 | 992 | .init = mixin_init, |
922 | 993 | .prepare = mixin_prepare, |
923 | 994 | .process = mixin_process, |
924 | 995 | .set_configuration = mixin_set_config, |
| 996 | +#if CONFIG_XRUN_NOTIFICATIONS_ENABLE |
| 997 | + .set_config_param = mixin_set_config_param, |
| 998 | + .get_config_param = mixin_get_config_param, |
| 999 | +#endif |
925 | 1000 | .reset = mixin_reset, |
926 | 1001 | .free = mixin_free |
927 | 1002 | }; |
|
0 commit comments