1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <errno.h>
18 #include <pthread.h>
19 #include <stdio.h>
20 #include <unistd.h>
21 #include <audio_utils/fifo.h>
22 
23 extern "C" {
24 #include "getch.h"
25 }
26 
27 struct Context {
28     audio_utils_fifo_writer *mInputWriter;
29     audio_utils_fifo_reader *mInputReader;
30     audio_utils_fifo_writer *mTransferWriter;
31     audio_utils_fifo_reader *mTransferReader;
32     audio_utils_fifo_writer *mOutputWriter;
33     audio_utils_fifo_reader *mOutputReader;
34 };
35 
input_routine(void * arg)36 void *input_routine(void *arg)
37 {
38     Context *context = (Context *) arg;
39     for (;;) {
40         struct timespec timeout;
41         timeout.tv_sec = 30;
42         timeout.tv_nsec = 0;
43         char buffer[4];
44         ssize_t actual = context->mInputReader->read(buffer, sizeof(buffer), &timeout);
45         // TODO this test is unreadable
46         if (actual > 0) {
47             if ((size_t) actual > sizeof(buffer)) {
48                 printf("input.read actual = %d\n", (int) actual);
49                 abort();
50             }
51             ssize_t actual2 = context->mTransferWriter->write(buffer, actual, &timeout);
52             if (actual2 != actual) {
53                 printf("transfer.write(%d) = %d\n", (int) actual, (int) actual2);
54             }
55             //sleep(10);
56         } else if (actual == -ETIMEDOUT) {
57             (void) write(1, "t", 1);
58         } else {
59             printf("input.read actual = %d\n", (int) actual);
60         }
61     }
62     return NULL;
63 }
64 
65 volatile bool outputPaused = false;
66 
output_routine(void * arg)67 void *output_routine(void *arg)
68 {
69     Context *context = (Context *) arg;
70     for (;;) {
71         if (outputPaused) {
72             sleep(1);
73             continue;
74         }
75         struct timespec timeout;
76         timeout.tv_sec = 60;
77         timeout.tv_nsec = 0;
78         char buffer[4];
79         ssize_t actual = context->mTransferReader->read(buffer, sizeof(buffer), &timeout);
80         if (actual > 0) {
81             if ((size_t) actual > sizeof(buffer)) {
82                 printf("transfer.read actual = %d\n", (int) actual);
83                 abort();
84             }
85             ssize_t actual2 = context->mOutputWriter->write(buffer, actual, NULL /*timeout*/);
86             if (actual2 != actual) {
87                 printf("output.write(%d) = %d\n", (int) actual, (int) actual2);
88             }
89         } else if (actual == -ETIMEDOUT) {
90             (void) write(1, "T", 1);
91         } else {
92             printf("transfer.read actual = %d\n", (int) actual);
93         }
94     }
95     return NULL;
96 }
97 
main(int argc,char ** argv)98 int main(int argc, char **argv)
99 {
100     set_conio_terminal_mode();
101     argc = argc + 0;
102     argv = &argv[0];
103 
104     char inputBuffer[16];
105     audio_utils_fifo inputFifo(sizeof(inputBuffer) /*frameCount*/, 1 /*frameSize*/, inputBuffer,
106             true /*throttlesWriter*/);
107     audio_utils_fifo_writer inputWriter(inputFifo);
108     audio_utils_fifo_reader inputReader(inputFifo, true /*throttlesWriter*/);
109     //inputWriter.setHysteresis(sizeof(inputBuffer) * 1/4, sizeof(inputBuffer) * 3/4);
110 
111     char transferBuffer[64];
112     audio_utils_fifo transferFifo(sizeof(transferBuffer) /*frameCount*/, 1 /*frameSize*/,
113             transferBuffer, true /*throttlesWriter*/);
114     audio_utils_fifo_writer transferWriter(transferFifo);
115     audio_utils_fifo_reader transferReader(transferFifo, true /*throttlesWriter*/);
116     transferReader.setHysteresis(sizeof(transferBuffer) * 3/4, sizeof(transferBuffer) * 1/4);
117     //transferWriter.setEffective(8);
118 
119     char outputBuffer[64];
120     audio_utils_fifo outputFifo(sizeof(outputBuffer) /*frameCount*/, 1 /*frameSize*/, outputBuffer,
121             true /*throttlesWriter*/);
122     audio_utils_fifo_writer outputWriter(outputFifo);
123     audio_utils_fifo_reader outputReader(outputFifo, true /*readerThrottlesWriter*/);
124 
125     Context context;
126     context.mInputWriter = &inputWriter;
127     context.mInputReader = &inputReader;
128     context.mTransferWriter = &transferWriter;
129     context.mTransferReader = &transferReader;
130     context.mOutputWriter = &outputWriter;
131     context.mOutputReader = &outputReader;
132 
133     pthread_t input_thread;
134     int ok = pthread_create(&input_thread, (const pthread_attr_t *) NULL, input_routine,
135             (void *) &context);
136     pthread_t output_thread;
137     ok = pthread_create(&output_thread, (const pthread_attr_t *) NULL, output_routine,
138             (void *) &context);
139     ok = ok + 0;
140 
141     for (;;) {
142         char buffer[4];
143         ssize_t actual = outputReader.read(buffer, sizeof(buffer), NULL /*timeout*/);
144         if (actual > 0) {
145             printf("%.*s", (int) actual, buffer);
146             fflush(stdout);
147         } else if (actual != 0) {
148             printf("outputReader.read actual = %d\n", (int) actual);
149         }
150         if (kbhit()) {
151             int ch = getch();
152             if (ch <= 0 || ch == '\003' /*control-C*/) {
153                 break;
154             }
155             if (ch == 'p')
156                 outputPaused = true;
157             else if (ch == 'p')
158                 outputPaused = false;
159             buffer[0] = ch;
160             actual = inputWriter.write(buffer, 1, NULL /*timeout*/);
161             if (actual != 1) {
162                 printf("inputWriter.write actual = %d\n", (int) actual);
163             }
164         }
165     }
166     reset_terminal_mode();
167 }
168