xref: /btstack/test/avdtp/portaudio_test.c (revision 4a7e70d324ee17b34ba489c52cbaac93503d9e1f)
1*4a7e70d3SMilanka Ringwald /*
2*4a7e70d3SMilanka Ringwald  * Copyright (C) 2016 BlueKitchen GmbH
3*4a7e70d3SMilanka Ringwald  *
4*4a7e70d3SMilanka Ringwald  * Redistribution and use in source and binary forms, with or without
5*4a7e70d3SMilanka Ringwald  * modification, are permitted provided that the following conditions
6*4a7e70d3SMilanka Ringwald  * are met:
7*4a7e70d3SMilanka Ringwald  *
8*4a7e70d3SMilanka Ringwald  * 1. Redistributions of source code must retain the above copyright
9*4a7e70d3SMilanka Ringwald  *    notice, this list of conditions and the following disclaimer.
10*4a7e70d3SMilanka Ringwald  * 2. Redistributions in binary form must reproduce the above copyright
11*4a7e70d3SMilanka Ringwald  *    notice, this list of conditions and the following disclaimer in the
12*4a7e70d3SMilanka Ringwald  *    documentation and/or other materials provided with the distribution.
13*4a7e70d3SMilanka Ringwald  * 3. Neither the name of the copyright holders nor the names of
14*4a7e70d3SMilanka Ringwald  *    contributors may be used to endorse or promote products derived
15*4a7e70d3SMilanka Ringwald  *    from this software without specific prior written permission.
16*4a7e70d3SMilanka Ringwald  * 4. Any redistribution, use, or modification is done solely for
17*4a7e70d3SMilanka Ringwald  *    personal benefit and not for any commercial purpose or for
18*4a7e70d3SMilanka Ringwald  *    monetary gain.
19*4a7e70d3SMilanka Ringwald  *
20*4a7e70d3SMilanka Ringwald  * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
21*4a7e70d3SMilanka Ringwald  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22*4a7e70d3SMilanka Ringwald  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23*4a7e70d3SMilanka Ringwald  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
24*4a7e70d3SMilanka Ringwald  * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25*4a7e70d3SMilanka Ringwald  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26*4a7e70d3SMilanka Ringwald  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
27*4a7e70d3SMilanka Ringwald  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28*4a7e70d3SMilanka Ringwald  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29*4a7e70d3SMilanka Ringwald  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
30*4a7e70d3SMilanka Ringwald  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31*4a7e70d3SMilanka Ringwald  * SUCH DAMAGE.
32*4a7e70d3SMilanka Ringwald  *
33*4a7e70d3SMilanka Ringwald  * Please inquire about commercial licensing options at
34*4a7e70d3SMilanka Ringwald  * [email protected]
35*4a7e70d3SMilanka Ringwald  *
36*4a7e70d3SMilanka Ringwald  */
37*4a7e70d3SMilanka Ringwald 
38*4a7e70d3SMilanka Ringwald #include <stdio.h>
39*4a7e70d3SMilanka Ringwald #include <math.h>
40*4a7e70d3SMilanka Ringwald #include <stdlib.h>
41*4a7e70d3SMilanka Ringwald #include <string.h>
42*4a7e70d3SMilanka Ringwald #include <portaudio.h>
43*4a7e70d3SMilanka Ringwald 
44*4a7e70d3SMilanka Ringwald #include "btstack_ring_buffer.h"
45*4a7e70d3SMilanka Ringwald #include "wav_util.h"
46*4a7e70d3SMilanka Ringwald 
47*4a7e70d3SMilanka Ringwald #define NUM_CHANNELS        2
48*4a7e70d3SMilanka Ringwald #define NUM_SECONDS         1
49*4a7e70d3SMilanka Ringwald #define PA_SAMPLE_TYPE      paInt16
50*4a7e70d3SMilanka Ringwald #define SAMPLE_RATE         44100
51*4a7e70d3SMilanka Ringwald #define FRAMES_PER_BUFFER   400
52*4a7e70d3SMilanka Ringwald #define BYTES_PER_FRAME     (2*NUM_CHANNELS)
53*4a7e70d3SMilanka Ringwald 
54*4a7e70d3SMilanka Ringwald #ifndef M_PI
55*4a7e70d3SMilanka Ringwald #define M_PI  3.14159265
56*4a7e70d3SMilanka Ringwald #endif
57*4a7e70d3SMilanka Ringwald 
58*4a7e70d3SMilanka Ringwald #define TABLE_SIZE   100
59*4a7e70d3SMilanka Ringwald 
60*4a7e70d3SMilanka Ringwald typedef struct {
61*4a7e70d3SMilanka Ringwald     float sine[TABLE_SIZE];
62*4a7e70d3SMilanka Ringwald     int left_phase;
63*4a7e70d3SMilanka Ringwald     int right_phase;
64*4a7e70d3SMilanka Ringwald     char message[20];
65*4a7e70d3SMilanka Ringwald } paTestData;
66*4a7e70d3SMilanka Ringwald 
67*4a7e70d3SMilanka Ringwald static uint8_t ring_buffer_storage[3*FRAMES_PER_BUFFER*BYTES_PER_FRAME];
68*4a7e70d3SMilanka Ringwald static btstack_ring_buffer_t ring_buffer;
69*4a7e70d3SMilanka Ringwald 
70*4a7e70d3SMilanka Ringwald static int total_num_samples = 0;
71*4a7e70d3SMilanka Ringwald static char * wav_filename = "portaudio_sine.wav";
72*4a7e70d3SMilanka Ringwald 
73*4a7e70d3SMilanka Ringwald static void write_wav_data(int16_t * data, int num_frames, int num_channels, int sample_rate){
74*4a7e70d3SMilanka Ringwald     wav_writer_write_int16(num_frames*num_channels, data);
75*4a7e70d3SMilanka Ringwald     total_num_samples+=num_frames*num_channels;
76*4a7e70d3SMilanka Ringwald     if (total_num_samples>5*SAMPLE_RATE) wav_writer_close();
77*4a7e70d3SMilanka Ringwald }
78*4a7e70d3SMilanka Ringwald 
79*4a7e70d3SMilanka Ringwald 
80*4a7e70d3SMilanka Ringwald static void fill_ring_buffer(void *userData){
81*4a7e70d3SMilanka Ringwald     paTestData *data = (paTestData*)userData;
82*4a7e70d3SMilanka Ringwald 
83*4a7e70d3SMilanka Ringwald     while (btstack_ring_buffer_bytes_free(&ring_buffer) > BYTES_PER_FRAME){
84*4a7e70d3SMilanka Ringwald         int16_t left = data->sine[data->left_phase] * 32767;
85*4a7e70d3SMilanka Ringwald         int16_t right = data->sine[data->right_phase] * 32767;
86*4a7e70d3SMilanka Ringwald 
87*4a7e70d3SMilanka Ringwald         uint8_t write_data[BYTES_PER_FRAME];
88*4a7e70d3SMilanka Ringwald         *(int16_t*)&write_data[0] = left;
89*4a7e70d3SMilanka Ringwald         *(int16_t*)&write_data[2] = right;
90*4a7e70d3SMilanka Ringwald         btstack_ring_buffer_write(&ring_buffer, write_data, BYTES_PER_FRAME);
91*4a7e70d3SMilanka Ringwald         write_wav_data((int16_t*)write_data, 1, NUM_CHANNELS, SAMPLE_RATE);
92*4a7e70d3SMilanka Ringwald 
93*4a7e70d3SMilanka Ringwald         data->left_phase += 1;
94*4a7e70d3SMilanka Ringwald         if (data->left_phase >= TABLE_SIZE){
95*4a7e70d3SMilanka Ringwald             data->left_phase -= TABLE_SIZE;
96*4a7e70d3SMilanka Ringwald         }
97*4a7e70d3SMilanka Ringwald         data->right_phase += 2; /* higher pitch so we can distinguish left and right. */
98*4a7e70d3SMilanka Ringwald         if (data->right_phase >= TABLE_SIZE){
99*4a7e70d3SMilanka Ringwald             data->right_phase -= TABLE_SIZE;
100*4a7e70d3SMilanka Ringwald         }
101*4a7e70d3SMilanka Ringwald     }
102*4a7e70d3SMilanka Ringwald }
103*4a7e70d3SMilanka Ringwald 
104*4a7e70d3SMilanka Ringwald static int patestCallback( const void *inputBuffer, void *outputBuffer,
105*4a7e70d3SMilanka Ringwald                            unsigned long framesPerBuffer,
106*4a7e70d3SMilanka Ringwald                            const PaStreamCallbackTimeInfo* timeInfo,
107*4a7e70d3SMilanka Ringwald                            PaStreamCallbackFlags statusFlags,
108*4a7e70d3SMilanka Ringwald                            void *userData ) {
109*4a7e70d3SMilanka Ringwald     (void) timeInfo; /* Prevent unused variable warnings. */
110*4a7e70d3SMilanka Ringwald     (void) statusFlags;
111*4a7e70d3SMilanka Ringwald     (void) inputBuffer;
112*4a7e70d3SMilanka Ringwald 
113*4a7e70d3SMilanka Ringwald     uint16_t bytes_read = 0;
114*4a7e70d3SMilanka Ringwald     int bytes_per_buffer = framesPerBuffer * BYTES_PER_FRAME;
115*4a7e70d3SMilanka Ringwald 
116*4a7e70d3SMilanka Ringwald     if (btstack_ring_buffer_bytes_available(&ring_buffer) >= bytes_per_buffer){
117*4a7e70d3SMilanka Ringwald         btstack_ring_buffer_read(&ring_buffer, outputBuffer, bytes_per_buffer, &bytes_read);
118*4a7e70d3SMilanka Ringwald     } else {
119*4a7e70d3SMilanka Ringwald         printf("NOT ENGOUGH DAT!\n");
120*4a7e70d3SMilanka Ringwald         memset(outputBuffer, 0, bytes_per_buffer);
121*4a7e70d3SMilanka Ringwald     }
122*4a7e70d3SMilanka Ringwald     return paContinue;
123*4a7e70d3SMilanka Ringwald }
124*4a7e70d3SMilanka Ringwald 
125*4a7e70d3SMilanka Ringwald 
126*4a7e70d3SMilanka Ringwald int main(int argc, const char * argv[]){
127*4a7e70d3SMilanka Ringwald 
128*4a7e70d3SMilanka Ringwald     PaError err;
129*4a7e70d3SMilanka Ringwald     static paTestData data;
130*4a7e70d3SMilanka Ringwald     static PaStream * stream;
131*4a7e70d3SMilanka Ringwald 
132*4a7e70d3SMilanka Ringwald     /* initialise sinusoidal wavetable */
133*4a7e70d3SMilanka Ringwald     int i;
134*4a7e70d3SMilanka Ringwald     for (i=0; i<TABLE_SIZE; i++){
135*4a7e70d3SMilanka Ringwald         data.sine[i] = (float) sin( ((double)i/(double)TABLE_SIZE) * M_PI * 2. );
136*4a7e70d3SMilanka Ringwald     }
137*4a7e70d3SMilanka Ringwald     data.left_phase = data.right_phase = 0;
138*4a7e70d3SMilanka Ringwald 
139*4a7e70d3SMilanka Ringwald     err = Pa_Initialize();
140*4a7e70d3SMilanka Ringwald     if (err != paNoError){
141*4a7e70d3SMilanka Ringwald         printf("Error initializing portaudio: \"%s\"\n",  Pa_GetErrorText(err));
142*4a7e70d3SMilanka Ringwald         return paNoError;
143*4a7e70d3SMilanka Ringwald     }
144*4a7e70d3SMilanka Ringwald 
145*4a7e70d3SMilanka Ringwald     PaStreamParameters outputParameters;
146*4a7e70d3SMilanka Ringwald 
147*4a7e70d3SMilanka Ringwald     /* -- setup input and output -- */
148*4a7e70d3SMilanka Ringwald     outputParameters.device = Pa_GetDefaultOutputDevice(); /* default output device */
149*4a7e70d3SMilanka Ringwald     outputParameters.channelCount = NUM_CHANNELS;
150*4a7e70d3SMilanka Ringwald     outputParameters.sampleFormat = PA_SAMPLE_TYPE;
151*4a7e70d3SMilanka Ringwald     outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultHighOutputLatency;
152*4a7e70d3SMilanka Ringwald     outputParameters.hostApiSpecificStreamInfo = NULL;
153*4a7e70d3SMilanka Ringwald     /* -- setup stream -- */
154*4a7e70d3SMilanka Ringwald     err = Pa_OpenStream(
155*4a7e70d3SMilanka Ringwald            &stream,
156*4a7e70d3SMilanka Ringwald            NULL,                /* &inputParameters */
157*4a7e70d3SMilanka Ringwald            &outputParameters,
158*4a7e70d3SMilanka Ringwald            SAMPLE_RATE,
159*4a7e70d3SMilanka Ringwald            FRAMES_PER_BUFFER,
160*4a7e70d3SMilanka Ringwald            paClipOff,           /* we won't output out of range samples so don't bother clipping them */
161*4a7e70d3SMilanka Ringwald            patestCallback,      /* use callback */
162*4a7e70d3SMilanka Ringwald            &data );              /* no callback userData yet */
163*4a7e70d3SMilanka Ringwald 
164*4a7e70d3SMilanka Ringwald     memset(ring_buffer_storage, 0, sizeof(ring_buffer_storage));
165*4a7e70d3SMilanka Ringwald     btstack_ring_buffer_init(&ring_buffer, ring_buffer_storage, sizeof(ring_buffer_storage));
166*4a7e70d3SMilanka Ringwald 
167*4a7e70d3SMilanka Ringwald     wav_writer_open(wav_filename, NUM_CHANNELS, SAMPLE_RATE);
168*4a7e70d3SMilanka Ringwald 
169*4a7e70d3SMilanka Ringwald     if (err != paNoError){
170*4a7e70d3SMilanka Ringwald         printf("Error opening default stream: \"%s\"\n",  Pa_GetErrorText(err));
171*4a7e70d3SMilanka Ringwald         return paNoError;
172*4a7e70d3SMilanka Ringwald     }
173*4a7e70d3SMilanka Ringwald 
174*4a7e70d3SMilanka Ringwald     err = Pa_StartStream(stream);
175*4a7e70d3SMilanka Ringwald     if (err != paNoError){
176*4a7e70d3SMilanka Ringwald         printf("Error starting the stream: \"%s\"\n",  Pa_GetErrorText(err));
177*4a7e70d3SMilanka Ringwald         return paNoError;
178*4a7e70d3SMilanka Ringwald     }
179*4a7e70d3SMilanka Ringwald 
180*4a7e70d3SMilanka Ringwald     /* Sleep for several seconds. */
181*4a7e70d3SMilanka Ringwald     while (1){
182*4a7e70d3SMilanka Ringwald         fill_ring_buffer(&data);
183*4a7e70d3SMilanka Ringwald         Pa_Sleep(1);
184*4a7e70d3SMilanka Ringwald     }
185*4a7e70d3SMilanka Ringwald 
186*4a7e70d3SMilanka Ringwald     err = Pa_StopStream(stream);
187*4a7e70d3SMilanka Ringwald     if (err != paNoError){
188*4a7e70d3SMilanka Ringwald         printf("Error stopping the stream: \"%s\"\n",  Pa_GetErrorText(err));
189*4a7e70d3SMilanka Ringwald         return paNoError;
190*4a7e70d3SMilanka Ringwald     }
191*4a7e70d3SMilanka Ringwald 
192*4a7e70d3SMilanka Ringwald     err = Pa_CloseStream(stream);
193*4a7e70d3SMilanka Ringwald     if (err != paNoError){
194*4a7e70d3SMilanka Ringwald         printf("Error closing the stream: \"%s\"\n",  Pa_GetErrorText(err));
195*4a7e70d3SMilanka Ringwald         return paNoError;
196*4a7e70d3SMilanka Ringwald     }
197*4a7e70d3SMilanka Ringwald 
198*4a7e70d3SMilanka Ringwald     err = Pa_Terminate();
199*4a7e70d3SMilanka Ringwald     if (err != paNoError){
200*4a7e70d3SMilanka Ringwald         printf("Error terminating portaudio: \"%s\"\n",  Pa_GetErrorText(err));
201*4a7e70d3SMilanka Ringwald         return paNoError;
202*4a7e70d3SMilanka Ringwald     }
203*4a7e70d3SMilanka Ringwald     return 0;
204*4a7e70d3SMilanka Ringwald }
205