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