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