1f4b0e603d3e27728ca19c02a44342607a54db7d4Andy Hung/*
2f4b0e603d3e27728ca19c02a44342607a54db7d4Andy Hung * Copyright (C) 2014 The Android Open Source Project
3f4b0e603d3e27728ca19c02a44342607a54db7d4Andy Hung *
4f4b0e603d3e27728ca19c02a44342607a54db7d4Andy Hung * Licensed under the Apache License, Version 2.0 (the "License");
5f4b0e603d3e27728ca19c02a44342607a54db7d4Andy Hung * you may not use this file except in compliance with the License.
6f4b0e603d3e27728ca19c02a44342607a54db7d4Andy Hung * You may obtain a copy of the License at
7f4b0e603d3e27728ca19c02a44342607a54db7d4Andy Hung *
8f4b0e603d3e27728ca19c02a44342607a54db7d4Andy Hung *      http://www.apache.org/licenses/LICENSE-2.0
9f4b0e603d3e27728ca19c02a44342607a54db7d4Andy Hung *
10f4b0e603d3e27728ca19c02a44342607a54db7d4Andy Hung * Unless required by applicable law or agreed to in writing, software
11f4b0e603d3e27728ca19c02a44342607a54db7d4Andy Hung * distributed under the License is distributed on an "AS IS" BASIS,
12f4b0e603d3e27728ca19c02a44342607a54db7d4Andy Hung * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13f4b0e603d3e27728ca19c02a44342607a54db7d4Andy Hung * See the License for the specific language governing permissions and
14f4b0e603d3e27728ca19c02a44342607a54db7d4Andy Hung * limitations under the License.
15f4b0e603d3e27728ca19c02a44342607a54db7d4Andy Hung */
16c297fccffc4ab1cb3b9f5c6a5b0802be057f3e0fAndreas Huber
17c6ac859f5a82ea8642bc6351a45508a15f224f32Marco Nelissen#include <sys/types.h>
18c6ac859f5a82ea8642bc6351a45508a15f224f32Marco Nelissen#include <sys/stat.h>
19c6ac859f5a82ea8642bc6351a45508a15f224f32Marco Nelissen#include <fcntl.h>
20c6ac859f5a82ea8642bc6351a45508a15f224f32Marco Nelissen
21be71aa29a3c86d2e01cd17839d2a72ab09a1bce5Svet Ganov#include <utils/String16.h>
22be71aa29a3c86d2e01cd17839d2a72ab09a1bce5Svet Ganov
23c297fccffc4ab1cb3b9f5c6a5b0802be057f3e0fAndreas Huber#include <binder/ProcessState.h>
24e7c9cb48fec02697227bd847cd2e69432659adfdAndreas Huber#include <media/mediarecorder.h>
25f1d5aa162c02a16b7195a43a9bcea4d592600ac4James Dong#include <media/stagefright/foundation/ADebug.h>
26bf03e42c7a246e2c8d53ba944b91f66ee3da10e6Lajos Molnar#include <media/stagefright/foundation/AMessage.h>
27e7c9cb48fec02697227bd847cd2e69432659adfdAndreas Huber#include <media/stagefright/AMRWriter.h>
28c297fccffc4ab1cb3b9f5c6a5b0802be057f3e0fAndreas Huber#include <media/stagefright/AudioPlayer.h>
29e7c9cb48fec02697227bd847cd2e69432659adfdAndreas Huber#include <media/stagefright/AudioSource.h>
30bf03e42c7a246e2c8d53ba944b91f66ee3da10e6Lajos Molnar#include <media/stagefright/MediaCodecSource.h>
31c297fccffc4ab1cb3b9f5c6a5b0802be057f3e0fAndreas Huber#include <media/stagefright/MediaDefs.h>
32c297fccffc4ab1cb3b9f5c6a5b0802be057f3e0fAndreas Huber#include <media/stagefright/MetaData.h>
33bf03e42c7a246e2c8d53ba944b91f66ee3da10e6Lajos Molnar#include <media/stagefright/SimpleDecodingSource.h>
34f4b0e603d3e27728ca19c02a44342607a54db7d4Andy Hung#include "SineSource.h"
35fce7a473248381cc83a01855f92581077d3c9ee2Dima Zavin
36c297fccffc4ab1cb3b9f5c6a5b0802be057f3e0fAndreas Huberusing namespace android;
37c297fccffc4ab1cb3b9f5c6a5b0802be057f3e0fAndreas Huber
38f4b0e603d3e27728ca19c02a44342607a54db7d4Andy Hungstatic void usage(const char* name)
39f4b0e603d3e27728ca19c02a44342607a54db7d4Andy Hung{
40be71aa29a3c86d2e01cd17839d2a72ab09a1bce5Svet Ganov    fprintf(stderr, "Usage: %s [-d du.ration] [-m] [-w] [<output-file>]\n", name);
41f4b0e603d3e27728ca19c02a44342607a54db7d4Andy Hung    fprintf(stderr, "Encodes either a sine wave or microphone input to AMR format\n");
42f4b0e603d3e27728ca19c02a44342607a54db7d4Andy Hung    fprintf(stderr, "    -d    duration in seconds, default 5 seconds\n");
43f4b0e603d3e27728ca19c02a44342607a54db7d4Andy Hung    fprintf(stderr, "    -m    use microphone for input, default sine source\n");
44f4b0e603d3e27728ca19c02a44342607a54db7d4Andy Hung    fprintf(stderr, "    -w    use AMR wideband (default narrowband)\n");
45f4b0e603d3e27728ca19c02a44342607a54db7d4Andy Hung    fprintf(stderr, "    <output-file> output file for AMR encoding,"
46f4b0e603d3e27728ca19c02a44342607a54db7d4Andy Hung            " if unspecified, decode to speaker.\n");
47f4b0e603d3e27728ca19c02a44342607a54db7d4Andy Hung}
48c297fccffc4ab1cb3b9f5c6a5b0802be057f3e0fAndreas Huber
49f4b0e603d3e27728ca19c02a44342607a54db7d4Andy Hungint main(int argc, char* argv[])
50f4b0e603d3e27728ca19c02a44342607a54db7d4Andy Hung{
51f4b0e603d3e27728ca19c02a44342607a54db7d4Andy Hung    static const int channels = 1; // not permitted to be stereo now
52f4b0e603d3e27728ca19c02a44342607a54db7d4Andy Hung    unsigned duration = 5;
53f4b0e603d3e27728ca19c02a44342607a54db7d4Andy Hung    bool useMic = false;
54f4b0e603d3e27728ca19c02a44342607a54db7d4Andy Hung    bool outputWBAMR = false;
55f4b0e603d3e27728ca19c02a44342607a54db7d4Andy Hung    bool playToSpeaker = true;
56f4b0e603d3e27728ca19c02a44342607a54db7d4Andy Hung    const char* fileOut = NULL;
57f4b0e603d3e27728ca19c02a44342607a54db7d4Andy Hung    int ch;
58f4b0e603d3e27728ca19c02a44342607a54db7d4Andy Hung    while ((ch = getopt(argc, argv, "d:mw")) != -1) {
59f4b0e603d3e27728ca19c02a44342607a54db7d4Andy Hung        switch (ch) {
60f4b0e603d3e27728ca19c02a44342607a54db7d4Andy Hung        case 'd':
61f4b0e603d3e27728ca19c02a44342607a54db7d4Andy Hung            duration = atoi(optarg);
62f4b0e603d3e27728ca19c02a44342607a54db7d4Andy Hung            break;
63f4b0e603d3e27728ca19c02a44342607a54db7d4Andy Hung        case 'm':
64f4b0e603d3e27728ca19c02a44342607a54db7d4Andy Hung            useMic = true;
65f4b0e603d3e27728ca19c02a44342607a54db7d4Andy Hung            break;
66f4b0e603d3e27728ca19c02a44342607a54db7d4Andy Hung        case 'w':
67f4b0e603d3e27728ca19c02a44342607a54db7d4Andy Hung            outputWBAMR = true;
68f4b0e603d3e27728ca19c02a44342607a54db7d4Andy Hung            break;
69f4b0e603d3e27728ca19c02a44342607a54db7d4Andy Hung        default:
70f4b0e603d3e27728ca19c02a44342607a54db7d4Andy Hung            usage(argv[0]);
71f4b0e603d3e27728ca19c02a44342607a54db7d4Andy Hung            return -1;
72f4b0e603d3e27728ca19c02a44342607a54db7d4Andy Hung        }
73f4b0e603d3e27728ca19c02a44342607a54db7d4Andy Hung    }
74f4b0e603d3e27728ca19c02a44342607a54db7d4Andy Hung    argc -= optind;
75f4b0e603d3e27728ca19c02a44342607a54db7d4Andy Hung    argv += optind;
76f4b0e603d3e27728ca19c02a44342607a54db7d4Andy Hung    if (argc == 1) {
77f4b0e603d3e27728ca19c02a44342607a54db7d4Andy Hung        fileOut = argv[0];
78f4b0e603d3e27728ca19c02a44342607a54db7d4Andy Hung    }
79f4b0e603d3e27728ca19c02a44342607a54db7d4Andy Hung    const int32_t kSampleRate = outputWBAMR ? 16000 : 8000;
80f4b0e603d3e27728ca19c02a44342607a54db7d4Andy Hung    const int32_t kBitRate = outputWBAMR ? 16000 : 8000;
81c297fccffc4ab1cb3b9f5c6a5b0802be057f3e0fAndreas Huber
82f4b0e603d3e27728ca19c02a44342607a54db7d4Andy Hung    android::ProcessState::self()->startThreadPool();
83f4b0e603d3e27728ca19c02a44342607a54db7d4Andy Hung    sp<MediaSource> source;
84f4b0e603d3e27728ca19c02a44342607a54db7d4Andy Hung
85f4b0e603d3e27728ca19c02a44342607a54db7d4Andy Hung    if (useMic) {
86f4b0e603d3e27728ca19c02a44342607a54db7d4Andy Hung        // talk into the appropriate microphone for the duration
87f4b0e603d3e27728ca19c02a44342607a54db7d4Andy Hung        source = new AudioSource(
88f4b0e603d3e27728ca19c02a44342607a54db7d4Andy Hung                AUDIO_SOURCE_MIC,
89be71aa29a3c86d2e01cd17839d2a72ab09a1bce5Svet Ganov                String16(),
90f4b0e603d3e27728ca19c02a44342607a54db7d4Andy Hung                kSampleRate,
91f4b0e603d3e27728ca19c02a44342607a54db7d4Andy Hung                channels);
92f4b0e603d3e27728ca19c02a44342607a54db7d4Andy Hung    } else {
93f4b0e603d3e27728ca19c02a44342607a54db7d4Andy Hung        // use a sine source at 500 hz.
94f4b0e603d3e27728ca19c02a44342607a54db7d4Andy Hung        source = new SineSource(kSampleRate, channels);
95f4b0e603d3e27728ca19c02a44342607a54db7d4Andy Hung    }
96c297fccffc4ab1cb3b9f5c6a5b0802be057f3e0fAndreas Huber
97bf03e42c7a246e2c8d53ba944b91f66ee3da10e6Lajos Molnar    sp<AMessage> meta = new AMessage;
98bf03e42c7a246e2c8d53ba944b91f66ee3da10e6Lajos Molnar    meta->setString(
99bf03e42c7a246e2c8d53ba944b91f66ee3da10e6Lajos Molnar            "mime",
100c297fccffc4ab1cb3b9f5c6a5b0802be057f3e0fAndreas Huber            outputWBAMR ? MEDIA_MIMETYPE_AUDIO_AMR_WB
101f4b0e603d3e27728ca19c02a44342607a54db7d4Andy Hung                    : MEDIA_MIMETYPE_AUDIO_AMR_NB);
102c297fccffc4ab1cb3b9f5c6a5b0802be057f3e0fAndreas Huber
103bf03e42c7a246e2c8d53ba944b91f66ee3da10e6Lajos Molnar    meta->setInt32("channel-count", channels);
104bf03e42c7a246e2c8d53ba944b91f66ee3da10e6Lajos Molnar    meta->setInt32("sample-rate", kSampleRate);
105bf03e42c7a246e2c8d53ba944b91f66ee3da10e6Lajos Molnar    meta->setInt32("bitrate", kBitRate);
106c297fccffc4ab1cb3b9f5c6a5b0802be057f3e0fAndreas Huber    int32_t maxInputSize;
107c297fccffc4ab1cb3b9f5c6a5b0802be057f3e0fAndreas Huber    if (source->getFormat()->findInt32(kKeyMaxInputSize, &maxInputSize)) {
108bf03e42c7a246e2c8d53ba944b91f66ee3da10e6Lajos Molnar        meta->setInt32("max-input-size", maxInputSize);
109c297fccffc4ab1cb3b9f5c6a5b0802be057f3e0fAndreas Huber    }
110c297fccffc4ab1cb3b9f5c6a5b0802be057f3e0fAndreas Huber
111bf03e42c7a246e2c8d53ba944b91f66ee3da10e6Lajos Molnar    sp<ALooper> looper = new ALooper;
112bf03e42c7a246e2c8d53ba944b91f66ee3da10e6Lajos Molnar    looper->setName("audioloop");
113bf03e42c7a246e2c8d53ba944b91f66ee3da10e6Lajos Molnar    looper->start();
114bf03e42c7a246e2c8d53ba944b91f66ee3da10e6Lajos Molnar
115bf03e42c7a246e2c8d53ba944b91f66ee3da10e6Lajos Molnar    sp<IMediaSource> encoder = MediaCodecSource::Create(looper, meta, source);
116c297fccffc4ab1cb3b9f5c6a5b0802be057f3e0fAndreas Huber
117f4b0e603d3e27728ca19c02a44342607a54db7d4Andy Hung    if (fileOut != NULL) {
118f4b0e603d3e27728ca19c02a44342607a54db7d4Andy Hung        // target file specified, write encoded AMR output
119c6ac859f5a82ea8642bc6351a45508a15f224f32Marco Nelissen        int fd = open(fileOut, O_CREAT | O_LARGEFILE | O_TRUNC | O_RDWR, S_IRUSR | S_IWUSR);
120c6ac859f5a82ea8642bc6351a45508a15f224f32Marco Nelissen        if (fd < 0) {
121c6ac859f5a82ea8642bc6351a45508a15f224f32Marco Nelissen            return 1;
122c6ac859f5a82ea8642bc6351a45508a15f224f32Marco Nelissen        }
123c6ac859f5a82ea8642bc6351a45508a15f224f32Marco Nelissen        sp<AMRWriter> writer = new AMRWriter(fd);
124c6ac859f5a82ea8642bc6351a45508a15f224f32Marco Nelissen        close(fd);
125f4b0e603d3e27728ca19c02a44342607a54db7d4Andy Hung        writer->addSource(encoder);
126f4b0e603d3e27728ca19c02a44342607a54db7d4Andy Hung        writer->start();
127f4b0e603d3e27728ca19c02a44342607a54db7d4Andy Hung        sleep(duration);
128f4b0e603d3e27728ca19c02a44342607a54db7d4Andy Hung        writer->stop();
129f4b0e603d3e27728ca19c02a44342607a54db7d4Andy Hung    } else {
130f4b0e603d3e27728ca19c02a44342607a54db7d4Andy Hung        // otherwise decode to speaker
131bf03e42c7a246e2c8d53ba944b91f66ee3da10e6Lajos Molnar        sp<IMediaSource> decoder = SimpleDecodingSource::Create(encoder);
132f4b0e603d3e27728ca19c02a44342607a54db7d4Andy Hung
133f4b0e603d3e27728ca19c02a44342607a54db7d4Andy Hung        if (playToSpeaker) {
134f4b0e603d3e27728ca19c02a44342607a54db7d4Andy Hung            AudioPlayer *player = new AudioPlayer(NULL);
135f4b0e603d3e27728ca19c02a44342607a54db7d4Andy Hung            player->setSource(decoder);
136f4b0e603d3e27728ca19c02a44342607a54db7d4Andy Hung            player->start();
137f4b0e603d3e27728ca19c02a44342607a54db7d4Andy Hung            sleep(duration);
138bf03e42c7a246e2c8d53ba944b91f66ee3da10e6Lajos Molnar
139bf03e42c7a246e2c8d53ba944b91f66ee3da10e6Lajos Molnar            decoder.clear(); // must clear |decoder| otherwise delete player will hang.
140f4b0e603d3e27728ca19c02a44342607a54db7d4Andy Hung            delete player; // there is no player->stop()...
141f4b0e603d3e27728ca19c02a44342607a54db7d4Andy Hung        } else {
142f4b0e603d3e27728ca19c02a44342607a54db7d4Andy Hung            CHECK_EQ(decoder->start(), (status_t)OK);
143f4b0e603d3e27728ca19c02a44342607a54db7d4Andy Hung            MediaBuffer* buffer;
144f4b0e603d3e27728ca19c02a44342607a54db7d4Andy Hung            while (decoder->read(&buffer) == OK) {
145f4b0e603d3e27728ca19c02a44342607a54db7d4Andy Hung                // do something with buffer (save it eventually?)
146f4b0e603d3e27728ca19c02a44342607a54db7d4Andy Hung                // need to stop after some count though...
147f4b0e603d3e27728ca19c02a44342607a54db7d4Andy Hung                putchar('.');
148f4b0e603d3e27728ca19c02a44342607a54db7d4Andy Hung                fflush(stdout);
149f4b0e603d3e27728ca19c02a44342607a54db7d4Andy Hung                buffer->release();
150f4b0e603d3e27728ca19c02a44342607a54db7d4Andy Hung                buffer = NULL;
151f4b0e603d3e27728ca19c02a44342607a54db7d4Andy Hung            }
152f4b0e603d3e27728ca19c02a44342607a54db7d4Andy Hung            CHECK_EQ(decoder->stop(), (status_t)OK);
153f4b0e603d3e27728ca19c02a44342607a54db7d4Andy Hung        }
154c297fccffc4ab1cb3b9f5c6a5b0802be057f3e0fAndreas Huber    }
155c297fccffc4ab1cb3b9f5c6a5b0802be057f3e0fAndreas Huber
156c297fccffc4ab1cb3b9f5c6a5b0802be057f3e0fAndreas Huber    return 0;
157c297fccffc4ab1cb3b9f5c6a5b0802be057f3e0fAndreas Huber}
158