1 /*
2 * Copyright © 2016 Mozilla Foundation
3 *
4 * This program is made available under an ISC-style license. See the
5 * accompanying file LICENSE for details.
6 */
7
8 /* libcubeb api/function test. Loops input back to output and check audio
9 * is flowing. */
10 #ifdef NDEBUG
11 #undef NDEBUG
12 #endif
13 #define _XOPEN_SOURCE 600
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <math.h>
17 #include <assert.h>
18
19 #include "cubeb/cubeb.h"
20 #include "common.h"
21 #ifdef CUBEB_GECKO_BUILD
22 #include "TestHarness.h"
23 #endif
24
25 #define SAMPLE_FREQUENCY 48000
26 #if (defined(_WIN32) || defined(__WIN32__))
27 #define STREAM_FORMAT CUBEB_SAMPLE_FLOAT32LE
28 #define SILENT_SAMPLE 0.0f
29 #else
30 #define STREAM_FORMAT CUBEB_SAMPLE_S16LE
31 #define SILENT_SAMPLE 0
32 #endif
33
34 struct user_state
35 {
36 bool seen_noise;
37 };
38
39
40
data_cb(cubeb_stream * stream,void * user,const void * inputbuffer,void * outputbuffer,long nframes)41 long data_cb(cubeb_stream * stream, void * user, const void * inputbuffer, void * outputbuffer, long nframes)
42 {
43 user_state * u = reinterpret_cast<user_state*>(user);
44 #if (defined(_WIN32) || defined(__WIN32__))
45 float *ib = (float *)inputbuffer;
46 float *ob = (float *)outputbuffer;
47 #else
48 short *ib = (short *)inputbuffer;
49 short *ob = (short *)outputbuffer;
50 #endif
51 bool seen_noise = false;
52
53 if (stream == NULL || inputbuffer == NULL || outputbuffer == NULL) {
54 return CUBEB_ERROR;
55 }
56
57 // Loop back: upmix the single input channel to the two output channels,
58 // checking if there is noise in the process.
59 long output_index = 0;
60 for (long i = 0; i < nframes; i++) {
61 if (ib[i] != SILENT_SAMPLE) {
62 seen_noise = true;
63 }
64 ob[output_index] = ob[output_index + 1] = ib[i];
65 output_index += 2;
66 }
67
68 u->seen_noise |= seen_noise;
69
70 return nframes;
71 }
72
state_cb(cubeb_stream * stream,void *,cubeb_state state)73 void state_cb(cubeb_stream * stream, void * /*user*/, cubeb_state state)
74 {
75 if (stream == NULL)
76 return;
77
78 switch (state) {
79 case CUBEB_STATE_STARTED:
80 printf("stream started\n"); break;
81 case CUBEB_STATE_STOPPED:
82 printf("stream stopped\n"); break;
83 case CUBEB_STATE_DRAINED:
84 printf("stream drained\n"); break;
85 default:
86 printf("unknown stream state %d\n", state);
87 }
88
89 return;
90 }
91
main(int,char * [])92 int main(int /*argc*/, char * /*argv*/[])
93 {
94 #ifdef CUBEB_GECKO_BUILD
95 ScopedXPCOM xpcom("test_duplex");
96 #endif
97
98 cubeb *ctx;
99 cubeb_stream *stream;
100 cubeb_stream_params input_params;
101 cubeb_stream_params output_params;
102 int r;
103 user_state stream_state = { false };
104 uint32_t latency_frames = 0;
105
106 r = cubeb_init(&ctx, "Cubeb duplex example");
107 if (r != CUBEB_OK) {
108 fprintf(stderr, "Error initializing cubeb library\n");
109 return r;
110 }
111
112 /* This test needs an available input device, skip it if this host does not
113 * have one. */
114 if (!has_available_input_device(ctx)) {
115 return 0;
116 }
117
118 /* typical user-case: mono input, stereo output, low latency. */
119 input_params.format = STREAM_FORMAT;
120 input_params.rate = 48000;
121 input_params.channels = 1;
122 output_params.format = STREAM_FORMAT;
123 output_params.rate = 48000;
124 output_params.channels = 2;
125
126 r = cubeb_get_min_latency(ctx, output_params, &latency_frames);
127
128 if (r != CUBEB_OK) {
129 fprintf(stderr, "Could not get minimal latency\n");
130 return r;
131 }
132
133 r = cubeb_stream_init(ctx, &stream, "Cubeb duplex",
134 NULL, &input_params, NULL, &output_params,
135 latency_frames, data_cb, state_cb, &stream_state);
136 if (r != CUBEB_OK) {
137 fprintf(stderr, "Error initializing cubeb stream\n");
138 return r;
139 }
140
141 cubeb_stream_start(stream);
142 delay(500);
143 cubeb_stream_stop(stream);
144
145 cubeb_stream_destroy(stream);
146 cubeb_destroy(ctx);
147
148 assert(stream_state.seen_noise);
149
150 return CUBEB_OK;
151 }
152