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