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