|
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,29 @@ 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 | + struct ipc_msg *notify; |
| 254 | + |
| 255 | + mixin_data->last_reported_underrun++; |
| 256 | + |
| 257 | + if (!source_avail && mixin_data->last_reported_underrun >= |
| 258 | + mixin_data->underrun_notification_period) { |
| 259 | + mixin_data->last_reported_underrun = 0; |
| 260 | + |
| 261 | + notify = ipc_notification_pool_get(IPC4_RESOURCE_EVENT_SIZE); |
| 262 | + if (!notify) |
| 263 | + return; |
| 264 | + |
| 265 | + mixer_underrun_notif_msg_init(notify, dev->ipc_config.id, false, |
| 266 | + source_avail, sinks_free); |
| 267 | + ipc_msg_send(notify, notify->tx_data, false); |
| 268 | + } |
| 269 | +} |
| 270 | +#endif |
| 271 | + |
240 | 272 | /* Most of the mixing is done here on mixin side. mixin mixes its source data |
241 | 273 | * into each connected mixout sink buffer. Basically, if mixout sink buffer has |
242 | 274 | * no data, mixin copies its source data into mixout sink buffer. If mixout sink |
@@ -356,6 +388,15 @@ static int mixin_process(struct processing_module *mod, |
356 | 388 | if (sinks_free_frames == 0 || sinks_free_frames == INT32_MAX) |
357 | 389 | return 0; |
358 | 390 |
|
| 391 | +#if CONFIG_XRUN_NOTIFICATIONS_ENABLE |
| 392 | + size_t frame_bytes = source_get_frame_bytes(sources[0]); |
| 393 | + size_t min_frames = MIN(dev->frames, sinks_free_frames); |
| 394 | + |
| 395 | + mixin_check_notify_underrun(dev, mixin_data, |
| 396 | + source_avail_frames * frame_bytes, |
| 397 | + min_frames * frame_bytes); |
| 398 | +#endif |
| 399 | + |
359 | 400 | if (source_avail_frames > 0) { |
360 | 401 | size_t buf_size; |
361 | 402 |
|
@@ -917,11 +958,49 @@ static int mixin_set_config(struct processing_module *mod, uint32_t config_id, |
917 | 958 | return 0; |
918 | 959 | } |
919 | 960 |
|
| 961 | +#if CONFIG_XRUN_NOTIFICATIONS_ENABLE |
| 962 | +static int mixin_set_config_param(struct processing_module *mod, uint32_t param_id_data) |
| 963 | +{ |
| 964 | + struct mixin_data *mixin_data = module_get_private_data(mod); |
| 965 | + union config_param_id_data cfg; |
| 966 | + |
| 967 | + cfg.dw = param_id_data; |
| 968 | + |
| 969 | + if (cfg.f.id == IPC4_MIXER_UNDERRUN_NOTIF_PERIOD) { |
| 970 | + if (cfg.f.data16 < MIXIN_MODULE_MIN_UNDERRUN_NOTIFICATION_PERIOD) |
| 971 | + return -EINVAL; |
| 972 | + |
| 973 | + mixin_data->underrun_notification_period = cfg.f.data16; |
| 974 | + return 0; |
| 975 | + } |
| 976 | + return -EINVAL; |
| 977 | +} |
| 978 | + |
| 979 | +static int mixin_get_config_param(struct processing_module *mod, uint32_t *param_id_data) |
| 980 | +{ |
| 981 | + struct mixin_data *mixin_data = module_get_private_data(mod); |
| 982 | + union config_param_id_data cfg; |
| 983 | + |
| 984 | + cfg.dw = *param_id_data; |
| 985 | + |
| 986 | + if (cfg.f.id == IPC4_MIXER_UNDERRUN_NOTIF_PERIOD) { |
| 987 | + cfg.f.data16 = mixin_data->underrun_notification_period; |
| 988 | + *param_id_data = cfg.dw; |
| 989 | + return 0; |
| 990 | + } |
| 991 | + return -EINVAL; |
| 992 | +} |
| 993 | +#endif |
| 994 | + |
920 | 995 | static const struct module_interface mixin_interface = { |
921 | 996 | .init = mixin_init, |
922 | 997 | .prepare = mixin_prepare, |
923 | 998 | .process = mixin_process, |
924 | 999 | .set_configuration = mixin_set_config, |
| 1000 | +#if CONFIG_XRUN_NOTIFICATIONS_ENABLE |
| 1001 | + .set_config_param = mixin_set_config_param, |
| 1002 | + .get_config_param = mixin_get_config_param, |
| 1003 | +#endif |
925 | 1004 | .reset = mixin_reset, |
926 | 1005 | .free = mixin_free |
927 | 1006 | }; |
|
0 commit comments