diff options
author | vivek mehta <mvivek@codeaurora.org> | 2012-12-04 11:46:08 -0800 |
---|---|---|
committer | Steve Kondik <shade@chemlab.org> | 2012-12-23 21:26:55 -0800 |
commit | 3a05365a93afccc5bb7db3bdc9f5d2efef69c8d3 (patch) | |
tree | 9384cf4640e68fb4eb9652bc6549b75ed074f5e0 /media/libmediaplayerservice | |
parent | 97343328d2920ec95fb06794b65ec467bce793af (diff) | |
download | frameworks_av-3a05365a93afccc5bb7db3bdc9f5d2efef69c8d3.zip frameworks_av-3a05365a93afccc5bb7db3bdc9f5d2efef69c8d3.tar.gz frameworks_av-3a05365a93afccc5bb7db3bdc9f5d2efef69c8d3.tar.bz2 |
Squashed commit of audio changes from CodeAurora
libstagefright: Add QC specific media format
- Add QC specific media extensions
- Add QC specific media definitions
Change-Id: I7dca90be3b977701d9537f5e017117790a030f1f
audio: Compile AudioParameter as shared library
- AudioParameter as shared lib is needed by BT
support in WFD source.
Change-Id: I464b428ace0cbb57ce6bf7bf3b57d51a7d56f032
libstagefright: Send flush on both i/p and o/p ports together
- ANR occurs in music due to race condition in OMX component if
flush is issued separately for i/p and o/p ports as DSP only
handles simultaneous flush on i/p and o/p ports.
Change-Id: I5b16cd5a9b57c857dc8bed489d2663b8f54769e3
libstagefright: Enable extended A\V format
- Add new files to support extended A\V format
Change-Id: I1e61d78d35b868d55fd8e99f95de8cab9c465db4
libstagefright: Framework to plug-in propritory parser
- Extend the current framework to plug-in propritory
parser
Change-Id: Ia586a3048420ddf1515261f20035589447263b7b
audio: add support for QCOM audio formats
- Add support for EVRC, QCELP, and WMA formats.
Change-Id: Iaf80f982fc8b08617132dbd7d524a1748866745c
frameworks/av: Support Tunnel Playback
- Implement DirectTrack and DirectTrackClient
- DirectTrack exposes API to client so it can create a direct
output.
- DirectTrackClient allows notifications to be sent to the
client from DirectTrack
- DirectTrack is being used for Tunnel Audio
Change-Id: I2fbb18a781d8e44b8d65da9a357f6e39375f063a
frameworks/av: Support LPA Playback
Add support to enable Playback in LPA mode
Change-Id: I1b8ac4904f4735017d62f3757ede7bbb56e62fd3
audio: Send correct channel mask in voice call recording.
-Using popCount function to get channel count gives incorrect value on
voice call recording.
-Only STEREO and MONO bits to be considered to count
channels on input
Change-Id: I04c2c802422e868bdba0538ff8623dbf9eb659fe
libstagefright: Thumbnail mode initial commit
- use sync frame decoding mode when kClientNeedsFrameBuffer
is set for hardware decoders
- hardware decoder will only expect I frames, OMXCodec will
set EOS on first ETB to stop more frames from being pulled
- skip EOS check on FTB so that the first frame will be
handled
Change-Id: I0e8974e088fdcc468e27764861c128cfe291499f
audio: Add support for QCOM's VOIP solution
Change-Id: I1150f536fa204b535ca4019fdaa84f33f4695d93
audio: define QCOM audio parameters
- Define QCOM audio paramters for FM, VOIP,
fluence, SSR, and A2DP
Change-Id: I29d02e37685846f6d4f00dee02e2726b015eaae7
Add ifdefs for QCOM enhanced features
Change-Id: Ic8e5fe6ecc058466ced71030883b1af6c2bc055c
Diffstat (limited to 'media/libmediaplayerservice')
-rw-r--r-- | media/libmediaplayerservice/Android.mk | 7 | ||||
-rw-r--r-- | media/libmediaplayerservice/MediaPlayerService.cpp | 152 | ||||
-rw-r--r-- | media/libmediaplayerservice/MediaPlayerService.h | 11 | ||||
-rw-r--r-- | media/libmediaplayerservice/StagefrightRecorder.cpp | 160 | ||||
-rw-r--r-- | media/libmediaplayerservice/StagefrightRecorder.h | 9 |
5 files changed, 314 insertions, 25 deletions
diff --git a/media/libmediaplayerservice/Android.mk b/media/libmediaplayerservice/Android.mk index 5b5ed71..a583d48 100644 --- a/media/libmediaplayerservice/Android.mk +++ b/media/libmediaplayerservice/Android.mk @@ -47,7 +47,12 @@ LOCAL_C_INCLUDES := \ $(TOP)/frameworks/av/media/libstagefright/rtsp \ $(TOP)/frameworks/av/media/libstagefright/wifi-display \ $(TOP)/frameworks/native/include/media/openmax \ - $(TOP)/external/tremolo/Tremolo \ + $(TOP)/external/tremolo/Tremolo + +ifeq ($(BOARD_USES_QCOM_HARDWARE),true) +LOCAL_C_INCLUDES += \ + $(TOP)/hardware/qcom/media/mm-core/inc +endif LOCAL_MODULE:= libmediaplayerservice diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp index 9bedff1..414c262 100644 --- a/media/libmediaplayerservice/MediaPlayerService.cpp +++ b/media/libmediaplayerservice/MediaPlayerService.cpp @@ -1,5 +1,9 @@ /* ** +** Copyright (c) 2012, The Linux Foundation. All rights reserved. +** Not a Contribution, Apache license notifications and license are retained +** for attribution purposes only. +** ** Copyright 2008, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); @@ -74,6 +78,7 @@ #include "Crypto.h" #include "HDCP.h" #include "RemoteDisplay.h" +#define DEFAULT_SAMPLE_RATE 44100 namespace { using android::media::Metadata; @@ -1363,6 +1368,22 @@ status_t MediaPlayerService::AudioOutput::getPosition(uint32_t *position) const return mTrack->getPosition(position); } +#ifdef QCOM_HARDWARE +ssize_t MediaPlayerService::AudioOutput::sampleRate() const +{ + if (mTrack == 0) return NO_INIT; + return DEFAULT_SAMPLE_RATE; +} + +status_t MediaPlayerService::AudioOutput::getTimeStamp(uint64_t *tstamp) +{ + if (tstamp == 0) return BAD_VALUE; + if (mTrack == 0) return NO_INIT; + mTrack->getTimeStamp(tstamp); + return NO_ERROR; +} +#endif + status_t MediaPlayerService::AudioOutput::getFramesWritten(uint32_t *frameswritten) const { if (mTrack == 0) return NO_INIT; @@ -1379,6 +1400,65 @@ status_t MediaPlayerService::AudioOutput::open( mCallback = cb; mCallbackCookie = cookie; +#ifdef QCOM_HARDWARE + if (flags & AUDIO_OUTPUT_FLAG_LPA || flags & AUDIO_OUTPUT_FLAG_TUNNEL) { + ALOGV("AudioOutput open: with flags %x",flags); + channelMask = audio_channel_out_mask_from_count(channelCount); + if (0 == channelMask) { + ALOGE("open() error, can't derive mask for %d audio channels", channelCount); + return NO_INIT; + } + AudioTrack *audioTrack = NULL; + CallbackData *newcbd = NULL; + if (mCallback != NULL) { + newcbd = new CallbackData(this); + audioTrack = new AudioTrack( + mStreamType, + sampleRate, + format, + channelMask, + 0, + flags, + CallbackWrapper, + newcbd, + 0, + mSessionId); + if ((audioTrack == 0) || (audioTrack->initCheck() != NO_ERROR)) { + ALOGE("Unable to create audio track"); + delete audioTrack; + delete newcbd; + return NO_INIT; + } + } else { + ALOGE("no callback supplied"); + return NO_INIT; + } + + if (mRecycledTrack) { + //usleep(500000); + // if we're not going to reuse the track, unblock and flush it + if (mCallbackData != NULL) { + mCallbackData->setOutput(NULL); + mCallbackData->endTrackSwitch(); + } + mRecycledTrack->flush(); + delete mRecycledTrack; + mRecycledTrack = NULL; + delete mCallbackData; + mCallbackData = NULL; + close(); + } + + ALOGV("setVolume"); + mCallbackData = newcbd; + audioTrack->setVolume(mLeftVolume, mRightVolume); + mSampleRateHz = sampleRate; + mFlags = flags; + mTrack = audioTrack; + return NO_ERROR; + } +#endif + // Check argument "bufferCount" against the mininum buffer count if (bufferCount < mMinBufferCount) { ALOGD("bufferCount (%d) is too small and increased to %d", bufferCount, mMinBufferCount); @@ -1551,7 +1631,7 @@ void MediaPlayerService::AudioOutput::switchToNextOutput() { ssize_t MediaPlayerService::AudioOutput::write(const void* buffer, size_t size) { - LOG_FATAL_IF(mCallback != NULL, "Don't call write if supplying a callback."); + //LOG_FATAL_IF(mCallback != NULL, "Don't call write if supplying a callback."); //ALOGV("write(%p, %u)", buffer, size); if (mTrack) { @@ -1637,35 +1717,56 @@ status_t MediaPlayerService::AudioOutput::attachAuxEffect(int effectId) void MediaPlayerService::AudioOutput::CallbackWrapper( int event, void *cookie, void *info) { //ALOGV("callbackwrapper"); - if (event != AudioTrack::EVENT_MORE_DATA) { - return; - } - - CallbackData *data = (CallbackData*)cookie; - data->lock(); - AudioOutput *me = data->getOutput(); - AudioTrack::Buffer *buffer = (AudioTrack::Buffer *)info; - if (me == NULL) { - // no output set, likely because the track was scheduled to be reused - // by another player, but the format turned out to be incompatible. +#ifdef QCOM_HARDWARE + if (event == AudioTrack::EVENT_UNDERRUN) { + ALOGW("Event underrun"); + CallbackData *data = (CallbackData*)cookie; + data->lock(); + AudioOutput *me = data->getOutput(); + if (me == NULL) { + // no output set, likely because the track was scheduled to be reused + // by another player, but the format turned out to be incompatible. + data->unlock(); + return; + } + ALOGD("Callback!!!"); + (*me->mCallback)( + me, NULL, (size_t)AudioTrack::EVENT_UNDERRUN, me->mCallbackCookie); data->unlock(); - buffer->size = 0; return; } +#endif + if (event == AudioTrack::EVENT_MORE_DATA) { + CallbackData *data = (CallbackData*)cookie; + data->lock(); + AudioOutput *me = data->getOutput(); + AudioTrack::Buffer *buffer = (AudioTrack::Buffer *)info; + if (me == NULL) { + // no output set, likely because the track was scheduled to be reused + // by another player, but the format turned out to be incompatible. + data->unlock(); + buffer->size = 0; + return; + } + + size_t actualSize = (*me->mCallback)( + me, buffer->raw, buffer->size, me->mCallbackCookie); - size_t actualSize = (*me->mCallback)( - me, buffer->raw, buffer->size, me->mCallbackCookie); + if (actualSize == 0 && buffer->size > 0 && me->mNextOutput == NULL) { + // We've reached EOS but the audio track is not stopped yet, + // keep playing silence. - if (actualSize == 0 && buffer->size > 0 && me->mNextOutput == NULL) { - // We've reached EOS but the audio track is not stopped yet, - // keep playing silence. + memset(buffer->raw, 0, buffer->size); + actualSize = buffer->size; + } - memset(buffer->raw, 0, buffer->size); - actualSize = buffer->size; + buffer->size = actualSize; + data->unlock(); } - buffer->size = actualSize; - data->unlock(); + return; + + } int MediaPlayerService::AudioOutput::getSessionId() const @@ -1700,6 +1801,13 @@ status_t MediaPlayerService::AudioCache::getPosition(uint32_t *position) const return NO_ERROR; } +#ifdef QCOM_HARDWARE +ssize_t MediaPlayerService::AudioCache::sampleRate() const +{ + return mSampleRate; +} +#endif + status_t MediaPlayerService::AudioCache::getFramesWritten(uint32_t *written) const { if (written == 0) return BAD_VALUE; diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h index fd648df..54df9d2 100644 --- a/media/libmediaplayerservice/MediaPlayerService.h +++ b/media/libmediaplayerservice/MediaPlayerService.h @@ -114,6 +114,10 @@ class MediaPlayerService : public BnMediaPlayerService void setNextOutput(const sp<AudioOutput>& nextOutput); void switchToNextOutput(); virtual bool needsTrailingPadding() { return mNextOutput == NULL; } +#ifdef QCOM_HARDWARE + virtual ssize_t sampleRate() const; + virtual status_t getTimeStamp(uint64_t *tstamp); +#endif private: static void setMinBufferCount(); @@ -205,8 +209,10 @@ class MediaPlayerService : public BnMediaPlayerService virtual void close() {} void setAudioStreamType(audio_stream_type_t streamType) {} void setVolume(float left, float right) {} - virtual status_t setPlaybackRatePermille(int32_t ratePermille) { return INVALID_OPERATION; } +#ifndef QCOM_HARDWARE uint32_t sampleRate() const { return mSampleRate; } +#endif + virtual status_t setPlaybackRatePermille(int32_t ratePermille) { return INVALID_OPERATION; } audio_format_t format() const { return mFormat; } size_t size() const { return mSize; } status_t wait(); @@ -216,6 +222,9 @@ class MediaPlayerService : public BnMediaPlayerService static void notify(void* cookie, int msg, int ext1, int ext2, const Parcel *obj); virtual status_t dump(int fd, const Vector<String16>& args) const; +#ifdef QCOM_HARDWARE + virtual ssize_t sampleRate() const; +#endif private: AudioCache(); diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp index 57b0ec2..aa25eff 100644 --- a/media/libmediaplayerservice/StagefrightRecorder.cpp +++ b/media/libmediaplayerservice/StagefrightRecorder.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2009 The Android Open Source Project + * Copyright (c) 2010 - 2012, The Linux Foundation. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -29,6 +30,10 @@ #include <media/stagefright/AudioSource.h> #include <media/stagefright/AMRWriter.h> #include <media/stagefright/AACWriter.h> +#ifdef QCOM_HARDWARE +#include <media/stagefright/ExtendedWriter.h> +#include <media/stagefright/WAVEWriter.h> +#endif #include <media/stagefright/CameraSource.h> #include <media/stagefright/CameraSourceTimeLapse.h> #include <media/stagefright/MPEG2TSWriter.h> @@ -49,6 +54,9 @@ #include <unistd.h> #include <system/audio.h> +#ifdef QCOM_HARDWARE +#include <QCMediaDefs.h> +#endif #include "ARTPWriter.h" @@ -159,6 +167,26 @@ status_t StagefrightRecorder::setAudioEncoder(audio_encoder ae) { mAudioEncoder = ae; } +#ifdef QCOM_HARDWARE + // Use default values if appropriate setparam's weren't called. + if(mAudioEncoder == AUDIO_ENCODER_AAC) { + mSampleRate = mSampleRate ? mSampleRate : 48000; + mAudioChannels = mAudioChannels ? mAudioChannels : 2; + mAudioBitRate = mAudioBitRate ? mAudioBitRate : 156000; + } else if(mAudioEncoder == AUDIO_ENCODER_LPCM) { + mSampleRate = mSampleRate ? mSampleRate : 48000; + mAudioChannels = mAudioChannels ? mAudioChannels : 2; + mAudioBitRate = mAudioBitRate ? mAudioBitRate : 4608000; + } else if(mAudioEncoder == AUDIO_ENCODER_AMR_WB) { + mSampleRate = 16000; + mAudioChannels = 1; + mAudioBitRate = 23850; + } else { + mSampleRate = mSampleRate ? mSampleRate : 8000; + mAudioChannels = mAudioChannels ? mAudioChannels : 1; + mAudioBitRate = mAudioBitRate ? mAudioBitRate : 12200; + } +#endif return OK; } @@ -768,7 +796,15 @@ status_t StagefrightRecorder::start() { case OUTPUT_FORMAT_MPEG2TS: status = startMPEG2TSRecording(); break; +#ifdef QCOM_HARDWARE + case OUTPUT_FORMAT_QCP: + status = startExtendedRecording( ); + break; + case OUTPUT_FORMAT_WAVE: + status = startWAVERecording( ); + break; +#endif default: ALOGE("Unsupported output file format: %d", mOutputFormat); status = UNKNOWN_ERROR; @@ -809,6 +845,11 @@ sp<MediaSource> StagefrightRecorder::createAudioSource() { sp<MetaData> encMeta = new MetaData; const char *mime; switch (mAudioEncoder) { +#ifdef QCOM_HARDWARE + case AUDIO_ENCODER_LPCM: + mime = MEDIA_MIMETYPE_AUDIO_RAW; + break; +#endif case AUDIO_ENCODER_AMR_NB: case AUDIO_ENCODER_DEFAULT: mime = MEDIA_MIMETYPE_AUDIO_AMR_NB; @@ -828,6 +869,14 @@ sp<MediaSource> StagefrightRecorder::createAudioSource() { mime = MEDIA_MIMETYPE_AUDIO_AAC; encMeta->setInt32(kKeyAACProfile, OMX_AUDIO_AACObjectELD); break; +#ifdef QCOM_HARDWARE + case AUDIO_ENCODER_EVRC: + mime = MEDIA_MIMETYPE_AUDIO_EVRC; + break; + case AUDIO_ENCODER_QCELP: + mime = MEDIA_MIMETYPE_AUDIO_QCELP; + break; +#endif default: ALOGE("Unknown audio encoder: %d", mAudioEncoder); @@ -852,6 +901,17 @@ sp<MediaSource> StagefrightRecorder::createAudioSource() { sp<MediaSource> audioEncoder = OMXCodec::Create(client.interface(), encMeta, true /* createEncoder */, audioSource); +#ifdef QCOM_HARDWARE + // If encoder could not be created (as in LPCM), then + // use the AudioSource directly as the MediaSource. + if (audioEncoder == NULL && AUDIO_ENCODER_LPCM) { + ALOGD("No encoder is needed, use the AudioSource directly as the MediaSource for LPCM format"); + audioEncoder = audioSource; + } + if (mAudioSourceNode != NULL) { + mAudioSourceNode.clear(); + } +#endif mAudioSourceNode = audioSource; return audioEncoder; @@ -888,13 +948,35 @@ status_t StagefrightRecorder::startAMRRecording() { mAudioEncoder); return BAD_VALUE; } +#ifdef QCOM_HARDWARE + if (mSampleRate != 8000) { + ALOGE("Invalid sampling rate %d used for AMRNB recording", + mSampleRate); + return BAD_VALUE; + } +#endif } else { // mOutputFormat must be OUTPUT_FORMAT_AMR_WB if (mAudioEncoder != AUDIO_ENCODER_AMR_WB) { ALOGE("Invlaid encoder %d used for AMRWB recording", mAudioEncoder); return BAD_VALUE; } +#ifdef QCOM_HARDWARE + if (mSampleRate != 16000) { + ALOGE("Invalid sample rate %d used for AMRWB recording", + mSampleRate); + return BAD_VALUE; + } +#endif + } + +#ifdef QCOM_HARDWARE + if (mAudioChannels != 1) { + ALOGE("Invalid number of audio channels %d used for amr recording", + mAudioChannels); + return BAD_VALUE; } +#endif mWriter = new AMRWriter(mOutputFd); status_t status = startRawAudioRecording(); @@ -905,6 +987,24 @@ status_t StagefrightRecorder::startAMRRecording() { return status; } +#ifdef QCOM_HARDWARE +status_t StagefrightRecorder::startWAVERecording() { + CHECK(mOutputFormat == OUTPUT_FORMAT_WAVE); + + CHECK(mAudioEncoder == AUDIO_ENCODER_LPCM); + CHECK(mAudioSource != AUDIO_SOURCE_CNT); + + mWriter = new WAVEWriter(mOutputFd); + status_t status = startRawAudioRecording(); + if (status != OK) { + mWriter.clear(); + mWriter = NULL; + } + + return status; +} +#endif + status_t StagefrightRecorder::startRawAudioRecording() { if (mAudioSource >= AUDIO_SOURCE_CNT) { ALOGE("Invalid audio source: %d", mAudioSource); @@ -1450,6 +1550,9 @@ status_t StagefrightRecorder::setupAudioEncoder(const sp<MediaWriter>& writer) { case AUDIO_ENCODER_AAC: case AUDIO_ENCODER_HE_AAC: case AUDIO_ENCODER_AAC_ELD: +#ifdef QCOM_HARDWARE + case AUDIO_ENCODER_LPCM: +#endif break; default: @@ -1611,7 +1714,12 @@ status_t StagefrightRecorder::stop() { ::close(mOutputFd); mOutputFd = -1; } - +#ifdef QCOM_HARDWARE + if (mAudioSourceNode != NULL) { + mAudioSourceNode.clear(); + mAudioSourceNode = NULL; + } +#endif if (mStarted) { mStarted = false; @@ -1653,9 +1761,15 @@ status_t StagefrightRecorder::reset() { mVideoHeight = 144; mFrameRate = -1; mVideoBitRate = 192000; +#ifdef QCOM_HARDWARE + mSampleRate = 0; + mAudioChannels = 0; + mAudioBitRate = 0; +#else mSampleRate = 8000; mAudioChannels = 1; mAudioBitRate = 12200; +#endif mInterleaveDurationUs = 0; mIFramesIntervalSec = 1; mAudioSourceNode = 0; @@ -1767,4 +1881,48 @@ status_t StagefrightRecorder::dump( ::write(fd, result.string(), result.size()); return OK; } + +#ifdef QCOM_HARDWARE +status_t StagefrightRecorder::startExtendedRecording() { + CHECK(mOutputFormat == OUTPUT_FORMAT_QCP); + + if (mSampleRate != 8000) { + ALOGE("Invalid sampling rate %d used for recording", + mSampleRate); + return BAD_VALUE; + } + if (mAudioChannels != 1) { + ALOGE("Invalid number of audio channels %d used for recording", + mAudioChannels); + return BAD_VALUE; + } + + if (mAudioSource >= AUDIO_SOURCE_CNT) { + ALOGE("Invalid audio source: %d", mAudioSource); + return BAD_VALUE; + } + + sp<MediaSource> audioEncoder = createAudioSource(); + + if (audioEncoder == NULL) { + ALOGE("AudioEncoder NULL"); + return UNKNOWN_ERROR; + } + + mWriter = new ExtendedWriter(dup(mOutputFd)); + mWriter->addSource(audioEncoder); + + if (mMaxFileDurationUs != 0) { + mWriter->setMaxFileDuration(mMaxFileDurationUs); + } + if (mMaxFileSizeBytes != 0) { + mWriter->setMaxFileSize(mMaxFileSizeBytes); + } + mWriter->setListener(mListener); + mWriter->start(); + + return OK; +} +#endif + } // namespace android diff --git a/media/libmediaplayerservice/StagefrightRecorder.h b/media/libmediaplayerservice/StagefrightRecorder.h index ec5ce7e..3f0b821 100644 --- a/media/libmediaplayerservice/StagefrightRecorder.h +++ b/media/libmediaplayerservice/StagefrightRecorder.h @@ -1,5 +1,6 @@ /* * Copyright (C) 2009 The Android Open Source Project + * Copyright (c) 2012, The Linux Foundation. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -132,6 +133,9 @@ private: status_t startMPEG4Recording(); status_t startAMRRecording(); status_t startAACRecording(); +#ifdef QCOM_HARDWARE + status_t startWAVERecording(); +#endif status_t startRawAudioRecording(); status_t startRTPRecording(); status_t startMPEG2TSRecording(); @@ -187,6 +191,11 @@ private: StagefrightRecorder(const StagefrightRecorder &); StagefrightRecorder &operator=(const StagefrightRecorder &); + +#ifdef QCOM_HARDWARE + /* extension */ + status_t startExtendedRecording(); +#endif }; } // namespace android |