Merge "AudioMixer can be configured for fewer max tracks"
diff --git a/include/common_time/local_clock.h b/include/common_time/local_clock.h
index 845d1c2..384c3de 100644
--- a/include/common_time/local_clock.h
+++ b/include/common_time/local_clock.h
@@ -28,7 +28,7 @@
class LocalClock {
public:
- LocalClock();
+ LocalClock();
bool initCheck();
diff --git a/include/media/AudioTrack.h b/include/media/AudioTrack.h
index 552e829..ad27a1e 100644
--- a/include/media/AudioTrack.h
+++ b/include/media/AudioTrack.h
@@ -169,7 +169,7 @@
callback_t cbf = 0,
void* user = 0,
int notificationFrames = 0,
- int sessionId = 0);
+ int sessionId = 0);
/* Creates an audio track and registers it with AudioFlinger. With this constructor,
* the PCM data to be rendered by AudioTrack is passed in a shared memory buffer
@@ -215,7 +215,7 @@
int notificationFrames = 0,
const sp<IMemory>& sharedBuffer = 0,
bool threadCanCallJava = false,
- int sessionId = 0);
+ int sessionId = 0);
/* Result of constructing the AudioTrack. This must be checked
@@ -468,6 +468,7 @@
// body of AudioTrackThread::threadLoop()
bool processAudioBuffer(const sp<AudioTrackThread>& thread);
+
status_t createTrack_l(audio_stream_type_t streamType,
uint32_t sampleRate,
audio_format_t format,
diff --git a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
index ca93ce5..40dffd4 100644
--- a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
+++ b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
@@ -1493,7 +1493,7 @@
pContext->pBundledContext->firstVolume = LVM_FALSE;
}
return 0;
-} /* end setVolumeLevel */
+} /* end VolumeSetVolumeLevel */
//----------------------------------------------------------------------------
// VolumeGetVolumeLevel()
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index 048be1d..55cd3ad 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -104,9 +104,10 @@
{
mStatus = set(streamType, sampleRate, format, channelMask,
frameCount, flags, cbf, user, notificationFrames,
- 0, false, sessionId);
+ 0 /*sharedBuffer*/, false /*threadCanCallJava*/, sessionId);
}
+// DEPRECATED
AudioTrack::AudioTrack(
int streamType,
uint32_t sampleRate,
@@ -124,7 +125,7 @@
{
mStatus = set((audio_stream_type_t)streamType, sampleRate, (audio_format_t)format, channelMask,
frameCount, (audio_policy_output_flags_t)flags, cbf, user, notificationFrames,
- 0, false, sessionId);
+ 0 /*sharedBuffer*/, false /*threadCanCallJava*/, sessionId);
}
AudioTrack::AudioTrack(
@@ -144,8 +145,8 @@
mPreviousSchedulingGroup(ANDROID_TGROUP_DEFAULT)
{
mStatus = set(streamType, sampleRate, format, channelMask,
- 0, flags, cbf, user, notificationFrames,
- sharedBuffer, false, sessionId);
+ 0 /*frameCount*/, flags, cbf, user, notificationFrames,
+ sharedBuffer, false /*threadCanCallJava*/, sessionId);
}
AudioTrack::~AudioTrack()
@@ -194,6 +195,7 @@
if (AudioSystem::getOutputSamplingRate(&afSampleRate, streamType) != NO_ERROR) {
return NO_INIT;
}
+
uint32_t afLatency;
if (AudioSystem::getOutputLatency(&afLatency, streamType) != NO_ERROR) {
return NO_INIT;
@@ -203,9 +205,11 @@
if (streamType == AUDIO_STREAM_DEFAULT) {
streamType = AUDIO_STREAM_MUSIC;
}
+
if (sampleRate == 0) {
sampleRate = afSampleRate;
}
+
// these below should probably come from the audioFlinger too...
if (format == AUDIO_FORMAT_DEFAULT) {
format = AUDIO_FORMAT_PCM_16_BIT;
diff --git a/media/libmedia/JetPlayer.cpp b/media/libmedia/JetPlayer.cpp
index f1f62f7..7fa6bb7 100644
--- a/media/libmedia/JetPlayer.cpp
+++ b/media/libmedia/JetPlayer.cpp
@@ -89,7 +89,7 @@
// create the output AudioTrack
mAudioTrack = new AudioTrack();
- mAudioTrack->set(AUDIO_STREAM_MUSIC, //TODO parametrize this
+ mAudioTrack->set(AUDIO_STREAM_MUSIC, //TODO parameterize this
pLibConfig->sampleRate,
AUDIO_FORMAT_PCM_16_BIT,
audio_channel_out_mask_from_count(pLibConfig->numChannels),
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 8f62ee4..148018d 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -1571,7 +1571,7 @@
AUDIO_POLICY_OUTPUT_FLAG_NONE,
CallbackWrapper,
mCallbackData,
- 0,
+ 0, // notification frames
mSessionId);
} else {
t = new AudioTrack(
diff --git a/media/libstagefright/MP3Extractor.cpp b/media/libstagefright/MP3Extractor.cpp
index 1886050..6abaf23 100644
--- a/media/libstagefright/MP3Extractor.cpp
+++ b/media/libstagefright/MP3Extractor.cpp
@@ -348,6 +348,37 @@
}
mInitCheck = OK;
+
+ // get iTunes-style gapless info if present
+ ID3 id3(mDataSource);
+ if (id3.isValid()) {
+ ID3::Iterator *com = new ID3::Iterator(id3, "COM");
+ if (com->done()) {
+ delete com;
+ com = new ID3::Iterator(id3, "COMM");
+ }
+ while(!com->done()) {
+ String8 commentdesc;
+ String8 commentvalue;
+ com->getString(&commentdesc, &commentvalue);
+ const char * desc = commentdesc.string();
+ const char * value = commentvalue.string();
+
+ // first 3 characters are the language, which we don't care about
+ if(strlen(desc) > 3 && strcmp(desc + 3, "iTunSMPB") == 0) {
+
+ int32_t delay, padding;
+ if (sscanf(value, " %*x %x %x %*x", &delay, &padding) == 2) {
+ mMeta->setInt32(kKeyEncoderDelay, delay);
+ mMeta->setInt32(kKeyEncoderPadding, padding);
+ }
+ break;
+ }
+ com->next();
+ }
+ delete com;
+ com = NULL;
+ }
}
size_t MP3Extractor::countTracks() {
@@ -555,33 +586,6 @@
return meta;
}
- ID3::Iterator *com = new ID3::Iterator(id3, "COM");
- if (com->done()) {
- delete com;
- com = new ID3::Iterator(id3, "COMM");
- }
- while(!com->done()) {
- String8 commentdesc;
- String8 commentvalue;
- com->getString(&commentdesc, &commentvalue);
- const char * desc = commentdesc.string();
- const char * value = commentvalue.string();
-
- // first 3 characters are the language, which we don't care about
- if(strlen(desc) > 3 && strcmp(desc + 3, "iTunSMPB") == 0) {
-
- int32_t delay, padding;
- if (sscanf(value, " %*x %x %x %*x", &delay, &padding) == 2) {
- mMeta->setInt32(kKeyEncoderDelay, delay);
- mMeta->setInt32(kKeyEncoderPadding, padding);
- }
- break;
- }
- com->next();
- }
- delete com;
- com = NULL;
-
struct Map {
int key;
const char *tag1;
diff --git a/media/libstagefright/timedtext/TimedText3GPPSource.cpp b/media/libstagefright/timedtext/TimedText3GPPSource.cpp
index c423ef0..4854121 100644
--- a/media/libstagefright/timedtext/TimedText3GPPSource.cpp
+++ b/media/libstagefright/timedtext/TimedText3GPPSource.cpp
@@ -39,19 +39,21 @@
}
status_t TimedText3GPPSource::read(
- int64_t *timeUs, Parcel *parcel, const MediaSource::ReadOptions *options) {
+ int64_t *startTimeUs, int64_t *endTimeUs, Parcel *parcel,
+ const MediaSource::ReadOptions *options) {
MediaBuffer *textBuffer = NULL;
status_t err = mSource->read(&textBuffer, options);
if (err != OK) {
return err;
}
CHECK(textBuffer != NULL);
- textBuffer->meta_data()->findInt64(kKeyTime, timeUs);
- // TODO: this is legacy code. when 'timeUs' can be <= 0?
- if (*timeUs > 0) {
- extractAndAppendLocalDescriptions(*timeUs, textBuffer, parcel);
- }
+ textBuffer->meta_data()->findInt64(kKeyTime, startTimeUs);
+ CHECK_GE(*startTimeUs, 0);
+ extractAndAppendLocalDescriptions(*startTimeUs, textBuffer, parcel);
textBuffer->release();
+ // endTimeUs is a dummy parameter for 3gpp timed text format.
+ // Set a negative value to it to mark it is unavailable.
+ *endTimeUs = -1;
return OK;
}
diff --git a/media/libstagefright/timedtext/TimedText3GPPSource.h b/media/libstagefright/timedtext/TimedText3GPPSource.h
index 4ec3d8a..4170940 100644
--- a/media/libstagefright/timedtext/TimedText3GPPSource.h
+++ b/media/libstagefright/timedtext/TimedText3GPPSource.h
@@ -33,7 +33,8 @@
virtual status_t start() { return mSource->start(); }
virtual status_t stop() { return mSource->stop(); }
virtual status_t read(
- int64_t *timeUs,
+ int64_t *startTimeUs,
+ int64_t *endTimeUs,
Parcel *parcel,
const MediaSource::ReadOptions *options = NULL);
virtual status_t extractGlobalDescriptions(Parcel *parcel);
diff --git a/media/libstagefright/timedtext/TimedTextPlayer.cpp b/media/libstagefright/timedtext/TimedTextPlayer.cpp
index 8717914..917c62a 100644
--- a/media/libstagefright/timedtext/TimedTextPlayer.cpp
+++ b/media/libstagefright/timedtext/TimedTextPlayer.cpp
@@ -31,6 +31,7 @@
namespace android {
static const int64_t kAdjustmentProcessingTimeUs = 100000ll;
+static const int64_t kWaitTimeUsToRetryRead = 100000ll;
TimedTextPlayer::TimedTextPlayer(const wp<MediaPlayerBase> &listener)
: mListener(listener),
@@ -139,13 +140,25 @@
}
void TimedTextPlayer::doRead(MediaSource::ReadOptions* options) {
- int64_t timeUs = 0;
+ int64_t startTimeUs = 0;
+ int64_t endTimeUs = 0;
sp<ParcelEvent> parcelEvent = new ParcelEvent();
- status_t err = mSource->read(&timeUs, &(parcelEvent->parcel), options);
- if (err != OK) {
+ status_t err = mSource->read(&startTimeUs, &endTimeUs,
+ &(parcelEvent->parcel), options);
+ if (err == WOULD_BLOCK) {
+ postTextEventDelayUs(NULL, kWaitTimeUsToRetryRead);
+ return;
+ } else if (err != OK) {
notifyError(err);
- } else {
- postTextEvent(parcelEvent, timeUs);
+ return;
+ }
+
+ postTextEvent(parcelEvent, startTimeUs);
+ if (endTimeUs > 0) {
+ CHECK_GE(endTimeUs, startTimeUs);
+ // send an empty timed text to clear the subtitle when it reaches to the
+ // end time.
+ postTextEvent(NULL, endTimeUs);
}
}
@@ -162,6 +175,13 @@
} else {
delayUs = timeUs - positionUs - kAdjustmentProcessingTimeUs;
}
+ postTextEventDelayUs(parcel, delayUs);
+ }
+}
+
+void TimedTextPlayer::postTextEventDelayUs(const sp<ParcelEvent>& parcel, int64_t delayUs) {
+ sp<MediaPlayerBase> listener = mListener.promote();
+ if (listener != NULL) {
sp<AMessage> msg = new AMessage(kWhatSendSubtitle, id());
msg->setInt32("generation", mSendSubtitleGeneration);
if (parcel != NULL) {
diff --git a/media/libstagefright/timedtext/TimedTextPlayer.h b/media/libstagefright/timedtext/TimedTextPlayer.h
index b869f18..47aff03 100644
--- a/media/libstagefright/timedtext/TimedTextPlayer.h
+++ b/media/libstagefright/timedtext/TimedTextPlayer.h
@@ -67,6 +67,7 @@
void doRead(MediaSource::ReadOptions* options = NULL);
void onTextEvent();
void postTextEvent(const sp<ParcelEvent>& parcel = NULL, int64_t timeUs = -1);
+ void postTextEventDelayUs(const sp<ParcelEvent>& parcel = NULL, int64_t delayUs = -1);
void notifyError(int error = 0);
void notifyListener(const Parcel *parcel = NULL);
diff --git a/media/libstagefright/timedtext/TimedTextSRTSource.cpp b/media/libstagefright/timedtext/TimedTextSRTSource.cpp
index c44a99b..7b1f7f6 100644
--- a/media/libstagefright/timedtext/TimedTextSRTSource.cpp
+++ b/media/libstagefright/timedtext/TimedTextSRTSource.cpp
@@ -19,6 +19,7 @@
#include <utils/Log.h>
#include <binder/Parcel.h>
+#include <media/stagefright/foundation/ADebug.h> // for CHECK_xx
#include <media/stagefright/foundation/AString.h>
#include <media/stagefright/DataSource.h>
#include <media/stagefright/MediaDefs.h> // for MEDIA_MIMETYPE_xxx
@@ -63,19 +64,18 @@
}
status_t TimedTextSRTSource::read(
- int64_t *timeUs,
+ int64_t *startTimeUs,
+ int64_t *endTimeUs,
Parcel *parcel,
const MediaSource::ReadOptions *options) {
- int64_t endTimeUs;
AString text;
- status_t err = getText(options, &text, timeUs, &endTimeUs);
+ status_t err = getText(options, &text, startTimeUs, endTimeUs);
if (err != OK) {
return err;
}
- if (*timeUs > 0) {
- extractAndAppendLocalDescriptions(*timeUs, text, parcel);
- }
+ CHECK_GE(*startTimeUs, 0);
+ extractAndAppendLocalDescriptions(*startTimeUs, text, parcel);
return OK;
}
diff --git a/media/libstagefright/timedtext/TimedTextSRTSource.h b/media/libstagefright/timedtext/TimedTextSRTSource.h
index 62710a0..e1371b8 100644
--- a/media/libstagefright/timedtext/TimedTextSRTSource.h
+++ b/media/libstagefright/timedtext/TimedTextSRTSource.h
@@ -36,7 +36,8 @@
virtual status_t start();
virtual status_t stop();
virtual status_t read(
- int64_t *timeUs,
+ int64_t *startTimeUs,
+ int64_t *endTimeUs,
Parcel *parcel,
const MediaSource::ReadOptions *options = NULL);
virtual sp<MetaData> getFormat();
diff --git a/media/libstagefright/timedtext/TimedTextSource.h b/media/libstagefright/timedtext/TimedTextSource.h
index 9349342..756cc31 100644
--- a/media/libstagefright/timedtext/TimedTextSource.h
+++ b/media/libstagefright/timedtext/TimedTextSource.h
@@ -43,7 +43,8 @@
virtual status_t stop() = 0;
// Returns subtitle parcel and its start time.
virtual status_t read(
- int64_t *timeUs,
+ int64_t *startTimeUs,
+ int64_t *endTimeUs,
Parcel *parcel,
const MediaSource::ReadOptions *options = NULL) = 0;
virtual status_t extractGlobalDescriptions(Parcel *parcel) {
diff --git a/services/audioflinger/Android.mk b/services/audioflinger/Android.mk
index 1652cae..257f62c 100644
--- a/services/audioflinger/Android.mk
+++ b/services/audioflinger/Android.mk
@@ -15,6 +15,7 @@
$(call include-path-for, audio-effects) \
$(call include-path-for, audio-utils)
+# FIXME keep libmedia_native but remove libmedia after split
LOCAL_SHARED_LIBRARIES := \
libaudioutils \
libcommon_time_client \
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index d83d19a..3ab4e34 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -894,7 +894,8 @@
// indicate output device change to all input threads for pre processing
AudioParameter param = AudioParameter(keyValuePairs);
int value;
- if (param.getInt(String8(AudioParameter::keyRouting), value) == NO_ERROR) {
+ if ((param.getInt(String8(AudioParameter::keyRouting), value) == NO_ERROR) &&
+ (value != 0)) {
for (size_t i = 0; i < mRecordThreads.size(); i++) {
mRecordThreads.valueAt(i)->setParameters(keyValuePairs);
}
@@ -1588,7 +1589,7 @@
}
// PlaybackThread::createTrack_l() must be called with AudioFlinger::mLock held
-sp<AudioFlinger::PlaybackThread::Track> AudioFlinger::PlaybackThread::createTrack_l(
+sp<AudioFlinger::PlaybackThread::Track> AudioFlinger::PlaybackThread::createTrack_l(
const sp<AudioFlinger::Client>& client,
audio_stream_type_t streamType,
uint32_t sampleRate,
@@ -2337,7 +2338,7 @@
size_t tracksWithEffect = 0;
float masterVolume = mMasterVolume;
- bool masterMute = mMasterMute;
+ bool masterMute = mMasterMute;
if (masterMute) {
masterVolume = 0;
@@ -2376,7 +2377,7 @@
// +1 for rounding and +1 for additional sample needed for interpolation
minFrames = (mFrameCount * t->sampleRate()) / mSampleRate + 1 + 1;
// add frames already consumed but not yet released by the resampler
- // because cblk->framesReady() will include these frames
+ // because cblk->framesReady() will include these frames
minFrames += mAudioMixer->getUnreleasedFrames(track->name());
// the minimum track buffer size is normally twice the number of frames necessary
// to fill one buffer and the resampler should not leave more than one buffer worth
@@ -2514,6 +2515,7 @@
// reset retry count
track->mRetryCount = kMaxTrackRetries;
+
// If one track is ready, set the mixer ready if:
// - the mixer was not ready during previous round OR
// - no other track is not ready
@@ -3372,19 +3374,19 @@
}
} else {
mCblk = (audio_track_cblk_t *)(new uint8_t[size]);
- // construct the shared structure in-place.
- new(mCblk) audio_track_cblk_t();
- // clear all buffers
- mCblk->frameCount = frameCount;
- mCblk->sampleRate = sampleRate;
- mChannelCount = channelCount;
- mChannelMask = channelMask;
- mBuffer = (char*)mCblk + sizeof(audio_track_cblk_t);
- memset(mBuffer, 0, frameCount*channelCount*sizeof(int16_t));
- // Force underrun condition to avoid false underrun callback until first data is
- // written to buffer (other flags are cleared)
- mCblk->flags = CBLK_UNDERRUN_ON;
- mBufferEnd = (uint8_t *)mBuffer + bufferSize;
+ // construct the shared structure in-place.
+ new(mCblk) audio_track_cblk_t();
+ // clear all buffers
+ mCblk->frameCount = frameCount;
+ mCblk->sampleRate = sampleRate;
+ mChannelCount = channelCount;
+ mChannelMask = channelMask;
+ mBuffer = (char*)mCblk + sizeof(audio_track_cblk_t);
+ memset(mBuffer, 0, frameCount*channelCount*sizeof(int16_t));
+ // Force underrun condition to avoid false underrun callback until first data is
+ // written to buffer (other flags are cleared)
+ mCblk->flags = CBLK_UNDERRUN_ON;
+ mBufferEnd = (uint8_t *)mBuffer + bufferSize;
}
}
@@ -3792,16 +3794,9 @@
if (!client->reserveTimedTrack())
return NULL;
- sp<TimedTrack> track = new TimedTrack(
+ return new TimedTrack(
thread, client, streamType, sampleRate, format, channelMask, frameCount,
sharedBuffer, sessionId);
-
- if (track == NULL) {
- client->releaseTimedTrack();
- return NULL;
- }
-
- return track;
}
AudioFlinger::PlaybackThread::TimedTrack::TimedTrack(
@@ -4261,7 +4256,7 @@
RecordThread *recordThread = (RecordThread *)thread.get();
recordThread->stop(this);
TrackBase::reset();
- // Force overerrun condition to avoid false overrun callback until first data is
+ // Force overrun condition to avoid false overrun callback until first data is
// read from buffer
android_atomic_or(CBLK_UNDERRUN_ON, &mCblk->flags);
}
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 0e4b24a..7a57613 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -899,6 +899,7 @@
protected:
SortedVector< wp<Track> > mActiveTracks;
+ // Allocate a track name. Returns name >= 0 if successful, -1 on failure.
virtual int getTrackName_l() = 0;
virtual void deleteTrackName_l(int name) = 0;
virtual uint32_t activeSleepTimeUs();
@@ -1559,9 +1560,10 @@
uint32_t mNewLeftVolume; // new volume on left channel
uint32_t mNewRightVolume; // new volume on right channel
uint32_t mStrategy; // strategy for this effect chain
- // mSuspendedEffects lists all effect currently suspended in the chain
- // use effect type UUID timelow field as key. There is no real risk of identical
+ // mSuspendedEffects lists all effects currently suspended in the chain.
+ // Use effect type UUID timelow field as key. There is no real risk of identical
// timeLow fields among effect type UUIDs.
+ // Updated by updateSuspendedSessions_l() only.
KeyedVector< int, sp<SuspendedEffectDesc> > mSuspendedEffects;
};
diff --git a/services/audioflinger/AudioMixer.cpp b/services/audioflinger/AudioMixer.cpp
index 91f7515..3f4c19a 100644
--- a/services/audioflinger/AudioMixer.cpp
+++ b/services/audioflinger/AudioMixer.cpp
@@ -60,6 +60,10 @@
mState.outputTemp = NULL;
mState.resampleTemp = NULL;
// mState.reserved
+
+ // FIXME Most of the following initialization is probably redundant since
+ // tracks[i] should only be referenced if (mTrackNames & (1 << i)) != 0
+ // and mTrackNames is initially 0. However, leave it here until that's verified.
track_t* t = mState.tracks;
for (unsigned i=0 ; i < MAX_NUM_TRACKS ; i++) {
t->needs = 0;
@@ -135,7 +139,7 @@
invalidateState(1<<name);
}
if (track.resampler != NULL) {
- // delete the resampler
+ // delete the resampler
delete track.resampler;
track.resampler = NULL;
track.sampleRate = mSampleRate;
diff --git a/services/audioflinger/AudioMixer.h b/services/audioflinger/AudioMixer.h
index 7a61467..856450c 100644
--- a/services/audioflinger/AudioMixer.h
+++ b/services/audioflinger/AudioMixer.h
@@ -71,9 +71,14 @@
// For all APIs with "name": TRACK0 <= name < TRACK0 + MAX_NUM_TRACKS
+
+ // Allocate a track name. Returns new track name if successful, -1 on failure.
int getTrackName();
+
+ // Free an allocated track by name
void deleteTrackName(int name);
+ // Enable or disable an allocated track by name
void enable(int name);
void disable(int name);