Skip to content

Commit be6ab7b

Browse files
committed
ASoC: SOF: ipc4-pcm: fix delay calculation when DSP resamples
When the sampling rates going in (host) and out (dai) from the DSP are different, the IPC4 delay reporting does not work correctly. Add support for this case by scaling the host position values to a common timebase before calculating real-time delay for the PCM. Signed-off-by: Kai Vehmanen <kai.vehmanen@linux.intel.com>
1 parent ea07943 commit be6ab7b

1 file changed

Lines changed: 64 additions & 4 deletions

File tree

sound/soc/sof/ipc4-pcm.c

Lines changed: 64 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,15 @@
1919
* struct sof_ipc4_timestamp_info - IPC4 timestamp info
2020
* @host_copier: the host copier of the pcm stream
2121
* @dai_copier: the dai copier of the pcm stream
22-
* @stream_start_offset: reported by fw in memory window (converted to frames)
23-
* @stream_end_offset: reported by fw in memory window (converted to frames)
22+
* @stream_start_offset: reported by fw in memory window (converted to
23+
* frames at dai_copier sampling rate)
24+
* @stream_end_offset: reported by fw in memory window (converted to
25+
* frames at dai_copier sampling rate)
2426
* @llp_offset: llp offset in memory window
2527
* @boundary: wrap boundary should be used for the LLP frame counter
2628
* @delay: Calculated and stored in pointer callback. The stored value is
27-
* returned in the delay callback.
29+
* returned in the delay callback. Expressed in frames at host copier
30+
* sampling rate.
2831
*/
2932
struct sof_ipc4_timestamp_info {
3033
struct sof_ipc4_copier *host_copier;
@@ -1113,6 +1116,53 @@ static int sof_ipc4_get_stream_start_offset(struct snd_sof_dev *sdev,
11131116
return 0;
11141117
}
11151118

1119+
static u64 sof_ipc4_time_scale(struct sof_ipc4_timestamp_info *time_info, u64 value, bool dai_to_host)
1120+
{
1121+
u64 dai_rate, host_rate, mul, div;
1122+
1123+
if (!time_info->dai_copier || !time_info->host_copier)
1124+
return value;
1125+
1126+
/*
1127+
* copiers do not change sampling rate, so we can use the
1128+
* out_format independently of stream direction
1129+
*/
1130+
dai_rate = time_info->dai_copier->data.out_format.sampling_frequency;
1131+
host_rate = time_info->host_copier->data.out_format.sampling_frequency;
1132+
1133+
if (!dai_rate || !host_rate)
1134+
return value;
1135+
1136+
if (dai_to_host) {
1137+
mul = host_rate;
1138+
div = dai_rate;
1139+
} else {
1140+
mul = dai_rate;
1141+
div = host_rate;
1142+
}
1143+
1144+
/* take care not to overflow u64, div/mul can be upto 768000 */
1145+
if (value > U32_MAX) {
1146+
value = DIV64_U64_ROUND_CLOSEST(value, div);
1147+
value *= mul;
1148+
} else {
1149+
value *= mul;
1150+
value = DIV64_U64_ROUND_CLOSEST(value, div);
1151+
}
1152+
1153+
return value;
1154+
}
1155+
1156+
static u64 sof_ipc4_time_dai_to_host(struct sof_ipc4_timestamp_info *time_info, u64 dai_time)
1157+
{
1158+
return sof_ipc4_time_scale(time_info, dai_time, true);
1159+
}
1160+
1161+
static u64 sof_ipc4_time_host_to_dai(struct sof_ipc4_timestamp_info *time_info, u64 host_time)
1162+
{
1163+
return sof_ipc4_time_scale(time_info, host_time, false);
1164+
}
1165+
11161166
static int sof_ipc4_pcm_pointer(struct snd_soc_component *component,
11171167
struct snd_pcm_substream *substream,
11181168
snd_pcm_uframes_t *pointer)
@@ -1149,8 +1199,13 @@ static int sof_ipc4_pcm_pointer(struct snd_soc_component *component,
11491199

11501200
/* For delay calculation we need the host counter */
11511201
host_cnt = snd_sof_pcm_get_host_byte_counter(sdev, component, substream);
1202+
1203+
/* Store the original value to host_ptr */
11521204
host_ptr = host_cnt;
11531205

1206+
/* Scale value to DAI time in case DAI running at different rate */
1207+
host_cnt = sof_ipc4_time_host_to_dai(time_info, host_cnt);
1208+
11541209
/* convert the host_cnt to frames */
11551210
host_cnt = div64_u64(host_cnt, frames_to_bytes(substream->runtime, 1));
11561211

@@ -1212,11 +1267,16 @@ static int sof_ipc4_pcm_pointer(struct snd_soc_component *component,
12121267
}
12131268

12141269
if (head_cnt < tail_cnt) {
1270+
/* TODO: is this correct in the SRC case? */
12151271
time_info->delay = time_info->boundary - tail_cnt + head_cnt;
12161272
goto out;
12171273
}
12181274

1219-
time_info->delay = head_cnt - tail_cnt;
1275+
/* delay in DAI time */
1276+
time_info->delay = head_cnt - tail_cnt;
1277+
1278+
/* convert delay to host time */
1279+
time_info->delay = sof_ipc4_time_dai_to_host(time_info, time_info->delay);
12201280

12211281
out:
12221282
/*

0 commit comments

Comments
 (0)