1d5ac70f0Sopenharmony_ci/*
2d5ac70f0Sopenharmony_ci * This program only tracks the difference between system time
3d5ac70f0Sopenharmony_ci * and audio time, as reported in snd_pcm_status(). It should be
4d5ac70f0Sopenharmony_ci * helpful to verify the information reported by drivers.
5d5ac70f0Sopenharmony_ci */
6d5ac70f0Sopenharmony_ci
7d5ac70f0Sopenharmony_ci#include "config.h"
8d5ac70f0Sopenharmony_ci#include <stdio.h>
9d5ac70f0Sopenharmony_ci#if HAVE_MALLOC_H
10d5ac70f0Sopenharmony_ci#include <malloc.h>
11d5ac70f0Sopenharmony_ci#endif
12d5ac70f0Sopenharmony_ci#include <unistd.h>
13d5ac70f0Sopenharmony_ci#include <stdlib.h>
14d5ac70f0Sopenharmony_ci#include <string.h>
15d5ac70f0Sopenharmony_ci#include <getopt.h>
16d5ac70f0Sopenharmony_ci#include <fcntl.h>
17d5ac70f0Sopenharmony_ci#include <ctype.h>
18d5ac70f0Sopenharmony_ci#include <errno.h>
19d5ac70f0Sopenharmony_ci#include <limits.h>
20d5ac70f0Sopenharmony_ci#include <time.h>
21d5ac70f0Sopenharmony_ci#include <locale.h>
22d5ac70f0Sopenharmony_ci#include <math.h>
23d5ac70f0Sopenharmony_ci#include "../include/asoundlib.h"
24d5ac70f0Sopenharmony_ci
25d5ac70f0Sopenharmony_cistatic char *pcm_name = "hw:0";
26d5ac70f0Sopenharmony_cisnd_output_t *output = NULL;
27d5ac70f0Sopenharmony_ci
28d5ac70f0Sopenharmony_cistatic void usage(char *command)
29d5ac70f0Sopenharmony_ci{
30d5ac70f0Sopenharmony_ci	printf("Usage: %s [OPTION]... \n"
31d5ac70f0Sopenharmony_ci		"\n"
32d5ac70f0Sopenharmony_ci		"-h, --help              help\n"
33d5ac70f0Sopenharmony_ci		"-c, --capture           capture tstamps \n"
34d5ac70f0Sopenharmony_ci		"-d, --delay             add delay \n"
35d5ac70f0Sopenharmony_ci		"-D, --device=NAME       select PCM by name \n"
36d5ac70f0Sopenharmony_ci		"-p, --playback          playback tstamps \n"
37d5ac70f0Sopenharmony_ci		"-t, --ts_type=TYPE      Compat(0),default(1),link(2),link_absolute(3),link_estimated(4),link_synchronized(5) \n"
38d5ac70f0Sopenharmony_ci		"-r, --report            show audio timestamp and accuracy validity\n"
39d5ac70f0Sopenharmony_ci		, command);
40d5ac70f0Sopenharmony_ci}
41d5ac70f0Sopenharmony_ci
42d5ac70f0Sopenharmony_ci
43d5ac70f0Sopenharmony_cilong long timestamp2ns(snd_htimestamp_t t)
44d5ac70f0Sopenharmony_ci{
45d5ac70f0Sopenharmony_ci	long long nsec;
46d5ac70f0Sopenharmony_ci
47d5ac70f0Sopenharmony_ci	nsec = t.tv_sec * 1000000000ULL;
48d5ac70f0Sopenharmony_ci	nsec += t.tv_nsec;
49d5ac70f0Sopenharmony_ci
50d5ac70f0Sopenharmony_ci	return nsec;
51d5ac70f0Sopenharmony_ci}
52d5ac70f0Sopenharmony_ci
53d5ac70f0Sopenharmony_cilong long timediff(snd_htimestamp_t t1, snd_htimestamp_t t2)
54d5ac70f0Sopenharmony_ci{
55d5ac70f0Sopenharmony_ci	long long nsec1, nsec2;
56d5ac70f0Sopenharmony_ci
57d5ac70f0Sopenharmony_ci	nsec1 = timestamp2ns(t1);
58d5ac70f0Sopenharmony_ci	nsec2 = timestamp2ns(t2);
59d5ac70f0Sopenharmony_ci
60d5ac70f0Sopenharmony_ci	return nsec1 - nsec2;
61d5ac70f0Sopenharmony_ci}
62d5ac70f0Sopenharmony_ci
63d5ac70f0Sopenharmony_civoid _gettimestamp(snd_pcm_t *handle, snd_htimestamp_t *timestamp,
64d5ac70f0Sopenharmony_ci		   snd_htimestamp_t *trigger_timestamp,
65d5ac70f0Sopenharmony_ci		   snd_htimestamp_t *audio_timestamp,
66d5ac70f0Sopenharmony_ci		   snd_pcm_audio_tstamp_config_t  *audio_tstamp_config,
67d5ac70f0Sopenharmony_ci		   snd_pcm_audio_tstamp_report_t  *audio_tstamp_report,
68d5ac70f0Sopenharmony_ci		   snd_pcm_uframes_t *avail, snd_pcm_sframes_t *delay)
69d5ac70f0Sopenharmony_ci{
70d5ac70f0Sopenharmony_ci	int err;
71d5ac70f0Sopenharmony_ci	snd_pcm_status_t *status;
72d5ac70f0Sopenharmony_ci
73d5ac70f0Sopenharmony_ci	snd_pcm_status_alloca(&status);
74d5ac70f0Sopenharmony_ci
75d5ac70f0Sopenharmony_ci	snd_pcm_status_set_audio_htstamp_config(status, audio_tstamp_config);
76d5ac70f0Sopenharmony_ci
77d5ac70f0Sopenharmony_ci	if ((err = snd_pcm_status(handle, status)) < 0) {
78d5ac70f0Sopenharmony_ci		printf("Stream status error: %s\n", snd_strerror(err));
79d5ac70f0Sopenharmony_ci		exit(0);
80d5ac70f0Sopenharmony_ci	}
81d5ac70f0Sopenharmony_ci	snd_pcm_status_get_trigger_htstamp(status, trigger_timestamp);
82d5ac70f0Sopenharmony_ci	snd_pcm_status_get_htstamp(status, timestamp);
83d5ac70f0Sopenharmony_ci	snd_pcm_status_get_audio_htstamp(status, audio_timestamp);
84d5ac70f0Sopenharmony_ci	snd_pcm_status_get_audio_htstamp_report(status, audio_tstamp_report);
85d5ac70f0Sopenharmony_ci	*avail = snd_pcm_status_get_avail(status);
86d5ac70f0Sopenharmony_ci	*delay = snd_pcm_status_get_delay(status);
87d5ac70f0Sopenharmony_ci}
88d5ac70f0Sopenharmony_ci
89d5ac70f0Sopenharmony_ci#define TIMESTAMP_FREQ 8 /* Hz */
90d5ac70f0Sopenharmony_ci#define SAMPLE_FREQ 48000
91d5ac70f0Sopenharmony_ci#define PERIOD (SAMPLE_FREQ/TIMESTAMP_FREQ)
92d5ac70f0Sopenharmony_ci#define PCM_LINK        /* sync start for playback and capture */
93d5ac70f0Sopenharmony_ci#define TRACK_CAPTURE   /* dump capture timing info  */
94d5ac70f0Sopenharmony_ci#define TRACK_PLAYBACK  /* dump playback timing info */
95d5ac70f0Sopenharmony_ci/*#define TRACK_SAMPLE_COUNTS */ /* show difference between sample counters and audiotimestamps returned by driver */
96d5ac70f0Sopenharmony_ci#define PLAYBACK_BUFFERS 4
97d5ac70f0Sopenharmony_ci#define TSTAMP_TYPE	SND_PCM_TSTAMP_TYPE_MONOTONIC_RAW
98d5ac70f0Sopenharmony_ci
99d5ac70f0Sopenharmony_ci
100d5ac70f0Sopenharmony_ciint main(int argc, char *argv[])
101d5ac70f0Sopenharmony_ci{
102d5ac70f0Sopenharmony_ci	int c;
103d5ac70f0Sopenharmony_ci	int err;
104d5ac70f0Sopenharmony_ci	unsigned int i;
105d5ac70f0Sopenharmony_ci	snd_pcm_t *handle_p = NULL;
106d5ac70f0Sopenharmony_ci	snd_pcm_t *handle_c = NULL;
107d5ac70f0Sopenharmony_ci	snd_pcm_sframes_t frames;
108d5ac70f0Sopenharmony_ci	snd_htimestamp_t tstamp_c, tstamp_p;
109d5ac70f0Sopenharmony_ci	snd_htimestamp_t trigger_tstamp_c, trigger_tstamp_p;
110d5ac70f0Sopenharmony_ci	snd_htimestamp_t audio_tstamp_c, audio_tstamp_p;
111d5ac70f0Sopenharmony_ci	unsigned char buffer_p[PERIOD*4*4];
112d5ac70f0Sopenharmony_ci	unsigned char buffer_c[PERIOD*4*4];
113d5ac70f0Sopenharmony_ci
114d5ac70f0Sopenharmony_ci	snd_pcm_hw_params_t *hwparams_p;
115d5ac70f0Sopenharmony_ci	snd_pcm_hw_params_t *hwparams_c;
116d5ac70f0Sopenharmony_ci
117d5ac70f0Sopenharmony_ci	snd_pcm_sw_params_t *swparams_p;
118d5ac70f0Sopenharmony_ci	snd_pcm_sw_params_t *swparams_c;
119d5ac70f0Sopenharmony_ci
120d5ac70f0Sopenharmony_ci	snd_pcm_uframes_t frame_count_c = 0;
121d5ac70f0Sopenharmony_ci	snd_pcm_uframes_t frame_count_p = 0;
122d5ac70f0Sopenharmony_ci
123d5ac70f0Sopenharmony_ci	snd_pcm_sframes_t delay_p, delay_c;
124d5ac70f0Sopenharmony_ci	snd_pcm_uframes_t avail_p, avail_c;
125d5ac70f0Sopenharmony_ci
126d5ac70f0Sopenharmony_ci	snd_pcm_audio_tstamp_config_t audio_tstamp_config_p;
127d5ac70f0Sopenharmony_ci	snd_pcm_audio_tstamp_config_t audio_tstamp_config_c;
128d5ac70f0Sopenharmony_ci	snd_pcm_audio_tstamp_report_t audio_tstamp_report_p;
129d5ac70f0Sopenharmony_ci	snd_pcm_audio_tstamp_report_t audio_tstamp_report_c;
130d5ac70f0Sopenharmony_ci
131d5ac70f0Sopenharmony_ci	int option_index;
132d5ac70f0Sopenharmony_ci	static const char short_options[] = "hcpdrD:t:";
133d5ac70f0Sopenharmony_ci
134d5ac70f0Sopenharmony_ci	static const struct option long_options[] = {
135d5ac70f0Sopenharmony_ci		{"capture", 0, 0, 'c'},
136d5ac70f0Sopenharmony_ci		{"delay", 0, 0, 'd'},
137d5ac70f0Sopenharmony_ci		{"device", required_argument, 0, 'D'},
138d5ac70f0Sopenharmony_ci		{"help", no_argument, 0, 'h'},
139d5ac70f0Sopenharmony_ci		{"playback", 0, 0, 'p'},
140d5ac70f0Sopenharmony_ci		{"ts_type", required_argument, 0, 't'},
141d5ac70f0Sopenharmony_ci		{"report", 0, 0, 'r'},
142d5ac70f0Sopenharmony_ci		{0, 0, 0, 0}
143d5ac70f0Sopenharmony_ci	};
144d5ac70f0Sopenharmony_ci
145d5ac70f0Sopenharmony_ci	int do_delay = 0;
146d5ac70f0Sopenharmony_ci	int do_playback = 0;
147d5ac70f0Sopenharmony_ci	int do_capture = 0;
148d5ac70f0Sopenharmony_ci	int type = 0;
149d5ac70f0Sopenharmony_ci	int do_report = 0;
150d5ac70f0Sopenharmony_ci
151d5ac70f0Sopenharmony_ci	while ((c = getopt_long(argc, argv, short_options, long_options, &option_index)) != -1) {
152d5ac70f0Sopenharmony_ci		switch (c) {
153d5ac70f0Sopenharmony_ci		case 'h':
154d5ac70f0Sopenharmony_ci			usage(argv[0]);
155d5ac70f0Sopenharmony_ci			return 0;
156d5ac70f0Sopenharmony_ci		case 'p':
157d5ac70f0Sopenharmony_ci			do_playback = 1;
158d5ac70f0Sopenharmony_ci			break;
159d5ac70f0Sopenharmony_ci		case 'c':
160d5ac70f0Sopenharmony_ci			do_capture = 1;
161d5ac70f0Sopenharmony_ci			break;
162d5ac70f0Sopenharmony_ci		case 'd':
163d5ac70f0Sopenharmony_ci			do_delay = 1;
164d5ac70f0Sopenharmony_ci			break;
165d5ac70f0Sopenharmony_ci		case 'D':
166d5ac70f0Sopenharmony_ci			pcm_name = optarg;
167d5ac70f0Sopenharmony_ci			break;
168d5ac70f0Sopenharmony_ci		case 't':
169d5ac70f0Sopenharmony_ci			type = atoi(optarg);
170d5ac70f0Sopenharmony_ci			break;
171d5ac70f0Sopenharmony_ci		case 'r':
172d5ac70f0Sopenharmony_ci			do_report = 1;
173d5ac70f0Sopenharmony_ci		}
174d5ac70f0Sopenharmony_ci	}
175d5ac70f0Sopenharmony_ci
176d5ac70f0Sopenharmony_ci	memset(&audio_tstamp_config_p, 0, sizeof(snd_pcm_audio_tstamp_config_t));
177d5ac70f0Sopenharmony_ci	memset(&audio_tstamp_config_c, 0, sizeof(snd_pcm_audio_tstamp_config_t));
178d5ac70f0Sopenharmony_ci	memset(&audio_tstamp_report_p, 0, sizeof(snd_pcm_audio_tstamp_report_t));
179d5ac70f0Sopenharmony_ci	memset(&audio_tstamp_report_c, 0, sizeof(snd_pcm_audio_tstamp_report_t));
180d5ac70f0Sopenharmony_ci
181d5ac70f0Sopenharmony_ci	if (do_playback) {
182d5ac70f0Sopenharmony_ci		if ((err = snd_pcm_open(&handle_p, pcm_name, SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
183d5ac70f0Sopenharmony_ci			printf("Playback open error: %s\n", snd_strerror(err));
184d5ac70f0Sopenharmony_ci			goto _exit;
185d5ac70f0Sopenharmony_ci		}
186d5ac70f0Sopenharmony_ci
187d5ac70f0Sopenharmony_ci		if ((err = snd_pcm_set_params(handle_p,
188d5ac70f0Sopenharmony_ci							SND_PCM_FORMAT_S16,
189d5ac70f0Sopenharmony_ci							SND_PCM_ACCESS_RW_INTERLEAVED,
190d5ac70f0Sopenharmony_ci							2,
191d5ac70f0Sopenharmony_ci							SAMPLE_FREQ,
192d5ac70f0Sopenharmony_ci							0,
193d5ac70f0Sopenharmony_ci							4*1000000/TIMESTAMP_FREQ)) < 0) {
194d5ac70f0Sopenharmony_ci			printf("Playback open error: %s\n", snd_strerror(err));
195d5ac70f0Sopenharmony_ci			goto _exit;
196d5ac70f0Sopenharmony_ci		}
197d5ac70f0Sopenharmony_ci
198d5ac70f0Sopenharmony_ci		snd_pcm_hw_params_alloca(&hwparams_p);
199d5ac70f0Sopenharmony_ci/* get the current hwparams */
200d5ac70f0Sopenharmony_ci		err = snd_pcm_hw_params_current(handle_p, hwparams_p);
201d5ac70f0Sopenharmony_ci		if (err < 0) {
202d5ac70f0Sopenharmony_ci			printf("Unable to determine current hwparams_p: %s\n", snd_strerror(err));
203d5ac70f0Sopenharmony_ci			goto _exit;
204d5ac70f0Sopenharmony_ci		}
205d5ac70f0Sopenharmony_ci
206d5ac70f0Sopenharmony_ci		if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_p, SND_PCM_AUDIO_TSTAMP_TYPE_COMPAT))
207d5ac70f0Sopenharmony_ci			printf("Playback supports audio compat timestamps\n");
208d5ac70f0Sopenharmony_ci		if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_p, SND_PCM_AUDIO_TSTAMP_TYPE_DEFAULT))
209d5ac70f0Sopenharmony_ci			printf("Playback supports audio default timestamps\n");
210d5ac70f0Sopenharmony_ci		if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_p, SND_PCM_AUDIO_TSTAMP_TYPE_LINK))
211d5ac70f0Sopenharmony_ci			printf("Playback supports audio link timestamps\n");
212d5ac70f0Sopenharmony_ci		if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_p, SND_PCM_AUDIO_TSTAMP_TYPE_LINK_ABSOLUTE))
213d5ac70f0Sopenharmony_ci			printf("Playback supports audio link absolute timestamps\n");
214d5ac70f0Sopenharmony_ci		if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_p, SND_PCM_AUDIO_TSTAMP_TYPE_LINK_ESTIMATED))
215d5ac70f0Sopenharmony_ci			printf("Playback supports audio link estimated timestamps\n");
216d5ac70f0Sopenharmony_ci		if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_p, SND_PCM_AUDIO_TSTAMP_TYPE_LINK_SYNCHRONIZED))
217d5ac70f0Sopenharmony_ci			printf("Playback supports audio link synchronized timestamps\n");
218d5ac70f0Sopenharmony_ci
219d5ac70f0Sopenharmony_ci		snd_pcm_sw_params_alloca(&swparams_p);
220d5ac70f0Sopenharmony_ci		/* get the current swparams */
221d5ac70f0Sopenharmony_ci		err = snd_pcm_sw_params_current(handle_p, swparams_p);
222d5ac70f0Sopenharmony_ci		if (err < 0) {
223d5ac70f0Sopenharmony_ci			printf("Unable to determine current swparams_p: %s\n", snd_strerror(err));
224d5ac70f0Sopenharmony_ci			goto _exit;
225d5ac70f0Sopenharmony_ci		}
226d5ac70f0Sopenharmony_ci
227d5ac70f0Sopenharmony_ci		/* enable tstamp */
228d5ac70f0Sopenharmony_ci		err = snd_pcm_sw_params_set_tstamp_mode(handle_p, swparams_p, SND_PCM_TSTAMP_ENABLE);
229d5ac70f0Sopenharmony_ci		if (err < 0) {
230d5ac70f0Sopenharmony_ci			printf("Unable to set tstamp mode : %s\n", snd_strerror(err));
231d5ac70f0Sopenharmony_ci			goto _exit;
232d5ac70f0Sopenharmony_ci		}
233d5ac70f0Sopenharmony_ci
234d5ac70f0Sopenharmony_ci		err = snd_pcm_sw_params_set_tstamp_type(handle_p, swparams_p, TSTAMP_TYPE);
235d5ac70f0Sopenharmony_ci		if (err < 0) {
236d5ac70f0Sopenharmony_ci			printf("Unable to set tstamp type : %s\n", snd_strerror(err));
237d5ac70f0Sopenharmony_ci			goto _exit;
238d5ac70f0Sopenharmony_ci		}
239d5ac70f0Sopenharmony_ci
240d5ac70f0Sopenharmony_ci		/* write the sw parameters */
241d5ac70f0Sopenharmony_ci		err = snd_pcm_sw_params(handle_p, swparams_p);
242d5ac70f0Sopenharmony_ci		if (err < 0) {
243d5ac70f0Sopenharmony_ci			printf("Unable to set swparams_p : %s\n", snd_strerror(err));
244d5ac70f0Sopenharmony_ci			goto _exit;
245d5ac70f0Sopenharmony_ci		}
246d5ac70f0Sopenharmony_ci
247d5ac70f0Sopenharmony_ci	}
248d5ac70f0Sopenharmony_ci
249d5ac70f0Sopenharmony_ci	if (do_capture) {
250d5ac70f0Sopenharmony_ci
251d5ac70f0Sopenharmony_ci		if ((err = snd_pcm_open(&handle_c, pcm_name, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK)) < 0) {
252d5ac70f0Sopenharmony_ci			printf("Capture open error: %s\n", snd_strerror(err));
253d5ac70f0Sopenharmony_ci			goto _exit;
254d5ac70f0Sopenharmony_ci		}
255d5ac70f0Sopenharmony_ci		if ((err = snd_pcm_set_params(handle_c,
256d5ac70f0Sopenharmony_ci							SND_PCM_FORMAT_S16,
257d5ac70f0Sopenharmony_ci							SND_PCM_ACCESS_RW_INTERLEAVED,
258d5ac70f0Sopenharmony_ci							2,
259d5ac70f0Sopenharmony_ci							SAMPLE_FREQ,
260d5ac70f0Sopenharmony_ci							0,
261d5ac70f0Sopenharmony_ci							4*1000000/TIMESTAMP_FREQ)) < 0) {
262d5ac70f0Sopenharmony_ci			printf("Capture open error: %s\n", snd_strerror(err));
263d5ac70f0Sopenharmony_ci			goto _exit;
264d5ac70f0Sopenharmony_ci		}
265d5ac70f0Sopenharmony_ci
266d5ac70f0Sopenharmony_ci		snd_pcm_hw_params_alloca(&hwparams_c);
267d5ac70f0Sopenharmony_ci		/* get the current hwparams */
268d5ac70f0Sopenharmony_ci		err = snd_pcm_hw_params_current(handle_c, hwparams_c);
269d5ac70f0Sopenharmony_ci		if (err < 0) {
270d5ac70f0Sopenharmony_ci			printf("Unable to determine current hwparams_c: %s\n", snd_strerror(err));
271d5ac70f0Sopenharmony_ci			goto _exit;
272d5ac70f0Sopenharmony_ci		}
273d5ac70f0Sopenharmony_ci
274d5ac70f0Sopenharmony_ci		if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_c, SND_PCM_AUDIO_TSTAMP_TYPE_COMPAT))
275d5ac70f0Sopenharmony_ci			printf("Capture supports audio compat timestamps\n");
276d5ac70f0Sopenharmony_ci		if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_c, SND_PCM_AUDIO_TSTAMP_TYPE_DEFAULT))
277d5ac70f0Sopenharmony_ci			printf("Capture supports audio default timestamps\n");
278d5ac70f0Sopenharmony_ci		if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_c, SND_PCM_AUDIO_TSTAMP_TYPE_LINK))
279d5ac70f0Sopenharmony_ci			printf("Capture supports audio link timestamps\n");
280d5ac70f0Sopenharmony_ci		if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_c, SND_PCM_AUDIO_TSTAMP_TYPE_LINK_ABSOLUTE))
281d5ac70f0Sopenharmony_ci			printf("Capture supports audio link absolute timestamps\n");
282d5ac70f0Sopenharmony_ci		if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_c, SND_PCM_AUDIO_TSTAMP_TYPE_LINK_ESTIMATED))
283d5ac70f0Sopenharmony_ci			printf("Capture supports audio link estimated timestamps\n");
284d5ac70f0Sopenharmony_ci		if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_c, SND_PCM_AUDIO_TSTAMP_TYPE_LINK_SYNCHRONIZED))
285d5ac70f0Sopenharmony_ci			printf("Capture supports audio link synchronized timestamps\n");
286d5ac70f0Sopenharmony_ci
287d5ac70f0Sopenharmony_ci		snd_pcm_sw_params_alloca(&swparams_c);
288d5ac70f0Sopenharmony_ci		/* get the current swparams */
289d5ac70f0Sopenharmony_ci		err = snd_pcm_sw_params_current(handle_c, swparams_c);
290d5ac70f0Sopenharmony_ci		if (err < 0) {
291d5ac70f0Sopenharmony_ci			printf("Unable to determine current swparams_c: %s\n", snd_strerror(err));
292d5ac70f0Sopenharmony_ci			goto _exit;
293d5ac70f0Sopenharmony_ci		}
294d5ac70f0Sopenharmony_ci
295d5ac70f0Sopenharmony_ci		/* enable tstamp */
296d5ac70f0Sopenharmony_ci		err = snd_pcm_sw_params_set_tstamp_mode(handle_c, swparams_c, SND_PCM_TSTAMP_ENABLE);
297d5ac70f0Sopenharmony_ci		if (err < 0) {
298d5ac70f0Sopenharmony_ci			printf("Unable to set tstamp mode : %s\n", snd_strerror(err));
299d5ac70f0Sopenharmony_ci			goto _exit;
300d5ac70f0Sopenharmony_ci		}
301d5ac70f0Sopenharmony_ci
302d5ac70f0Sopenharmony_ci		err = snd_pcm_sw_params_set_tstamp_type(handle_c, swparams_c, TSTAMP_TYPE);
303d5ac70f0Sopenharmony_ci		if (err < 0) {
304d5ac70f0Sopenharmony_ci			printf("Unable to set tstamp type : %s\n", snd_strerror(err));
305d5ac70f0Sopenharmony_ci			goto _exit;
306d5ac70f0Sopenharmony_ci		}
307d5ac70f0Sopenharmony_ci
308d5ac70f0Sopenharmony_ci		/* write the sw parameters */
309d5ac70f0Sopenharmony_ci		err = snd_pcm_sw_params(handle_c, swparams_c);
310d5ac70f0Sopenharmony_ci		if (err < 0) {
311d5ac70f0Sopenharmony_ci			printf("Unable to set swparams_c : %s\n", snd_strerror(err));
312d5ac70f0Sopenharmony_ci			goto _exit;
313d5ac70f0Sopenharmony_ci		}
314d5ac70f0Sopenharmony_ci	}
315d5ac70f0Sopenharmony_ci
316d5ac70f0Sopenharmony_ci	if (do_playback && do_capture) {
317d5ac70f0Sopenharmony_ci#ifdef PCM_LINK
318d5ac70f0Sopenharmony_ci		if ((err = snd_pcm_link(handle_c, handle_p)) < 0) {
319d5ac70f0Sopenharmony_ci			printf("Streams link error: %s\n", snd_strerror(err));
320d5ac70f0Sopenharmony_ci			exit(0);
321d5ac70f0Sopenharmony_ci		}
322d5ac70f0Sopenharmony_ci#endif
323d5ac70f0Sopenharmony_ci	}
324d5ac70f0Sopenharmony_ci
325d5ac70f0Sopenharmony_ci	if (do_playback) {
326d5ac70f0Sopenharmony_ci		i = PLAYBACK_BUFFERS;
327d5ac70f0Sopenharmony_ci		while (i--) {
328d5ac70f0Sopenharmony_ci			frames = snd_pcm_writei(handle_p, buffer_p, PERIOD);
329d5ac70f0Sopenharmony_ci			if (frames < 0) {
330d5ac70f0Sopenharmony_ci				printf("snd_pcm_writei failed: %s\n", snd_strerror(frames));
331d5ac70f0Sopenharmony_ci				goto _exit;
332d5ac70f0Sopenharmony_ci			}
333d5ac70f0Sopenharmony_ci			frame_count_p += frames;
334d5ac70f0Sopenharmony_ci		}
335d5ac70f0Sopenharmony_ci
336d5ac70f0Sopenharmony_ci		if (PLAYBACK_BUFFERS != 4)
337d5ac70f0Sopenharmony_ci			snd_pcm_start(handle_p);
338d5ac70f0Sopenharmony_ci	}
339d5ac70f0Sopenharmony_ci
340d5ac70f0Sopenharmony_ci	if (do_capture) {
341d5ac70f0Sopenharmony_ci#ifndef PCM_LINK
342d5ac70f0Sopenharmony_ci		/* need to start capture explicitly */
343d5ac70f0Sopenharmony_ci		snd_pcm_start(handle_c);
344d5ac70f0Sopenharmony_ci#else
345d5ac70f0Sopenharmony_ci		if (!do_playback)
346d5ac70f0Sopenharmony_ci			/* need to start capture explicitly */
347d5ac70f0Sopenharmony_ci			snd_pcm_start(handle_c);
348d5ac70f0Sopenharmony_ci#endif
349d5ac70f0Sopenharmony_ci	}
350d5ac70f0Sopenharmony_ci
351d5ac70f0Sopenharmony_ci	while (1) {
352d5ac70f0Sopenharmony_ci
353d5ac70f0Sopenharmony_ci		if (do_capture) {
354d5ac70f0Sopenharmony_ci
355d5ac70f0Sopenharmony_ci			frames = snd_pcm_wait(handle_c, -1);
356d5ac70f0Sopenharmony_ci			if (frames < 0) {
357d5ac70f0Sopenharmony_ci				printf("snd_pcm_wait failed: %s\n", snd_strerror(frames));
358d5ac70f0Sopenharmony_ci				goto _exit;
359d5ac70f0Sopenharmony_ci			}
360d5ac70f0Sopenharmony_ci
361d5ac70f0Sopenharmony_ci			frames = snd_pcm_readi(handle_c, buffer_c, PERIOD);
362d5ac70f0Sopenharmony_ci			if (frames < 0) {
363d5ac70f0Sopenharmony_ci				printf("snd_pcm_readi failed: %s\n", snd_strerror(frames));
364d5ac70f0Sopenharmony_ci				goto _exit;
365d5ac70f0Sopenharmony_ci			}
366d5ac70f0Sopenharmony_ci			frame_count_c += frames;
367d5ac70f0Sopenharmony_ci
368d5ac70f0Sopenharmony_ci#if defined(TRACK_CAPTURE)
369d5ac70f0Sopenharmony_ci			audio_tstamp_config_c.type_requested = type;
370d5ac70f0Sopenharmony_ci			audio_tstamp_config_c.report_delay = do_delay;
371d5ac70f0Sopenharmony_ci			_gettimestamp(handle_c, &tstamp_c, &trigger_tstamp_c,
372d5ac70f0Sopenharmony_ci				&audio_tstamp_c, &audio_tstamp_config_c, &audio_tstamp_report_c,
373d5ac70f0Sopenharmony_ci				&avail_c, &delay_c);
374d5ac70f0Sopenharmony_ci#if defined(TRACK_SAMPLE_COUNTS)
375d5ac70f0Sopenharmony_ci			curr_count_c = frame_count_c + delay_c; /* read plus queued */
376d5ac70f0Sopenharmony_ci
377d5ac70f0Sopenharmony_ci
378d5ac70f0Sopenharmony_ci			printf("capture: curr_count %lli driver count %lli, delta %lli\n",
379d5ac70f0Sopenharmony_ci				(long long)curr_count_c * 1000000000LL / SAMPLE_FREQ ,
380d5ac70f0Sopenharmony_ci				timestamp2ns(audio_tstamp_c),
381d5ac70f0Sopenharmony_ci				(long long)curr_count_c * 1000000000LL / SAMPLE_FREQ - timestamp2ns(audio_tstamp_c)
382d5ac70f0Sopenharmony_ci				);
383d5ac70f0Sopenharmony_ci#endif
384d5ac70f0Sopenharmony_ci			if (do_report) {
385d5ac70f0Sopenharmony_ci				if (audio_tstamp_report_c.valid == 0)
386d5ac70f0Sopenharmony_ci					printf("Audio capture timestamp report invalid - ");
387d5ac70f0Sopenharmony_ci				if (audio_tstamp_report_c.accuracy_report == 0)
388d5ac70f0Sopenharmony_ci					printf("Audio capture timestamp accuracy report invalid");
389d5ac70f0Sopenharmony_ci				printf("\n");
390d5ac70f0Sopenharmony_ci			}
391d5ac70f0Sopenharmony_ci
392d5ac70f0Sopenharmony_ci
393d5ac70f0Sopenharmony_ci			printf("\t capture: systime: %lli nsec, audio time %lli nsec, \tsystime delta %lli \t resolution %d ns \n",
394d5ac70f0Sopenharmony_ci				timediff(tstamp_c, trigger_tstamp_c),
395d5ac70f0Sopenharmony_ci				timestamp2ns(audio_tstamp_c),
396d5ac70f0Sopenharmony_ci				timediff(tstamp_c, trigger_tstamp_c) - timestamp2ns(audio_tstamp_c), audio_tstamp_report_c.accuracy
397d5ac70f0Sopenharmony_ci				);
398d5ac70f0Sopenharmony_ci#endif
399d5ac70f0Sopenharmony_ci		}
400d5ac70f0Sopenharmony_ci
401d5ac70f0Sopenharmony_ci		if (do_playback) {
402d5ac70f0Sopenharmony_ci			frames = snd_pcm_writei(handle_p, buffer_p, PERIOD);
403d5ac70f0Sopenharmony_ci			if (frames < 0) {
404d5ac70f0Sopenharmony_ci				printf("snd_pcm_writei failed: %s\n", snd_strerror(frames));
405d5ac70f0Sopenharmony_ci				goto _exit;
406d5ac70f0Sopenharmony_ci			}
407d5ac70f0Sopenharmony_ci
408d5ac70f0Sopenharmony_ci			frame_count_p += frames;
409d5ac70f0Sopenharmony_ci
410d5ac70f0Sopenharmony_ci#if defined(TRACK_PLAYBACK)
411d5ac70f0Sopenharmony_ci
412d5ac70f0Sopenharmony_ci			audio_tstamp_config_p.type_requested = type;
413d5ac70f0Sopenharmony_ci			audio_tstamp_config_p.report_delay = do_delay;
414d5ac70f0Sopenharmony_ci			_gettimestamp(handle_p, &tstamp_p, &trigger_tstamp_p,
415d5ac70f0Sopenharmony_ci				&audio_tstamp_p, &audio_tstamp_config_p, &audio_tstamp_report_p,
416d5ac70f0Sopenharmony_ci				&avail_p, &delay_p);
417d5ac70f0Sopenharmony_ci
418d5ac70f0Sopenharmony_ci#if defined(TRACK_SAMPLE_COUNTS)
419d5ac70f0Sopenharmony_ci			curr_count_p = frame_count_p - delay_p; /* written minus queued */
420d5ac70f0Sopenharmony_ci
421d5ac70f0Sopenharmony_ci			printf("playback: curr_count %lli driver count %lli, delta %lli\n",
422d5ac70f0Sopenharmony_ci				(long long)curr_count_p * 1000000000LL / SAMPLE_FREQ ,
423d5ac70f0Sopenharmony_ci				timestamp2ns(audio_tstamp_p),
424d5ac70f0Sopenharmony_ci				(long long)curr_count_p * 1000000000LL / SAMPLE_FREQ - timestamp2ns(audio_tstamp_p)
425d5ac70f0Sopenharmony_ci				);
426d5ac70f0Sopenharmony_ci#endif
427d5ac70f0Sopenharmony_ci			if (do_report) {
428d5ac70f0Sopenharmony_ci				if (audio_tstamp_report_p.valid == 0)
429d5ac70f0Sopenharmony_ci					printf("Audio playback timestamp report invalid - ");
430d5ac70f0Sopenharmony_ci				if (audio_tstamp_report_p.accuracy_report == 0)
431d5ac70f0Sopenharmony_ci					printf("Audio playback timestamp accuracy report invalid");
432d5ac70f0Sopenharmony_ci				printf("\n");
433d5ac70f0Sopenharmony_ci			}
434d5ac70f0Sopenharmony_ci
435d5ac70f0Sopenharmony_ci			printf("playback: systime: %lli nsec, audio time %lli nsec, \tsystime delta %lli resolution %d ns\n",
436d5ac70f0Sopenharmony_ci				timediff(tstamp_p, trigger_tstamp_p),
437d5ac70f0Sopenharmony_ci				timestamp2ns(audio_tstamp_p),
438d5ac70f0Sopenharmony_ci				timediff(tstamp_p, trigger_tstamp_p) - timestamp2ns(audio_tstamp_p), audio_tstamp_report_p.accuracy
439d5ac70f0Sopenharmony_ci				);
440d5ac70f0Sopenharmony_ci#endif
441d5ac70f0Sopenharmony_ci		}
442d5ac70f0Sopenharmony_ci
443d5ac70f0Sopenharmony_ci
444d5ac70f0Sopenharmony_ci	} /* while(1) */
445d5ac70f0Sopenharmony_ci
446d5ac70f0Sopenharmony_ci_exit:
447d5ac70f0Sopenharmony_ci	if (handle_p)
448d5ac70f0Sopenharmony_ci		snd_pcm_close(handle_p);
449d5ac70f0Sopenharmony_ci	if (handle_c)
450d5ac70f0Sopenharmony_ci		snd_pcm_close(handle_c);
451d5ac70f0Sopenharmony_ci
452d5ac70f0Sopenharmony_ci	return 0;
453d5ac70f0Sopenharmony_ci}
454