1 /*
2 * Copyright (C) 2014 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 #define LOG_NDEBUG 0
18 #define LOG_TAG "audioloop"
19 #include <utils/Log.h>
20
21 #include <sys/types.h>
22 #include <sys/stat.h>
23 #include <fcntl.h>
24
25 #include <utils/String16.h>
26
27 #include <binder/ProcessState.h>
28 #include <media/mediarecorder.h>
29 #include <media/stagefright/foundation/ADebug.h>
30 #include <media/stagefright/foundation/AMessage.h>
31 #include <media/stagefright/AMRWriter.h>
32 #include <media/stagefright/AudioSource.h>
33 #include <media/stagefright/MediaCodecSource.h>
34 #include <media/stagefright/MediaDefs.h>
35 #include <media/stagefright/SimpleDecodingSource.h>
36 #include "AudioPlayer.h"
37 #include "SineSource.h"
38
39 using namespace android;
40
usage(const char * name)41 static void usage(const char* name)
42 {
43 fprintf(stderr, "Usage: %s [-d du.ration] [-m] [-w] [-N name] [<output-file>]\n", name);
44 fprintf(stderr, "Encodes either a sine wave or microphone input to AMR format\n");
45 fprintf(stderr, " -d duration in seconds, default 5 seconds\n");
46 fprintf(stderr, " -m use microphone for input, default sine source\n");
47 fprintf(stderr, " -w use AMR wideband (default narrowband)\n");
48 fprintf(stderr, " -N name of the encoder; must be set with -M\n");
49 fprintf(stderr, " -M media type of the encoder; must be set with -N\n");
50 fprintf(stderr, " <output-file> output file for AMR encoding,"
51 " if unspecified, decode to speaker.\n");
52 }
53
main(int argc,char * argv[])54 int main(int argc, char* argv[])
55 {
56 static const int channels = 1; // not permitted to be stereo now
57 unsigned duration = 5;
58 bool useMic = false;
59 bool outputWBAMR = false;
60 bool playToSpeaker = true;
61 const char* fileOut = NULL;
62 AString name;
63 AString mediaType;
64 int ch;
65 while ((ch = getopt(argc, argv, "d:mwN:M:")) != -1) {
66 switch (ch) {
67 case 'd':
68 duration = atoi(optarg);
69 break;
70 case 'm':
71 useMic = true;
72 break;
73 case 'w':
74 outputWBAMR = true;
75 break;
76 case 'N':
77 name.setTo(optarg);
78 break;
79 case 'M':
80 mediaType.setTo(optarg);
81 break;
82 default:
83 usage(argv[0]);
84 return -1;
85 }
86 }
87 argc -= optind;
88 argv += optind;
89 if (argc == 1) {
90 fileOut = argv[0];
91 }
92 if ((name.empty() && !mediaType.empty()) || (!name.empty() && mediaType.empty())) {
93 fprintf(stderr, "-N and -M must be set together\n");
94 usage(argv[0]);
95 return -1;
96 }
97 if (!name.empty() && fileOut != NULL) {
98 fprintf(stderr, "-N and -M cannot be used with <output file>\n");
99 usage(argv[0]);
100 return -1;
101 }
102 int32_t sampleRate = !name.empty() ? 44100 : outputWBAMR ? 16000 : 8000;
103 int32_t bitRate = sampleRate;
104
105 android::ProcessState::self()->startThreadPool();
106 sp<MediaSource> source;
107
108 if (useMic) {
109 // talk into the appropriate microphone for the duration
110 source = new AudioSource(
111 AUDIO_SOURCE_MIC,
112 String16(),
113 sampleRate,
114 channels);
115 } else {
116 // use a sine source at 500 hz.
117 source = new SineSource(sampleRate, channels);
118 }
119
120 sp<AMessage> meta = new AMessage;
121 if (name.empty()) {
122 meta->setString(
123 "mime",
124 outputWBAMR ? MEDIA_MIMETYPE_AUDIO_AMR_WB
125 : MEDIA_MIMETYPE_AUDIO_AMR_NB);
126 } else {
127 meta->setString("mime", mediaType);
128 meta->setString("testing-name", name);
129 }
130
131 meta->setInt32("channel-count", channels);
132 meta->setInt32("sample-rate", sampleRate);
133 meta->setInt32("bitrate", bitRate);
134 int32_t maxInputSize;
135 if (source->getFormat()->findInt32(kKeyMaxInputSize, &maxInputSize)) {
136 meta->setInt32("max-input-size", maxInputSize);
137 }
138
139 sp<ALooper> looper = new ALooper;
140 looper->setName("audioloop");
141 looper->start();
142
143 sp<MediaSource> encoder = MediaCodecSource::Create(looper, meta, source);
144
145 if (fileOut != NULL) {
146 // target file specified, write encoded AMR output
147 int fd = open(fileOut, O_CREAT | O_LARGEFILE | O_TRUNC | O_RDWR, S_IRUSR | S_IWUSR);
148 if (fd < 0) {
149 return 1;
150 }
151 sp<AMRWriter> writer = new AMRWriter(fd);
152 close(fd);
153 writer->addSource(encoder);
154 writer->start();
155 sleep(duration);
156 writer->stop();
157 } else {
158 // otherwise decode to speaker
159 sp<MediaSource> decoder = SimpleDecodingSource::Create(encoder);
160
161 if (playToSpeaker) {
162 AudioPlayer player(NULL);
163 player.setSource(decoder);
164 player.start();
165 sleep(duration);
166
167 ALOGI("Line: %d", __LINE__);
168 decoder.clear(); // must clear |decoder| otherwise delete player will hang.
169 ALOGI("Line: %d", __LINE__);
170 } else {
171 CHECK_EQ(decoder->start(), (status_t)OK);
172 MediaBufferBase* buffer;
173 while (decoder->read(&buffer) == OK) {
174 // do something with buffer (save it eventually?)
175 // need to stop after some count though...
176 putchar('.');
177 fflush(stdout);
178 buffer->release();
179 buffer = NULL;
180 }
181 CHECK_EQ(decoder->stop(), (status_t)OK);
182 }
183 ALOGI("Line: %d", __LINE__);
184 }
185
186 return 0;
187 }
188