From e7c9cb48fec02697227bd847cd2e69432659adfd Mon Sep 17 00:00:00 2001 From: Andreas Huber Date: Mon, 25 Jan 2010 14:27:12 -0800 Subject: Initial checkin of AudioSource and AMRWriter, a pair of classes supporting pure-audio recording in stagefright. related-to-bug: 2295449 --- media/libstagefright/AMRWriter.cpp | 184 +++++++++++++++++++++++++++++++++++++ 1 file changed, 184 insertions(+) create mode 100644 media/libstagefright/AMRWriter.cpp (limited to 'media/libstagefright/AMRWriter.cpp') diff --git a/media/libstagefright/AMRWriter.cpp b/media/libstagefright/AMRWriter.cpp new file mode 100644 index 0000000..7b681f1 --- /dev/null +++ b/media/libstagefright/AMRWriter.cpp @@ -0,0 +1,184 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include +#include +#include +#include +#include +#include + +namespace android { + +AMRWriter::AMRWriter(const char *filename) + : mFile(fopen(filename, "wb")), + mInitCheck(mFile != NULL ? OK : NO_INIT), + mStarted(false) { +} + +AMRWriter::AMRWriter(int fd) + : mFile(fdopen(fd, "wb")), + mInitCheck(mFile != NULL ? OK : NO_INIT), + mStarted(false) { +} + +AMRWriter::~AMRWriter() { + if (mStarted) { + stop(); + } + + if (mFile != NULL) { + fclose(mFile); + mFile = NULL; + } +} + +status_t AMRWriter::initCheck() const { + return mInitCheck; +} + +status_t AMRWriter::addSource(const sp &source) { + Mutex::Autolock autoLock(mLock); + + if (mInitCheck != OK) { + return mInitCheck; + } + + if (mSource != NULL) { + // AMR files only support a single track of audio. + return UNKNOWN_ERROR; + } + + sp meta = source->getFormat(); + + const char *mime; + CHECK(meta->findCString(kKeyMIMEType, &mime)); + + bool isWide = false; + if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_WB)) { + isWide = true; + } else if (strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_NB)) { + return ERROR_UNSUPPORTED; + } + + int32_t channelCount; + int32_t sampleRate; + CHECK(meta->findInt32(kKeyChannelCount, &channelCount)); + CHECK_EQ(channelCount, 1); + CHECK(meta->findInt32(kKeySampleRate, &sampleRate)); + CHECK_EQ(sampleRate, (isWide ? 16000 : 8000)); + + mSource = source; + + const char *kHeader = isWide ? "#!AMR-WB\n" : "#!AMR\n"; + size_t n = strlen(kHeader); + if (fwrite(kHeader, 1, n, mFile) != n) { + return ERROR_IO; + } + + return OK; +} + +status_t AMRWriter::start() { + Mutex::Autolock autoLock(mLock); + + if (mInitCheck != OK) { + return mInitCheck; + } + + if (mStarted || mSource == NULL) { + return UNKNOWN_ERROR; + } + + status_t err = mSource->start(); + + if (err != OK) { + return err; + } + + pthread_attr_t attr; + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); + + mDone = false; + + pthread_create(&mThread, &attr, ThreadWrapper, this); + pthread_attr_destroy(&attr); + + mStarted = true; + + return OK; +} + +void AMRWriter::stop() { + { + Mutex::Autolock autoLock(mLock); + + if (!mStarted) { + return; + } + + mDone = true; + } + + void *dummy; + pthread_join(mThread, &dummy); + + mSource->stop(); + + mStarted = false; +} + +// static +void *AMRWriter::ThreadWrapper(void *me) { + static_cast(me)->threadFunc(); + + return NULL; +} + +void AMRWriter::threadFunc() { + for (;;) { + Mutex::Autolock autoLock(mLock); + + if (mDone) { + break; + } + + MediaBuffer *buffer; + status_t err = mSource->read(&buffer); + + if (err != OK) { + break; + } + + ssize_t n = fwrite( + (const uint8_t *)buffer->data() + buffer->range_offset(), + 1, + buffer->range_length(), + mFile); + + buffer->release(); + buffer = NULL; + + if (n < (ssize_t)buffer->range_length()) { + break; + } + } +} + +} // namespace android -- cgit v1.1