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