1 #include <math.h>
2 #include <util/bmem.h>
3 #include <util/threading.h>
4 #include <util/platform.h>
5 #include <obs.h>
6 
7 struct sinewave_data {
8 	bool initialized_thread;
9 	pthread_t thread;
10 	os_event_t *event;
11 	obs_source_t *source;
12 };
13 
14 /* middle C */
15 static const double rate = 261.63 / 48000.0;
16 
17 #ifndef M_PI
18 #define M_PI 3.1415926535897932384626433832795
19 #endif
20 
21 #define M_PI_X2 M_PI * 2
22 
sinewave_thread(void * pdata)23 static void *sinewave_thread(void *pdata)
24 {
25 	struct sinewave_data *swd = pdata;
26 	uint64_t last_time = os_gettime_ns();
27 	uint64_t ts = 0;
28 	double cos_val = 0.0;
29 	uint8_t bytes[480];
30 
31 	while (os_event_try(swd->event) == EAGAIN) {
32 		if (!os_sleepto_ns(last_time += 10000000))
33 			last_time = os_gettime_ns();
34 
35 		for (size_t i = 0; i < 480; i++) {
36 			cos_val += rate * M_PI_X2;
37 			if (cos_val > M_PI_X2)
38 				cos_val -= M_PI_X2;
39 
40 			double wave = cos(cos_val) * 0.5;
41 			bytes[i] = (uint8_t)((wave + 1.0) * 0.5 * 255.0);
42 		}
43 
44 		struct obs_source_audio data;
45 		data.data[0] = bytes;
46 		data.frames = 480;
47 		data.speakers = SPEAKERS_MONO;
48 		data.samples_per_sec = 48000;
49 		data.timestamp = ts;
50 		data.format = AUDIO_FORMAT_U8BIT;
51 		obs_source_output_audio(swd->source, &data);
52 
53 		ts += 10000000;
54 	}
55 
56 	return NULL;
57 }
58 
59 /* ------------------------------------------------------------------------- */
60 
sinewave_getname(void * unused)61 static const char *sinewave_getname(void *unused)
62 {
63 	UNUSED_PARAMETER(unused);
64 	return "Sinewave Sound Source (Test)";
65 }
66 
sinewave_destroy(void * data)67 static void sinewave_destroy(void *data)
68 {
69 	struct sinewave_data *swd = data;
70 
71 	if (swd) {
72 		if (swd->initialized_thread) {
73 			void *ret;
74 			os_event_signal(swd->event);
75 			pthread_join(swd->thread, &ret);
76 		}
77 
78 		os_event_destroy(swd->event);
79 		bfree(swd);
80 	}
81 }
82 
sinewave_create(obs_data_t * settings,obs_source_t * source)83 static void *sinewave_create(obs_data_t *settings, obs_source_t *source)
84 {
85 	struct sinewave_data *swd = bzalloc(sizeof(struct sinewave_data));
86 	swd->source = source;
87 
88 	if (os_event_init(&swd->event, OS_EVENT_TYPE_MANUAL) != 0)
89 		goto fail;
90 	if (pthread_create(&swd->thread, NULL, sinewave_thread, swd) != 0)
91 		goto fail;
92 
93 	swd->initialized_thread = true;
94 
95 	UNUSED_PARAMETER(settings);
96 	return swd;
97 
98 fail:
99 	sinewave_destroy(swd);
100 	return NULL;
101 }
102 
103 struct obs_source_info test_sinewave = {
104 	.id = "test_sinewave",
105 	.type = OBS_SOURCE_TYPE_INPUT,
106 	.output_flags = OBS_SOURCE_AUDIO,
107 	.get_name = sinewave_getname,
108 	.create = sinewave_create,
109 	.destroy = sinewave_destroy,
110 };
111