summaryrefslogtreecommitdiffstats
path: root/media/libmedia
diff options
context:
space:
mode:
Diffstat (limited to 'media/libmedia')
-rw-r--r--media/libmedia/Android.mk30
-rw-r--r--media/libmedia/AudioEffect.cpp4
-rw-r--r--media/libmedia/AudioRecord.cpp263
-rw-r--r--media/libmedia/AudioSystem.cpp114
-rw-r--r--media/libmedia/AudioTrack.cpp424
-rw-r--r--media/libmedia/AudioTrackShared.cpp12
-rw-r--r--media/libmedia/CharacterEncodingDetector.cpp441
-rw-r--r--media/libmedia/CharacterEncodingDetector.h63
-rw-r--r--media/libmedia/CharacterEncodingDetectorTables.h2092
-rw-r--r--media/libmedia/IAudioFlinger.cpp137
-rw-r--r--media/libmedia/IAudioPolicyService.cpp15
-rw-r--r--media/libmedia/IAudioRecord.cpp3
-rw-r--r--media/libmedia/IAudioTrack.cpp6
-rw-r--r--media/libmedia/IEffect.cpp3
-rw-r--r--media/libmedia/IMediaDeathNotifier.cpp2
-rw-r--r--media/libmedia/IMediaHTTPConnection.cpp182
-rw-r--r--media/libmedia/IMediaHTTPService.cpp58
-rw-r--r--media/libmedia/IMediaMetadataRetriever.cpp19
-rw-r--r--media/libmedia/IMediaPlayer.cpp19
-rw-r--r--media/libmedia/IMediaPlayerService.cpp68
-rw-r--r--media/libmedia/JetPlayer.cpp2
-rw-r--r--media/libmedia/MediaProfiles.cpp20
-rw-r--r--media/libmedia/MediaScannerClient.cpp202
-rw-r--r--media/libmedia/SoundPool.cpp26
-rw-r--r--media/libmedia/ToneGenerator.cpp2
-rw-r--r--media/libmedia/autodetect.cpp885
-rw-r--r--media/libmedia/autodetect.h37
-rw-r--r--media/libmedia/mediametadataretriever.cpp9
-rw-r--r--media/libmedia/mediaplayer.cpp43
29 files changed, 3571 insertions, 1610 deletions
diff --git a/media/libmedia/Android.mk b/media/libmedia/Android.mk
index 56e7787..f3770e4 100644
--- a/media/libmedia/Android.mk
+++ b/media/libmedia/Android.mk
@@ -25,6 +25,8 @@ LOCAL_SRC_FILES:= \
AudioRecord.cpp \
AudioSystem.cpp \
mediaplayer.cpp \
+ IMediaHTTPConnection.cpp \
+ IMediaHTTPService.cpp \
IMediaLogService.cpp \
IMediaPlayerService.cpp \
IMediaPlayerClient.cpp \
@@ -44,7 +46,7 @@ LOCAL_SRC_FILES:= \
IAudioPolicyService.cpp \
MediaScanner.cpp \
MediaScannerClient.cpp \
- autodetect.cpp \
+ CharacterEncodingDetector.cpp \
IMediaDeathNotifier.cpp \
MediaProfiles.cpp \
IEffect.cpp \
@@ -58,26 +60,34 @@ LOCAL_SRC_FILES:= \
LOCAL_SRC_FILES += ../libnbaio/roundup.c
-# for <cutils/atomic-inline.h>
-LOCAL_CFLAGS += -DANDROID_SMP=$(if $(findstring true,$(TARGET_CPU_SMP)),1,0)
-LOCAL_SRC_FILES += SingleStateQueue.cpp
-LOCAL_CFLAGS += -DSINGLE_STATE_QUEUE_INSTANTIATIONS='"SingleStateQueueInstantiations.cpp"'
-# Consider a separate a library for SingleStateQueueInstantiations.
-
LOCAL_SHARED_LIBRARIES := \
- libui liblog libcutils libutils libbinder libsonivox libicuuc libexpat \
+ libui liblog libcutils libutils libbinder libsonivox libicuuc libicui18n libexpat \
libcamera_client libstagefright_foundation \
- libgui libdl libaudioutils
+ libgui libdl libaudioutils libnbaio
+
+LOCAL_STATIC_LIBRARIES += libinstantssq
LOCAL_WHOLE_STATIC_LIBRARY := libmedia_helper
LOCAL_MODULE:= libmedia
LOCAL_C_INCLUDES := \
- $(call include-path-for, graphics corecg) \
$(TOP)/frameworks/native/include/media/openmax \
external/icu4c/common \
+ external/icu4c/i18n \
$(call include-path-for, audio-effects) \
$(call include-path-for, audio-utils)
include $(BUILD_SHARED_LIBRARY)
+
+include $(CLEAR_VARS)
+
+# for <cutils/atomic-inline.h>
+LOCAL_CFLAGS += -DANDROID_SMP=$(if $(findstring true,$(TARGET_CPU_SMP)),1,0)
+LOCAL_SRC_FILES += SingleStateQueue.cpp
+LOCAL_CFLAGS += -DSINGLE_STATE_QUEUE_INSTANTIATIONS='"SingleStateQueueInstantiations.cpp"'
+
+LOCAL_MODULE := libinstantssq
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/media/libmedia/AudioEffect.cpp b/media/libmedia/AudioEffect.cpp
index 8dfffb3..35f6557 100644
--- a/media/libmedia/AudioEffect.cpp
+++ b/media/libmedia/AudioEffect.cpp
@@ -380,9 +380,9 @@ void AudioEffect::enableStatusChanged(bool enabled)
}
void AudioEffect::commandExecuted(uint32_t cmdCode,
- uint32_t cmdSize,
+ uint32_t cmdSize __unused,
void *cmdData,
- uint32_t replySize,
+ uint32_t replySize __unused,
void *replyData)
{
if (cmdData == NULL || replyData == NULL) {
diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp
index ccbc5a3..a7bf380 100644
--- a/media/libmedia/AudioRecord.cpp
+++ b/media/libmedia/AudioRecord.cpp
@@ -41,37 +41,29 @@ status_t AudioRecord::getMinFrameCount(
return BAD_VALUE;
}
- // default to 0 in case of error
- *frameCount = 0;
-
- size_t size = 0;
+ size_t size;
status_t status = AudioSystem::getInputBufferSize(sampleRate, format, channelMask, &size);
if (status != NO_ERROR) {
- ALOGE("AudioSystem could not query the input buffer size; status %d", status);
- return NO_INIT;
+ ALOGE("AudioSystem could not query the input buffer size for sampleRate %u, format %#x, "
+ "channelMask %#x; status %d", sampleRate, format, channelMask, status);
+ return status;
}
- if (size == 0) {
- ALOGE("Unsupported configuration: sampleRate %u, format %d, channelMask %#x",
+ // We double the size of input buffer for ping pong use of record buffer.
+ // Assumes audio_is_linear_pcm(format)
+ if ((*frameCount = (size * 2) / (popcount(channelMask) * audio_bytes_per_sample(format))) == 0) {
+ ALOGE("Unsupported configuration: sampleRate %u, format %#x, channelMask %#x",
sampleRate, format, channelMask);
return BAD_VALUE;
}
- // We double the size of input buffer for ping pong use of record buffer.
- size <<= 1;
-
- // Assumes audio_is_linear_pcm(format)
- uint32_t channelCount = popcount(channelMask);
- size /= channelCount * audio_bytes_per_sample(format);
-
- *frameCount = size;
return NO_ERROR;
}
// ---------------------------------------------------------------------------
AudioRecord::AudioRecord()
- : mStatus(NO_INIT), mSessionId(0),
+ : mStatus(NO_INIT), mSessionId(AUDIO_SESSION_ALLOCATE),
mPreviousPriority(ANDROID_PRIORITY_NORMAL), mPreviousSchedulingGroup(SP_DEFAULT)
{
}
@@ -81,14 +73,14 @@ AudioRecord::AudioRecord(
uint32_t sampleRate,
audio_format_t format,
audio_channel_mask_t channelMask,
- int frameCount,
+ size_t frameCount,
callback_t cbf,
void* user,
- int notificationFrames,
+ uint32_t notificationFrames,
int sessionId,
transfer_type transferType,
- audio_input_flags_t flags)
- : mStatus(NO_INIT), mSessionId(0),
+ audio_input_flags_t flags __unused)
+ : mStatus(NO_INIT), mSessionId(AUDIO_SESSION_ALLOCATE),
mPreviousPriority(ANDROID_PRIORITY_NORMAL),
mPreviousSchedulingGroup(SP_DEFAULT),
mProxy(NULL)
@@ -110,12 +102,10 @@ AudioRecord::~AudioRecord()
mAudioRecordThread->requestExitAndWait();
mAudioRecordThread.clear();
}
- if (mAudioRecord != 0) {
- mAudioRecord->asBinder()->unlinkToDeath(mDeathNotifier, this);
- mAudioRecord.clear();
- }
+ mAudioRecord->asBinder()->unlinkToDeath(mDeathNotifier, this);
+ mAudioRecord.clear();
IPCThreadState::self()->flushCommands();
- AudioSystem::releaseAudioSessionId(mSessionId);
+ AudioSystem::releaseAudioSessionId(mSessionId, -1);
}
}
@@ -124,15 +114,20 @@ status_t AudioRecord::set(
uint32_t sampleRate,
audio_format_t format,
audio_channel_mask_t channelMask,
- int frameCountInt,
+ size_t frameCount,
callback_t cbf,
void* user,
- int notificationFrames,
+ uint32_t notificationFrames,
bool threadCanCallJava,
int sessionId,
transfer_type transferType,
audio_input_flags_t flags)
{
+ ALOGV("set(): inputSource %d, sampleRate %u, format %#x, channelMask %#x, frameCount %zu, "
+ "notificationFrames %u, sessionId %d, transferType %d, flags %#x",
+ inputSource, sampleRate, format, channelMask, frameCount, notificationFrames,
+ sessionId, transferType, flags);
+
switch (transferType) {
case TRANSFER_DEFAULT:
if (cbf == NULL || threadCanCallJava) {
@@ -156,23 +151,15 @@ status_t AudioRecord::set(
}
mTransfer = transferType;
- // FIXME "int" here is legacy and will be replaced by size_t later
- if (frameCountInt < 0) {
- ALOGE("Invalid frame count %d", frameCountInt);
- return BAD_VALUE;
- }
- size_t frameCount = frameCountInt;
-
- ALOGV("set(): sampleRate %u, channelMask %#x, frameCount %u", sampleRate, channelMask,
- frameCount);
-
AutoMutex lock(mLock);
+ // invariant that mAudioRecord != 0 is true only after set() returns successfully
if (mAudioRecord != 0) {
ALOGE("Track already in use");
return INVALID_OPERATION;
}
+ // handle default values first.
if (inputSource == AUDIO_SOURCE_DEFAULT) {
inputSource = AUDIO_SOURCE_MIC;
}
@@ -191,12 +178,12 @@ status_t AudioRecord::set(
// validate parameters
if (!audio_is_valid_format(format)) {
- ALOGE("Invalid format %d", format);
+ ALOGE("Invalid format %#x", format);
return BAD_VALUE;
}
// Temporary restriction: AudioFlinger currently supports 16-bit PCM only
if (format != AUDIO_FORMAT_PCM_16_BIT) {
- ALOGE("Format %d is not supported", format);
+ ALOGE("Format %#x is not supported", format);
return BAD_VALUE;
}
mFormat = format;
@@ -209,15 +196,19 @@ status_t AudioRecord::set(
uint32_t channelCount = popcount(channelMask);
mChannelCount = channelCount;
- // Assumes audio_is_linear_pcm(format), else sizeof(uint8_t)
- mFrameSize = channelCount * audio_bytes_per_sample(format);
+ if (audio_is_linear_pcm(format)) {
+ mFrameSize = channelCount * audio_bytes_per_sample(format);
+ } else {
+ mFrameSize = sizeof(uint8_t);
+ }
// validate framecount
- size_t minFrameCount = 0;
+ size_t minFrameCount;
status_t status = AudioRecord::getMinFrameCount(&minFrameCount,
sampleRate, format, channelMask);
if (status != NO_ERROR) {
- ALOGE("getMinFrameCount() failed; status %d", status);
+ ALOGE("getMinFrameCount() failed for sampleRate %u, format %#x, channelMask %#x; status %d",
+ sampleRate, format, channelMask, status);
return status;
}
ALOGV("AudioRecord::set() minFrameCount = %d", minFrameCount);
@@ -228,12 +219,13 @@ status_t AudioRecord::set(
ALOGE("frameCount %u < minFrameCount %u", frameCount, minFrameCount);
return BAD_VALUE;
}
- mFrameCount = frameCount;
+ // mFrameCount is initialized in openRecord_l
+ mReqFrameCount = frameCount;
mNotificationFramesReq = notificationFrames;
mNotificationFramesAct = 0;
- if (sessionId == 0 ) {
+ if (sessionId == AUDIO_SESSION_ALLOCATE) {
mSessionId = AudioSystem::newAudioSessionId();
} else {
mSessionId = sessionId;
@@ -241,26 +233,27 @@ status_t AudioRecord::set(
ALOGV("set(): mSessionId %d", mSessionId);
mFlags = flags;
-
- // create the IAudioRecord
- status = openRecord_l(0 /*epoch*/);
- if (status) {
- return status;
- }
+ mCbf = cbf;
if (cbf != NULL) {
mAudioRecordThread = new AudioRecordThread(*this, threadCanCallJava);
mAudioRecordThread->run("AudioRecord", ANDROID_PRIORITY_AUDIO);
}
- mStatus = NO_ERROR;
+ // create the IAudioRecord
+ status = openRecord_l(0 /*epoch*/);
- // Update buffer size in case it has been limited by AudioFlinger during track creation
- mFrameCount = mCblk->frameCount_;
+ if (status != NO_ERROR) {
+ if (mAudioRecordThread != 0) {
+ mAudioRecordThread->requestExit(); // see comment in AudioRecord.h
+ mAudioRecordThread->requestExitAndWait();
+ mAudioRecordThread.clear();
+ }
+ return status;
+ }
+ mStatus = NO_ERROR;
mActive = false;
- mCbf = cbf;
- mRefreshRemaining = true;
mUserData = user;
// TODO: add audio hardware input latency here
mLatency = (1000*mFrameCount) / sampleRate;
@@ -268,7 +261,7 @@ status_t AudioRecord::set(
mMarkerReached = false;
mNewPosition = 0;
mUpdatePeriod = 0;
- AudioSystem::acquireAudioSessionId(mSessionId);
+ AudioSystem::acquireAudioSessionId(mSessionId, -1);
mSequence = 1;
mObservedSequence = mSequence;
mInOverrun = false;
@@ -289,6 +282,9 @@ status_t AudioRecord::start(AudioSystem::sync_event_t event, int triggerSession)
// reset current position as seen by client to 0
mProxy->setEpoch(mProxy->getEpoch() - mProxy->getPosition());
+ // force refresh of remaining frames by processAudioBuffer() as last
+ // read before stop could be partial.
+ mRefreshRemaining = true;
mNewPosition = mProxy->getPosition() + mUpdatePeriod;
int32_t flags = android_atomic_acquire_load(&mCblk->mFlags);
@@ -352,6 +348,7 @@ bool AudioRecord::stopped() const
status_t AudioRecord::setMarkerPosition(uint32_t marker)
{
+ // The only purpose of setting marker position is to get a callback
if (mCbf == NULL) {
return INVALID_OPERATION;
}
@@ -377,6 +374,7 @@ status_t AudioRecord::getMarkerPosition(uint32_t *marker) const
status_t AudioRecord::setPositionUpdatePeriod(uint32_t updatePeriod)
{
+ // The only purpose of setting position update period is to get a callback
if (mCbf == NULL) {
return INVALID_OPERATION;
}
@@ -412,7 +410,7 @@ status_t AudioRecord::getPosition(uint32_t *position) const
return NO_ERROR;
}
-unsigned int AudioRecord::getInputFramesLost() const
+uint32_t AudioRecord::getInputFramesLost() const
{
// no need to check mActive, because if inactive this will return 0, which is what we want
return AudioSystem::getInputFramesLost(getInput());
@@ -430,55 +428,82 @@ status_t AudioRecord::openRecord_l(size_t epoch)
return NO_INIT;
}
- IAudioFlinger::track_flags_t trackFlags = IAudioFlinger::TRACK_DEFAULT;
- pid_t tid = -1;
+ // Fast tracks must be at the primary _output_ [sic] sampling rate,
+ // because there is currently no concept of a primary input sampling rate
+ uint32_t afSampleRate = AudioSystem::getPrimaryOutputSamplingRate();
+ if (afSampleRate == 0) {
+ ALOGW("getPrimaryOutputSamplingRate failed");
+ }
// Client can only express a preference for FAST. Server will perform additional tests.
- // The only supported use case for FAST is callback transfer mode.
+ if ((mFlags & AUDIO_INPUT_FLAG_FAST) && !(
+ // use case: callback transfer mode
+ (mTransfer == TRANSFER_CALLBACK) &&
+ // matching sample rate
+ (mSampleRate == afSampleRate))) {
+ ALOGW("AUDIO_INPUT_FLAG_FAST denied by client");
+ // once denied, do not request again if IAudioRecord is re-created
+ mFlags = (audio_input_flags_t) (mFlags & ~AUDIO_INPUT_FLAG_FAST);
+ }
+
+ IAudioFlinger::track_flags_t trackFlags = IAudioFlinger::TRACK_DEFAULT;
+
+ pid_t tid = -1;
if (mFlags & AUDIO_INPUT_FLAG_FAST) {
- if ((mTransfer != TRANSFER_CALLBACK) || (mAudioRecordThread == 0)) {
- ALOGW("AUDIO_INPUT_FLAG_FAST denied by client");
- // once denied, do not request again if IAudioRecord is re-created
- mFlags = (audio_input_flags_t) (mFlags & ~AUDIO_INPUT_FLAG_FAST);
- } else {
- trackFlags |= IAudioFlinger::TRACK_FAST;
+ trackFlags |= IAudioFlinger::TRACK_FAST;
+ if (mAudioRecordThread != 0) {
tid = mAudioRecordThread->getTid();
}
}
+ // FIXME Assume double buffering, because we don't know the true HAL sample rate
+ const uint32_t nBuffering = 2;
+
mNotificationFramesAct = mNotificationFramesReq;
+ size_t frameCount = mReqFrameCount;
if (!(mFlags & AUDIO_INPUT_FLAG_FAST)) {
// Make sure that application is notified with sufficient margin before overrun
- if (mNotificationFramesAct == 0 || mNotificationFramesAct > mFrameCount/2) {
- mNotificationFramesAct = mFrameCount/2;
+ if (mNotificationFramesAct == 0 || mNotificationFramesAct > frameCount/2) {
+ mNotificationFramesAct = frameCount/2;
}
}
audio_io_handle_t input = AudioSystem::getInput(mInputSource, mSampleRate, mFormat,
mChannelMask, mSessionId);
- if (input == 0) {
- ALOGE("Could not get audio input for record source %d", mInputSource);
+ if (input == AUDIO_IO_HANDLE_NONE) {
+ ALOGE("Could not get audio input for record source %d, sample rate %u, format %#x, "
+ "channel mask %#x, session %d",
+ mInputSource, mSampleRate, mFormat, mChannelMask, mSessionId);
return BAD_VALUE;
}
+ {
+ // Now that we have a reference to an I/O handle and have not yet handed it off to AudioFlinger,
+ // we must release it ourselves if anything goes wrong.
+ size_t temp = frameCount; // temp may be replaced by a revised value of frameCount,
+ // but we will still need the original value also
int originalSessionId = mSessionId;
sp<IAudioRecord> record = audioFlinger->openRecord(input,
mSampleRate, mFormat,
mChannelMask,
- mFrameCount,
+ &temp,
&trackFlags,
tid,
&mSessionId,
&status);
- ALOGE_IF(originalSessionId != 0 && mSessionId != originalSessionId,
+ ALOGE_IF(originalSessionId != AUDIO_SESSION_ALLOCATE && mSessionId != originalSessionId,
"session ID changed from %d to %d", originalSessionId, mSessionId);
- if (record == 0 || status != NO_ERROR) {
+ if (status != NO_ERROR) {
ALOGE("AudioFlinger could not create record track, status: %d", status);
- AudioSystem::releaseInput(input);
- return status;
+ goto release;
}
+ ALOG_ASSERT(record != 0);
+
+ // AudioFlinger now owns the reference to the I/O handle,
+ // so we are no longer responsible for releasing it.
+
sp<IMemory> iMem = record->getCblk();
if (iMem == 0) {
ALOGE("Could not get control block");
@@ -489,38 +514,56 @@ status_t AudioRecord::openRecord_l(size_t epoch)
ALOGE("Could not get control block pointer");
return NO_INIT;
}
+ // invariant that mAudioRecord != 0 is true only after set() returns successfully
if (mAudioRecord != 0) {
mAudioRecord->asBinder()->unlinkToDeath(mDeathNotifier, this);
mDeathNotifier.clear();
}
- mInput = input;
mAudioRecord = record;
+
mCblkMemory = iMem;
audio_track_cblk_t* cblk = static_cast<audio_track_cblk_t*>(iMemPointer);
mCblk = cblk;
- // FIXME missing fast track frameCount logic
+ // note that temp is the (possibly revised) value of frameCount
+ if (temp < frameCount || (frameCount == 0 && temp == 0)) {
+ ALOGW("Requested frameCount %u but received frameCount %u", frameCount, temp);
+ }
+ frameCount = temp;
+
mAwaitBoost = false;
if (mFlags & AUDIO_INPUT_FLAG_FAST) {
if (trackFlags & IAudioFlinger::TRACK_FAST) {
- ALOGV("AUDIO_INPUT_FLAG_FAST successful; frameCount %u", mFrameCount);
+ ALOGV("AUDIO_INPUT_FLAG_FAST successful; frameCount %u", frameCount);
mAwaitBoost = true;
- // double-buffering is not required for fast tracks, due to tighter scheduling
- if (mNotificationFramesAct == 0 || mNotificationFramesAct > mFrameCount) {
- mNotificationFramesAct = mFrameCount;
- }
} else {
- ALOGV("AUDIO_INPUT_FLAG_FAST denied by server; frameCount %u", mFrameCount);
+ ALOGV("AUDIO_INPUT_FLAG_FAST denied by server; frameCount %u", frameCount);
// once denied, do not request again if IAudioRecord is re-created
mFlags = (audio_input_flags_t) (mFlags & ~AUDIO_INPUT_FLAG_FAST);
- if (mNotificationFramesAct == 0 || mNotificationFramesAct > mFrameCount/2) {
- mNotificationFramesAct = mFrameCount/2;
- }
+ }
+ // Theoretically double-buffering is not required for fast tracks,
+ // due to tighter scheduling. But in practice, to accomodate kernels with
+ // scheduling jitter, and apps with computation jitter, we use double-buffering.
+ if (mNotificationFramesAct == 0 || mNotificationFramesAct > frameCount/nBuffering) {
+ mNotificationFramesAct = frameCount/nBuffering;
}
}
- // starting address of buffers in shared memory
+ // We retain a copy of the I/O handle, but don't own the reference
+ mInput = input;
+ mRefreshRemaining = true;
+
+ // Starting address of buffers in shared memory, immediately after the control block. This
+ // address is for the mapping within client address space. AudioFlinger::TrackBase::mBuffer
+ // is for the server address space.
void *buffers = (char*)cblk + sizeof(audio_track_cblk_t);
+ mFrameCount = frameCount;
+ // If IAudioRecord is re-created, don't let the requested frameCount
+ // decrease. This can confuse clients that cache frameCount().
+ if (frameCount > mReqFrameCount) {
+ mReqFrameCount = frameCount;
+ }
+
// update proxy
mProxy = new AudioRecordClientProxy(cblk, buffers, mFrameCount, mFrameSize);
mProxy->setEpoch(epoch);
@@ -530,6 +573,14 @@ status_t AudioRecord::openRecord_l(size_t epoch)
mAudioRecord->asBinder()->linkToDeath(mDeathNotifier, this);
return NO_ERROR;
+ }
+
+release:
+ AudioSystem::releaseInput(input);
+ if (status == NO_ERROR) {
+ status = NO_INIT;
+ }
+ return status;
}
status_t AudioRecord::obtainBuffer(Buffer* audioBuffer, int32_t waitCount)
@@ -591,6 +642,9 @@ status_t AudioRecord::obtainBuffer(Buffer* audioBuffer, const struct timespec *r
if (newSequence == oldSequence) {
status = restoreRecord_l("obtainBuffer");
if (status != NO_ERROR) {
+ buffer.mFrameCount = 0;
+ buffer.mRaw = NULL;
+ buffer.mNonContig = 0;
break;
}
}
@@ -692,7 +746,7 @@ ssize_t AudioRecord::read(void* buffer, size_t userSize)
// -------------------------------------------------------------------------
-nsecs_t AudioRecord::processAudioBuffer(const sp<AudioRecordThread>& thread)
+nsecs_t AudioRecord::processAudioBuffer()
{
mLock.lock();
if (mAwaitBoost) {
@@ -760,17 +814,17 @@ nsecs_t AudioRecord::processAudioBuffer(const sp<AudioRecordThread>& thread)
}
// Cache other fields that will be needed soon
- size_t notificationFrames = mNotificationFramesAct;
+ uint32_t notificationFrames = mNotificationFramesAct;
if (mRefreshRemaining) {
mRefreshRemaining = false;
mRemainingFrames = notificationFrames;
mRetryOnPartialBuffer = false;
}
size_t misalignment = mProxy->getMisalignment();
- int32_t sequence = mSequence;
+ uint32_t sequence = mSequence;
// These fields don't need to be cached, because they are assigned only by set():
- // mTransfer, mCbf, mUserData, mSampleRate
+ // mTransfer, mCbf, mUserData, mSampleRate, mFrameSize
mLock.unlock();
@@ -844,8 +898,8 @@ nsecs_t AudioRecord::processAudioBuffer(const sp<AudioRecordThread>& thread)
"obtainBuffer() err=%d frameCount=%u", err, audioBuffer.frameCount);
requested = &ClientProxy::kNonBlocking;
size_t avail = audioBuffer.frameCount + nonContig;
- ALOGV("obtainBuffer(%u) returned %u = %u + %u",
- mRemainingFrames, avail, audioBuffer.frameCount, nonContig);
+ ALOGV("obtainBuffer(%u) returned %u = %u + %u err %d",
+ mRemainingFrames, avail, audioBuffer.frameCount, nonContig, err);
if (err != NO_ERROR) {
if (err == TIMED_OUT || err == WOULD_BLOCK || err == -EINTR) {
break;
@@ -954,7 +1008,7 @@ status_t AudioRecord::restoreRecord_l(const char *from)
// =========================================================================
-void AudioRecord::DeathNotifier::binderDied(const wp<IBinder>& who)
+void AudioRecord::DeathNotifier::binderDied(const wp<IBinder>& who __unused)
{
sp<AudioRecord> audioRecord = mAudioRecord.promote();
if (audioRecord != 0) {
@@ -966,7 +1020,8 @@ void AudioRecord::DeathNotifier::binderDied(const wp<IBinder>& who)
// =========================================================================
AudioRecord::AudioRecordThread::AudioRecordThread(AudioRecord& receiver, bool bCanCallJava)
- : Thread(bCanCallJava), mReceiver(receiver), mPaused(true), mPausedInt(false), mPausedNs(0LL)
+ : Thread(bCanCallJava), mReceiver(receiver), mPaused(true), mPausedInt(false), mPausedNs(0LL),
+ mIgnoreNextPausedInt(false)
{
}
@@ -983,6 +1038,10 @@ bool AudioRecord::AudioRecordThread::threadLoop()
// caller will check for exitPending()
return true;
}
+ if (mIgnoreNextPausedInt) {
+ mIgnoreNextPausedInt = false;
+ mPausedInt = false;
+ }
if (mPausedInt) {
if (mPausedNs > 0) {
(void) mMyCond.waitRelative(mMyLock, mPausedNs);
@@ -993,7 +1052,7 @@ bool AudioRecord::AudioRecordThread::threadLoop()
return true;
}
}
- nsecs_t ns = mReceiver.processAudioBuffer(this);
+ nsecs_t ns = mReceiver.processAudioBuffer();
switch (ns) {
case 0:
return true;
@@ -1017,12 +1076,7 @@ void AudioRecord::AudioRecordThread::requestExit()
{
// must be in this order to avoid a race condition
Thread::requestExit();
- AutoMutex _l(mMyLock);
- if (mPaused || mPausedInt) {
- mPaused = false;
- mPausedInt = false;
- mMyCond.signal();
- }
+ resume();
}
void AudioRecord::AudioRecordThread::pause()
@@ -1034,6 +1088,7 @@ void AudioRecord::AudioRecordThread::pause()
void AudioRecord::AudioRecordThread::resume()
{
AutoMutex _l(mMyLock);
+ mIgnoreNextPausedInt = true;
if (mPaused || mPausedInt) {
mPaused = false;
mPausedInt = false;
diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp
index cc5b810..2f16444 100644
--- a/media/libmedia/AudioSystem.cpp
+++ b/media/libmedia/AudioSystem.cpp
@@ -35,15 +35,15 @@ Mutex AudioSystem::gLock;
sp<IAudioFlinger> AudioSystem::gAudioFlinger;
sp<AudioSystem::AudioFlingerClient> AudioSystem::gAudioFlingerClient;
audio_error_callback AudioSystem::gAudioErrorCallback = NULL;
-// Cached values
-DefaultKeyedVector<audio_io_handle_t, AudioSystem::OutputDescriptor *> AudioSystem::gOutputs(0);
+// Cached values for output handles
+DefaultKeyedVector<audio_io_handle_t, AudioSystem::OutputDescriptor *> AudioSystem::gOutputs(NULL);
// Cached values for recording queries, all protected by gLock
-uint32_t AudioSystem::gPrevInSamplingRate = 16000;
-audio_format_t AudioSystem::gPrevInFormat = AUDIO_FORMAT_PCM_16_BIT;
-audio_channel_mask_t AudioSystem::gPrevInChannelMask = AUDIO_CHANNEL_IN_MONO;
-size_t AudioSystem::gInBuffSize = 0;
+uint32_t AudioSystem::gPrevInSamplingRate;
+audio_format_t AudioSystem::gPrevInFormat;
+audio_channel_mask_t AudioSystem::gPrevInChannelMask;
+size_t AudioSystem::gInBuffSize = 0; // zero indicates cache is invalid
// establish binder interface to AudioFlinger service
@@ -84,13 +84,15 @@ const sp<IAudioFlinger>& AudioSystem::get_audio_flinger()
return DEAD_OBJECT;
}
-status_t AudioSystem::muteMicrophone(bool state) {
+status_t AudioSystem::muteMicrophone(bool state)
+{
const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
if (af == 0) return PERMISSION_DENIED;
return af->setMicMute(state);
}
-status_t AudioSystem::isMicrophoneMuted(bool* state) {
+status_t AudioSystem::isMicrophoneMuted(bool* state)
+{
const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
if (af == 0) return PERMISSION_DENIED;
*state = af->getMicMute();
@@ -175,13 +177,15 @@ status_t AudioSystem::setMode(audio_mode_t mode)
return af->setMode(mode);
}
-status_t AudioSystem::setParameters(audio_io_handle_t ioHandle, const String8& keyValuePairs) {
+status_t AudioSystem::setParameters(audio_io_handle_t ioHandle, const String8& keyValuePairs)
+{
const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
if (af == 0) return PERMISSION_DENIED;
return af->setParameters(ioHandle, keyValuePairs);
}
-String8 AudioSystem::getParameters(audio_io_handle_t ioHandle, const String8& keys) {
+String8 AudioSystem::getParameters(audio_io_handle_t ioHandle, const String8& keys)
+{
const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
String8 result = String8("");
if (af == 0) return result;
@@ -190,6 +194,16 @@ String8 AudioSystem::getParameters(audio_io_handle_t ioHandle, const String8& ke
return result;
}
+status_t AudioSystem::setParameters(const String8& keyValuePairs)
+{
+ return setParameters(AUDIO_IO_HANDLE_NONE, keyValuePairs);
+}
+
+String8 AudioSystem::getParameters(const String8& keys)
+{
+ return getParameters(AUDIO_IO_HANDLE_NONE, keys);
+}
+
// convert volume steps to natural log scale
// change this value to change volume scaling
@@ -249,6 +263,11 @@ status_t AudioSystem::getSamplingRate(audio_io_handle_t output,
*samplingRate = outputDesc->samplingRate;
gLock.unlock();
}
+ if (*samplingRate == 0) {
+ ALOGE("AudioSystem::getSamplingRate failed for output %d stream type %d",
+ output, streamType);
+ return BAD_VALUE;
+ }
ALOGV("getSamplingRate() streamType %d, output %d, sampling rate %u", streamType, output,
*samplingRate);
@@ -265,7 +284,7 @@ status_t AudioSystem::getOutputFrameCount(size_t* frameCount, audio_stream_type_
}
output = getOutput(streamType);
- if (output == 0) {
+ if (output == AUDIO_IO_HANDLE_NONE) {
return PERMISSION_DENIED;
}
@@ -289,6 +308,11 @@ status_t AudioSystem::getFrameCount(audio_io_handle_t output,
*frameCount = outputDesc->frameCount;
gLock.unlock();
}
+ if (*frameCount == 0) {
+ ALOGE("AudioSystem::getFrameCount failed for output %d stream type %d",
+ output, streamType);
+ return BAD_VALUE;
+ }
ALOGV("getFrameCount() streamType %d, output %d, frameCount %d", streamType, output,
*frameCount);
@@ -305,15 +329,14 @@ status_t AudioSystem::getOutputLatency(uint32_t* latency, audio_stream_type_t st
}
output = getOutput(streamType);
- if (output == 0) {
+ if (output == AUDIO_IO_HANDLE_NONE) {
return PERMISSION_DENIED;
}
- return getLatency(output, streamType, latency);
+ return getLatency(output, latency);
}
status_t AudioSystem::getLatency(audio_io_handle_t output,
- audio_stream_type_t streamType,
uint32_t* latency)
{
OutputDescriptor *outputDesc;
@@ -330,7 +353,7 @@ status_t AudioSystem::getLatency(audio_io_handle_t output,
gLock.unlock();
}
- ALOGV("getLatency() streamType %d, output %d, latency %d", streamType, output, *latency);
+ ALOGV("getLatency() output %d, latency %d", output, *latency);
return NO_ERROR;
}
@@ -349,6 +372,12 @@ status_t AudioSystem::getInputBufferSize(uint32_t sampleRate, audio_format_t for
return PERMISSION_DENIED;
}
inBuffSize = af->getInputBufferSize(sampleRate, format, channelMask);
+ if (inBuffSize == 0) {
+ ALOGE("AudioSystem::getInputBufferSize failed sampleRate %d format %#x channelMask %x",
+ sampleRate, format, channelMask);
+ return BAD_VALUE;
+ }
+ // A benign race is possible here: we could overwrite a fresher cache entry
gLock.lock();
// save the request params
gPrevInSamplingRate = sampleRate;
@@ -371,55 +400,52 @@ status_t AudioSystem::setVoiceVolume(float value)
}
status_t AudioSystem::getRenderPosition(audio_io_handle_t output, uint32_t *halFrames,
- uint32_t *dspFrames, audio_stream_type_t stream)
+ uint32_t *dspFrames)
{
const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
if (af == 0) return PERMISSION_DENIED;
- if (stream == AUDIO_STREAM_DEFAULT) {
- stream = AUDIO_STREAM_MUSIC;
- }
-
- if (output == 0) {
- output = getOutput(stream);
- }
-
return af->getRenderPosition(halFrames, dspFrames, output);
}
-size_t AudioSystem::getInputFramesLost(audio_io_handle_t ioHandle) {
+uint32_t AudioSystem::getInputFramesLost(audio_io_handle_t ioHandle)
+{
const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
- unsigned int result = 0;
+ uint32_t result = 0;
if (af == 0) return result;
- if (ioHandle == 0) return result;
+ if (ioHandle == AUDIO_IO_HANDLE_NONE) return result;
result = af->getInputFramesLost(ioHandle);
return result;
}
-int AudioSystem::newAudioSessionId() {
+int AudioSystem::newAudioSessionId()
+{
const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
- if (af == 0) return 0;
+ if (af == 0) return AUDIO_SESSION_ALLOCATE;
return af->newAudioSessionId();
}
-void AudioSystem::acquireAudioSessionId(int audioSession) {
+void AudioSystem::acquireAudioSessionId(int audioSession, pid_t pid)
+{
const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
if (af != 0) {
- af->acquireAudioSessionId(audioSession);
+ af->acquireAudioSessionId(audioSession, pid);
}
}
-void AudioSystem::releaseAudioSessionId(int audioSession) {
+void AudioSystem::releaseAudioSessionId(int audioSession, pid_t pid)
+{
const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
if (af != 0) {
- af->releaseAudioSessionId(audioSession);
+ af->releaseAudioSessionId(audioSession, pid);
}
}
// ---------------------------------------------------------------------------
-void AudioSystem::AudioFlingerClient::binderDied(const wp<IBinder>& who) {
+void AudioSystem::AudioFlingerClient::binderDied(const wp<IBinder>& who __unused)
+{
Mutex::Autolock _l(AudioSystem::gLock);
AudioSystem::gAudioFlinger.clear();
@@ -438,7 +464,7 @@ void AudioSystem::AudioFlingerClient::ioConfigChanged(int event, audio_io_handle
const OutputDescriptor *desc;
audio_stream_type_t stream;
- if (ioHandle == 0) return;
+ if (ioHandle == AUDIO_IO_HANDLE_NONE) return;
Mutex::Autolock _l(AudioSystem::gLock);
@@ -455,7 +481,7 @@ void AudioSystem::AudioFlingerClient::ioConfigChanged(int event, audio_io_handle
OutputDescriptor *outputDesc = new OutputDescriptor(*desc);
gOutputs.add(ioHandle, outputDesc);
- ALOGV("ioConfigChanged() new output samplingRate %u, format %d channel mask %#x frameCount %u "
+ ALOGV("ioConfigChanged() new output samplingRate %u, format %#x channel mask %#x frameCount %u "
"latency %d",
outputDesc->samplingRate, outputDesc->format, outputDesc->channelMask,
outputDesc->frameCount, outputDesc->latency);
@@ -479,7 +505,7 @@ void AudioSystem::AudioFlingerClient::ioConfigChanged(int event, audio_io_handle
if (param2 == NULL) break;
desc = (const OutputDescriptor *)param2;
- ALOGV("ioConfigChanged() new config for output %d samplingRate %u, format %d channel mask %#x "
+ ALOGV("ioConfigChanged() new config for output %d samplingRate %u, format %#x channel mask %#x "
"frameCount %d latency %d",
ioHandle, desc->samplingRate, desc->format,
desc->channelMask, desc->frameCount, desc->latency);
@@ -496,12 +522,14 @@ void AudioSystem::AudioFlingerClient::ioConfigChanged(int event, audio_io_handle
}
}
-void AudioSystem::setErrorCallback(audio_error_callback cb) {
+void AudioSystem::setErrorCallback(audio_error_callback cb)
+{
Mutex::Autolock _l(gLock);
gAudioErrorCallback = cb;
}
-bool AudioSystem::routedToA2dpOutput(audio_stream_type_t streamType) {
+bool AudioSystem::routedToA2dpOutput(audio_stream_type_t streamType)
+{
switch (streamType) {
case AUDIO_STREAM_MUSIC:
case AUDIO_STREAM_VOICE_CALL:
@@ -702,14 +730,15 @@ uint32_t AudioSystem::getStrategyForStream(audio_stream_type_t stream)
audio_devices_t AudioSystem::getDevicesForStream(audio_stream_type_t stream)
{
const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
- if (aps == 0) return (audio_devices_t)0;
+ if (aps == 0) return AUDIO_DEVICE_NONE;
return aps->getDevicesForStream(stream);
}
audio_io_handle_t AudioSystem::getOutputForEffect(const effect_descriptor_t *desc)
{
const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
- if (aps == 0) return PERMISSION_DENIED;
+ // FIXME change return type to status_t, and return PERMISSION_DENIED here
+ if (aps == 0) return AUDIO_IO_HANDLE_NONE;
return aps->getOutputForEffect(desc);
}
@@ -804,7 +833,8 @@ bool AudioSystem::isOffloadSupported(const audio_offload_info_t& info)
// ---------------------------------------------------------------------------
-void AudioSystem::AudioPolicyServiceClient::binderDied(const wp<IBinder>& who) {
+void AudioSystem::AudioPolicyServiceClient::binderDied(const wp<IBinder>& who __unused)
+{
Mutex::Autolock _l(AudioSystem::gLock);
AudioSystem::gAudioPolicyService.clear();
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index 3f3a88c..fbfd3da 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -44,9 +44,6 @@ status_t AudioTrack::getMinFrameCount(
return BAD_VALUE;
}
- // default to 0 in case of error
- *frameCount = 0;
-
// FIXME merge with similar code in createTrack_l(), except we're missing
// some information here that is available in createTrack_l():
// audio_io_handle_t output
@@ -54,16 +51,26 @@ status_t AudioTrack::getMinFrameCount(
// audio_channel_mask_t channelMask
// audio_output_flags_t flags
uint32_t afSampleRate;
- if (AudioSystem::getOutputSamplingRate(&afSampleRate, streamType) != NO_ERROR) {
- return NO_INIT;
+ status_t status;
+ status = AudioSystem::getOutputSamplingRate(&afSampleRate, streamType);
+ if (status != NO_ERROR) {
+ ALOGE("Unable to query output sample rate for stream type %d; status %d",
+ streamType, status);
+ return status;
}
size_t afFrameCount;
- if (AudioSystem::getOutputFrameCount(&afFrameCount, streamType) != NO_ERROR) {
- return NO_INIT;
+ status = AudioSystem::getOutputFrameCount(&afFrameCount, streamType);
+ if (status != NO_ERROR) {
+ ALOGE("Unable to query output frame count for stream type %d; status %d",
+ streamType, status);
+ return status;
}
uint32_t afLatency;
- if (AudioSystem::getOutputLatency(&afLatency, streamType) != NO_ERROR) {
- return NO_INIT;
+ status = AudioSystem::getOutputLatency(&afLatency, streamType);
+ if (status != NO_ERROR) {
+ ALOGE("Unable to query output latency for stream type %d; status %d",
+ streamType, status);
+ return status;
}
// Ensure that buffer depth covers at least audio hardware latency
@@ -74,6 +81,13 @@ status_t AudioTrack::getMinFrameCount(
*frameCount = (sampleRate == 0) ? afFrameCount * minBufCount :
afFrameCount * minBufCount * sampleRate / afSampleRate;
+ // The formula above should always produce a non-zero value, but return an error
+ // in the unlikely event that it does not, as that's part of the API contract.
+ if (*frameCount == 0) {
+ ALOGE("AudioTrack::getMinFrameCount failed for streamType %d, sampleRate %d",
+ streamType, sampleRate);
+ return BAD_VALUE;
+ }
ALOGV("getMinFrameCount=%d: afFrameCount=%d, minBufCount=%d, afSampleRate=%d, afLatency=%d",
*frameCount, afFrameCount, minBufCount, afSampleRate, afLatency);
return NO_ERROR;
@@ -95,15 +109,16 @@ AudioTrack::AudioTrack(
uint32_t sampleRate,
audio_format_t format,
audio_channel_mask_t channelMask,
- int frameCount,
+ size_t frameCount,
audio_output_flags_t flags,
callback_t cbf,
void* user,
- int notificationFrames,
+ uint32_t notificationFrames,
int sessionId,
transfer_type transferType,
const audio_offload_info_t *offloadInfo,
- int uid)
+ int uid,
+ pid_t pid)
: mStatus(NO_INIT),
mIsTimed(false),
mPreviousPriority(ANDROID_PRIORITY_NORMAL),
@@ -113,7 +128,7 @@ AudioTrack::AudioTrack(
mStatus = set(streamType, sampleRate, format, channelMask,
frameCount, flags, cbf, user, notificationFrames,
0 /*sharedBuffer*/, false /*threadCanCallJava*/, sessionId, transferType,
- offloadInfo, uid);
+ offloadInfo, uid, pid);
}
AudioTrack::AudioTrack(
@@ -125,11 +140,12 @@ AudioTrack::AudioTrack(
audio_output_flags_t flags,
callback_t cbf,
void* user,
- int notificationFrames,
+ uint32_t notificationFrames,
int sessionId,
transfer_type transferType,
const audio_offload_info_t *offloadInfo,
- int uid)
+ int uid,
+ pid_t pid)
: mStatus(NO_INIT),
mIsTimed(false),
mPreviousPriority(ANDROID_PRIORITY_NORMAL),
@@ -138,7 +154,8 @@ AudioTrack::AudioTrack(
{
mStatus = set(streamType, sampleRate, format, channelMask,
0 /*frameCount*/, flags, cbf, user, notificationFrames,
- sharedBuffer, false /*threadCanCallJava*/, sessionId, transferType, offloadInfo, uid);
+ sharedBuffer, false /*threadCanCallJava*/, sessionId, transferType, offloadInfo,
+ uid, pid);
}
AudioTrack::~AudioTrack()
@@ -157,7 +174,9 @@ AudioTrack::~AudioTrack()
mAudioTrack->asBinder()->unlinkToDeath(mDeathNotifier, this);
mAudioTrack.clear();
IPCThreadState::self()->flushCommands();
- AudioSystem::releaseAudioSessionId(mSessionId);
+ ALOGV("~AudioTrack, releasing session id from %d on behalf of %d",
+ IPCThreadState::self()->getCallingPid(), mClientPid);
+ AudioSystem::releaseAudioSessionId(mSessionId, mClientPid);
}
}
@@ -166,18 +185,24 @@ status_t AudioTrack::set(
uint32_t sampleRate,
audio_format_t format,
audio_channel_mask_t channelMask,
- int frameCountInt,
+ size_t frameCount,
audio_output_flags_t flags,
callback_t cbf,
void* user,
- int notificationFrames,
+ uint32_t notificationFrames,
const sp<IMemory>& sharedBuffer,
bool threadCanCallJava,
int sessionId,
transfer_type transferType,
const audio_offload_info_t *offloadInfo,
- int uid)
+ int uid,
+ pid_t pid)
{
+ ALOGV("set(): streamType %d, sampleRate %u, format %#x, channelMask %#x, frameCount %zu, "
+ "flags #%x, notificationFrames %u, sessionId %d, transferType %d",
+ streamType, sampleRate, format, channelMask, frameCount, flags, notificationFrames,
+ sessionId, transferType);
+
switch (transferType) {
case TRANSFER_DEFAULT:
if (sharedBuffer != 0) {
@@ -211,15 +236,9 @@ status_t AudioTrack::set(
ALOGE("Invalid transfer type %d", transferType);
return BAD_VALUE;
}
+ mSharedBuffer = sharedBuffer;
mTransfer = transferType;
- // FIXME "int" here is legacy and will be replaced by size_t later
- if (frameCountInt < 0) {
- ALOGE("Invalid frame count %d", frameCountInt);
- return BAD_VALUE;
- }
- size_t frameCount = frameCountInt;
-
ALOGV_IF(sharedBuffer != 0, "sharedBuffer: %p, size: %d", sharedBuffer->pointer(),
sharedBuffer->size());
@@ -233,19 +252,24 @@ status_t AudioTrack::set(
return INVALID_OPERATION;
}
- mOutput = 0;
-
// handle default values first.
if (streamType == AUDIO_STREAM_DEFAULT) {
streamType = AUDIO_STREAM_MUSIC;
}
+ if (uint32_t(streamType) >= AUDIO_STREAM_CNT) {
+ ALOGE("Invalid stream type %d", streamType);
+ return BAD_VALUE;
+ }
+ mStreamType = streamType;
+ status_t status;
if (sampleRate == 0) {
- uint32_t afSampleRate;
- if (AudioSystem::getOutputSamplingRate(&afSampleRate, streamType) != NO_ERROR) {
- return NO_INIT;
+ status = AudioSystem::getOutputSamplingRate(&sampleRate, streamType);
+ if (status != NO_ERROR) {
+ ALOGE("Could not get output sample rate for stream type %d; status %d",
+ streamType, status);
+ return status;
}
- sampleRate = afSampleRate;
}
mSampleRate = sampleRate;
@@ -253,15 +277,21 @@ status_t AudioTrack::set(
if (format == AUDIO_FORMAT_DEFAULT) {
format = AUDIO_FORMAT_PCM_16_BIT;
}
- if (channelMask == 0) {
- channelMask = AUDIO_CHANNEL_OUT_STEREO;
- }
// validate parameters
if (!audio_is_valid_format(format)) {
- ALOGE("Invalid format %d", format);
+ ALOGE("Invalid format %#x", format);
return BAD_VALUE;
}
+ mFormat = format;
+
+ if (!audio_is_output_channel(channelMask)) {
+ ALOGE("Invalid channel mask %#x", channelMask);
+ return BAD_VALUE;
+ }
+ mChannelMask = channelMask;
+ uint32_t channelCount = popcount(channelMask);
+ mChannelCount = channelCount;
// AudioFlinger does not currently support 8-bit data in shared memory
if (format == AUDIO_FORMAT_PCM_8_BIT && sharedBuffer != 0) {
@@ -285,14 +315,6 @@ status_t AudioTrack::set(
flags = (audio_output_flags_t)(flags &~AUDIO_OUTPUT_FLAG_DEEP_BUFFER);
}
- if (!audio_is_output_channel(channelMask)) {
- ALOGE("Invalid channel mask %#x", channelMask);
- return BAD_VALUE;
- }
- mChannelMask = channelMask;
- uint32_t channelCount = popcount(channelMask);
- mChannelCount = channelCount;
-
if (audio_is_linear_pcm(format)) {
mFrameSize = channelCount * audio_bytes_per_sample(format);
mFrameSizeAF = channelCount * sizeof(int16_t);
@@ -301,30 +323,36 @@ status_t AudioTrack::set(
mFrameSizeAF = sizeof(uint8_t);
}
- audio_io_handle_t output = AudioSystem::getOutput(
- streamType,
- sampleRate, format, channelMask,
- flags,
- offloadInfo);
-
- if (output == 0) {
- ALOGE("Could not get audio output for stream type %d", streamType);
- return BAD_VALUE;
+ // Make copy of input parameter offloadInfo so that in the future:
+ // (a) createTrack_l doesn't need it as an input parameter
+ // (b) we can support re-creation of offloaded tracks
+ if (offloadInfo != NULL) {
+ mOffloadInfoCopy = *offloadInfo;
+ mOffloadInfo = &mOffloadInfoCopy;
+ } else {
+ mOffloadInfo = NULL;
}
- mVolume[LEFT] = 1.0f;
- mVolume[RIGHT] = 1.0f;
+ mVolume[AUDIO_INTERLEAVE_LEFT] = 1.0f;
+ mVolume[AUDIO_INTERLEAVE_RIGHT] = 1.0f;
mSendLevel = 0.0f;
- mFrameCount = frameCount;
+ // mFrameCount is initialized in createTrack_l
mReqFrameCount = frameCount;
mNotificationFramesReq = notificationFrames;
mNotificationFramesAct = 0;
mSessionId = sessionId;
- if (uid == -1 || (IPCThreadState::self()->getCallingPid() != getpid())) {
+ int callingpid = IPCThreadState::self()->getCallingPid();
+ int mypid = getpid();
+ if (uid == -1 || (callingpid != mypid)) {
mClientUid = IPCThreadState::self()->getCallingUid();
} else {
mClientUid = uid;
}
+ if (pid == -1 || (callingpid != mypid)) {
+ mClientPid = callingpid;
+ } else {
+ mClientPid = pid;
+ }
mAuxEffectId = 0;
mFlags = flags;
mCbf = cbf;
@@ -335,14 +363,7 @@ status_t AudioTrack::set(
}
// create the IAudioTrack
- status_t status = createTrack_l(streamType,
- sampleRate,
- format,
- frameCount,
- flags,
- sharedBuffer,
- output,
- 0 /*epoch*/);
+ status = createTrack_l(0 /*epoch*/);
if (status != NO_ERROR) {
if (mAudioTrackThread != 0) {
@@ -350,17 +371,10 @@ status_t AudioTrack::set(
mAudioTrackThread->requestExitAndWait();
mAudioTrackThread.clear();
}
- //Use of direct and offloaded output streams is ref counted by audio policy manager.
- // As getOutput was called above and resulted in an output stream to be opened,
- // we need to release it.
- AudioSystem::releaseOutput(output);
return status;
}
mStatus = NO_ERROR;
- mStreamType = streamType;
- mFormat = format;
- mSharedBuffer = sharedBuffer;
mState = STATE_STOPPED;
mUserData = user;
mLoopPeriod = 0;
@@ -368,11 +382,10 @@ status_t AudioTrack::set(
mMarkerReached = false;
mNewPosition = 0;
mUpdatePeriod = 0;
- AudioSystem::acquireAudioSessionId(mSessionId);
+ AudioSystem::acquireAudioSessionId(mSessionId, mClientPid);
mSequence = 1;
mObservedSequence = mSequence;
mInUnderrun = false;
- mOutput = output;
return NO_ERROR;
}
@@ -448,12 +461,11 @@ status_t AudioTrack::start()
void AudioTrack::stop()
{
AutoMutex lock(mLock);
- // FIXME pause then stop should not be a nop
- if (mState != STATE_ACTIVE) {
+ if (mState != STATE_ACTIVE && mState != STATE_PAUSED) {
return;
}
- if (isOffloaded()) {
+ if (isOffloaded_l()) {
mState = STATE_STOPPING;
} else {
mState = STATE_STOPPED;
@@ -475,7 +487,7 @@ void AudioTrack::stop()
sp<AudioTrackThread> t = mAudioTrackThread;
if (t != 0) {
- if (!isOffloaded()) {
+ if (!isOffloaded_l()) {
t->pause();
}
} else {
@@ -513,7 +525,7 @@ void AudioTrack::flush_l()
mRefreshRemaining = true;
mState = STATE_FLUSHED;
- if (isOffloaded()) {
+ if (isOffloaded_l()) {
mProxy->interrupt();
}
mProxy->flush();
@@ -533,8 +545,8 @@ void AudioTrack::pause()
mProxy->interrupt();
mAudioTrack->pause();
- if (isOffloaded()) {
- if (mOutput != 0) {
+ if (isOffloaded_l()) {
+ if (mOutput != AUDIO_IO_HANDLE_NONE) {
uint32_t halFrames;
// OffloadThread sends HAL pause in its threadLoop.. time saved
// here can be slightly off
@@ -551,12 +563,12 @@ status_t AudioTrack::setVolume(float left, float right)
}
AutoMutex lock(mLock);
- mVolume[LEFT] = left;
- mVolume[RIGHT] = right;
+ mVolume[AUDIO_INTERLEAVE_LEFT] = left;
+ mVolume[AUDIO_INTERLEAVE_RIGHT] = right;
mProxy->setVolumeLR((uint32_t(uint16_t(right * 0x1000)) << 16) | uint16_t(left * 0x1000));
- if (isOffloaded()) {
+ if (isOffloaded_l()) {
mAudioTrack->signal();
}
return NO_ERROR;
@@ -620,8 +632,8 @@ uint32_t AudioTrack::getSampleRate() const
// sample rate can be updated during playback by the offloaded decoder so we need to
// query the HAL and update if needed.
// FIXME use Proxy return channel to update the rate from server and avoid polling here
- if (isOffloaded()) {
- if (mOutput != 0) {
+ if (isOffloaded_l()) {
+ if (mOutput != AUDIO_IO_HANDLE_NONE) {
uint32_t sampleRate = 0;
status_t status = AudioSystem::getSamplingRate(mOutput, mStreamType, &sampleRate);
if (status == NO_ERROR) {
@@ -704,6 +716,7 @@ status_t AudioTrack::setPositionUpdatePeriod(uint32_t updatePeriod)
AutoMutex lock(mLock);
mNewPosition = mProxy->getPosition() + updatePeriod;
mUpdatePeriod = updatePeriod;
+
return NO_ERROR;
}
@@ -757,7 +770,7 @@ status_t AudioTrack::getPosition(uint32_t *position) const
}
AutoMutex lock(mLock);
- if (isOffloaded()) {
+ if (isOffloaded_l()) {
uint32_t dspFrames = 0;
if ((mState == STATE_PAUSED) || (mState == STATE_PAUSED_STOPPING)) {
@@ -766,7 +779,7 @@ status_t AudioTrack::getPosition(uint32_t *position) const
return NO_ERROR;
}
- if (mOutput != 0) {
+ if (mOutput != AUDIO_IO_HANDLE_NONE) {
uint32_t halFrames;
AudioSystem::getRenderPosition(mOutput, &halFrames, &dspFrames);
}
@@ -812,23 +825,12 @@ status_t AudioTrack::reload()
return NO_ERROR;
}
-audio_io_handle_t AudioTrack::getOutput()
+audio_io_handle_t AudioTrack::getOutput() const
{
AutoMutex lock(mLock);
return mOutput;
}
-// must be called with mLock held
-audio_io_handle_t AudioTrack::getOutput_l()
-{
- if (mOutput) {
- return mOutput;
- } else {
- return AudioSystem::getOutput(mStreamType,
- mSampleRate, mFormat, mChannelMask, mFlags);
- }
-}
-
status_t AudioTrack::attachAuxEffect(int effectId)
{
AutoMutex lock(mLock);
@@ -842,15 +844,7 @@ status_t AudioTrack::attachAuxEffect(int effectId)
// -------------------------------------------------------------------------
// must be called with mLock held
-status_t AudioTrack::createTrack_l(
- audio_stream_type_t streamType,
- uint32_t sampleRate,
- audio_format_t format,
- size_t frameCount,
- audio_output_flags_t flags,
- const sp<IMemory>& sharedBuffer,
- audio_io_handle_t output,
- size_t epoch)
+status_t AudioTrack::createTrack_l(size_t epoch)
{
status_t status;
const sp<IAudioFlinger>& audioFlinger = AudioSystem::get_audio_flinger();
@@ -859,50 +853,57 @@ status_t AudioTrack::createTrack_l(
return NO_INIT;
}
+ audio_io_handle_t output = AudioSystem::getOutput(mStreamType, mSampleRate, mFormat,
+ mChannelMask, mFlags, mOffloadInfo);
+ if (output == AUDIO_IO_HANDLE_NONE) {
+ ALOGE("Could not get audio output for stream type %d, sample rate %u, format %#x, "
+ "channel mask %#x, flags %#x",
+ mStreamType, mSampleRate, mFormat, mChannelMask, mFlags);
+ return BAD_VALUE;
+ }
+ {
+ // Now that we have a reference to an I/O handle and have not yet handed it off to AudioFlinger,
+ // we must release it ourselves if anything goes wrong.
+
// Not all of these values are needed under all conditions, but it is easier to get them all
uint32_t afLatency;
- status = AudioSystem::getLatency(output, streamType, &afLatency);
+ status = AudioSystem::getLatency(output, &afLatency);
if (status != NO_ERROR) {
ALOGE("getLatency(%d) failed status %d", output, status);
- return NO_INIT;
+ goto release;
}
size_t afFrameCount;
- status = AudioSystem::getFrameCount(output, streamType, &afFrameCount);
+ status = AudioSystem::getFrameCount(output, mStreamType, &afFrameCount);
if (status != NO_ERROR) {
- ALOGE("getFrameCount(output=%d, streamType=%d) status %d", output, streamType, status);
- return NO_INIT;
+ ALOGE("getFrameCount(output=%d, streamType=%d) status %d", output, mStreamType, status);
+ goto release;
}
uint32_t afSampleRate;
- status = AudioSystem::getSamplingRate(output, streamType, &afSampleRate);
+ status = AudioSystem::getSamplingRate(output, mStreamType, &afSampleRate);
if (status != NO_ERROR) {
- ALOGE("getSamplingRate(output=%d, streamType=%d) status %d", output, streamType, status);
- return NO_INIT;
+ ALOGE("getSamplingRate(output=%d, streamType=%d) status %d", output, mStreamType, status);
+ goto release;
}
// Client decides whether the track is TIMED (see below), but can only express a preference
// for FAST. Server will perform additional tests.
- if ((flags & AUDIO_OUTPUT_FLAG_FAST) && !(
+ if ((mFlags & AUDIO_OUTPUT_FLAG_FAST) && !((
// either of these use cases:
// use case 1: shared buffer
- (sharedBuffer != 0) ||
- // use case 2: callback handler
- (mCbf != NULL))) {
+ (mSharedBuffer != 0) ||
+ // use case 2: callback transfer mode
+ (mTransfer == TRANSFER_CALLBACK)) &&
+ // matching sample rate
+ (mSampleRate == afSampleRate))) {
ALOGW("AUDIO_OUTPUT_FLAG_FAST denied by client");
// once denied, do not request again if IAudioTrack is re-created
- flags = (audio_output_flags_t) (flags & ~AUDIO_OUTPUT_FLAG_FAST);
- mFlags = flags;
+ mFlags = (audio_output_flags_t) (mFlags & ~AUDIO_OUTPUT_FLAG_FAST);
}
ALOGV("createTrack_l() output %d afLatency %d", output, afLatency);
- if ((flags & AUDIO_OUTPUT_FLAG_FAST) && sampleRate != afSampleRate) {
- ALOGW("AUDIO_OUTPUT_FLAG_FAST denied by client due to mismatching sample rate (%d vs %d)",
- sampleRate, afSampleRate);
- flags = (audio_output_flags_t) (flags & ~AUDIO_OUTPUT_FLAG_FAST);
- }
-
// The client's AudioTrack buffer is divided into n parts for purpose of wakeup by server, where
// n = 1 fast track with single buffering; nBuffering is ignored
// n = 2 fast track with double buffering
@@ -910,43 +911,45 @@ status_t AudioTrack::createTrack_l(
// n = 3 normal track, with sample rate conversion
// (pessimistic; some non-1:1 conversion ratios don't actually need triple-buffering)
// n > 3 very high latency or very small notification interval; nBuffering is ignored
- const uint32_t nBuffering = (sampleRate == afSampleRate) ? 2 : 3;
+ const uint32_t nBuffering = (mSampleRate == afSampleRate) ? 2 : 3;
mNotificationFramesAct = mNotificationFramesReq;
- if (!audio_is_linear_pcm(format)) {
+ size_t frameCount = mReqFrameCount;
+ if (!audio_is_linear_pcm(mFormat)) {
- if (sharedBuffer != 0) {
+ if (mSharedBuffer != 0) {
// Same comment as below about ignoring frameCount parameter for set()
- frameCount = sharedBuffer->size();
+ frameCount = mSharedBuffer->size();
} else if (frameCount == 0) {
frameCount = afFrameCount;
}
if (mNotificationFramesAct != frameCount) {
mNotificationFramesAct = frameCount;
}
- } else if (sharedBuffer != 0) {
+ } else if (mSharedBuffer != 0) {
// Ensure that buffer alignment matches channel count
// 8-bit data in shared memory is not currently supported by AudioFlinger
- size_t alignment = /* format == AUDIO_FORMAT_PCM_8_BIT ? 1 : */ 2;
+ size_t alignment = /* mFormat == AUDIO_FORMAT_PCM_8_BIT ? 1 : */ 2;
if (mChannelCount > 1) {
// More than 2 channels does not require stronger alignment than stereo
alignment <<= 1;
}
- if (((uintptr_t)sharedBuffer->pointer() & (alignment - 1)) != 0) {
+ if (((uintptr_t)mSharedBuffer->pointer() & (alignment - 1)) != 0) {
ALOGE("Invalid buffer alignment: address %p, channel count %u",
- sharedBuffer->pointer(), mChannelCount);
- return BAD_VALUE;
+ mSharedBuffer->pointer(), mChannelCount);
+ status = BAD_VALUE;
+ goto release;
}
// When initializing a shared buffer AudioTrack via constructors,
// there's no frameCount parameter.
// But when initializing a shared buffer AudioTrack via set(),
// there _is_ a frameCount parameter. We silently ignore it.
- frameCount = sharedBuffer->size()/mChannelCount/sizeof(int16_t);
+ frameCount = mSharedBuffer->size()/mChannelCount/sizeof(int16_t);
- } else if (!(flags & AUDIO_OUTPUT_FLAG_FAST)) {
+ } else if (!(mFlags & AUDIO_OUTPUT_FLAG_FAST)) {
// FIXME move these calculations and associated checks to server
@@ -958,10 +961,10 @@ status_t AudioTrack::createTrack_l(
minBufCount = nBuffering;
}
- size_t minFrameCount = (afFrameCount*sampleRate*minBufCount)/afSampleRate;
+ size_t minFrameCount = (afFrameCount*mSampleRate*minBufCount)/afSampleRate;
ALOGV("minFrameCount: %u, afFrameCount=%d, minBufCount=%d, sampleRate=%u, afSampleRate=%u"
", afLatency=%d",
- minFrameCount, afFrameCount, minBufCount, sampleRate, afSampleRate, afLatency);
+ minFrameCount, afFrameCount, minBufCount, mSampleRate, afSampleRate, afLatency);
if (frameCount == 0) {
frameCount = minFrameCount;
@@ -986,52 +989,64 @@ status_t AudioTrack::createTrack_l(
}
pid_t tid = -1;
- if (flags & AUDIO_OUTPUT_FLAG_FAST) {
+ if (mFlags & AUDIO_OUTPUT_FLAG_FAST) {
trackFlags |= IAudioFlinger::TRACK_FAST;
if (mAudioTrackThread != 0) {
tid = mAudioTrackThread->getTid();
}
}
- if (flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
+ if (mFlags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
trackFlags |= IAudioFlinger::TRACK_OFFLOAD;
}
- sp<IAudioTrack> track = audioFlinger->createTrack(streamType,
- sampleRate,
+ size_t temp = frameCount; // temp may be replaced by a revised value of frameCount,
+ // but we will still need the original value also
+ sp<IAudioTrack> track = audioFlinger->createTrack(mStreamType,
+ mSampleRate,
// AudioFlinger only sees 16-bit PCM
- format == AUDIO_FORMAT_PCM_8_BIT ?
- AUDIO_FORMAT_PCM_16_BIT : format,
+ mFormat == AUDIO_FORMAT_PCM_8_BIT ?
+ AUDIO_FORMAT_PCM_16_BIT : mFormat,
mChannelMask,
- frameCount,
+ &temp,
&trackFlags,
- sharedBuffer,
+ mSharedBuffer,
output,
tid,
&mSessionId,
- mName,
mClientUid,
&status);
- if (track == 0) {
+ if (status != NO_ERROR) {
ALOGE("AudioFlinger could not create track, status: %d", status);
- return status;
+ goto release;
}
+ ALOG_ASSERT(track != 0);
+
+ // AudioFlinger now owns the reference to the I/O handle,
+ // so we are no longer responsible for releasing it.
+
sp<IMemory> iMem = track->getCblk();
if (iMem == 0) {
ALOGE("Could not get control block");
return NO_INIT;
}
+ void *iMemPointer = iMem->pointer();
+ if (iMemPointer == NULL) {
+ ALOGE("Could not get control block pointer");
+ return NO_INIT;
+ }
// invariant that mAudioTrack != 0 is true only after set() returns successfully
if (mAudioTrack != 0) {
mAudioTrack->asBinder()->unlinkToDeath(mDeathNotifier, this);
mDeathNotifier.clear();
}
mAudioTrack = track;
+
mCblkMemory = iMem;
- audio_track_cblk_t* cblk = static_cast<audio_track_cblk_t*>(iMem->pointer());
+ audio_track_cblk_t* cblk = static_cast<audio_track_cblk_t*>(iMemPointer);
mCblk = cblk;
- size_t temp = cblk->frameCount_;
+ // note that temp is the (possibly revised) value of frameCount
if (temp < frameCount || (frameCount == 0 && temp == 0)) {
// In current design, AudioTrack client checks and ensures frame count validity before
// passing it to AudioFlinger so AudioFlinger should not return a different value except
@@ -1039,12 +1054,13 @@ status_t AudioTrack::createTrack_l(
ALOGW("Requested frameCount %u but received frameCount %u", frameCount, temp);
}
frameCount = temp;
+
mAwaitBoost = false;
- if (flags & AUDIO_OUTPUT_FLAG_FAST) {
+ if (mFlags & AUDIO_OUTPUT_FLAG_FAST) {
if (trackFlags & IAudioFlinger::TRACK_FAST) {
ALOGV("AUDIO_OUTPUT_FLAG_FAST successful; frameCount %u", frameCount);
mAwaitBoost = true;
- if (sharedBuffer == 0) {
+ if (mSharedBuffer == 0) {
// Theoretically double-buffering is not required for fast tracks,
// due to tighter scheduling. But in practice, to accommodate kernels with
// scheduling jitter, and apps with computation jitter, we use double-buffering.
@@ -1055,26 +1071,27 @@ status_t AudioTrack::createTrack_l(
} else {
ALOGV("AUDIO_OUTPUT_FLAG_FAST denied by server; frameCount %u", frameCount);
// once denied, do not request again if IAudioTrack is re-created
- flags = (audio_output_flags_t) (flags & ~AUDIO_OUTPUT_FLAG_FAST);
- mFlags = flags;
- if (sharedBuffer == 0) {
+ mFlags = (audio_output_flags_t) (mFlags & ~AUDIO_OUTPUT_FLAG_FAST);
+ if (mSharedBuffer == 0) {
if (mNotificationFramesAct == 0 || mNotificationFramesAct > frameCount/nBuffering) {
mNotificationFramesAct = frameCount/nBuffering;
}
}
}
}
- if (flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
+ if (mFlags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
if (trackFlags & IAudioFlinger::TRACK_OFFLOAD) {
ALOGV("AUDIO_OUTPUT_FLAG_OFFLOAD successful");
} else {
ALOGW("AUDIO_OUTPUT_FLAG_OFFLOAD denied by server");
- flags = (audio_output_flags_t) (flags & ~AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD);
- mFlags = flags;
- return NO_INIT;
+ mFlags = (audio_output_flags_t) (mFlags & ~AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD);
+ // FIXME This is a warning, not an error, so don't return error status
+ //return NO_INIT;
}
}
+ // We retain a copy of the I/O handle, but don't own the reference
+ mOutput = output;
mRefreshRemaining = true;
// Starting address of buffers in shared memory. If there is a shared buffer, buffers
@@ -1082,15 +1099,16 @@ status_t AudioTrack::createTrack_l(
// immediately after the control block. This address is for the mapping within client
// address space. AudioFlinger::TrackBase::mBuffer is for the server address space.
void* buffers;
- if (sharedBuffer == 0) {
+ if (mSharedBuffer == 0) {
buffers = (char*)cblk + sizeof(audio_track_cblk_t);
} else {
- buffers = sharedBuffer->pointer();
+ buffers = mSharedBuffer->pointer();
}
mAudioTrack->attachAuxEffect(mAuxEffectId);
// FIXME don't believe this lie
- mLatency = afLatency + (1000*frameCount) / sampleRate;
+ mLatency = afLatency + (1000*frameCount) / mSampleRate;
+
mFrameCount = frameCount;
// If IAudioTrack is re-created, don't let the requested frameCount
// decrease. This can confuse clients that cache frameCount().
@@ -1099,15 +1117,15 @@ status_t AudioTrack::createTrack_l(
}
// update proxy
- if (sharedBuffer == 0) {
+ if (mSharedBuffer == 0) {
mStaticProxy.clear();
mProxy = new AudioTrackClientProxy(cblk, buffers, frameCount, mFrameSizeAF);
} else {
mStaticProxy = new StaticAudioTrackClientProxy(cblk, buffers, frameCount, mFrameSizeAF);
mProxy = mStaticProxy;
}
- mProxy->setVolumeLR((uint32_t(uint16_t(mVolume[RIGHT] * 0x1000)) << 16) |
- uint16_t(mVolume[LEFT] * 0x1000));
+ mProxy->setVolumeLR((uint32_t(uint16_t(mVolume[AUDIO_INTERLEAVE_RIGHT] * 0x1000)) << 16) |
+ uint16_t(mVolume[AUDIO_INTERLEAVE_LEFT] * 0x1000));
mProxy->setSendLevel(mSendLevel);
mProxy->setSampleRate(mSampleRate);
mProxy->setEpoch(epoch);
@@ -1117,6 +1135,14 @@ status_t AudioTrack::createTrack_l(
mAudioTrack->asBinder()->linkToDeath(mDeathNotifier, this);
return NO_ERROR;
+ }
+
+release:
+ AudioSystem::releaseOutput(output);
+ if (status == NO_ERROR) {
+ status = NO_INIT;
+ }
+ return status;
}
status_t AudioTrack::obtainBuffer(Buffer* audioBuffer, int32_t waitCount)
@@ -1244,8 +1270,7 @@ void AudioTrack::releaseBuffer(Buffer* audioBuffer)
if (mState == STATE_ACTIVE) {
audio_track_cblk_t* cblk = mCblk;
if (android_atomic_and(~CBLK_DISABLED, &cblk->mFlags) & CBLK_DISABLED) {
- ALOGW("releaseBuffer() track %p name=%s disabled due to previous underrun, restarting",
- this, mName.string());
+ ALOGW("releaseBuffer() track %p disabled due to previous underrun, restarting", this);
// FIXME ignoring status
mAudioTrack->start();
}
@@ -1254,7 +1279,7 @@ void AudioTrack::releaseBuffer(Buffer* audioBuffer)
// -------------------------------------------------------------------------
-ssize_t AudioTrack::write(const void* buffer, size_t userSize)
+ssize_t AudioTrack::write(const void* buffer, size_t userSize, bool blocking)
{
if (mTransfer != TRANSFER_SYNC || mIsTimed) {
return INVALID_OPERATION;
@@ -1273,7 +1298,8 @@ ssize_t AudioTrack::write(const void* buffer, size_t userSize)
while (userSize >= mFrameSize) {
audioBuffer.frameCount = userSize / mFrameSize;
- status_t err = obtainBuffer(&audioBuffer, &ClientProxy::kForever);
+ status_t err = obtainBuffer(&audioBuffer,
+ blocking ? &ClientProxy::kForever : &ClientProxy::kNonBlocking);
if (err < 0) {
if (written > 0) {
break;
@@ -1369,7 +1395,7 @@ status_t TimedAudioTrack::setMediaTimeTransform(const LinearTransform& xform,
// -------------------------------------------------------------------------
-nsecs_t AudioTrack::processAudioBuffer(const sp<AudioTrackThread>& thread)
+nsecs_t AudioTrack::processAudioBuffer()
{
// Currently the AudioTrack thread is not created if there are no callbacks.
// Would it ever make sense to run the thread, even without callbacks?
@@ -1407,7 +1433,7 @@ nsecs_t AudioTrack::processAudioBuffer(const sp<AudioTrackThread>& thread)
// for offloaded tracks restoreTrack_l() will just update the sequence and clear
// AudioSystem cache. We should not exit here but after calling the callback so
// that the upper layers can recreate the track
- if (!isOffloaded() || (mSequence == mObservedSequence)) {
+ if (!isOffloaded_l() || (mSequence == mObservedSequence)) {
status_t status = restoreTrack_l("processAudioBuffer");
mLock.unlock();
// Run again immediately, but with a new IAudioTrack
@@ -1462,7 +1488,7 @@ nsecs_t AudioTrack::processAudioBuffer(const sp<AudioTrackThread>& thread)
// Cache other fields that will be needed soon
uint32_t loopPeriod = mLoopPeriod;
uint32_t sampleRate = mSampleRate;
- size_t notificationFrames = mNotificationFramesAct;
+ uint32_t notificationFrames = mNotificationFramesAct;
if (mRefreshRemaining) {
mRefreshRemaining = false;
mRemainingFrames = notificationFrames;
@@ -1626,7 +1652,6 @@ nsecs_t AudioTrack::processAudioBuffer(const sp<AudioTrackThread>& thread)
size_t reqSize = audioBuffer.size;
mCbf(EVENT_MORE_DATA, mUserData, &audioBuffer);
size_t writtenSize = audioBuffer.size;
- size_t writtenFrames = writtenSize / mFrameSize;
// Sanity check on returned size
if (ssize_t(writtenSize) < 0 || writtenSize > reqSize) {
@@ -1692,22 +1717,19 @@ nsecs_t AudioTrack::processAudioBuffer(const sp<AudioTrackThread>& thread)
status_t AudioTrack::restoreTrack_l(const char *from)
{
ALOGW("dead IAudioTrack, %s, creating a new one from %s()",
- isOffloaded() ? "Offloaded" : "PCM", from);
+ isOffloaded_l() ? "Offloaded" : "PCM", from);
++mSequence;
status_t result;
// refresh the audio configuration cache in this process to make sure we get new
- // output parameters in getOutput_l() and createTrack_l()
+ // output parameters in createTrack_l()
AudioSystem::clearAudioConfigCache();
- if (isOffloaded()) {
+ if (isOffloaded_l()) {
+ // FIXME re-creation of offloaded tracks is not yet implemented
return DEAD_OBJECT;
}
- // force new output query from audio policy manager;
- mOutput = 0;
- audio_io_handle_t output = getOutput_l();
-
// if the new IAudioTrack is created, createTrack_l() will modify the
// following member variables: mAudioTrack, mCblkMemory and mCblk.
// It will also delete the strong references on previous IAudioTrack and IMemory
@@ -1715,14 +1737,7 @@ status_t AudioTrack::restoreTrack_l(const char *from)
// take the frames that will be lost by track recreation into account in saved position
size_t position = mProxy->getPosition() + mProxy->getFramesFilled();
size_t bufferPosition = mStaticProxy != NULL ? mStaticProxy->getBufferPosition() : 0;
- result = createTrack_l(mStreamType,
- mSampleRate,
- mFormat,
- mReqFrameCount, // so that frame count never goes down
- mFlags,
- mSharedBuffer,
- output,
- position /*epoch*/);
+ result = createTrack_l(position /*epoch*/);
if (result == NO_ERROR) {
// continue playback from last known position, but
@@ -1750,10 +1765,6 @@ status_t AudioTrack::restoreTrack_l(const char *from)
}
}
if (result != NO_ERROR) {
- //Use of direct and offloaded output streams is ref counted by audio policy manager.
- // As getOutput was called above and resulted in an output stream to be opened,
- // we need to release it.
- AudioSystem::releaseOutput(output);
ALOGW("restoreTrack_l() failed status %d", result);
mState = STATE_STOPPED;
}
@@ -1786,14 +1797,21 @@ status_t AudioTrack::getTimestamp(AudioTimestamp& timestamp)
String8 AudioTrack::getParameters(const String8& keys)
{
- if (mOutput) {
- return AudioSystem::getParameters(mOutput, keys);
+ audio_io_handle_t output = getOutput();
+ if (output != AUDIO_IO_HANDLE_NONE) {
+ return AudioSystem::getParameters(output, keys);
} else {
return String8::empty();
}
}
-status_t AudioTrack::dump(int fd, const Vector<String16>& args) const
+bool AudioTrack::isOffloaded() const
+{
+ AutoMutex lock(mLock);
+ return isOffloaded_l();
+}
+
+status_t AudioTrack::dump(int fd, const Vector<String16>& args __unused) const
{
const size_t SIZE = 256;
@@ -1823,7 +1841,7 @@ uint32_t AudioTrack::getUnderrunFrames() const
// =========================================================================
-void AudioTrack::DeathNotifier::binderDied(const wp<IBinder>& who)
+void AudioTrack::DeathNotifier::binderDied(const wp<IBinder>& who __unused)
{
sp<AudioTrack> audioTrack = mAudioTrack.promote();
if (audioTrack != 0) {
@@ -1867,7 +1885,7 @@ bool AudioTrack::AudioTrackThread::threadLoop()
return true;
}
}
- nsecs_t ns = mReceiver.processAudioBuffer(this);
+ nsecs_t ns = mReceiver.processAudioBuffer();
switch (ns) {
case 0:
return true;
diff --git a/media/libmedia/AudioTrackShared.cpp b/media/libmedia/AudioTrackShared.cpp
index e898109..58c9fc1 100644
--- a/media/libmedia/AudioTrackShared.cpp
+++ b/media/libmedia/AudioTrackShared.cpp
@@ -26,7 +26,7 @@ extern "C" {
namespace android {
audio_track_cblk_t::audio_track_cblk_t()
- : mServer(0), frameCount_(0), mFutex(0), mMinimum(0),
+ : mServer(0), mFutex(0), mMinimum(0),
mVolumeLR(0x10001000), mSampleRate(0), mSendLevel(0), mFlags(0)
{
memset(&u, 0, sizeof(u));
@@ -200,7 +200,7 @@ status_t ClientProxy::obtainBuffer(Buffer* buffer, const struct timespec *reques
ts = &remaining;
break;
default:
- LOG_FATAL("obtainBuffer() timeout=%d", timeout);
+ LOG_ALWAYS_FATAL("obtainBuffer() timeout=%d", timeout);
ts = NULL;
break;
}
@@ -429,7 +429,7 @@ status_t AudioTrackClientProxy::waitStreamEndDone(const struct timespec *request
ts = &remaining;
break;
default:
- LOG_FATAL("waitStreamEndDone() timeout=%d", timeout);
+ LOG_ALWAYS_FATAL("waitStreamEndDone() timeout=%d", timeout);
ts = NULL;
break;
}
@@ -470,7 +470,7 @@ StaticAudioTrackClientProxy::StaticAudioTrackClientProxy(audio_track_cblk_t* cbl
void StaticAudioTrackClientProxy::flush()
{
- LOG_FATAL("static flush");
+ LOG_ALWAYS_FATAL("static flush");
}
void StaticAudioTrackClientProxy::setLoop(size_t loopStart, size_t loopEnd, int loopCount)
@@ -771,7 +771,7 @@ ssize_t StaticAudioTrackServerProxy::pollPosition()
return (ssize_t) position;
}
-status_t StaticAudioTrackServerProxy::obtainBuffer(Buffer* buffer, bool ackFlush)
+status_t StaticAudioTrackServerProxy::obtainBuffer(Buffer* buffer, bool ackFlush __unused)
{
if (mIsShutdown) {
buffer->mFrameCount = 0;
@@ -854,7 +854,7 @@ void StaticAudioTrackServerProxy::releaseBuffer(Buffer* buffer)
buffer->mNonContig = 0;
}
-void StaticAudioTrackServerProxy::tallyUnderrunFrames(uint32_t frameCount)
+void StaticAudioTrackServerProxy::tallyUnderrunFrames(uint32_t frameCount __unused)
{
// Unlike AudioTrackServerProxy::tallyUnderrunFrames() used for streaming tracks,
// we don't have a location to count underrun frames. The underrun frame counter
diff --git a/media/libmedia/CharacterEncodingDetector.cpp b/media/libmedia/CharacterEncodingDetector.cpp
new file mode 100644
index 0000000..4992798
--- /dev/null
+++ b/media/libmedia/CharacterEncodingDetector.cpp
@@ -0,0 +1,441 @@
+/*
+ * Copyright (C) 2013 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "CharacterEncodingDector"
+#include <utils/Log.h>
+
+#include "CharacterEncodingDetector.h"
+#include "CharacterEncodingDetectorTables.h"
+
+#include "utils/Vector.h"
+#include "StringArray.h"
+
+#include "unicode/ucnv.h"
+#include "unicode/ucsdet.h"
+#include "unicode/ustring.h"
+
+namespace android {
+
+CharacterEncodingDetector::CharacterEncodingDetector() {
+
+ UErrorCode status = U_ZERO_ERROR;
+ mUtf8Conv = ucnv_open("UTF-8", &status);
+ if (U_FAILURE(status)) {
+ ALOGE("could not create UConverter for UTF-8");
+ mUtf8Conv = NULL;
+ }
+}
+
+CharacterEncodingDetector::~CharacterEncodingDetector() {
+ ucnv_close(mUtf8Conv);
+}
+
+void CharacterEncodingDetector::addTag(const char *name, const char *value) {
+ mNames.push_back(name);
+ mValues.push_back(value);
+}
+
+size_t CharacterEncodingDetector::size() {
+ return mNames.size();
+}
+
+status_t CharacterEncodingDetector::getTag(int index, const char **name, const char**value) {
+ if (index >= mNames.size()) {
+ return BAD_VALUE;
+ }
+
+ *name = mNames.getEntry(index);
+ *value = mValues.getEntry(index);
+ return OK;
+}
+
+static bool isPrintableAscii(const char *value, size_t len) {
+ for (size_t i = 0; i < len; i++) {
+ if ((value[i] & 0x80) || value[i] < 0x20 || value[i] == 0x7f) {
+ return false;
+ }
+ }
+ return true;
+}
+
+void CharacterEncodingDetector::detectAndConvert() {
+
+ int size = mNames.size();
+ ALOGV("%d tags before conversion", size);
+ for (int i = 0; i < size; i++) {
+ ALOGV("%s: %s", mNames.getEntry(i), mValues.getEntry(i));
+ }
+
+ if (size && mUtf8Conv) {
+
+ UErrorCode status = U_ZERO_ERROR;
+ UCharsetDetector *csd = ucsdet_open(&status);
+ const UCharsetMatch *ucm;
+
+ // try combined detection of artist/album/title etc.
+ char buf[1024];
+ buf[0] = 0;
+ int idx;
+ bool allprintable = true;
+ for (int i = 0; i < size; i++) {
+ const char *name = mNames.getEntry(i);
+ const char *value = mValues.getEntry(i);
+ if (!isPrintableAscii(value, strlen(value)) && (
+ !strcmp(name, "artist") ||
+ !strcmp(name, "albumartist") ||
+ !strcmp(name, "composer") ||
+ !strcmp(name, "genre") ||
+ !strcmp(name, "album") ||
+ !strcmp(name, "title"))) {
+ strlcat(buf, value, sizeof(buf));
+ // separate tags by space so ICU's ngram detector can do its job
+ strlcat(buf, " ", sizeof(buf));
+ allprintable = false;
+ }
+ }
+
+ const char *combinedenc = "UTF-8";
+ if (allprintable) {
+ // since 'buf' is empty, ICU would return a UTF-8 matcher with low confidence, so
+ // no need to even call it
+ ALOGV("all tags are printable, assuming ascii (%d)", strlen(buf));
+ } else {
+ ucsdet_setText(csd, buf, strlen(buf), &status);
+ int32_t matches;
+ const UCharsetMatch** ucma = ucsdet_detectAll(csd, &matches, &status);
+ bool goodmatch = true;
+ const UCharsetMatch* bestCombinedMatch = getPreferred(buf, strlen(buf),
+ ucma, matches, &goodmatch);
+
+ if (!goodmatch && strlen(buf) < 20) {
+ ALOGV("not a good match, trying with more data");
+ // This string might be too short for ICU to do anything useful with.
+ // (real world example: "Björk" in ISO-8859-1 might be detected as GB18030, because
+ // the ISO detector reports a confidence of 0, while the GB18030 detector reports
+ // a confidence of 10 with no invalid characters)
+ // Append artist, album and title if they were previously omitted because they
+ // were printable ascii.
+ bool added = false;
+ for (int i = 0; i < size; i++) {
+ const char *name = mNames.getEntry(i);
+ const char *value = mValues.getEntry(i);
+ if (isPrintableAscii(value, strlen(value)) && (
+ !strcmp(name, "artist") ||
+ !strcmp(name, "album") ||
+ !strcmp(name, "title"))) {
+ strlcat(buf, value, sizeof(buf));
+ strlcat(buf, " ", sizeof(buf));
+ added = true;
+ }
+ }
+ if (added) {
+ ucsdet_setText(csd, buf, strlen(buf), &status);
+ ucma = ucsdet_detectAll(csd, &matches, &status);
+ bestCombinedMatch = getPreferred(buf, strlen(buf),
+ ucma, matches, &goodmatch);
+ if (!goodmatch) {
+ ALOGV("still not a good match after adding printable tags");
+ }
+ } else {
+ ALOGV("no printable tags to add");
+ }
+ }
+
+ if (bestCombinedMatch != NULL) {
+ combinedenc = ucsdet_getName(bestCombinedMatch, &status);
+ }
+ }
+
+ for (int i = 0; i < size; i++) {
+ const char *name = mNames.getEntry(i);
+ uint8_t* src = (uint8_t *)mValues.getEntry(i);
+ int len = strlen((char *)src);
+ uint8_t* dest = src;
+
+ ALOGV("@@@ checking %s", name);
+ const char *s = mValues.getEntry(i);
+ int32_t inputLength = strlen(s);
+ const char *enc;
+
+ if (!allprintable && (!strcmp(name, "artist") ||
+ !strcmp(name, "albumartist") ||
+ !strcmp(name, "composer") ||
+ !strcmp(name, "genre") ||
+ !strcmp(name, "album") ||
+ !strcmp(name, "title"))) {
+ // use encoding determined from the combination of artist/album/title etc.
+ enc = combinedenc;
+ } else {
+ if (isPrintableAscii(s, inputLength)) {
+ enc = "UTF-8";
+ ALOGV("@@@@ %s is ascii", mNames.getEntry(i));
+ } else {
+ ucsdet_setText(csd, s, inputLength, &status);
+ ucm = ucsdet_detect(csd, &status);
+ if (!ucm) {
+ mValues.setEntry(i, "???");
+ continue;
+ }
+ enc = ucsdet_getName(ucm, &status);
+ ALOGV("@@@@ recognized charset: %s for %s confidence %d",
+ enc, mNames.getEntry(i), ucsdet_getConfidence(ucm, &status));
+ }
+ }
+
+ if (strcmp(enc,"UTF-8") != 0) {
+ // only convert if the source encoding isn't already UTF-8
+ ALOGV("@@@ using converter %s for %s", enc, mNames.getEntry(i));
+ UConverter *conv = ucnv_open(enc, &status);
+ if (U_FAILURE(status)) {
+ ALOGE("could not create UConverter for %s", enc);
+ continue;
+ }
+
+ // convert from native encoding to UTF-8
+ const char* source = mValues.getEntry(i);
+ int targetLength = len * 3 + 1;
+ char* buffer = new char[targetLength];
+ // don't normally check for NULL, but in this case targetLength may be large
+ if (!buffer)
+ break;
+ char* target = buffer;
+
+ ucnv_convertEx(mUtf8Conv, conv, &target, target + targetLength,
+ &source, source + strlen(source),
+ NULL, NULL, NULL, NULL, TRUE, TRUE, &status);
+
+ if (U_FAILURE(status)) {
+ ALOGE("ucnv_convertEx failed: %d", status);
+ mValues.setEntry(i, "???");
+ } else {
+ // zero terminate
+ *target = 0;
+ mValues.setEntry(i, buffer);
+ }
+
+ delete[] buffer;
+
+ ucnv_close(conv);
+ }
+ }
+
+ for (int i = size - 1; i >= 0; --i) {
+ if (strlen(mValues.getEntry(i)) == 0) {
+ ALOGV("erasing %s because entry is empty", mNames.getEntry(i));
+ mNames.erase(i);
+ mValues.erase(i);
+ }
+ }
+
+ ucsdet_close(csd);
+ }
+}
+
+/*
+ * When ICU detects multiple encoding matches, apply additional heuristics to determine
+ * which one is the best match, since ICU can't always be trusted to make the right choice.
+ *
+ * What this method does is:
+ * - decode the input using each of the matches found
+ * - recalculate the starting confidence level for multibyte encodings using a different
+ * algorithm and larger frequent character lists than ICU
+ * - devalue encoding where the conversion contains unlikely characters (symbols, reserved, etc)
+ * - pick the highest match
+ * - signal to the caller whether this match is considered good: confidence > 15, and confidence
+ * delta with the next runner up > 15
+ */
+const UCharsetMatch *CharacterEncodingDetector::getPreferred(
+ const char *input, size_t len,
+ const UCharsetMatch** ucma, size_t nummatches,
+ bool *goodmatch) {
+
+ *goodmatch = false;
+ Vector<const UCharsetMatch*> matches;
+ UErrorCode status = U_ZERO_ERROR;
+
+ ALOGV("%d matches", nummatches);
+ for (size_t i = 0; i < nummatches; i++) {
+ const char *encname = ucsdet_getName(ucma[i], &status);
+ int confidence = ucsdet_getConfidence(ucma[i], &status);
+ ALOGV("%d: %s %d", i, encname, confidence);
+ matches.push_back(ucma[i]);
+ }
+
+ size_t num = matches.size();
+ if (num == 0) {
+ return NULL;
+ }
+ if (num == 1) {
+ int confidence = ucsdet_getConfidence(matches[0], &status);
+ if (confidence > 15) {
+ *goodmatch = true;
+ }
+ return matches[0];
+ }
+
+ ALOGV("considering %d matches", num);
+
+ // keep track of how many "special" characters result when converting the input using each
+ // encoding
+ Vector<int> newconfidence;
+ for (size_t i = 0; i < num; i++) {
+ const uint16_t *freqdata = NULL;
+ float freqcoverage = 0;
+ status = U_ZERO_ERROR;
+ const char *encname = ucsdet_getName(matches[i], &status);
+ int confidence = ucsdet_getConfidence(matches[i], &status);
+ if (!strcmp("GB18030", encname)) {
+ freqdata = frequent_zhCN;
+ freqcoverage = frequent_zhCN_coverage;
+ } else if (!strcmp("Big5", encname)) {
+ freqdata = frequent_zhTW;
+ freqcoverage = frequent_zhTW_coverage;
+ } else if (!strcmp("EUC-KR", encname)) {
+ freqdata = frequent_ko;
+ freqcoverage = frequent_ko_coverage;
+ } else if (!strcmp("EUC-JP", encname)) {
+ freqdata = frequent_ja;
+ freqcoverage = frequent_ja_coverage;
+ } else if (!strcmp("Shift_JIS", encname)) {
+ freqdata = frequent_ja;
+ freqcoverage = frequent_ja_coverage;
+ }
+
+ ALOGV("%d: %s %d", i, encname, confidence);
+ UConverter *conv = ucnv_open(encname, &status);
+ const char *source = input;
+ const char *sourceLimit = input + len;
+ status = U_ZERO_ERROR;
+ int demerit = 0;
+ int frequentchars = 0;
+ int totalchars = 0;
+ while (true) {
+ // demerit the current encoding for each "special" character found after conversion.
+ // The amount of demerit is somewhat arbitrarily chosen.
+ int inchar;
+ if (source != sourceLimit) {
+ inchar = (source[0] << 8) + source[1];
+ }
+ UChar32 c = ucnv_getNextUChar(conv, &source, sourceLimit, &status);
+ if (!U_SUCCESS(status)) {
+ break;
+ }
+ if (c < 0x20 || (c >= 0x7f && c <= 0x009f)) {
+ ALOGV("control character %x", c);
+ demerit += 100;
+ } else if ((c >= 0xa0 && c <= 0xbe) // symbols, superscripts
+ || (c == 0xd7) || (c == 0xf7) // multiplication and division signs
+ || (c >= 0x2000 && c <= 0x209f)) { // punctuation, superscripts
+ ALOGV("unlikely character %x", c);
+ demerit += 10;
+ } else if (c >= 0xe000 && c <= 0xf8ff) {
+ ALOGV("private use character %x", c);
+ demerit += 30;
+ } else if (c >= 0x2190 && c <= 0x2bff) {
+ // this range comprises various symbol ranges that are unlikely to appear in
+ // music file metadata.
+ ALOGV("symbol %x", c);
+ demerit += 10;
+ } else if (c == 0xfffd) {
+ ALOGV("replacement character");
+ demerit += 50;
+ } else if (c >= 0xfff0 && c <= 0xfffc) {
+ ALOGV("unicode special %x", c);
+ demerit += 50;
+ } else if (freqdata != NULL) {
+ totalchars++;
+ if (isFrequent(freqdata, c)) {
+ frequentchars++;
+ }
+ }
+ }
+ if (freqdata != NULL && totalchars != 0) {
+ int myconfidence = 10 + float((100 * frequentchars) / totalchars) / freqcoverage;
+ ALOGV("ICU confidence: %d, my confidence: %d (%d %d)", confidence, myconfidence,
+ totalchars, frequentchars);
+ if (myconfidence > 100) myconfidence = 100;
+ if (myconfidence < 0) myconfidence = 0;
+ confidence = myconfidence;
+ }
+ ALOGV("%d-%d=%d", confidence, demerit, confidence - demerit);
+ newconfidence.push_back(confidence - demerit);
+ ucnv_close(conv);
+ if (i == 0 && (confidence - demerit) == 100) {
+ // no need to check any further, we'll end up using this match anyway
+ break;
+ }
+ }
+
+ // find match with highest confidence after adjusting for unlikely characters
+ int highest = newconfidence[0];
+ size_t highestidx = 0;
+ int runnerup = -10000;
+ int runnerupidx = -10000;
+ num = newconfidence.size();
+ for (size_t i = 1; i < num; i++) {
+ if (newconfidence[i] > highest) {
+ runnerup = highest;
+ runnerupidx = highestidx;
+ highest = newconfidence[i];
+ highestidx = i;
+ } else if (newconfidence[i] > runnerup){
+ runnerup = newconfidence[i];
+ runnerupidx = i;
+ }
+ }
+ status = U_ZERO_ERROR;
+ ALOGV("selecting: '%s' w/ %d confidence",
+ ucsdet_getName(matches[highestidx], &status), highest);
+ if (runnerupidx < 0) {
+ ALOGV("no runner up");
+ if (highest > 15) {
+ *goodmatch = true;
+ }
+ } else {
+ ALOGV("runner up: '%s' w/ %d confidence",
+ ucsdet_getName(matches[runnerupidx], &status), runnerup);
+ if ((highest - runnerup) > 15) {
+ *goodmatch = true;
+ }
+ }
+ return matches[highestidx];
+}
+
+
+bool CharacterEncodingDetector::isFrequent(const uint16_t *values, uint32_t c) {
+
+ int start = 0;
+ int end = 511; // All the tables have 512 entries
+ int mid = (start+end)/2;
+
+ while(start <= end) {
+ if(c == values[mid]) {
+ return true;
+ } else if (c > values[mid]) {
+ start = mid + 1;
+ } else {
+ end = mid - 1;
+ }
+
+ mid = (start + end) / 2;
+ }
+
+ return false;
+}
+
+
+} // namespace android
diff --git a/media/libmedia/CharacterEncodingDetector.h b/media/libmedia/CharacterEncodingDetector.h
new file mode 100644
index 0000000..7b5ed86
--- /dev/null
+++ b/media/libmedia/CharacterEncodingDetector.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2013 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.
+ */
+
+#ifndef _CHARACTER_ENCODING_DETECTOR_H
+#define _CHARACTER_ENCODING_DETECTOR_H
+
+#include <media/mediascanner.h>
+
+#include "StringArray.h"
+
+#include "unicode/ucnv.h"
+#include "unicode/ucsdet.h"
+#include "unicode/ustring.h"
+
+namespace android {
+
+class CharacterEncodingDetector {
+
+ public:
+ CharacterEncodingDetector();
+ ~CharacterEncodingDetector();
+
+ void addTag(const char *name, const char *value);
+ size_t size();
+
+ void detectAndConvert();
+ status_t getTag(int index, const char **name, const char**value);
+
+ private:
+ const UCharsetMatch *getPreferred(
+ const char *input, size_t len,
+ const UCharsetMatch** ucma, size_t matches,
+ bool *goodmatch);
+
+ bool isFrequent(const uint16_t *values, uint32_t c);
+
+ // cached name and value strings, for native encoding support.
+ // TODO: replace these with byte blob arrays that don't require the data to be
+ // singlenullbyte-terminated
+ StringArray mNames;
+ StringArray mValues;
+
+ UConverter* mUtf8Conv;
+};
+
+
+
+}; // namespace android
+
+#endif
diff --git a/media/libmedia/CharacterEncodingDetectorTables.h b/media/libmedia/CharacterEncodingDetectorTables.h
new file mode 100644
index 0000000..1fe1137
--- /dev/null
+++ b/media/libmedia/CharacterEncodingDetectorTables.h
@@ -0,0 +1,2092 @@
+/*
+ * Copyright (C) 2013 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.
+ */
+
+// The 512 most frequently occuring characters for the zhCN language in a sample of the Internet.
+// Ordered by codepoint, comment shows character and ranking by frequency
+const uint16_t frequent_zhCN[] = {
+ 0x4E00, // 一, #2
+ 0x4E07, // 万, #306
+ 0x4E09, // 三, #138
+ 0x4E0A, // 上, #16
+ 0x4E0B, // 下, #25
+ 0x4E0D, // 不, #7
+ 0x4E0E, // 与, #133
+ 0x4E13, // 专, #151
+ 0x4E16, // 世, #346
+ 0x4E1A, // 业, #39
+ 0x4E1C, // 东, #197
+ 0x4E24, // 两, #376
+ 0x4E2A, // 个, #23
+ 0x4E2D, // 中, #4
+ 0x4E3A, // 为, #31
+ 0x4E3B, // 主, #95
+ 0x4E3E, // 举, #418
+ 0x4E48, // 么, #93
+ 0x4E4B, // 之, #131
+ 0x4E50, // 乐, #130
+ 0x4E5F, // 也, #145
+ 0x4E66, // 书, #283
+ 0x4E70, // 买, #483
+ 0x4E86, // 了, #13
+ 0x4E8B, // 事, #168
+ 0x4E8C, // 二, #218
+ 0x4E8E, // 于, #64
+ 0x4E94, // 五, #430
+ 0x4E9A, // 亚, #468
+ 0x4E9B, // 些, #366
+ 0x4EA4, // 交, #243
+ 0x4EA7, // 产, #86
+ 0x4EAB, // 享, #345
+ 0x4EAC, // 京, #206
+ 0x4EBA, // 人, #3
+ 0x4EC0, // 什, #287
+ 0x4ECB, // 介, #478
+ 0x4ECE, // 从, #381
+ 0x4ED6, // 他, #129
+ 0x4EE3, // 代, #241
+ 0x4EE5, // 以, #51
+ 0x4EEC, // 们, #83
+ 0x4EF6, // 件, #141
+ 0x4EF7, // 价, #140
+ 0x4EFB, // 任, #383
+ 0x4F01, // 企, #439
+ 0x4F18, // 优, #374
+ 0x4F1A, // 会, #29
+ 0x4F20, // 传, #222
+ 0x4F46, // 但, #451
+ 0x4F4D, // 位, #208
+ 0x4F53, // 体, #98
+ 0x4F55, // 何, #339
+ 0x4F5C, // 作, #44
+ 0x4F60, // 你, #76
+ 0x4F7F, // 使, #272
+ 0x4F9B, // 供, #375
+ 0x4FDD, // 保, #180
+ 0x4FE1, // 信, #84
+ 0x4FEE, // 修, #437
+ 0x503C, // 值, #450
+ 0x505A, // 做, #368
+ 0x5065, // 健, #484
+ 0x50CF, // 像, #487
+ 0x513F, // 儿, #326
+ 0x5143, // 元, #202
+ 0x5148, // 先, #485
+ 0x5149, // 光, #254
+ 0x514B, // 克, #503
+ 0x514D, // 免, #349
+ 0x5165, // 入, #156
+ 0x5168, // 全, #47
+ 0x516C, // 公, #35
+ 0x5171, // 共, #448
+ 0x5173, // 关, #49
+ 0x5176, // 其, #195
+ 0x5177, // 具, #329
+ 0x5185, // 内, #109
+ 0x518C, // 册, #225
+ 0x519B, // 军, #466
+ 0x51FA, // 出, #53
+ 0x51FB, // 击, #359
+ 0x5206, // 分, #22
+ 0x5217, // 列, #410
+ 0x521B, // 创, #399
+ 0x5229, // 利, #296
+ 0x522B, // 别, #372
+ 0x5230, // 到, #33
+ 0x5236, // 制, #192
+ 0x524D, // 前, #117
+ 0x529B, // 力, #173
+ 0x529E, // 办, #436
+ 0x529F, // 功, #455
+ 0x52A0, // 加, #97
+ 0x52A1, // 务, #100
+ 0x52A8, // 动, #46
+ 0x52A9, // 助, #365
+ 0x5305, // 包, #331
+ 0x5316, // 化, #155
+ 0x5317, // 北, #194
+ 0x533A, // 区, #105
+ 0x533B, // 医, #234
+ 0x5341, // 十, #294
+ 0x534E, // 华, #205
+ 0x5355, // 单, #259
+ 0x5357, // 南, #182
+ 0x535A, // 博, #153
+ 0x5361, // 卡, #332
+ 0x539F, // 原, #271
+ 0x53BB, // 去, #282
+ 0x53C2, // 参, #500
+ 0x53CA, // 及, #255
+ 0x53CB, // 友, #186
+ 0x53CD, // 反, #422
+ 0x53D1, // 发, #15
+ 0x53D7, // 受, #507
+ 0x53D8, // 变, #395
+ 0x53E3, // 口, #293
+ 0x53EA, // 只, #340
+ 0x53EF, // 可, #45
+ 0x53F0, // 台, #267
+ 0x53F7, // 号, #121
+ 0x53F8, // 司, #150
+ 0x5404, // 各, #491
+ 0x5408, // 合, #115
+ 0x540C, // 同, #189
+ 0x540D, // 名, #127
+ 0x540E, // 后, #75
+ 0x5411, // 向, #459
+ 0x5427, // 吧, #353
+ 0x544A, // 告, #318
+ 0x5458, // 员, #232
+ 0x5468, // 周, #347
+ 0x548C, // 和, #43
+ 0x54C1, // 品, #36
+ 0x5546, // 商, #148
+ 0x5668, // 器, #228
+ 0x56DB, // 四, #352
+ 0x56DE, // 回, #38
+ 0x56E0, // 因, #355
+ 0x56E2, // 团, #412
+ 0x56ED, // 园, #470
+ 0x56FD, // 国, #12
+ 0x56FE, // 图, #32
+ 0x5728, // 在, #10
+ 0x5730, // 地, #30
+ 0x573A, // 场, #177
+ 0x575B, // 坛, #364
+ 0x578B, // 型, #274
+ 0x57CE, // 城, #172
+ 0x57FA, // 基, #315
+ 0x58EB, // 士, #434
+ 0x58F0, // 声, #397
+ 0x5904, // 处, #416
+ 0x5907, // 备, #270
+ 0x590D, // 复, #122
+ 0x5916, // 外, #190
+ 0x591A, // 多, #40
+ 0x5927, // 大, #8
+ 0x5929, // 天, #52
+ 0x592A, // 太, #456
+ 0x5934, // 头, #258
+ 0x5973, // 女, #65
+ 0x597D, // 好, #62
+ 0x5982, // 如, #135
+ 0x5A31, // 娱, #452
+ 0x5B50, // 子, #37
+ 0x5B57, // 字, #285
+ 0x5B66, // 学, #19
+ 0x5B89, // 安, #144
+ 0x5B8C, // 完, #469
+ 0x5B9A, // 定, #179
+ 0x5B9D, // 宝, #188
+ 0x5B9E, // 实, #154
+ 0x5BA2, // 客, #174
+ 0x5BB6, // 家, #26
+ 0x5BB9, // 容, #307
+ 0x5BC6, // 密, #471
+ 0x5BF9, // 对, #90
+ 0x5BFC, // 导, #348
+ 0x5C06, // 将, #265
+ 0x5C0F, // 小, #28
+ 0x5C11, // 少, #379
+ 0x5C14, // 尔, #490
+ 0x5C31, // 就, #101
+ 0x5C55, // 展, #291
+ 0x5C71, // 山, #239
+ 0x5DDE, // 州, #227
+ 0x5DE5, // 工, #73
+ 0x5DF1, // 己, #480
+ 0x5DF2, // 已, #310
+ 0x5E02, // 市, #78
+ 0x5E03, // 布, #350
+ 0x5E08, // 师, #277
+ 0x5E16, // 帖, #396
+ 0x5E26, // 带, #449
+ 0x5E2E, // 帮, #461
+ 0x5E38, // 常, #319
+ 0x5E73, // 平, #217
+ 0x5E74, // 年, #20
+ 0x5E76, // 并, #440
+ 0x5E7F, // 广, #166
+ 0x5E93, // 库, #446
+ 0x5E94, // 应, #187
+ 0x5E97, // 店, #320
+ 0x5EA6, // 度, #114
+ 0x5EB7, // 康, #499
+ 0x5EFA, // 建, #211
+ 0x5F00, // 开, #72
+ 0x5F0F, // 式, #207
+ 0x5F15, // 引, #495
+ 0x5F20, // 张, #385
+ 0x5F3A, // 强, #404
+ 0x5F53, // 当, #233
+ 0x5F55, // 录, #146
+ 0x5F62, // 形, #494
+ 0x5F69, // 彩, #356
+ 0x5F71, // 影, #214
+ 0x5F88, // 很, #300
+ 0x5F97, // 得, #193
+ 0x5FAE, // 微, #245
+ 0x5FC3, // 心, #70
+ 0x5FEB, // 快, #324
+ 0x6001, // 态, #508
+ 0x600E, // 怎, #370
+ 0x6027, // 性, #99
+ 0x603B, // 总, #398
+ 0x606F, // 息, #176
+ 0x60A8, // 您, #251
+ 0x60C5, // 情, #87
+ 0x60F3, // 想, #290
+ 0x610F, // 意, #184
+ 0x611F, // 感, #253
+ 0x620F, // 戏, #237
+ 0x6210, // 成, #71
+ 0x6211, // 我, #11
+ 0x6216, // 或, #321
+ 0x6218, // 战, #369
+ 0x6237, // 户, #215
+ 0x623F, // 房, #236
+ 0x6240, // 所, #147
+ 0x624B, // 手, #55
+ 0x624D, // 才, #407
+ 0x6253, // 打, #281
+ 0x6280, // 技, #203
+ 0x6295, // 投, #408
+ 0x62A4, // 护, #502
+ 0x62A5, // 报, #113
+ 0x62DB, // 招, #363
+ 0x6301, // 持, #403
+ 0x6307, // 指, #414
+ 0x636E, // 据, #409
+ 0x6392, // 排, #377
+ 0x63A5, // 接, #266
+ 0x63A8, // 推, #244
+ 0x63D0, // 提, #181
+ 0x641C, // 搜, #301
+ 0x64AD, // 播, #401
+ 0x652F, // 支, #400
+ 0x6536, // 收, #158
+ 0x653E, // 放, #317
+ 0x653F, // 政, #380
+ 0x6548, // 效, #496
+ 0x6559, // 教, #170
+ 0x6570, // 数, #136
+ 0x6587, // 文, #21
+ 0x6599, // 料, #295
+ 0x65AF, // 斯, #473
+ 0x65B0, // 新, #14
+ 0x65B9, // 方, #68
+ 0x65C5, // 旅, #457
+ 0x65E0, // 无, #164
+ 0x65E5, // 日, #50
+ 0x65F6, // 时, #18
+ 0x660E, // 明, #132
+ 0x6613, // 易, #428
+ 0x661F, // 星, #240
+ 0x662F, // 是, #6
+ 0x663E, // 显, #486
+ 0x66F4, // 更, #103
+ 0x6700, // 最, #61
+ 0x6708, // 月, #80
+ 0x6709, // 有, #5
+ 0x670D, // 服, #94
+ 0x671F, // 期, #139
+ 0x672C, // 本, #56
+ 0x672F, // 术, #216
+ 0x673A, // 机, #27
+ 0x6743, // 权, #250
+ 0x6761, // 条, #309
+ 0x6765, // 来, #42
+ 0x677F, // 板, #505
+ 0x6797, // 林, #475
+ 0x679C, // 果, #212
+ 0x67E5, // 查, #165
+ 0x6807, // 标, #269
+ 0x6821, // 校, #462
+ 0x6837, // 样, #314
+ 0x683C, // 格, #238
+ 0x6848, // 案, #378
+ 0x697C, // 楼, #342
+ 0x6A21, // 模, #413
+ 0x6B21, // 次, #263
+ 0x6B22, // 欢, #443
+ 0x6B3E, // 款, #358
+ 0x6B63, // 正, #219
+ 0x6B64, // 此, #362
+ 0x6BD4, // 比, #298
+ 0x6C11, // 民, #279
+ 0x6C14, // 气, #303
+ 0x6C34, // 水, #163
+ 0x6C42, // 求, #373
+ 0x6C5F, // 江, #336
+ 0x6CA1, // 没, #229
+ 0x6CBB, // 治, #425
+ 0x6CD5, // 法, #85
+ 0x6CE8, // 注, #119
+ 0x6D3B, // 活, #231
+ 0x6D41, // 流, #280
+ 0x6D4B, // 测, #460
+ 0x6D77, // 海, #124
+ 0x6D88, // 消, #415
+ 0x6DF1, // 深, #477
+ 0x6E05, // 清, #311
+ 0x6E38, // 游, #81
+ 0x6E90, // 源, #325
+ 0x706B, // 火, #498
+ 0x70B9, // 点, #58
+ 0x70ED, // 热, #183
+ 0x7136, // 然, #308
+ 0x7167, // 照, #431
+ 0x7231, // 爱, #223
+ 0x7247, // 片, #128
+ 0x7248, // 版, #91
+ 0x724C, // 牌, #429
+ 0x7269, // 物, #169
+ 0x7279, // 特, #224
+ 0x738B, // 王, #351
+ 0x73A9, // 玩, #476
+ 0x73B0, // 现, #125
+ 0x7403, // 球, #367
+ 0x7406, // 理, #69
+ 0x751F, // 生, #24
+ 0x7528, // 用, #17
+ 0x7531, // 由, #441
+ 0x7535, // 电, #34
+ 0x7537, // 男, #275
+ 0x754C, // 界, #419
+ 0x75C5, // 病, #371
+ 0x767B, // 登, #204
+ 0x767D, // 白, #338
+ 0x767E, // 百, #157
+ 0x7684, // 的, #1
+ 0x76D8, // 盘, #493
+ 0x76EE, // 目, #261
+ 0x76F4, // 直, #391
+ 0x76F8, // 相, #143
+ 0x7701, // 省, #464
+ 0x770B, // 看, #54
+ 0x771F, // 真, #249
+ 0x7740, // 着, #302
+ 0x77E5, // 知, #142
+ 0x7801, // 码, #257
+ 0x7814, // 研, #387
+ 0x793A, // 示, #334
+ 0x793E, // 社, #343
+ 0x795E, // 神, #330
+ 0x798F, // 福, #509
+ 0x79BB, // 离, #454
+ 0x79CD, // 种, #278
+ 0x79D1, // 科, #126
+ 0x79EF, // 积, #390
+ 0x7A0B, // 程, #209
+ 0x7A76, // 究, #504
+ 0x7A7A, // 空, #312
+ 0x7ACB, // 立, #393
+ 0x7AD9, // 站, #107
+ 0x7AE0, // 章, #304
+ 0x7B2C, // 第, #96
+ 0x7B49, // 等, #210
+ 0x7B54, // 答, #256
+ 0x7B80, // 简, #474
+ 0x7BA1, // 管, #221
+ 0x7C7B, // 类, #246
+ 0x7CBE, // 精, #226
+ 0x7CFB, // 系, #89
+ 0x7D22, // 索, #354
+ 0x7EA2, // 红, #417
+ 0x7EA7, // 级, #178
+ 0x7EBF, // 线, #108
+ 0x7EC4, // 组, #389
+ 0x7EC6, // 细, #442
+ 0x7ECF, // 经, #74
+ 0x7ED3, // 结, #333
+ 0x7ED9, // 给, #384
+ 0x7EDC, // 络, #472
+ 0x7EDF, // 统, #344
+ 0x7F16, // 编, #424
+ 0x7F51, // 网, #9
+ 0x7F6E, // 置, #411
+ 0x7F8E, // 美, #60
+ 0x8001, // 老, #292
+ 0x8003, // 考, #288
+ 0x8005, // 者, #106
+ 0x800C, // 而, #297
+ 0x8054, // 联, #159
+ 0x80B2, // 育, #327
+ 0x80FD, // 能, #59
+ 0x81EA, // 自, #77
+ 0x8272, // 色, #198
+ 0x8282, // 节, #361
+ 0x82B1, // 花, #299
+ 0x82F1, // 英, #316
+ 0x8350, // 荐, #402
+ 0x836F, // 药, #481
+ 0x8425, // 营, #394
+ 0x85CF, // 藏, #337
+ 0x884C, // 行, #41
+ 0x8868, // 表, #104
+ 0x88AB, // 被, #289
+ 0x88C5, // 装, #161
+ 0x897F, // 西, #199
+ 0x8981, // 要, #48
+ 0x89C1, // 见, #360
+ 0x89C2, // 观, #423
+ 0x89C4, // 规, #453
+ 0x89C6, // 视, #120
+ 0x89E3, // 解, #264
+ 0x8A00, // 言, #433
+ 0x8BA1, // 计, #191
+ 0x8BA4, // 认, #482
+ 0x8BA9, // 让, #421
+ 0x8BAE, // 议, #427
+ 0x8BAF, // 讯, #388
+ 0x8BB0, // 记, #273
+ 0x8BBA, // 论, #66
+ 0x8BBE, // 设, #162
+ 0x8BC1, // 证, #201
+ 0x8BC4, // 评, #111
+ 0x8BC6, // 识, #463
+ 0x8BD5, // 试, #323
+ 0x8BDD, // 话, #247
+ 0x8BE2, // 询, #432
+ 0x8BE5, // 该, #447
+ 0x8BE6, // 详, #497
+ 0x8BED, // 语, #268
+ 0x8BF4, // 说, #112
+ 0x8BF7, // 请, #213
+ 0x8BFB, // 读, #341
+ 0x8C03, // 调, #438
+ 0x8D22, // 财, #488
+ 0x8D28, // 质, #386
+ 0x8D2D, // 购, #260
+ 0x8D34, // 贴, #510
+ 0x8D39, // 费, #242
+ 0x8D44, // 资, #116
+ 0x8D77, // 起, #220
+ 0x8D85, // 超, #406
+ 0x8DEF, // 路, #235
+ 0x8EAB, // 身, #262
+ 0x8F66, // 车, #82
+ 0x8F6C, // 转, #322
+ 0x8F7D, // 载, #175
+ 0x8FBE, // 达, #435
+ 0x8FC7, // 过, #118
+ 0x8FD0, // 运, #357
+ 0x8FD1, // 近, #492
+ 0x8FD8, // 还, #171
+ 0x8FD9, // 这, #57
+ 0x8FDB, // 进, #160
+ 0x8FDE, // 连, #489
+ 0x9009, // 选, #328
+ 0x901A, // 通, #137
+ 0x901F, // 速, #458
+ 0x9020, // 造, #511
+ 0x9053, // 道, #79
+ 0x90A3, // 那, #305
+ 0x90E8, // 部, #102
+ 0x90FD, // 都, #167
+ 0x914D, // 配, #479
+ 0x9152, // 酒, #444
+ 0x91CC, // 里, #196
+ 0x91CD, // 重, #230
+ 0x91CF, // 量, #248
+ 0x91D1, // 金, #134
+ 0x9500, // 销, #465
+ 0x957F, // 长, #152
+ 0x95E8, // 门, #185
+ 0x95EE, // 问, #92
+ 0x95F4, // 间, #88
+ 0x95FB, // 闻, #313
+ 0x9605, // 阅, #467
+ 0x9633, // 阳, #420
+ 0x9645, // 际, #501
+ 0x9650, // 限, #286
+ 0x9662, // 院, #276
+ 0x96C6, // 集, #284
+ 0x9700, // 需, #405
+ 0x9762, // 面, #123
+ 0x97F3, // 音, #335
+ 0x9875, // 页, #63
+ 0x9879, // 项, #506
+ 0x9891, // 频, #200
+ 0x9898, // 题, #110
+ 0x98CE, // 风, #252
+ 0x98DF, // 食, #445
+ 0x9996, // 首, #149
+ 0x9999, // 香, #512
+ 0x9A6C, // 马, #392
+ 0x9A8C, // 验, #382
+ 0x9AD8, // 高, #67
+ 0x9F99, // 龙, #426
+};
+// the percentage of the sample covered by the above characters
+static const float frequent_zhCN_coverage=0.718950369339973;
+
+// The 512 most frequently occuring characters for the zhTW language in a sample of the Internet.
+// Ordered by codepoint, comment shows character and ranking by frequency
+const uint16_t frequent_zhTW[] = {
+ 0x4E00, // 一, #2
+ 0x4E09, // 三, #131
+ 0x4E0A, // 上, #12
+ 0x4E0B, // 下, #37
+ 0x4E0D, // 不, #6
+ 0x4E16, // 世, #312
+ 0x4E26, // 並, #434
+ 0x4E2D, // 中, #9
+ 0x4E3B, // 主, #97
+ 0x4E4B, // 之, #55
+ 0x4E5F, // 也, #95
+ 0x4E86, // 了, #19
+ 0x4E8B, // 事, #128
+ 0x4E8C, // 二, #187
+ 0x4E94, // 五, #339
+ 0x4E9B, // 些, #435
+ 0x4E9E, // 亞, #432
+ 0x4EA4, // 交, #264
+ 0x4EAB, // 享, #160
+ 0x4EBA, // 人, #3
+ 0x4EC0, // 什, #483
+ 0x4ECA, // 今, #380
+ 0x4ECB, // 介, #468
+ 0x4ED6, // 他, #65
+ 0x4EE3, // 代, #284
+ 0x4EE5, // 以, #26
+ 0x4EF6, // 件, #234
+ 0x4EFB, // 任, #381
+ 0x4EFD, // 份, #447
+ 0x4F46, // 但, #281
+ 0x4F4D, // 位, #202
+ 0x4F4F, // 住, #471
+ 0x4F55, // 何, #334
+ 0x4F5C, // 作, #56
+ 0x4F60, // 你, #64
+ 0x4F7F, // 使, #236
+ 0x4F86, // 來, #38
+ 0x4F9B, // 供, #397
+ 0x4FBF, // 便, #440
+ 0x4FC2, // 係, #506
+ 0x4FDD, // 保, #161
+ 0x4FE1, // 信, #268
+ 0x4FEE, // 修, #473
+ 0x500B, // 個, #27
+ 0x5011, // 們, #109
+ 0x505A, // 做, #383
+ 0x5065, // 健, #415
+ 0x5099, // 備, #461
+ 0x50B3, // 傳, #277
+ 0x50CF, // 像, #403
+ 0x50F9, // 價, #93
+ 0x512A, // 優, #396
+ 0x5143, // 元, #158
+ 0x5148, // 先, #382
+ 0x5149, // 光, #216
+ 0x514D, // 免, #321
+ 0x5152, // 兒, #374
+ 0x5165, // 入, #58
+ 0x5167, // 內, #106
+ 0x5168, // 全, #67
+ 0x5169, // 兩, #322
+ 0x516C, // 公, #53
+ 0x516D, // 六, #493
+ 0x5171, // 共, #456
+ 0x5176, // 其, #148
+ 0x5177, // 具, #328
+ 0x518A, // 冊, #360
+ 0x518D, // 再, #311
+ 0x51FA, // 出, #44
+ 0x5206, // 分, #15
+ 0x5217, // 列, #259
+ 0x5225, // 別, #361
+ 0x5229, // 利, #251
+ 0x5230, // 到, #29
+ 0x5247, // 則, #511
+ 0x524D, // 前, #82
+ 0x5275, // 創, #409
+ 0x529B, // 力, #176
+ 0x529F, // 功, #430
+ 0x52A0, // 加, #87
+ 0x52A9, // 助, #465
+ 0x52D5, // 動, #48
+ 0x52D9, // 務, #102
+ 0x5305, // 包, #248
+ 0x5316, // 化, #223
+ 0x5317, // 北, #145
+ 0x5340, // 區, #60
+ 0x5341, // 十, #242
+ 0x5357, // 南, #261
+ 0x535A, // 博, #484
+ 0x5361, // 卡, #327
+ 0x5370, // 印, #498
+ 0x5373, // 即, #351
+ 0x539F, // 原, #237
+ 0x53BB, // 去, #190
+ 0x53C3, // 參, #444
+ 0x53C8, // 又, #426
+ 0x53CA, // 及, #136
+ 0x53CB, // 友, #142
+ 0x53D6, // 取, #422
+ 0x53D7, // 受, #410
+ 0x53E3, // 口, #357
+ 0x53EA, // 只, #250
+ 0x53EF, // 可, #35
+ 0x53F0, // 台, #34
+ 0x53F8, // 司, #226
+ 0x5403, // 吃, #362
+ 0x5404, // 各, #454
+ 0x5408, // 合, #147
+ 0x540C, // 同, #173
+ 0x540D, // 名, #108
+ 0x544A, // 告, #186
+ 0x548C, // 和, #130
+ 0x54C1, // 品, #23
+ 0x54E1, // 員, #150
+ 0x5546, // 商, #75
+ 0x554F, // 問, #120
+ 0x559C, // 喜, #502
+ 0x55AE, // 單, #210
+ 0x55CE, // 嗎, #443
+ 0x5668, // 器, #305
+ 0x56DB, // 四, #318
+ 0x56DE, // 回, #59
+ 0x56E0, // 因, #253
+ 0x570B, // 國, #21
+ 0x5712, // 園, #345
+ 0x5716, // 圖, #73
+ 0x5718, // 團, #338
+ 0x5728, // 在, #11
+ 0x5730, // 地, #50
+ 0x578B, // 型, #270
+ 0x57CE, // 城, #466
+ 0x57FA, // 基, #349
+ 0x5831, // 報, #127
+ 0x5834, // 場, #165
+ 0x58EB, // 士, #372
+ 0x5916, // 外, #152
+ 0x591A, // 多, #54
+ 0x5927, // 大, #8
+ 0x5929, // 天, #43
+ 0x592A, // 太, #343
+ 0x5947, // 奇, #325
+ 0x5973, // 女, #85
+ 0x5979, // 她, #420
+ 0x597D, // 好, #22
+ 0x5982, // 如, #144
+ 0x5B50, // 子, #46
+ 0x5B57, // 字, #275
+ 0x5B78, // 學, #49
+ 0x5B89, // 安, #239
+ 0x5B8C, // 完, #320
+ 0x5B9A, // 定, #159
+ 0x5BA2, // 客, #188
+ 0x5BB6, // 家, #31
+ 0x5BB9, // 容, #244
+ 0x5BE6, // 實, #198
+ 0x5BF6, // 寶, #367
+ 0x5C07, // 將, #232
+ 0x5C08, // 專, #133
+ 0x5C0B, // 尋, #352
+ 0x5C0D, // 對, #126
+ 0x5C0E, // 導, #418
+ 0x5C0F, // 小, #20
+ 0x5C11, // 少, #368
+ 0x5C31, // 就, #63
+ 0x5C55, // 展, #341
+ 0x5C71, // 山, #273
+ 0x5DE5, // 工, #121
+ 0x5DF1, // 己, #402
+ 0x5DF2, // 已, #299
+ 0x5E02, // 市, #81
+ 0x5E2B, // 師, #262
+ 0x5E36, // 帶, #470
+ 0x5E38, // 常, #303
+ 0x5E73, // 平, #297
+ 0x5E74, // 年, #30
+ 0x5E97, // 店, #171
+ 0x5EA6, // 度, #220
+ 0x5EB7, // 康, #441
+ 0x5EE3, // 廣, #279
+ 0x5EFA, // 建, #254
+ 0x5F0F, // 式, #155
+ 0x5F15, // 引, #346
+ 0x5F35, // 張, #366
+ 0x5F37, // 強, #437
+ 0x5F71, // 影, #94
+ 0x5F88, // 很, #177
+ 0x5F8C, // 後, #66
+ 0x5F97, // 得, #113
+ 0x5F9E, // 從, #436
+ 0x5FC3, // 心, #57
+ 0x5FEB, // 快, #292
+ 0x6027, // 性, #175
+ 0x606F, // 息, #378
+ 0x60A8, // 您, #252
+ 0x60C5, // 情, #123
+ 0x60F3, // 想, #178
+ 0x610F, // 意, #168
+ 0x611B, // 愛, #125
+ 0x611F, // 感, #211
+ 0x61C9, // 應, #164
+ 0x6210, // 成, #86
+ 0x6211, // 我, #7
+ 0x6216, // 或, #199
+ 0x6230, // 戰, #438
+ 0x6232, // 戲, #309
+ 0x6236, // 戶, #497
+ 0x623F, // 房, #274
+ 0x6240, // 所, #79
+ 0x624B, // 手, #68
+ 0x624D, // 才, #400
+ 0x6253, // 打, #278
+ 0x627E, // 找, #449
+ 0x6280, // 技, #332
+ 0x6295, // 投, #425
+ 0x62C9, // 拉, #500
+ 0x62CD, // 拍, #398
+ 0x6307, // 指, #407
+ 0x6392, // 排, #458
+ 0x63A5, // 接, #326
+ 0x63A8, // 推, #153
+ 0x63D0, // 提, #235
+ 0x641C, // 搜, #314
+ 0x6469, // 摩, #472
+ 0x6536, // 收, #249
+ 0x6539, // 改, #508
+ 0x653E, // 放, #331
+ 0x653F, // 政, #295
+ 0x6559, // 教, #184
+ 0x6574, // 整, #394
+ 0x6578, // 數, #134
+ 0x6587, // 文, #16
+ 0x6599, // 料, #167
+ 0x65AF, // 斯, #476
+ 0x65B0, // 新, #10
+ 0x65B9, // 方, #96
+ 0x65BC, // 於, #70
+ 0x65C5, // 旅, #289
+ 0x65E5, // 日, #18
+ 0x660E, // 明, #118
+ 0x6613, // 易, #482
+ 0x661F, // 星, #205
+ 0x662F, // 是, #5
+ 0x6642, // 時, #13
+ 0x66F4, // 更, #149
+ 0x66F8, // 書, #209
+ 0x6700, // 最, #51
+ 0x6703, // 會, #14
+ 0x6708, // 月, #25
+ 0x6709, // 有, #4
+ 0x670D, // 服, #99
+ 0x671F, // 期, #139
+ 0x672A, // 未, #404
+ 0x672C, // 本, #45
+ 0x6771, // 東, #221
+ 0x677F, // 板, #364
+ 0x6797, // 林, #330
+ 0x679C, // 果, #179
+ 0x67E5, // 查, #283
+ 0x683C, // 格, #157
+ 0x6848, // 案, #392
+ 0x689D, // 條, #406
+ 0x696D, // 業, #103
+ 0x6A02, // 樂, #116
+ 0x6A13, // 樓, #411
+ 0x6A19, // 標, #384
+ 0x6A23, // 樣, #306
+ 0x6A5F, // 機, #40
+ 0x6AA2, // 檢, #359
+ 0x6B0A, // 權, #228
+ 0x6B21, // 次, #227
+ 0x6B3E, // 款, #276
+ 0x6B4C, // 歌, #496
+ 0x6B61, // 歡, #427
+ 0x6B63, // 正, #206
+ 0x6B64, // 此, #247
+ 0x6BCF, // 每, #391
+ 0x6BD4, // 比, #257
+ 0x6C11, // 民, #230
+ 0x6C23, // 氣, #200
+ 0x6C34, // 水, #140
+ 0x6C42, // 求, #501
+ 0x6C92, // 沒, #162
+ 0x6CD5, // 法, #89
+ 0x6D3B, // 活, #124
+ 0x6D41, // 流, #315
+ 0x6D77, // 海, #258
+ 0x6D88, // 消, #342
+ 0x6E05, // 清, #329
+ 0x6E2F, // 港, #293
+ 0x6F14, // 演, #491
+ 0x7063, // 灣, #195
+ 0x70BA, // 為, #39
+ 0x7121, // 無, #107
+ 0x7136, // 然, #215
+ 0x7167, // 照, #376
+ 0x71B1, // 熱, #245
+ 0x7247, // 片, #90
+ 0x7248, // 版, #112
+ 0x724C, // 牌, #467
+ 0x7269, // 物, #110
+ 0x7279, // 特, #183
+ 0x738B, // 王, #287
+ 0x73A9, // 玩, #354
+ 0x73FE, // 現, #143
+ 0x7403, // 球, #350
+ 0x7406, // 理, #105
+ 0x751F, // 生, #24
+ 0x7522, // 產, #201
+ 0x7528, // 用, #17
+ 0x7531, // 由, #288
+ 0x7537, // 男, #298
+ 0x754C, // 界, #399
+ 0x7559, // 留, #218
+ 0x756B, // 畫, #412
+ 0x7576, // 當, #185
+ 0x767B, // 登, #138
+ 0x767C, // 發, #28
+ 0x767D, // 白, #377
+ 0x767E, // 百, #393
+ 0x7684, // 的, #1
+ 0x76EE, // 目, #271
+ 0x76F4, // 直, #379
+ 0x76F8, // 相, #98
+ 0x770B, // 看, #52
+ 0x771F, // 真, #180
+ 0x773C, // 眼, #433
+ 0x77E5, // 知, #170
+ 0x78BC, // 碼, #481
+ 0x793A, // 示, #353
+ 0x793E, // 社, #333
+ 0x795E, // 神, #304
+ 0x7968, // 票, #477
+ 0x798F, // 福, #494
+ 0x79C1, // 私, #507
+ 0x79D1, // 科, #280
+ 0x7A0B, // 程, #272
+ 0x7A2E, // 種, #337
+ 0x7A4D, // 積, #385
+ 0x7A7A, // 空, #324
+ 0x7ACB, // 立, #286
+ 0x7AD9, // 站, #117
+ 0x7AE0, // 章, #141
+ 0x7B2C, // 第, #135
+ 0x7B49, // 等, #240
+ 0x7BA1, // 管, #340
+ 0x7BC0, // 節, #431
+ 0x7BC7, // 篇, #479
+ 0x7C21, // 簡, #499
+ 0x7CBE, // 精, #213
+ 0x7CFB, // 系, #212
+ 0x7D04, // 約, #462
+ 0x7D05, // 紅, #452
+ 0x7D1A, // 級, #267
+ 0x7D30, // 細, #486
+ 0x7D44, // 組, #335
+ 0x7D50, // 結, #243
+ 0x7D66, // 給, #355
+ 0x7D71, // 統, #375
+ 0x7D93, // 經, #111
+ 0x7DB2, // 網, #32
+ 0x7DDA, // 線, #151
+ 0x7E23, // 縣, #439
+ 0x7E3D, // 總, #370
+ 0x7F8E, // 美, #41
+ 0x7FA9, // 義, #504
+ 0x8001, // 老, #290
+ 0x8003, // 考, #428
+ 0x8005, // 者, #92
+ 0x800C, // 而, #217
+ 0x805E, // 聞, #181
+ 0x806F, // 聯, #310
+ 0x8072, // 聲, #413
+ 0x80A1, // 股, #390
+ 0x80B2, // 育, #453
+ 0x80FD, // 能, #71
+ 0x8166, // 腦, #408
+ 0x81EA, // 自, #61
+ 0x81F3, // 至, #344
+ 0x8207, // 與, #84
+ 0x8209, // 舉, #463
+ 0x8272, // 色, #192
+ 0x82B1, // 花, #255
+ 0x82F1, // 英, #348
+ 0x83EF, // 華, #196
+ 0x842C, // 萬, #316
+ 0x843D, // 落, #308
+ 0x8457, // 著, #233
+ 0x85A6, // 薦, #401
+ 0x85CF, // 藏, #503
+ 0x85DD, // 藝, #488
+ 0x8655, // 處, #419
+ 0x865F, // 號, #191
+ 0x884C, // 行, #47
+ 0x8853, // 術, #395
+ 0x8868, // 表, #77
+ 0x88AB, // 被, #291
+ 0x88DD, // 裝, #256
+ 0x88E1, // 裡, #369
+ 0x88FD, // 製, #510
+ 0x897F, // 西, #300
+ 0x8981, // 要, #36
+ 0x898B, // 見, #307
+ 0x8996, // 視, #204
+ 0x89BA, // 覺, #450
+ 0x89BD, // 覽, #387
+ 0x89C0, // 觀, #365
+ 0x89E3, // 解, #323
+ 0x8A00, // 言, #169
+ 0x8A02, // 訂, #423
+ 0x8A08, // 計, #225
+ 0x8A0A, // 訊, #156
+ 0x8A0E, // 討, #373
+ 0x8A18, // 記, #222
+ 0x8A2D, // 設, #174
+ 0x8A3B, // 註, #356
+ 0x8A55, // 評, #246
+ 0x8A66, // 試, #448
+ 0x8A71, // 話, #229
+ 0x8A72, // 該, #446
+ 0x8A8D, // 認, #464
+ 0x8A9E, // 語, #371
+ 0x8AAA, // 說, #91
+ 0x8ABF, // 調, #509
+ 0x8ACB, // 請, #119
+ 0x8AD6, // 論, #114
+ 0x8B1D, // 謝, #389
+ 0x8B49, // 證, #429
+ 0x8B58, // 識, #416
+ 0x8B70, // 議, #485
+ 0x8B77, // 護, #475
+ 0x8B80, // 讀, #386
+ 0x8B8A, // 變, #388
+ 0x8B93, // 讓, #336
+ 0x8CA8, // 貨, #313
+ 0x8CB7, // 買, #260
+ 0x8CBB, // 費, #203
+ 0x8CC7, // 資, #62
+ 0x8CE3, // 賣, #294
+ 0x8CEA, // 質, #457
+ 0x8CFC, // 購, #189
+ 0x8D77, // 起, #214
+ 0x8D85, // 超, #296
+ 0x8DDF, // 跟, #489
+ 0x8DEF, // 路, #137
+ 0x8EAB, // 身, #197
+ 0x8ECA, // 車, #76
+ 0x8F09, // 載, #301
+ 0x8F49, // 轉, #282
+ 0x8FD1, // 近, #414
+ 0x9001, // 送, #363
+ 0x9019, // 這, #42
+ 0x901A, // 通, #207
+ 0x901F, // 速, #495
+ 0x9020, // 造, #455
+ 0x9023, // 連, #285
+ 0x9032, // 進, #231
+ 0x904A, // 遊, #132
+ 0x904B, // 運, #219
+ 0x904E, // 過, #101
+ 0x9053, // 道, #146
+ 0x9054, // 達, #417
+ 0x9078, // 選, #182
+ 0x9084, // 還, #154
+ 0x908A, // 邊, #487
+ 0x90A3, // 那, #269
+ 0x90E8, // 部, #78
+ 0x90FD, // 都, #104
+ 0x914D, // 配, #421
+ 0x9152, // 酒, #512
+ 0x91AB, // 醫, #358
+ 0x91CD, // 重, #224
+ 0x91CF, // 量, #319
+ 0x91D1, // 金, #115
+ 0x9304, // 錄, #302
+ 0x9577, // 長, #172
+ 0x9580, // 門, #193
+ 0x958B, // 開, #72
+ 0x9593, // 間, #80
+ 0x95B1, // 閱, #405
+ 0x95DC, // 關, #74
+ 0x963F, // 阿, #460
+ 0x9650, // 限, #265
+ 0x9662, // 院, #474
+ 0x9664, // 除, #478
+ 0x969B, // 際, #459
+ 0x96C6, // 集, #347
+ 0x96E2, // 離, #442
+ 0x96FB, // 電, #33
+ 0x9700, // 需, #445
+ 0x975E, // 非, #451
+ 0x9762, // 面, #129
+ 0x97F3, // 音, #194
+ 0x9801, // 頁, #83
+ 0x982D, // 頭, #238
+ 0x984C, // 題, #122
+ 0x985E, // 類, #163
+ 0x98A8, // 風, #266
+ 0x98DF, // 食, #208
+ 0x9910, // 餐, #469
+ 0x9928, // 館, #424
+ 0x9996, // 首, #166
+ 0x9999, // 香, #263
+ 0x99AC, // 馬, #317
+ 0x9A57, // 驗, #492
+ 0x9AD4, // 體, #100
+ 0x9AD8, // 高, #88
+ 0x9EBC, // 麼, #241
+ 0x9EC3, // 黃, #480
+ 0x9ED1, // 黑, #490
+ 0x9EDE, // 點, #69
+ 0x9F8D, // 龍, #505
+};
+// the percentage of the sample covered by the above characters
+static const float frequent_zhTW_coverage=0.704841200026877;
+
+// The 512 most frequently occuring characters for the ja language in a sample of the Internet.
+// Ordered by codepoint, comment shows character and ranking by frequency
+const uint16_t frequent_ja[] = {
+ 0x3005, // 々, #352
+ 0x3041, // ぁ, #486
+ 0x3042, // あ, #50
+ 0x3044, // い, #2
+ 0x3046, // う, #33
+ 0x3048, // え, #83
+ 0x304A, // お, #37
+ 0x304B, // か, #21
+ 0x304C, // が, #17
+ 0x304D, // き, #51
+ 0x304E, // ぎ, #324
+ 0x304F, // く, #38
+ 0x3050, // ぐ, #334
+ 0x3051, // け, #60
+ 0x3052, // げ, #296
+ 0x3053, // こ, #34
+ 0x3054, // ご, #100
+ 0x3055, // さ, #31
+ 0x3056, // ざ, #378
+ 0x3057, // し, #4
+ 0x3058, // じ, #121
+ 0x3059, // す, #12
+ 0x305A, // ず, #215
+ 0x305B, // せ, #86
+ 0x305D, // そ, #68
+ 0x305F, // た, #11
+ 0x3060, // だ, #42
+ 0x3061, // ち, #67
+ 0x3063, // っ, #23
+ 0x3064, // つ, #73
+ 0x3066, // て, #7
+ 0x3067, // で, #6
+ 0x3068, // と, #14
+ 0x3069, // ど, #75
+ 0x306A, // な, #8
+ 0x306B, // に, #5
+ 0x306D, // ね, #123
+ 0x306E, // の, #1
+ 0x306F, // は, #16
+ 0x3070, // ば, #150
+ 0x3071, // ぱ, #259
+ 0x3072, // ひ, #364
+ 0x3073, // び, #266
+ 0x3075, // ふ, #484
+ 0x3076, // ぶ, #330
+ 0x3078, // へ, #146
+ 0x3079, // べ, #207
+ 0x307B, // ほ, #254
+ 0x307E, // ま, #18
+ 0x307F, // み, #74
+ 0x3080, // む, #285
+ 0x3081, // め, #78
+ 0x3082, // も, #32
+ 0x3083, // ゃ, #111
+ 0x3084, // や, #85
+ 0x3086, // ゆ, #392
+ 0x3087, // ょ, #224
+ 0x3088, // よ, #63
+ 0x3089, // ら, #29
+ 0x308A, // り, #28
+ 0x308B, // る, #9
+ 0x308C, // れ, #35
+ 0x308D, // ろ, #127
+ 0x308F, // わ, #88
+ 0x3092, // を, #19
+ 0x3093, // ん, #22
+ 0x30A1, // ァ, #193
+ 0x30A2, // ア, #27
+ 0x30A3, // ィ, #70
+ 0x30A4, // イ, #15
+ 0x30A6, // ウ, #89
+ 0x30A7, // ェ, #134
+ 0x30A8, // エ, #81
+ 0x30A9, // ォ, #225
+ 0x30AA, // オ, #76
+ 0x30AB, // カ, #52
+ 0x30AC, // ガ, #147
+ 0x30AD, // キ, #66
+ 0x30AE, // ギ, #246
+ 0x30AF, // ク, #25
+ 0x30B0, // グ, #39
+ 0x30B1, // ケ, #137
+ 0x30B2, // ゲ, #200
+ 0x30B3, // コ, #46
+ 0x30B4, // ゴ, #183
+ 0x30B5, // サ, #64
+ 0x30B6, // ザ, #221
+ 0x30B7, // シ, #48
+ 0x30B8, // ジ, #55
+ 0x30B9, // ス, #13
+ 0x30BA, // ズ, #103
+ 0x30BB, // セ, #109
+ 0x30BC, // ゼ, #499
+ 0x30BD, // ソ, #175
+ 0x30BF, // タ, #45
+ 0x30C0, // ダ, #104
+ 0x30C1, // チ, #71
+ 0x30C3, // ッ, #20
+ 0x30C4, // ツ, #119
+ 0x30C6, // テ, #59
+ 0x30C7, // デ, #82
+ 0x30C8, // ト, #10
+ 0x30C9, // ド, #44
+ 0x30CA, // ナ, #102
+ 0x30CB, // ニ, #72
+ 0x30CD, // ネ, #117
+ 0x30CE, // ノ, #192
+ 0x30CF, // ハ, #164
+ 0x30D0, // バ, #62
+ 0x30D1, // パ, #90
+ 0x30D2, // ヒ, #398
+ 0x30D3, // ビ, #77
+ 0x30D4, // ピ, #135
+ 0x30D5, // フ, #47
+ 0x30D6, // ブ, #56
+ 0x30D7, // プ, #43
+ 0x30D8, // ヘ, #268
+ 0x30D9, // ベ, #157
+ 0x30DA, // ペ, #125
+ 0x30DB, // ホ, #155
+ 0x30DC, // ボ, #168
+ 0x30DD, // ポ, #114
+ 0x30DE, // マ, #57
+ 0x30DF, // ミ, #97
+ 0x30E0, // ム, #69
+ 0x30E1, // メ, #53
+ 0x30E2, // モ, #142
+ 0x30E3, // ャ, #93
+ 0x30E4, // ヤ, #258
+ 0x30E5, // ュ, #79
+ 0x30E6, // ユ, #405
+ 0x30E7, // ョ, #98
+ 0x30E9, // ラ, #26
+ 0x30EA, // リ, #30
+ 0x30EB, // ル, #24
+ 0x30EC, // レ, #41
+ 0x30ED, // ロ, #40
+ 0x30EF, // ワ, #144
+ 0x30F3, // ン, #3
+ 0x30F4, // ヴ, #483
+ 0x30FD, // ヽ, #501
+ 0x4E00, // 一, #84
+ 0x4E07, // 万, #337
+ 0x4E09, // 三, #323
+ 0x4E0A, // 上, #133
+ 0x4E0B, // 下, #180
+ 0x4E0D, // 不, #277
+ 0x4E16, // 世, #385
+ 0x4E2D, // 中, #87
+ 0x4E3B, // 主, #432
+ 0x4E88, // 予, #326
+ 0x4E8B, // 事, #95
+ 0x4E8C, // 二, #394
+ 0x4E95, // 井, #468
+ 0x4EA4, // 交, #410
+ 0x4EAC, // 京, #260
+ 0x4EBA, // 人, #61
+ 0x4ECA, // 今, #184
+ 0x4ECB, // 介, #358
+ 0x4ED5, // 仕, #391
+ 0x4ED6, // 他, #256
+ 0x4ED8, // 付, #243
+ 0x4EE3, // 代, #280
+ 0x4EE5, // 以, #216
+ 0x4EF6, // 件, #190
+ 0x4F1A, // 会, #105
+ 0x4F4D, // 位, #177
+ 0x4F4F, // 住, #376
+ 0x4F53, // 体, #223
+ 0x4F55, // 何, #294
+ 0x4F5C, // 作, #154
+ 0x4F7F, // 使, #233
+ 0x4F9B, // 供, #503
+ 0x4FA1, // 価, #217
+ 0x4FBF, // 便, #511
+ 0x4FDD, // 保, #279
+ 0x4FE1, // 信, #271
+ 0x500B, // 個, #415
+ 0x50CF, // 像, #178
+ 0x512A, // 優, #403
+ 0x5143, // 元, #384
+ 0x5148, // 先, #311
+ 0x5149, // 光, #488
+ 0x5165, // 入, #115
+ 0x5168, // 全, #173
+ 0x516C, // 公, #287
+ 0x5177, // 具, #447
+ 0x5185, // 内, #169
+ 0x5186, // 円, #131
+ 0x5199, // 写, #275
+ 0x51FA, // 出, #110
+ 0x5206, // 分, #130
+ 0x5207, // 切, #401
+ 0x521D, // 初, #319
+ 0x5225, // 別, #290
+ 0x5229, // 利, #226
+ 0x5236, // 制, #507
+ 0x524D, // 前, #124
+ 0x529B, // 力, #272
+ 0x52A0, // 加, #249
+ 0x52D5, // 動, #120
+ 0x52D9, // 務, #421
+ 0x52DF, // 募, #476
+ 0x5316, // 化, #308
+ 0x5317, // 北, #341
+ 0x533A, // 区, #348
+ 0x539F, // 原, #321
+ 0x53C2, // 参, #452
+ 0x53CB, // 友, #451
+ 0x53D6, // 取, #237
+ 0x53D7, // 受, #354
+ 0x53E3, // 口, #289
+ 0x53E4, // 古, #339
+ 0x53EF, // 可, #298
+ 0x53F0, // 台, #439
+ 0x53F7, // 号, #361
+ 0x5408, // 合, #118
+ 0x540C, // 同, #263
+ 0x540D, // 名, #65
+ 0x5411, // 向, #434
+ 0x544A, // 告, #386
+ 0x5468, // 周, #393
+ 0x5473, // 味, #299
+ 0x548C, // 和, #350
+ 0x54C1, // 品, #96
+ 0x54E1, // 員, #293
+ 0x5546, // 商, #198
+ 0x554F, // 問, #158
+ 0x55B6, // 営, #438
+ 0x5668, // 器, #366
+ 0x56DE, // 回, #143
+ 0x56F3, // 図, #444
+ 0x56FD, // 国, #153
+ 0x5712, // 園, #435
+ 0x571F, // 土, #239
+ 0x5728, // 在, #351
+ 0x5730, // 地, #163
+ 0x578B, // 型, #430
+ 0x5831, // 報, #112
+ 0x5834, // 場, #139
+ 0x58F2, // 売, #232
+ 0x5909, // 変, #306
+ 0x5916, // 外, #222
+ 0x591A, // 多, #336
+ 0x5927, // 大, #80
+ 0x5929, // 天, #278
+ 0x5973, // 女, #161
+ 0x597D, // 好, #349
+ 0x5A5A, // 婚, #479
+ 0x5B50, // 子, #113
+ 0x5B57, // 字, #492
+ 0x5B66, // 学, #132
+ 0x5B89, // 安, #295
+ 0x5B9A, // 定, #145
+ 0x5B9F, // 実, #220
+ 0x5BA4, // 室, #482
+ 0x5BAE, // 宮, #487
+ 0x5BB6, // 家, #211
+ 0x5BB9, // 容, #333
+ 0x5BFE, // 対, #252
+ 0x5C02, // 専, #474
+ 0x5C0F, // 小, #212
+ 0x5C11, // 少, #377
+ 0x5C4B, // 屋, #284
+ 0x5C71, // 山, #206
+ 0x5CA1, // 岡, #429
+ 0x5CF6, // 島, #297
+ 0x5DDD, // 川, #253
+ 0x5DE5, // 工, #374
+ 0x5E02, // 市, #159
+ 0x5E2F, // 帯, #416
+ 0x5E38, // 常, #437
+ 0x5E73, // 平, #390
+ 0x5E74, // 年, #54
+ 0x5E83, // 広, #367
+ 0x5E97, // 店, #149
+ 0x5EA6, // 度, #269
+ 0x5EAB, // 庫, #380
+ 0x5F0F, // 式, #265
+ 0x5F15, // 引, #345
+ 0x5F37, // 強, #446
+ 0x5F53, // 当, #240
+ 0x5F62, // 形, #502
+ 0x5F8C, // 後, #230
+ 0x5F97, // 得, #490
+ 0x5FC3, // 心, #307
+ 0x5FC5, // 必, #422
+ 0x5FDC, // 応, #356
+ 0x601D, // 思, #189
+ 0x6027, // 性, #201
+ 0x6075, // 恵, #400
+ 0x60C5, // 情, #140
+ 0x60F3, // 想, #477
+ 0x610F, // 意, #305
+ 0x611B, // 愛, #273
+ 0x611F, // 感, #257
+ 0x6210, // 成, #262
+ 0x6226, // 戦, #365
+ 0x6240, // 所, #236
+ 0x624B, // 手, #160
+ 0x6295, // 投, #129
+ 0x6301, // 持, #355
+ 0x6307, // 指, #425
+ 0x63A2, // 探, #369
+ 0x63B2, // 掲, #399
+ 0x643A, // 携, #459
+ 0x652F, // 支, #512
+ 0x653E, // 放, #469
+ 0x6559, // 教, #270
+ 0x6570, // 数, #181
+ 0x6587, // 文, #202
+ 0x6599, // 料, #106
+ 0x65B0, // 新, #99
+ 0x65B9, // 方, #126
+ 0x65C5, // 旅, #445
+ 0x65E5, // 日, #36
+ 0x660E, // 明, #300
+ 0x6620, // 映, #418
+ 0x6642, // 時, #107
+ 0x66F4, // 更, #359
+ 0x66F8, // 書, #174
+ 0x6700, // 最, #152
+ 0x6708, // 月, #49
+ 0x6709, // 有, #302
+ 0x671F, // 期, #332
+ 0x6728, // 木, #203
+ 0x672C, // 本, #92
+ 0x6750, // 材, #489
+ 0x6751, // 村, #466
+ 0x6765, // 来, #267
+ 0x6771, // 東, #191
+ 0x677F, // 板, #411
+ 0x679C, // 果, #441
+ 0x6821, // 校, #327
+ 0x682A, // 株, #412
+ 0x683C, // 格, #228
+ 0x691C, // 検, #179
+ 0x696D, // 業, #166
+ 0x697D, // 楽, #172
+ 0x69D8, // 様, #255
+ 0x6A5F, // 機, #235
+ 0x6B21, // 次, #318
+ 0x6B62, // 止, #475
+ 0x6B63, // 正, #312
+ 0x6C17, // 気, #116
+ 0x6C34, // 水, #165
+ 0x6C42, // 求, #465
+ 0x6C7A, // 決, #370
+ 0x6CBB, // 治, #505
+ 0x6CC1, // 況, #462
+ 0x6CD5, // 法, #227
+ 0x6CE8, // 注, #372
+ 0x6D3B, // 活, #303
+ 0x6D41, // 流, #480
+ 0x6D77, // 海, #274
+ 0x6E08, // 済, #417
+ 0x6F14, // 演, #504
+ 0x706B, // 火, #264
+ 0x70B9, // 点, #331
+ 0x7121, // 無, #58
+ 0x7248, // 版, #409
+ 0x7269, // 物, #170
+ 0x7279, // 特, #242
+ 0x72B6, // 状, #458
+ 0x73FE, // 現, #322
+ 0x7406, // 理, #162
+ 0x751F, // 生, #122
+ 0x7523, // 産, #320
+ 0x7528, // 用, #94
+ 0x7530, // 田, #195
+ 0x7537, // 男, #373
+ 0x753A, // 町, #314
+ 0x753B, // 画, #91
+ 0x754C, // 界, #436
+ 0x756A, // 番, #261
+ 0x75C5, // 病, #428
+ 0x767A, // 発, #194
+ 0x767B, // 登, #231
+ 0x767D, // 白, #419
+ 0x7684, // 的, #251
+ 0x76EE, // 目, #197
+ 0x76F4, // 直, #497
+ 0x76F8, // 相, #286
+ 0x770C, // 県, #199
+ 0x771F, // 真, #219
+ 0x7740, // 着, #283
+ 0x77E5, // 知, #185
+ 0x77F3, // 石, #500
+ 0x78BA, // 確, #383
+ 0x793A, // 示, #241
+ 0x793E, // 社, #167
+ 0x795E, // 神, #315
+ 0x798F, // 福, #423
+ 0x79C1, // 私, #347
+ 0x79D1, // 科, #420
+ 0x7A0E, // 税, #368
+ 0x7A2E, // 種, #455
+ 0x7A3F, // 稿, #148
+ 0x7A7A, // 空, #427
+ 0x7ACB, // 立, #309
+ 0x7B11, // 笑, #454
+ 0x7B2C, // 第, #317
+ 0x7B49, // 等, #457
+ 0x7B54, // 答, #426
+ 0x7BA1, // 管, #481
+ 0x7CFB, // 系, #408
+ 0x7D04, // 約, #276
+ 0x7D20, // 素, #407
+ 0x7D22, // 索, #214
+ 0x7D30, // 細, #381
+ 0x7D39, // 紹, #471
+ 0x7D42, // 終, #456
+ 0x7D44, // 組, #424
+ 0x7D4C, // 経, #360
+ 0x7D50, // 結, #291
+ 0x7D9A, // 続, #357
+ 0x7DCF, // 総, #467
+ 0x7DDA, // 線, #338
+ 0x7DE8, // 編, #453
+ 0x7F8E, // 美, #204
+ 0x8003, // 考, #387
+ 0x8005, // 者, #151
+ 0x805E, // 聞, #463
+ 0x8077, // 職, #363
+ 0x80B2, // 育, #433
+ 0x80FD, // 能, #250
+ 0x8179, // 腹, #396
+ 0x81EA, // 自, #156
+ 0x826F, // 良, #329
+ 0x8272, // 色, #402
+ 0x82B1, // 花, #440
+ 0x82B8, // 芸, #413
+ 0x82F1, // 英, #485
+ 0x8449, // 葉, #472
+ 0x884C, // 行, #128
+ 0x8853, // 術, #460
+ 0x8868, // 表, #209
+ 0x88FD, // 製, #431
+ 0x897F, // 西, #406
+ 0x8981, // 要, #313
+ 0x898B, // 見, #101
+ 0x898F, // 規, #375
+ 0x89A7, // 覧, #171
+ 0x89E3, // 解, #388
+ 0x8A00, // 言, #210
+ 0x8A08, // 計, #343
+ 0x8A18, // 記, #136
+ 0x8A2D, // 設, #292
+ 0x8A71, // 話, #213
+ 0x8A73, // 詳, #371
+ 0x8A8D, // 認, #404
+ 0x8A9E, // 語, #234
+ 0x8AAC, // 説, #494
+ 0x8AAD, // 読, #301
+ 0x8ABF, // 調, #443
+ 0x8AC7, // 談, #448
+ 0x8B77, // 護, #509
+ 0x8C37, // 谷, #506
+ 0x8CA9, // 販, #362
+ 0x8CB7, // 買, #346
+ 0x8CC7, // 資, #473
+ 0x8CEA, // 質, #281
+ 0x8CFC, // 購, #495
+ 0x8EAB, // 身, #470
+ 0x8ECA, // 車, #205
+ 0x8EE2, // 転, #335
+ 0x8F09, // 載, #342
+ 0x8FBC, // 込, #229
+ 0x8FD1, // 近, #304
+ 0x8FD4, // 返, #461
+ 0x8FFD, // 追, #379
+ 0x9001, // 送, #186
+ 0x901A, // 通, #182
+ 0x901F, // 速, #340
+ 0x9023, // 連, #244
+ 0x904B, // 運, #382
+ 0x904E, // 過, #498
+ 0x9053, // 道, #282
+ 0x9054, // 達, #450
+ 0x9055, // 違, #414
+ 0x9078, // 選, #288
+ 0x90E8, // 部, #208
+ 0x90FD, // 都, #344
+ 0x914D, // 配, #389
+ 0x91CD, // 重, #478
+ 0x91CE, // 野, #245
+ 0x91D1, // 金, #138
+ 0x9332, // 録, #238
+ 0x9577, // 長, #247
+ 0x9580, // 門, #508
+ 0x958B, // 開, #248
+ 0x9593, // 間, #141
+ 0x95A2, // 関, #188
+ 0x962A, // 阪, #496
+ 0x9650, // 限, #395
+ 0x9662, // 院, #449
+ 0x9664, // 除, #510
+ 0x969B, // 際, #493
+ 0x96C6, // 集, #196
+ 0x96D1, // 雑, #442
+ 0x96FB, // 電, #187
+ 0x9762, // 面, #328
+ 0x97F3, // 音, #325
+ 0x984C, // 題, #310
+ 0x985E, // 類, #491
+ 0x98A8, // 風, #353
+ 0x98DF, // 食, #218
+ 0x9928, // 館, #464
+ 0x99C5, // 駅, #316
+ 0x9A13, // 験, #397
+ 0x9AD8, // 高, #176
+ 0xFF57, // w, #108
+};
+// the percentage of the sample covered by the above characters
+static const float frequent_ja_coverage=0.880569589120162;
+
+// The 512 most frequently occuring characters for the ko language in a sample of the Internet.
+// Ordered by codepoint, comment shows character and ranking by frequency
+const uint16_t frequent_ko[] = {
+ 0x314B, // ㅋ, #148
+ 0x314E, // ㅎ, #390
+ 0x3160, // ㅠ, #354
+ 0x318D, // ㆍ, #439
+ 0xAC00, // 가, #6
+ 0xAC01, // 각, #231
+ 0xAC04, // 간, #106
+ 0xAC08, // 갈, #362
+ 0xAC10, // 감, #122
+ 0xAC11, // 갑, #493
+ 0xAC15, // 강, #155
+ 0xAC19, // 같, #264
+ 0xAC1C, // 개, #87
+ 0xAC1D, // 객, #198
+ 0xAC24, // 갤, #457
+ 0xAC70, // 거, #91
+ 0xAC74, // 건, #161
+ 0xAC78, // 걸, #338
+ 0xAC80, // 검, #184
+ 0xAC83, // 것, #116
+ 0xAC8C, // 게, #36
+ 0xACA0, // 겠, #233
+ 0xACA8, // 겨, #341
+ 0xACA9, // 격, #245
+ 0xACAC, // 견, #413
+ 0xACB0, // 결, #202
+ 0xACBD, // 경, #62
+ 0xACC4, // 계, #142
+ 0xACE0, // 고, #12
+ 0xACE1, // 곡, #444
+ 0xACE8, // 골, #379
+ 0xACF3, // 곳, #388
+ 0xACF5, // 공, #59
+ 0xACFC, // 과, #69
+ 0xAD00, // 관, #95
+ 0xAD11, // 광, #235
+ 0xAD50, // 교, #128
+ 0xAD6C, // 구, #52
+ 0xAD6D, // 국, #85
+ 0xAD70, // 군, #293
+ 0xAD74, // 굴, #487
+ 0xAD81, // 궁, #441
+ 0xAD8C, // 권, #192
+ 0xADC0, // 귀, #386
+ 0xADDC, // 규, #367
+ 0xADF8, // 그, #30
+ 0xADF9, // 극, #424
+ 0xADFC, // 근, #241
+ 0xAE00, // 글, #61
+ 0xAE08, // 금, #138
+ 0xAE09, // 급, #269
+ 0xAE30, // 기, #3
+ 0xAE34, // 긴, #465
+ 0xAE38, // 길, #297
+ 0xAE40, // 김, #205
+ 0xAE4C, // 까, #171
+ 0xAED8, // 께, #273
+ 0xAF43, // 꽃, #475
+ 0xB05D, // 끝, #505
+ 0xB07C, // 끼, #490
+ 0xB098, // 나, #39
+ 0xB09C, // 난, #274
+ 0xB0A0, // 날, #292
+ 0xB0A8, // 남, #139
+ 0xB0B4, // 내, #56
+ 0xB108, // 너, #272
+ 0xB110, // 널, #476
+ 0xB118, // 넘, #492
+ 0xB124, // 네, #100
+ 0xB137, // 넷, #329
+ 0xB140, // 녀, #288
+ 0xB144, // 년, #151
+ 0xB178, // 노, #149
+ 0xB17C, // 논, #491
+ 0xB180, // 놀, #464
+ 0xB18D, // 농, #442
+ 0xB204, // 누, #319
+ 0xB208, // 눈, #383
+ 0xB274, // 뉴, #173
+ 0xB290, // 느, #368
+ 0xB294, // 는, #5
+ 0xB298, // 늘, #322
+ 0xB2A5, // 능, #190
+ 0xB2C8, // 니, #16
+ 0xB2D8, // 님, #153
+ 0xB2E4, // 다, #2
+ 0xB2E8, // 단, #134
+ 0xB2EB, // 닫, #195
+ 0xB2EC, // 달, #243
+ 0xB2F4, // 담, #254
+ 0xB2F5, // 답, #287
+ 0xB2F9, // 당, #159
+ 0xB300, // 대, #33
+ 0xB313, // 댓, #303
+ 0xB354, // 더, #140
+ 0xB358, // 던, #252
+ 0xB367, // 덧, #463
+ 0xB370, // 데, #104
+ 0xB378, // 델, #429
+ 0xB3C4, // 도, #25
+ 0xB3C5, // 독, #301
+ 0xB3CC, // 돌, #309
+ 0xB3D9, // 동, #58
+ 0xB418, // 되, #82
+ 0xB41C, // 된, #189
+ 0xB420, // 될, #408
+ 0xB429, // 됩, #332
+ 0xB450, // 두, #199
+ 0xB4A4, // 뒤, #496
+ 0xB4DC, // 드, #40
+ 0xB4E0, // 든, #283
+ 0xB4E4, // 들, #54
+ 0xB4EF, // 듯, #478
+ 0xB4F1, // 등, #90
+ 0xB514, // 디, #133
+ 0xB529, // 딩, #462
+ 0xB530, // 따, #333
+ 0xB54C, // 때, #240
+ 0xB610, // 또, #313
+ 0xB77C, // 라, #42
+ 0xB77D, // 락, #355
+ 0xB780, // 란, #290
+ 0xB78C, // 람, #246
+ 0xB78D, // 랍, #420
+ 0xB791, // 랑, #270
+ 0xB798, // 래, #174
+ 0xB799, // 랙, #381
+ 0xB79C, // 랜, #357
+ 0xB7A8, // 램, #359
+ 0xB7A9, // 랩, #402
+ 0xB7C9, // 량, #346
+ 0xB7EC, // 러, #130
+ 0xB7F0, // 런, #312
+ 0xB7FC, // 럼, #327
+ 0xB7FD, // 럽, #447
+ 0xB807, // 렇, #412
+ 0xB808, // 레, #114
+ 0xB80C, // 렌, #395
+ 0xB824, // 려, #158
+ 0xB825, // 력, #194
+ 0xB828, // 련, #326
+ 0xB839, // 령, #389
+ 0xB85C, // 로, #4
+ 0xB85D, // 록, #84
+ 0xB860, // 론, #366
+ 0xB8CC, // 료, #154
+ 0xB8E8, // 루, #236
+ 0xB958, // 류, #265
+ 0xB974, // 르, #212
+ 0xB978, // 른, #250
+ 0xB97C, // 를, #35
+ 0xB984, // 름, #276
+ 0xB9AC, // 리, #19
+ 0xB9AD, // 릭, #394
+ 0xB9B0, // 린, #259
+ 0xB9B4, // 릴, #485
+ 0xB9BC, // 림, #305
+ 0xB9BD, // 립, #217
+ 0xB9C1, // 링, #351
+ 0xB9C8, // 마, #67
+ 0xB9C9, // 막, #310
+ 0xB9CC, // 만, #65
+ 0xB9CE, // 많, #257
+ 0xB9D0, // 말, #188
+ 0xB9DB, // 맛, #397
+ 0xB9DD, // 망, #370
+ 0xB9DE, // 맞, #399
+ 0xB9E4, // 매, #125
+ 0xB9E8, // 맨, #422
+ 0xBA38, // 머, #311
+ 0xBA39, // 먹, #377
+ 0xBA3C, // 먼, #469
+ 0xBA54, // 메, #147
+ 0xBA70, // 며, #191
+ 0xBA74, // 면, #72
+ 0xBA85, // 명, #131
+ 0xBAA8, // 모, #73
+ 0xBAA9, // 목, #157
+ 0xBAB0, // 몰, #401
+ 0xBAB8, // 몸, #437
+ 0xBABB, // 못, #336
+ 0xBB34, // 무, #80
+ 0xBB38, // 문, #57
+ 0xBB3C, // 물, #94
+ 0xBBA4, // 뮤, #431
+ 0xBBF8, // 미, #76
+ 0xBBFC, // 민, #200
+ 0xBC00, // 밀, #308
+ 0xBC0F, // 및, #249
+ 0xBC14, // 바, #89
+ 0xBC15, // 박, #226
+ 0xBC18, // 반, #175
+ 0xBC1B, // 받, #248
+ 0xBC1C, // 발, #164
+ 0xBC29, // 방, #92
+ 0xBC30, // 배, #162
+ 0xBC31, // 백, #256
+ 0xBC84, // 버, #111
+ 0xBC88, // 번, #167
+ 0xBC8C, // 벌, #423
+ 0xBC94, // 범, #427
+ 0xBC95, // 법, #207
+ 0xBCA0, // 베, #281
+ 0xBCA4, // 벤, #378
+ 0xBCA8, // 벨, #387
+ 0xBCC0, // 변, #253
+ 0xBCC4, // 별, #262
+ 0xBCD1, // 병, #340
+ 0xBCF4, // 보, #20
+ 0xBCF5, // 복, #204
+ 0xBCF8, // 본, #182
+ 0xBCFC, // 볼, #385
+ 0xBD09, // 봉, #405
+ 0xBD80, // 부, #46
+ 0xBD81, // 북, #261
+ 0xBD84, // 분, #105
+ 0xBD88, // 불, #225
+ 0xBDF0, // 뷰, #350
+ 0xBE0C, // 브, #214
+ 0xBE14, // 블, #99
+ 0xBE44, // 비, #55
+ 0xBE4C, // 빌, #510
+ 0xBE60, // 빠, #398
+ 0xC0AC, // 사, #14
+ 0xC0AD, // 삭, #342
+ 0xC0B0, // 산, #121
+ 0xC0B4, // 살, #279
+ 0xC0BC, // 삼, #348
+ 0xC0C1, // 상, #41
+ 0xC0C8, // 새, #282
+ 0xC0C9, // 색, #181
+ 0xC0DD, // 생, #109
+ 0xC11C, // 서, #21
+ 0xC11D, // 석, #234
+ 0xC120, // 선, #107
+ 0xC124, // 설, #170
+ 0xC131, // 성, #50
+ 0xC138, // 세, #60
+ 0xC139, // 섹, #456
+ 0xC13C, // 센, #267
+ 0xC154, // 셔, #455
+ 0xC158, // 션, #237
+ 0xC15C, // 셜, #448
+ 0xC168, // 셨, #421
+ 0xC18C, // 소, #51
+ 0xC18D, // 속, #219
+ 0xC190, // 손, #323
+ 0xC1A1, // 송, #203
+ 0xC1C4, // 쇄, #501
+ 0xC1FC, // 쇼, #364
+ 0xC218, // 수, #27
+ 0xC219, // 숙, #467
+ 0xC21C, // 순, #258
+ 0xC220, // 술, #302
+ 0xC26C, // 쉬, #511
+ 0xC288, // 슈, #384
+ 0xC2A4, // 스, #11
+ 0xC2AC, // 슬, #438
+ 0xC2B4, // 슴, #504
+ 0xC2B5, // 습, #77
+ 0xC2B9, // 승, #299
+ 0xC2DC, // 시, #13
+ 0xC2DD, // 식, #137
+ 0xC2E0, // 신, #47
+ 0xC2E4, // 실, #132
+ 0xC2EC, // 심, #196
+ 0xC2ED, // 십, #482
+ 0xC2F6, // 싶, #352
+ 0xC2F8, // 싸, #419
+ 0xC4F0, // 쓰, #278
+ 0xC528, // 씨, #360
+ 0xC544, // 아, #23
+ 0xC545, // 악, #296
+ 0xC548, // 안, #71
+ 0xC54A, // 않, #209
+ 0xC54C, // 알, #222
+ 0xC554, // 암, #460
+ 0xC558, // 았, #349
+ 0xC559, // 앙, #473
+ 0xC55E, // 앞, #434
+ 0xC560, // 애, #271
+ 0xC561, // 액, #415
+ 0xC571, // 앱, #477
+ 0xC57C, // 야, #124
+ 0xC57D, // 약, #229
+ 0xC591, // 양, #177
+ 0xC5B4, // 어, #24
+ 0xC5B5, // 억, #407
+ 0xC5B8, // 언, #294
+ 0xC5BC, // 얼, #356
+ 0xC5C4, // 엄, #426
+ 0xC5C5, // 업, #118
+ 0xC5C6, // 없, #178
+ 0xC5C8, // 었, #165
+ 0xC5D0, // 에, #9
+ 0xC5D4, // 엔, #375
+ 0xC5D8, // 엘, #506
+ 0xC5EC, // 여, #66
+ 0xC5ED, // 역, #186
+ 0xC5EE, // 엮, #488
+ 0xC5F0, // 연, #96
+ 0xC5F4, // 열, #266
+ 0xC5FC, // 염, #449
+ 0xC600, // 였, #374
+ 0xC601, // 영, #83
+ 0xC608, // 예, #168
+ 0xC624, // 오, #75
+ 0xC628, // 온, #300
+ 0xC62C, // 올, #306
+ 0xC640, // 와, #119
+ 0xC644, // 완, #361
+ 0xC654, // 왔, #489
+ 0xC655, // 왕, #418
+ 0xC678, // 외, #218
+ 0xC694, // 요, #43
+ 0xC695, // 욕, #479
+ 0xC6A9, // 용, #48
+ 0xC6B0, // 우, #64
+ 0xC6B1, // 욱, #503
+ 0xC6B4, // 운, #108
+ 0xC6B8, // 울, #223
+ 0xC6C0, // 움, #317
+ 0xC6C3, // 웃, #404
+ 0xC6CC, // 워, #280
+ 0xC6D0, // 원, #45
+ 0xC6D4, // 월, #150
+ 0xC6E8, // 웨, #446
+ 0xC6F9, // 웹, #500
+ 0xC704, // 위, #78
+ 0xC720, // 유, #81
+ 0xC721, // 육, #321
+ 0xC724, // 윤, #416
+ 0xC73C, // 으, #49
+ 0xC740, // 은, #31
+ 0xC744, // 을, #17
+ 0xC74C, // 음, #112
+ 0xC751, // 응, #461
+ 0xC758, // 의, #8
+ 0xC774, // 이, #1
+ 0xC775, // 익, #403
+ 0xC778, // 인, #18
+ 0xC77C, // 일, #28
+ 0xC784, // 임, #160
+ 0xC785, // 입, #93
+ 0xC788, // 있, #44
+ 0xC790, // 자, #22
+ 0xC791, // 작, #88
+ 0xC798, // 잘, #347
+ 0xC7A1, // 잡, #372
+ 0xC7A5, // 장, #53
+ 0xC7AC, // 재, #120
+ 0xC7C1, // 쟁, #483
+ 0xC800, // 저, #98
+ 0xC801, // 적, #97
+ 0xC804, // 전, #34
+ 0xC808, // 절, #320
+ 0xC810, // 점, #201
+ 0xC811, // 접, #331
+ 0xC815, // 정, #26
+ 0xC81C, // 제, #29
+ 0xC838, // 져, #414
+ 0xC870, // 조, #86
+ 0xC871, // 족, #373
+ 0xC874, // 존, #432
+ 0xC880, // 좀, #470
+ 0xC885, // 종, #208
+ 0xC88B, // 좋, #239
+ 0xC8E0, // 죠, #451
+ 0xC8FC, // 주, #38
+ 0xC8FD, // 죽, #471
+ 0xC900, // 준, #286
+ 0xC904, // 줄, #392
+ 0xC911, // 중, #103
+ 0xC988, // 즈, #255
+ 0xC98C, // 즌, #507
+ 0xC990, // 즐, #371
+ 0xC99D, // 증, #260
+ 0xC9C0, // 지, #10
+ 0xC9C1, // 직, #216
+ 0xC9C4, // 진, #79
+ 0xC9C8, // 질, #238
+ 0xC9D1, // 집, #206
+ 0xC9DC, // 짜, #411
+ 0xC9F8, // 째, #494
+ 0xCABD, // 쪽, #435
+ 0xCC28, // 차, #146
+ 0xCC29, // 착, #443
+ 0xCC2C, // 찬, #481
+ 0xCC30, // 찰, #440
+ 0xCC38, // 참, #343
+ 0xCC3D, // 창, #304
+ 0xCC3E, // 찾, #335
+ 0xCC44, // 채, #284
+ 0xCC45, // 책, #298
+ 0xCC98, // 처, #242
+ 0xCC9C, // 천, #143
+ 0xCCA0, // 철, #380
+ 0xCCA8, // 첨, #452
+ 0xCCAB, // 첫, #484
+ 0xCCAD, // 청, #197
+ 0xCCB4, // 체, #126
+ 0xCCD0, // 쳐, #472
+ 0xCD08, // 초, #220
+ 0xCD1D, // 총, #406
+ 0xCD5C, // 최, #179
+ 0xCD94, // 추, #136
+ 0xCD95, // 축, #337
+ 0xCD9C, // 출, #166
+ 0xCDA9, // 충, #369
+ 0xCDE8, // 취, #210
+ 0xCE20, // 츠, #215
+ 0xCE21, // 측, #468
+ 0xCE35, // 층, #512
+ 0xCE58, // 치, #102
+ 0xCE5C, // 친, #325
+ 0xCE68, // 침, #263
+ 0xCE74, // 카, #115
+ 0xCE7C, // 칼, #466
+ 0xCE90, // 캐, #454
+ 0xCEE4, // 커, #285
+ 0xCEE8, // 컨, #328
+ 0xCEF4, // 컴, #417
+ 0xCF00, // 케, #339
+ 0xCF13, // 켓, #509
+ 0xCF1C, // 켜, #508
+ 0xCF54, // 코, #193
+ 0xCF58, // 콘, #391
+ 0xCFE0, // 쿠, #393
+ 0xD035, // 퀵, #453
+ 0xD06C, // 크, #101
+ 0xD070, // 큰, #495
+ 0xD074, // 클, #289
+ 0xD0A4, // 키, #230
+ 0xD0C0, // 타, #127
+ 0xD0C1, // 탁, #314
+ 0xD0C4, // 탄, #450
+ 0xD0C8, // 탈, #436
+ 0xD0DC, // 태, #221
+ 0xD0DD, // 택, #275
+ 0xD130, // 터, #70
+ 0xD14C, // 테, #213
+ 0xD150, // 텐, #324
+ 0xD154, // 텔, #430
+ 0xD15C, // 템, #382
+ 0xD1A0, // 토, #145
+ 0xD1B5, // 통, #156
+ 0xD22C, // 투, #227
+ 0xD2B8, // 트, #37
+ 0xD2B9, // 특, #247
+ 0xD2F0, // 티, #187
+ 0xD305, // 팅, #410
+ 0xD30C, // 파, #141
+ 0xD310, // 판, #163
+ 0xD314, // 팔, #499
+ 0xD328, // 패, #307
+ 0xD32C, // 팬, #459
+ 0xD338, // 팸, #433
+ 0xD37C, // 퍼, #344
+ 0xD398, // 페, #172
+ 0xD3B8, // 편, #251
+ 0xD3C9, // 평, #291
+ 0xD3EC, // 포, #68
+ 0xD3ED, // 폭, #445
+ 0xD3F0, // 폰, #318
+ 0xD45C, // 표, #232
+ 0xD480, // 풀, #497
+ 0xD488, // 품, #113
+ 0xD48D, // 풍, #425
+ 0xD504, // 프, #110
+ 0xD508, // 픈, #498
+ 0xD50C, // 플, #211
+ 0xD53C, // 피, #169
+ 0xD544, // 필, #295
+ 0xD551, // 핑, #376
+ 0xD558, // 하, #7
+ 0xD559, // 학, #129
+ 0xD55C, // 한, #15
+ 0xD560, // 할, #144
+ 0xD568, // 함, #152
+ 0xD569, // 합, #123
+ 0xD56D, // 항, #268
+ 0xD574, // 해, #32
+ 0xD588, // 했, #180
+ 0xD589, // 행, #135
+ 0xD5A5, // 향, #345
+ 0xD5C8, // 허, #396
+ 0xD5D8, // 험, #316
+ 0xD5E4, // 헤, #474
+ 0xD604, // 현, #185
+ 0xD611, // 협, #315
+ 0xD615, // 형, #244
+ 0xD61C, // 혜, #428
+ 0xD638, // 호, #117
+ 0xD63C, // 혼, #358
+ 0xD648, // 홈, #330
+ 0xD64D, // 홍, #363
+ 0xD654, // 화, #63
+ 0xD655, // 확, #183
+ 0xD658, // 환, #224
+ 0xD65C, // 활, #277
+ 0xD669, // 황, #353
+ 0xD68C, // 회, #74
+ 0xD68D, // 획, #458
+ 0xD69F, // 횟, #409
+ 0xD6A8, // 효, #400
+ 0xD6C4, // 후, #176
+ 0xD6C8, // 훈, #486
+ 0xD734, // 휴, #365
+ 0xD754, // 흔, #480
+ 0xD76C, // 희, #334
+ 0xD788, // 히, #228
+ 0xD798, // 힘, #502
+};
+// the percentage of the sample covered by the above characters
+static const float frequent_ko_coverage=0.948157021464184;
+
diff --git a/media/libmedia/IAudioFlinger.cpp b/media/libmedia/IAudioFlinger.cpp
index 86ff8bd..eb813bd 100644
--- a/media/libmedia/IAudioFlinger.cpp
+++ b/media/libmedia/IAudioFlinger.cpp
@@ -58,7 +58,7 @@ enum {
RESTORE_OUTPUT,
OPEN_INPUT,
CLOSE_INPUT,
- SET_STREAM_OUTPUT,
+ INVALIDATE_STREAM,
SET_VOICE_VOLUME,
GET_RENDER_POSITION,
GET_INPUT_FRAMES_LOST,
@@ -89,13 +89,12 @@ public:
uint32_t sampleRate,
audio_format_t format,
audio_channel_mask_t channelMask,
- size_t frameCount,
+ size_t *pFrameCount,
track_flags_t *flags,
const sp<IMemory>& sharedBuffer,
audio_io_handle_t output,
pid_t tid,
int *sessionId,
- String8& name,
int clientUid,
status_t *status)
{
@@ -106,9 +105,11 @@ public:
data.writeInt32(sampleRate);
data.writeInt32(format);
data.writeInt32(channelMask);
+ size_t frameCount = pFrameCount != NULL ? *pFrameCount : 0;
data.writeInt32(frameCount);
track_flags_t lFlags = flags != NULL ? *flags : (track_flags_t) TRACK_DEFAULT;
data.writeInt32(lFlags);
+ // haveSharedBuffer
if (sharedBuffer != 0) {
data.writeInt32(true);
data.writeStrongBinder(sharedBuffer->asBinder());
@@ -117,7 +118,7 @@ public:
}
data.writeInt32((int32_t) output);
data.writeInt32((int32_t) tid);
- int lSessionId = 0;
+ int lSessionId = AUDIO_SESSION_ALLOCATE;
if (sessionId != NULL) {
lSessionId = *sessionId;
}
@@ -127,6 +128,10 @@ public:
if (lStatus != NO_ERROR) {
ALOGE("createTrack error: %s", strerror(-lStatus));
} else {
+ frameCount = reply.readInt32();
+ if (pFrameCount != NULL) {
+ *pFrameCount = frameCount;
+ }
lFlags = reply.readInt32();
if (flags != NULL) {
*flags = lFlags;
@@ -135,11 +140,21 @@ public:
if (sessionId != NULL) {
*sessionId = lSessionId;
}
- name = reply.readString8();
lStatus = reply.readInt32();
track = interface_cast<IAudioTrack>(reply.readStrongBinder());
+ if (lStatus == NO_ERROR) {
+ if (track == 0) {
+ ALOGE("createTrack should have returned an IAudioTrack");
+ lStatus = UNKNOWN_ERROR;
+ }
+ } else {
+ if (track != 0) {
+ ALOGE("createTrack returned an IAudioTrack but with status %d", lStatus);
+ track.clear();
+ }
+ }
}
- if (status) {
+ if (status != NULL) {
*status = lStatus;
}
return track;
@@ -150,7 +165,7 @@ public:
uint32_t sampleRate,
audio_format_t format,
audio_channel_mask_t channelMask,
- size_t frameCount,
+ size_t *pFrameCount,
track_flags_t *flags,
pid_t tid,
int *sessionId,
@@ -163,11 +178,12 @@ public:
data.writeInt32(sampleRate);
data.writeInt32(format);
data.writeInt32(channelMask);
+ size_t frameCount = pFrameCount != NULL ? *pFrameCount : 0;
data.writeInt32(frameCount);
track_flags_t lFlags = flags != NULL ? *flags : (track_flags_t) TRACK_DEFAULT;
data.writeInt32(lFlags);
data.writeInt32((int32_t) tid);
- int lSessionId = 0;
+ int lSessionId = AUDIO_SESSION_ALLOCATE;
if (sessionId != NULL) {
lSessionId = *sessionId;
}
@@ -176,6 +192,10 @@ public:
if (lStatus != NO_ERROR) {
ALOGE("openRecord error: %s", strerror(-lStatus));
} else {
+ frameCount = reply.readInt32();
+ if (pFrameCount != NULL) {
+ *pFrameCount = frameCount;
+ }
lFlags = reply.readInt32();
if (flags != NULL) {
*flags = lFlags;
@@ -198,7 +218,7 @@ public:
}
}
}
- if (status) {
+ if (status != NULL) {
*status = lStatus;
}
return record;
@@ -391,7 +411,7 @@ public:
const audio_offload_info_t *offloadInfo)
{
Parcel data, reply;
- audio_devices_t devices = pDevices != NULL ? *pDevices : (audio_devices_t)0;
+ audio_devices_t devices = pDevices != NULL ? *pDevices : AUDIO_DEVICE_NONE;
uint32_t samplingRate = pSamplingRate != NULL ? *pSamplingRate : 0;
audio_format_t format = pFormat != NULL ? *pFormat : AUDIO_FORMAT_DEFAULT;
audio_channel_mask_t channelMask = pChannelMask != NULL ?
@@ -405,6 +425,7 @@ public:
data.writeInt32(channelMask);
data.writeInt32(latency);
data.writeInt32((int32_t) flags);
+ // hasOffloadInfo
if (offloadInfo == NULL) {
data.writeInt32(0);
} else {
@@ -415,15 +436,25 @@ public:
audio_io_handle_t output = (audio_io_handle_t) reply.readInt32();
ALOGV("openOutput() returned output, %d", output);
devices = (audio_devices_t)reply.readInt32();
- if (pDevices != NULL) *pDevices = devices;
+ if (pDevices != NULL) {
+ *pDevices = devices;
+ }
samplingRate = reply.readInt32();
- if (pSamplingRate != NULL) *pSamplingRate = samplingRate;
+ if (pSamplingRate != NULL) {
+ *pSamplingRate = samplingRate;
+ }
format = (audio_format_t) reply.readInt32();
- if (pFormat != NULL) *pFormat = format;
+ if (pFormat != NULL) {
+ *pFormat = format;
+ }
channelMask = (audio_channel_mask_t)reply.readInt32();
- if (pChannelMask != NULL) *pChannelMask = channelMask;
+ if (pChannelMask != NULL) {
+ *pChannelMask = channelMask;
+ }
latency = reply.readInt32();
- if (pLatencyMs != NULL) *pLatencyMs = latency;
+ if (pLatencyMs != NULL) {
+ *pLatencyMs = latency;
+ }
return output;
}
@@ -472,7 +503,7 @@ public:
audio_channel_mask_t *pChannelMask)
{
Parcel data, reply;
- audio_devices_t devices = pDevices != NULL ? *pDevices : (audio_devices_t)0;
+ audio_devices_t devices = pDevices != NULL ? *pDevices : AUDIO_DEVICE_NONE;
uint32_t samplingRate = pSamplingRate != NULL ? *pSamplingRate : 0;
audio_format_t format = pFormat != NULL ? *pFormat : AUDIO_FORMAT_DEFAULT;
audio_channel_mask_t channelMask = pChannelMask != NULL ?
@@ -487,13 +518,21 @@ public:
remote()->transact(OPEN_INPUT, data, &reply);
audio_io_handle_t input = (audio_io_handle_t) reply.readInt32();
devices = (audio_devices_t)reply.readInt32();
- if (pDevices != NULL) *pDevices = devices;
+ if (pDevices != NULL) {
+ *pDevices = devices;
+ }
samplingRate = reply.readInt32();
- if (pSamplingRate != NULL) *pSamplingRate = samplingRate;
+ if (pSamplingRate != NULL) {
+ *pSamplingRate = samplingRate;
+ }
format = (audio_format_t) reply.readInt32();
- if (pFormat != NULL) *pFormat = format;
+ if (pFormat != NULL) {
+ *pFormat = format;
+ }
channelMask = (audio_channel_mask_t)reply.readInt32();
- if (pChannelMask != NULL) *pChannelMask = channelMask;
+ if (pChannelMask != NULL) {
+ *pChannelMask = channelMask;
+ }
return input;
}
@@ -506,13 +545,12 @@ public:
return reply.readInt32();
}
- virtual status_t setStreamOutput(audio_stream_type_t stream, audio_io_handle_t output)
+ virtual status_t invalidateStream(audio_stream_type_t stream)
{
Parcel data, reply;
data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
data.writeInt32((int32_t) stream);
- data.writeInt32((int32_t) output);
- remote()->transact(SET_STREAM_OUTPUT, data, &reply);
+ remote()->transact(INVALIDATE_STREAM, data, &reply);
return reply.readInt32();
}
@@ -535,11 +573,11 @@ public:
status_t status = reply.readInt32();
if (status == NO_ERROR) {
uint32_t tmp = reply.readInt32();
- if (halFrames) {
+ if (halFrames != NULL) {
*halFrames = tmp;
}
tmp = reply.readInt32();
- if (dspFrames) {
+ if (dspFrames != NULL) {
*dspFrames = tmp;
}
}
@@ -551,8 +589,11 @@ public:
Parcel data, reply;
data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
data.writeInt32((int32_t) ioHandle);
- remote()->transact(GET_INPUT_FRAMES_LOST, data, &reply);
- return reply.readInt32();
+ status_t status = remote()->transact(GET_INPUT_FRAMES_LOST, data, &reply);
+ if (status != NO_ERROR) {
+ return 0;
+ }
+ return (uint32_t) reply.readInt32();
}
virtual int newAudioSessionId()
@@ -560,26 +601,28 @@ public:
Parcel data, reply;
data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
status_t status = remote()->transact(NEW_AUDIO_SESSION_ID, data, &reply);
- int id = 0;
+ int id = AUDIO_SESSION_ALLOCATE;
if (status == NO_ERROR) {
id = reply.readInt32();
}
return id;
}
- virtual void acquireAudioSessionId(int audioSession)
+ virtual void acquireAudioSessionId(int audioSession, int pid)
{
Parcel data, reply;
data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
data.writeInt32(audioSession);
+ data.writeInt32(pid);
remote()->transact(ACQUIRE_AUDIO_SESSION_ID, data, &reply);
}
- virtual void releaseAudioSessionId(int audioSession)
+ virtual void releaseAudioSessionId(int audioSession, int pid)
{
Parcel data, reply;
data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
data.writeInt32(audioSession);
+ data.writeInt32(pid);
remote()->transact(RELEASE_AUDIO_SESSION_ID, data, &reply);
}
@@ -657,7 +700,7 @@ public:
if (pDesc == NULL) {
return effect;
- if (status) {
+ if (status != NULL) {
*status = BAD_VALUE;
}
}
@@ -675,7 +718,7 @@ public:
} else {
lStatus = reply.readInt32();
int tmp = reply.readInt32();
- if (id) {
+ if (id != NULL) {
*id = tmp;
}
tmp = reply.readInt32();
@@ -685,7 +728,7 @@ public:
effect = interface_cast<IEffect>(reply.readStrongBinder());
reply.read(pDesc, sizeof(effect_descriptor_t));
}
- if (status) {
+ if (status != NULL) {
*status = lStatus;
}
@@ -765,7 +808,6 @@ status_t BnAudioFlinger::onTransact(
pid_t tid = (pid_t) data.readInt32();
int sessionId = data.readInt32();
int clientUid = data.readInt32();
- String8 name;
status_t status;
sp<IAudioTrack> track;
if ((haveSharedBuffer && (buffer == 0)) ||
@@ -775,12 +817,13 @@ status_t BnAudioFlinger::onTransact(
} else {
track = createTrack(
(audio_stream_type_t) streamType, sampleRate, format,
- channelMask, frameCount, &flags, buffer, output, tid,
- &sessionId, name, clientUid, &status);
+ channelMask, &frameCount, &flags, buffer, output, tid,
+ &sessionId, clientUid, &status);
+ LOG_ALWAYS_FATAL_IF((track != 0) != (status == NO_ERROR));
}
+ reply->writeInt32(frameCount);
reply->writeInt32(flags);
reply->writeInt32(sessionId);
- reply->writeString8(name);
reply->writeInt32(status);
reply->writeStrongBinder(track->asBinder());
return NO_ERROR;
@@ -797,8 +840,9 @@ status_t BnAudioFlinger::onTransact(
int sessionId = data.readInt32();
status_t status;
sp<IAudioRecord> record = openRecord(input,
- sampleRate, format, channelMask, frameCount, &flags, tid, &sessionId, &status);
+ sampleRate, format, channelMask, &frameCount, &flags, tid, &sessionId, &status);
LOG_ALWAYS_FATAL_IF((record != 0) != (status == NO_ERROR));
+ reply->writeInt32(frameCount);
reply->writeInt32(flags);
reply->writeInt32(sessionId);
reply->writeInt32(status);
@@ -941,7 +985,7 @@ status_t BnAudioFlinger::onTransact(
&latency,
flags,
hasOffloadInfo ? &offloadInfo : NULL);
- ALOGV("OPEN_OUTPUT output, %p", output);
+ ALOGV("OPEN_OUTPUT output, %d", output);
reply->writeInt32((int32_t) output);
reply->writeInt32(devices);
reply->writeInt32(samplingRate);
@@ -997,11 +1041,10 @@ status_t BnAudioFlinger::onTransact(
reply->writeInt32(closeInput((audio_io_handle_t) data.readInt32()));
return NO_ERROR;
} break;
- case SET_STREAM_OUTPUT: {
+ case INVALIDATE_STREAM: {
CHECK_INTERFACE(IAudioFlinger, data, reply);
- uint32_t stream = data.readInt32();
- audio_io_handle_t output = (audio_io_handle_t) data.readInt32();
- reply->writeInt32(setStreamOutput((audio_stream_type_t) stream, output));
+ audio_stream_type_t stream = (audio_stream_type_t) data.readInt32();
+ reply->writeInt32(invalidateStream(stream));
return NO_ERROR;
} break;
case SET_VOICE_VOLUME: {
@@ -1026,7 +1069,7 @@ status_t BnAudioFlinger::onTransact(
case GET_INPUT_FRAMES_LOST: {
CHECK_INTERFACE(IAudioFlinger, data, reply);
audio_io_handle_t ioHandle = (audio_io_handle_t) data.readInt32();
- reply->writeInt32(getInputFramesLost(ioHandle));
+ reply->writeInt32((int32_t) getInputFramesLost(ioHandle));
return NO_ERROR;
} break;
case NEW_AUDIO_SESSION_ID: {
@@ -1037,13 +1080,15 @@ status_t BnAudioFlinger::onTransact(
case ACQUIRE_AUDIO_SESSION_ID: {
CHECK_INTERFACE(IAudioFlinger, data, reply);
int audioSession = data.readInt32();
- acquireAudioSessionId(audioSession);
+ int pid = data.readInt32();
+ acquireAudioSessionId(audioSession, pid);
return NO_ERROR;
} break;
case RELEASE_AUDIO_SESSION_ID: {
CHECK_INTERFACE(IAudioFlinger, data, reply);
int audioSession = data.readInt32();
- releaseAudioSessionId(audioSession);
+ int pid = data.readInt32();
+ releaseAudioSessionId(audioSession, pid);
return NO_ERROR;
} break;
case QUERY_NUM_EFFECTS: {
diff --git a/media/libmedia/IAudioPolicyService.cpp b/media/libmedia/IAudioPolicyService.cpp
index 4be3c09..9bb4a49 100644
--- a/media/libmedia/IAudioPolicyService.cpp
+++ b/media/libmedia/IAudioPolicyService.cpp
@@ -137,6 +137,7 @@ public:
data.writeInt32(static_cast <uint32_t>(format));
data.writeInt32(channelMask);
data.writeInt32(static_cast <uint32_t>(flags));
+ // hasOffloadInfo
if (offloadInfo == NULL) {
data.writeInt32(0);
} else {
@@ -476,10 +477,11 @@ status_t BnAudioPolicyService::onTransact(
case START_OUTPUT: {
CHECK_INTERFACE(IAudioPolicyService, data, reply);
audio_io_handle_t output = static_cast <audio_io_handle_t>(data.readInt32());
- uint32_t stream = data.readInt32();
+ audio_stream_type_t stream =
+ static_cast <audio_stream_type_t>(data.readInt32());
int session = data.readInt32();
reply->writeInt32(static_cast <uint32_t>(startOutput(output,
- (audio_stream_type_t)stream,
+ stream,
session)));
return NO_ERROR;
} break;
@@ -487,10 +489,11 @@ status_t BnAudioPolicyService::onTransact(
case STOP_OUTPUT: {
CHECK_INTERFACE(IAudioPolicyService, data, reply);
audio_io_handle_t output = static_cast <audio_io_handle_t>(data.readInt32());
- uint32_t stream = data.readInt32();
+ audio_stream_type_t stream =
+ static_cast <audio_stream_type_t>(data.readInt32());
int session = data.readInt32();
reply->writeInt32(static_cast <uint32_t>(stopOutput(output,
- (audio_stream_type_t)stream,
+ stream,
session)));
return NO_ERROR;
} break;
@@ -633,7 +636,7 @@ status_t BnAudioPolicyService::onTransact(
CHECK_INTERFACE(IAudioPolicyService, data, reply);
audio_stream_type_t stream = (audio_stream_type_t) data.readInt32();
uint32_t inPastMs = (uint32_t)data.readInt32();
- reply->writeInt32( isStreamActive((audio_stream_type_t) stream, inPastMs) );
+ reply->writeInt32( isStreamActive(stream, inPastMs) );
return NO_ERROR;
} break;
@@ -641,7 +644,7 @@ status_t BnAudioPolicyService::onTransact(
CHECK_INTERFACE(IAudioPolicyService, data, reply);
audio_stream_type_t stream = (audio_stream_type_t) data.readInt32();
uint32_t inPastMs = (uint32_t)data.readInt32();
- reply->writeInt32( isStreamActiveRemotely((audio_stream_type_t) stream, inPastMs) );
+ reply->writeInt32( isStreamActiveRemotely(stream, inPastMs) );
return NO_ERROR;
} break;
diff --git a/media/libmedia/IAudioRecord.cpp b/media/libmedia/IAudioRecord.cpp
index 4a7de65..9866d70 100644
--- a/media/libmedia/IAudioRecord.cpp
+++ b/media/libmedia/IAudioRecord.cpp
@@ -50,6 +50,9 @@ public:
status_t status = remote()->transact(GET_CBLK, data, &reply);
if (status == NO_ERROR) {
cblk = interface_cast<IMemory>(reply.readStrongBinder());
+ if (cblk != 0 && cblk->pointer() == NULL) {
+ cblk.clear();
+ }
}
return cblk;
}
diff --git a/media/libmedia/IAudioTrack.cpp b/media/libmedia/IAudioTrack.cpp
index 3cd9cfd..ffc21fc 100644
--- a/media/libmedia/IAudioTrack.cpp
+++ b/media/libmedia/IAudioTrack.cpp
@@ -60,6 +60,9 @@ public:
status_t status = remote()->transact(GET_CBLK, data, &reply);
if (status == NO_ERROR) {
cblk = interface_cast<IMemory>(reply.readStrongBinder());
+ if (cblk != 0 && cblk->pointer() == NULL) {
+ cblk.clear();
+ }
}
return cblk;
}
@@ -122,6 +125,9 @@ public:
status = reply.readInt32();
if (status == NO_ERROR) {
*buffer = interface_cast<IMemory>(reply.readStrongBinder());
+ if (*buffer != 0 && (*buffer)->pointer() == NULL) {
+ (*buffer).clear();
+ }
}
}
return status;
diff --git a/media/libmedia/IEffect.cpp b/media/libmedia/IEffect.cpp
index a303a8f..b94012a 100644
--- a/media/libmedia/IEffect.cpp
+++ b/media/libmedia/IEffect.cpp
@@ -117,6 +117,9 @@ public:
status_t status = remote()->transact(GET_CBLK, data, &reply);
if (status == NO_ERROR) {
cblk = interface_cast<IMemory>(reply.readStrongBinder());
+ if (cblk != 0 && cblk->pointer() == NULL) {
+ cblk.clear();
+ }
}
return cblk;
}
diff --git a/media/libmedia/IMediaDeathNotifier.cpp b/media/libmedia/IMediaDeathNotifier.cpp
index 9db5b1b..10b4934 100644
--- a/media/libmedia/IMediaDeathNotifier.cpp
+++ b/media/libmedia/IMediaDeathNotifier.cpp
@@ -75,7 +75,7 @@ IMediaDeathNotifier::removeObitRecipient(const wp<IMediaDeathNotifier>& recipien
}
void
-IMediaDeathNotifier::DeathNotifier::binderDied(const wp<IBinder>& who) {
+IMediaDeathNotifier::DeathNotifier::binderDied(const wp<IBinder>& who __unused) {
ALOGW("media server died");
// Need to do this with the lock held
diff --git a/media/libmedia/IMediaHTTPConnection.cpp b/media/libmedia/IMediaHTTPConnection.cpp
new file mode 100644
index 0000000..7e26ee6
--- /dev/null
+++ b/media/libmedia/IMediaHTTPConnection.cpp
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) 2013 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "IMediaHTTPConnection"
+#include <utils/Log.h>
+
+#include <media/IMediaHTTPConnection.h>
+
+#include <binder/IMemory.h>
+#include <binder/Parcel.h>
+#include <utils/String8.h>
+#include <media/stagefright/foundation/ADebug.h>
+
+namespace android {
+
+enum {
+ CONNECT = IBinder::FIRST_CALL_TRANSACTION,
+ DISCONNECT,
+ READ_AT,
+ GET_SIZE,
+ GET_MIME_TYPE,
+ GET_URI
+};
+
+struct BpMediaHTTPConnection : public BpInterface<IMediaHTTPConnection> {
+ BpMediaHTTPConnection(const sp<IBinder> &impl)
+ : BpInterface<IMediaHTTPConnection>(impl) {
+ }
+
+ virtual bool connect(
+ const char *uri, const KeyedVector<String8, String8> *headers) {
+ Parcel data, reply;
+ data.writeInterfaceToken(
+ IMediaHTTPConnection::getInterfaceDescriptor());
+
+ String16 tmp(uri);
+ data.writeString16(tmp);
+
+ tmp = String16("");
+ if (headers != NULL) {
+ for (size_t i = 0; i < headers->size(); ++i) {
+ String16 key(headers->keyAt(i).string());
+ String16 val(headers->valueAt(i).string());
+
+ tmp.append(key);
+ tmp.append(String16(": "));
+ tmp.append(val);
+ tmp.append(String16("\r\n"));
+ }
+ }
+ data.writeString16(tmp);
+
+ remote()->transact(CONNECT, data, &reply);
+
+ int32_t exceptionCode = reply.readExceptionCode();
+
+ if (exceptionCode) {
+ return UNKNOWN_ERROR;
+ }
+
+ sp<IBinder> binder = reply.readStrongBinder();
+ mMemory = interface_cast<IMemory>(binder);
+
+ return mMemory != NULL;
+ }
+
+ virtual void disconnect() {
+ Parcel data, reply;
+ data.writeInterfaceToken(
+ IMediaHTTPConnection::getInterfaceDescriptor());
+
+ remote()->transact(DISCONNECT, data, &reply);
+ }
+
+ virtual ssize_t readAt(off64_t offset, void *buffer, size_t size) {
+ Parcel data, reply;
+ data.writeInterfaceToken(
+ IMediaHTTPConnection::getInterfaceDescriptor());
+
+ data.writeInt64(offset);
+ data.writeInt32(size);
+
+ status_t err = remote()->transact(READ_AT, data, &reply);
+ if (err != OK) {
+ ALOGE("remote readAt failed");
+ return UNKNOWN_ERROR;
+ }
+
+ int32_t exceptionCode = reply.readExceptionCode();
+
+ if (exceptionCode) {
+ return UNKNOWN_ERROR;
+ }
+
+ int32_t len = reply.readInt32();
+
+ if (len > 0) {
+ memcpy(buffer, mMemory->pointer(), len);
+ }
+
+ return len;
+ }
+
+ virtual off64_t getSize() {
+ Parcel data, reply;
+ data.writeInterfaceToken(
+ IMediaHTTPConnection::getInterfaceDescriptor());
+
+ remote()->transact(GET_SIZE, data, &reply);
+
+ int32_t exceptionCode = reply.readExceptionCode();
+
+ if (exceptionCode) {
+ return UNKNOWN_ERROR;
+ }
+
+ return reply.readInt64();
+ }
+
+ virtual status_t getMIMEType(String8 *mimeType) {
+ *mimeType = String8("");
+
+ Parcel data, reply;
+ data.writeInterfaceToken(
+ IMediaHTTPConnection::getInterfaceDescriptor());
+
+ remote()->transact(GET_MIME_TYPE, data, &reply);
+
+ int32_t exceptionCode = reply.readExceptionCode();
+
+ if (exceptionCode) {
+ return UNKNOWN_ERROR;
+ }
+
+ *mimeType = String8(reply.readString16());
+
+ return OK;
+ }
+
+ virtual status_t getUri(String8 *uri) {
+ *uri = String8("");
+
+ Parcel data, reply;
+ data.writeInterfaceToken(
+ IMediaHTTPConnection::getInterfaceDescriptor());
+
+ remote()->transact(GET_URI, data, &reply);
+
+ int32_t exceptionCode = reply.readExceptionCode();
+
+ if (exceptionCode) {
+ return UNKNOWN_ERROR;
+ }
+
+ *uri = String8(reply.readString16());
+
+ return OK;
+ }
+
+private:
+ sp<IMemory> mMemory;
+};
+
+IMPLEMENT_META_INTERFACE(
+ MediaHTTPConnection, "android.media.IMediaHTTPConnection");
+
+} // namespace android
+
diff --git a/media/libmedia/IMediaHTTPService.cpp b/media/libmedia/IMediaHTTPService.cpp
new file mode 100644
index 0000000..1260582
--- /dev/null
+++ b/media/libmedia/IMediaHTTPService.cpp
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2013 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "IMediaHTTPService"
+#include <utils/Log.h>
+
+#include <media/IMediaHTTPService.h>
+
+#include <binder/Parcel.h>
+#include <media/IMediaHTTPConnection.h>
+
+namespace android {
+
+enum {
+ MAKE_HTTP = IBinder::FIRST_CALL_TRANSACTION,
+};
+
+struct BpMediaHTTPService : public BpInterface<IMediaHTTPService> {
+ BpMediaHTTPService(const sp<IBinder> &impl)
+ : BpInterface<IMediaHTTPService>(impl) {
+ }
+
+ virtual sp<IMediaHTTPConnection> makeHTTPConnection() {
+ Parcel data, reply;
+ data.writeInterfaceToken(
+ IMediaHTTPService::getInterfaceDescriptor());
+
+ remote()->transact(MAKE_HTTP, data, &reply);
+
+ status_t err = reply.readInt32();
+
+ if (err != OK) {
+ return NULL;
+ }
+
+ return interface_cast<IMediaHTTPConnection>(reply.readStrongBinder());
+ }
+};
+
+IMPLEMENT_META_INTERFACE(
+ MediaHTTPService, "android.media.IMediaHTTPService");
+
+} // namespace android
+
diff --git a/media/libmedia/IMediaMetadataRetriever.cpp b/media/libmedia/IMediaMetadataRetriever.cpp
index bb066a0..c7d9d51 100644
--- a/media/libmedia/IMediaMetadataRetriever.cpp
+++ b/media/libmedia/IMediaMetadataRetriever.cpp
@@ -18,6 +18,7 @@
#include <stdint.h>
#include <sys/types.h>
#include <binder/Parcel.h>
+#include <media/IMediaHTTPService.h>
#include <media/IMediaMetadataRetriever.h>
#include <utils/String8.h>
#include <utils/KeyedVector.h>
@@ -84,10 +85,16 @@ public:
}
status_t setDataSource(
- const char *srcUrl, const KeyedVector<String8, String8> *headers)
+ const sp<IMediaHTTPService> &httpService,
+ const char *srcUrl,
+ const KeyedVector<String8, String8> *headers)
{
Parcel data, reply;
data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
+ data.writeInt32(httpService != NULL);
+ if (httpService != NULL) {
+ data.writeStrongBinder(httpService->asBinder());
+ }
data.writeCString(srcUrl);
if (headers == NULL) {
@@ -195,6 +202,13 @@ status_t BnMediaMetadataRetriever::onTransact(
} break;
case SET_DATA_SOURCE_URL: {
CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
+
+ sp<IMediaHTTPService> httpService;
+ if (data.readInt32()) {
+ httpService =
+ interface_cast<IMediaHTTPService>(data.readStrongBinder());
+ }
+
const char* srcUrl = data.readCString();
KeyedVector<String8, String8> headers;
@@ -206,7 +220,8 @@ status_t BnMediaMetadataRetriever::onTransact(
}
reply->writeInt32(
- setDataSource(srcUrl, numHeaders > 0 ? &headers : NULL));
+ setDataSource(
+ httpService, srcUrl, numHeaders > 0 ? &headers : NULL));
return NO_ERROR;
} break;
diff --git a/media/libmedia/IMediaPlayer.cpp b/media/libmedia/IMediaPlayer.cpp
index e79bcd2..d778d05 100644
--- a/media/libmedia/IMediaPlayer.cpp
+++ b/media/libmedia/IMediaPlayer.cpp
@@ -21,6 +21,7 @@
#include <binder/Parcel.h>
+#include <media/IMediaHTTPService.h>
#include <media/IMediaPlayer.h>
#include <media/IStreamSource.h>
@@ -75,11 +76,17 @@ public:
remote()->transact(DISCONNECT, data, &reply);
}
- status_t setDataSource(const char* url,
+ status_t setDataSource(
+ const sp<IMediaHTTPService> &httpService,
+ const char* url,
const KeyedVector<String8, String8>* headers)
{
Parcel data, reply;
data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
+ data.writeInt32(httpService != NULL);
+ if (httpService != NULL) {
+ data.writeStrongBinder(httpService->asBinder());
+ }
data.writeCString(url);
if (headers == NULL) {
data.writeInt32(0);
@@ -355,6 +362,13 @@ status_t BnMediaPlayer::onTransact(
} break;
case SET_DATA_SOURCE_URL: {
CHECK_INTERFACE(IMediaPlayer, data, reply);
+
+ sp<IMediaHTTPService> httpService;
+ if (data.readInt32()) {
+ httpService =
+ interface_cast<IMediaHTTPService>(data.readStrongBinder());
+ }
+
const char* url = data.readCString();
KeyedVector<String8, String8> headers;
int32_t numHeaders = data.readInt32();
@@ -363,7 +377,8 @@ status_t BnMediaPlayer::onTransact(
String8 value = data.readString8();
headers.add(key, value);
}
- reply->writeInt32(setDataSource(url, numHeaders > 0 ? &headers : NULL));
+ reply->writeInt32(setDataSource(
+ httpService, url, numHeaders > 0 ? &headers : NULL));
return NO_ERROR;
} break;
case SET_DATA_SOURCE_FD: {
diff --git a/media/libmedia/IMediaPlayerService.cpp b/media/libmedia/IMediaPlayerService.cpp
index 3c22b4c..d116b14 100644
--- a/media/libmedia/IMediaPlayerService.cpp
+++ b/media/libmedia/IMediaPlayerService.cpp
@@ -23,6 +23,7 @@
#include <media/ICrypto.h>
#include <media/IDrm.h>
#include <media/IHDCP.h>
+#include <media/IMediaHTTPService.h>
#include <media/IMediaPlayerService.h>
#include <media/IMediaRecorder.h>
#include <media/IOMX.h>
@@ -48,7 +49,6 @@ enum {
ADD_BATTERY_DATA,
PULL_BATTERY_DATA,
LISTEN_FOR_REMOTE_DISPLAY,
- UPDATE_PROXY_CONFIG,
};
class BpMediaPlayerService: public BpInterface<IMediaPlayerService>
@@ -86,12 +86,21 @@ public:
return interface_cast<IMediaRecorder>(reply.readStrongBinder());
}
- virtual status_t decode(const char* url, uint32_t *pSampleRate, int* pNumChannels,
- audio_format_t* pFormat,
- const sp<IMemoryHeap>& heap, size_t *pSize)
+ virtual status_t decode(
+ const sp<IMediaHTTPService> &httpService,
+ const char* url,
+ uint32_t *pSampleRate,
+ int* pNumChannels,
+ audio_format_t* pFormat,
+ const sp<IMemoryHeap>& heap,
+ size_t *pSize)
{
Parcel data, reply;
data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
+ data.writeInt32(httpService != NULL);
+ if (httpService != NULL) {
+ data.writeStrongBinder(httpService->asBinder());
+ }
data.writeCString(url);
data.writeStrongBinder(heap->asBinder());
status_t status = remote()->transact(DECODE_URL, data, &reply);
@@ -182,25 +191,6 @@ public:
remote()->transact(LISTEN_FOR_REMOTE_DISPLAY, data, &reply);
return interface_cast<IRemoteDisplay>(reply.readStrongBinder());
}
-
- virtual status_t updateProxyConfig(
- const char *host, int32_t port, const char *exclusionList) {
- Parcel data, reply;
-
- data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
- if (host == NULL) {
- data.writeInt32(0);
- } else {
- data.writeInt32(1);
- data.writeCString(host);
- data.writeInt32(port);
- data.writeCString(exclusionList);
- }
-
- remote()->transact(UPDATE_PROXY_CONFIG, data, &reply);
-
- return reply.readInt32();
- }
};
IMPLEMENT_META_INTERFACE(MediaPlayerService, "android.media.IMediaPlayerService");
@@ -222,13 +212,25 @@ status_t BnMediaPlayerService::onTransact(
} break;
case DECODE_URL: {
CHECK_INTERFACE(IMediaPlayerService, data, reply);
+ sp<IMediaHTTPService> httpService;
+ if (data.readInt32()) {
+ httpService =
+ interface_cast<IMediaHTTPService>(data.readStrongBinder());
+ }
const char* url = data.readCString();
sp<IMemoryHeap> heap = interface_cast<IMemoryHeap>(data.readStrongBinder());
uint32_t sampleRate;
int numChannels;
audio_format_t format;
size_t size;
- status_t status = decode(url, &sampleRate, &numChannels, &format, heap, &size);
+ status_t status =
+ decode(httpService,
+ url,
+ &sampleRate,
+ &numChannels,
+ &format,
+ heap,
+ &size);
reply->writeInt32(status);
if (status == NO_ERROR) {
reply->writeInt32(sampleRate);
@@ -316,24 +318,6 @@ status_t BnMediaPlayerService::onTransact(
reply->writeStrongBinder(display->asBinder());
return NO_ERROR;
} break;
- case UPDATE_PROXY_CONFIG:
- {
- CHECK_INTERFACE(IMediaPlayerService, data, reply);
-
- const char *host = NULL;
- int32_t port = 0;
- const char *exclusionList = NULL;
-
- if (data.readInt32()) {
- host = data.readCString();
- port = data.readInt32();
- exclusionList = data.readCString();
- }
-
- reply->writeInt32(updateProxyConfig(host, port, exclusionList));
-
- return OK;
- }
default:
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/media/libmedia/JetPlayer.cpp b/media/libmedia/JetPlayer.cpp
index e914b34..f0f1832 100644
--- a/media/libmedia/JetPlayer.cpp
+++ b/media/libmedia/JetPlayer.cpp
@@ -90,7 +90,7 @@ int JetPlayer::init()
pLibConfig->sampleRate,
AUDIO_FORMAT_PCM_16_BIT,
audio_channel_out_mask_from_count(pLibConfig->numChannels),
- mTrackBufferSize,
+ (size_t) mTrackBufferSize,
AUDIO_OUTPUT_FLAG_NONE);
// create render and playback thread
diff --git a/media/libmedia/MediaProfiles.cpp b/media/libmedia/MediaProfiles.cpp
index 8319cd7..1074da9 100644
--- a/media/libmedia/MediaProfiles.cpp
+++ b/media/libmedia/MediaProfiles.cpp
@@ -81,8 +81,14 @@ const MediaProfiles::NameToTagMap MediaProfiles::sCamcorderQualityNameMap[] = {
{"timelapseqvga", CAMCORDER_QUALITY_TIME_LAPSE_QVGA},
};
+#if LOG_NDEBUG
+#define UNUSED __unused
+#else
+#define UNUSED
+#endif
+
/*static*/ void
-MediaProfiles::logVideoCodec(const MediaProfiles::VideoCodec& codec)
+MediaProfiles::logVideoCodec(const MediaProfiles::VideoCodec& codec UNUSED)
{
ALOGV("video codec:");
ALOGV("codec = %d", codec.mCodec);
@@ -93,7 +99,7 @@ MediaProfiles::logVideoCodec(const MediaProfiles::VideoCodec& codec)
}
/*static*/ void
-MediaProfiles::logAudioCodec(const MediaProfiles::AudioCodec& codec)
+MediaProfiles::logAudioCodec(const MediaProfiles::AudioCodec& codec UNUSED)
{
ALOGV("audio codec:");
ALOGV("codec = %d", codec.mCodec);
@@ -103,7 +109,7 @@ MediaProfiles::logAudioCodec(const MediaProfiles::AudioCodec& codec)
}
/*static*/ void
-MediaProfiles::logVideoEncoderCap(const MediaProfiles::VideoEncoderCap& cap)
+MediaProfiles::logVideoEncoderCap(const MediaProfiles::VideoEncoderCap& cap UNUSED)
{
ALOGV("video encoder cap:");
ALOGV("codec = %d", cap.mCodec);
@@ -114,7 +120,7 @@ MediaProfiles::logVideoEncoderCap(const MediaProfiles::VideoEncoderCap& cap)
}
/*static*/ void
-MediaProfiles::logAudioEncoderCap(const MediaProfiles::AudioEncoderCap& cap)
+MediaProfiles::logAudioEncoderCap(const MediaProfiles::AudioEncoderCap& cap UNUSED)
{
ALOGV("audio encoder cap:");
ALOGV("codec = %d", cap.mCodec);
@@ -124,21 +130,21 @@ MediaProfiles::logAudioEncoderCap(const MediaProfiles::AudioEncoderCap& cap)
}
/*static*/ void
-MediaProfiles::logVideoDecoderCap(const MediaProfiles::VideoDecoderCap& cap)
+MediaProfiles::logVideoDecoderCap(const MediaProfiles::VideoDecoderCap& cap UNUSED)
{
ALOGV("video decoder cap:");
ALOGV("codec = %d", cap.mCodec);
}
/*static*/ void
-MediaProfiles::logAudioDecoderCap(const MediaProfiles::AudioDecoderCap& cap)
+MediaProfiles::logAudioDecoderCap(const MediaProfiles::AudioDecoderCap& cap UNUSED)
{
ALOGV("audio codec cap:");
ALOGV("codec = %d", cap.mCodec);
}
/*static*/ void
-MediaProfiles::logVideoEditorCap(const MediaProfiles::VideoEditorCap& cap)
+MediaProfiles::logVideoEditorCap(const MediaProfiles::VideoEditorCap& cap UNUSED)
{
ALOGV("videoeditor cap:");
ALOGV("mMaxInputFrameWidth = %d", cap.mMaxInputFrameWidth);
diff --git a/media/libmedia/MediaScannerClient.cpp b/media/libmedia/MediaScannerClient.cpp
index 93a4a4c..1661f04 100644
--- a/media/libmedia/MediaScannerClient.cpp
+++ b/media/libmedia/MediaScannerClient.cpp
@@ -14,217 +14,57 @@
* limitations under the License.
*/
+//#define LOG_NDEBUG 0
+#define LOG_TAG "MediaScannerClient"
+#include <utils/Log.h>
+
#include <media/mediascanner.h>
+#include "CharacterEncodingDetector.h"
#include "StringArray.h"
-#include "autodetect.h"
-#include "unicode/ucnv.h"
-#include "unicode/ustring.h"
-
namespace android {
MediaScannerClient::MediaScannerClient()
- : mNames(NULL),
- mValues(NULL),
- mLocaleEncoding(kEncodingNone)
+ : mEncodingDetector(NULL)
{
}
MediaScannerClient::~MediaScannerClient()
{
- delete mNames;
- delete mValues;
+ delete mEncodingDetector;
}
void MediaScannerClient::setLocale(const char* locale)
{
- if (!locale) return;
-
- if (!strncmp(locale, "ja", 2))
- mLocaleEncoding = kEncodingShiftJIS;
- else if (!strncmp(locale, "ko", 2))
- mLocaleEncoding = kEncodingEUCKR;
- else if (!strncmp(locale, "zh", 2)) {
- if (!strcmp(locale, "zh_CN")) {
- // simplified chinese for mainland China
- mLocaleEncoding = kEncodingGBK;
- } else {
- // assume traditional for non-mainland Chinese locales (Taiwan, Hong Kong, Singapore)
- mLocaleEncoding = kEncodingBig5;
- }
- }
+ mLocale = locale; // not currently used
}
void MediaScannerClient::beginFile()
{
- mNames = new StringArray;
- mValues = new StringArray;
+ delete mEncodingDetector;
+ mEncodingDetector = new CharacterEncodingDetector();
}
status_t MediaScannerClient::addStringTag(const char* name, const char* value)
{
- if (mLocaleEncoding != kEncodingNone) {
- // don't bother caching strings that are all ASCII.
- // call handleStringTag directly instead.
- // check to see if value (which should be utf8) has any non-ASCII characters
- bool nonAscii = false;
- const char* chp = value;
- char ch;
- while ((ch = *chp++)) {
- if (ch & 0x80) {
- nonAscii = true;
- break;
- }
- }
-
- if (nonAscii) {
- // save the strings for later so they can be used for native encoding detection
- mNames->push_back(name);
- mValues->push_back(value);
- return OK;
- }
- // else fall through
- }
-
- // autodetection is not necessary, so no need to cache the values
- // pass directly to the client instead
- return handleStringTag(name, value);
-}
-
-static uint32_t possibleEncodings(const char* s)
-{
- uint32_t result = kEncodingAll;
- // if s contains a native encoding, then it was mistakenly encoded in utf8 as if it were latin-1
- // so we need to reverse the latin-1 -> utf8 conversion to get the native chars back
- uint8_t ch1, ch2;
- uint8_t* chp = (uint8_t *)s;
-
- while ((ch1 = *chp++)) {
- if (ch1 & 0x80) {
- ch2 = *chp++;
- ch1 = ((ch1 << 6) & 0xC0) | (ch2 & 0x3F);
- // ch1 is now the first byte of the potential native char
-
- ch2 = *chp++;
- if (ch2 & 0x80)
- ch2 = ((ch2 << 6) & 0xC0) | (*chp++ & 0x3F);
- // ch2 is now the second byte of the potential native char
- int ch = (int)ch1 << 8 | (int)ch2;
- result &= findPossibleEncodings(ch);
- }
- // else ASCII character, which could be anything
- }
-
- return result;
-}
-
-void MediaScannerClient::convertValues(uint32_t encoding)
-{
- const char* enc = NULL;
- switch (encoding) {
- case kEncodingShiftJIS:
- enc = "shift-jis";
- break;
- case kEncodingGBK:
- enc = "gbk";
- break;
- case kEncodingBig5:
- enc = "Big5";
- break;
- case kEncodingEUCKR:
- enc = "EUC-KR";
- break;
- }
-
- if (enc) {
- UErrorCode status = U_ZERO_ERROR;
-
- UConverter *conv = ucnv_open(enc, &status);
- if (U_FAILURE(status)) {
- ALOGE("could not create UConverter for %s", enc);
- return;
- }
- UConverter *utf8Conv = ucnv_open("UTF-8", &status);
- if (U_FAILURE(status)) {
- ALOGE("could not create UConverter for UTF-8");
- ucnv_close(conv);
- return;
- }
-
- // for each value string, convert from native encoding to UTF-8
- for (int i = 0; i < mNames->size(); i++) {
- // first we need to untangle the utf8 and convert it back to the original bytes
- // since we are reducing the length of the string, we can do this in place
- uint8_t* src = (uint8_t *)mValues->getEntry(i);
- int len = strlen((char *)src);
- uint8_t* dest = src;
-
- uint8_t uch;
- while ((uch = *src++)) {
- if (uch & 0x80)
- *dest++ = ((uch << 6) & 0xC0) | (*src++ & 0x3F);
- else
- *dest++ = uch;
- }
- *dest = 0;
-
- // now convert from native encoding to UTF-8
- const char* source = mValues->getEntry(i);
- int targetLength = len * 3 + 1;
- char* buffer = new char[targetLength];
- // don't normally check for NULL, but in this case targetLength may be large
- if (!buffer)
- break;
- char* target = buffer;
-
- ucnv_convertEx(utf8Conv, conv, &target, target + targetLength,
- &source, (const char *)dest, NULL, NULL, NULL, NULL, TRUE, TRUE, &status);
- if (U_FAILURE(status)) {
- ALOGE("ucnv_convertEx failed: %d", status);
- mValues->setEntry(i, "???");
- } else {
- // zero terminate
- *target = 0;
- mValues->setEntry(i, buffer);
- }
-
- delete[] buffer;
- }
-
- ucnv_close(conv);
- ucnv_close(utf8Conv);
- }
+ mEncodingDetector->addTag(name, value);
+ return OK;
}
void MediaScannerClient::endFile()
{
- if (mLocaleEncoding != kEncodingNone) {
- int size = mNames->size();
- uint32_t encoding = kEncodingAll;
-
- // compute a bit mask containing all possible encodings
- for (int i = 0; i < mNames->size(); i++)
- encoding &= possibleEncodings(mValues->getEntry(i));
-
- // if the locale encoding matches, then assume we have a native encoding.
- if (encoding & mLocaleEncoding)
- convertValues(mLocaleEncoding);
-
- // finally, push all name/value pairs to the client
- for (int i = 0; i < mNames->size(); i++) {
- status_t status = handleStringTag(mNames->getEntry(i), mValues->getEntry(i));
- if (status) {
- break;
- }
+ mEncodingDetector->detectAndConvert();
+
+ int size = mEncodingDetector->size();
+ if (size) {
+ for (int i = 0; i < size; i++) {
+ const char *name;
+ const char *value;
+ mEncodingDetector->getTag(i, &name, &value);
+ handleStringTag(name, value);
}
}
- // else addStringTag() has done all the work so we have nothing to do
-
- delete mNames;
- delete mValues;
- mNames = NULL;
- mValues = NULL;
}
} // namespace android
diff --git a/media/libmedia/SoundPool.cpp b/media/libmedia/SoundPool.cpp
index 22e9fad..a55e09c 100644
--- a/media/libmedia/SoundPool.cpp
+++ b/media/libmedia/SoundPool.cpp
@@ -21,6 +21,7 @@
#define USE_SHARED_MEM_BUFFER
#include <media/AudioTrack.h>
+#include <media/IMediaHTTPService.h>
#include <media/mediaplayer.h>
#include <media/SoundPool.h>
#include "SoundPoolThread.h"
@@ -199,7 +200,7 @@ SoundChannel* SoundPool::findNextChannel(int channelID)
return NULL;
}
-int SoundPool::load(const char* path, int priority)
+int SoundPool::load(const char* path, int priority __unused)
{
ALOGV("load: path=%s, priority=%d", path, priority);
Mutex::Autolock lock(&mLock);
@@ -209,7 +210,7 @@ int SoundPool::load(const char* path, int priority)
return sample->sampleID();
}
-int SoundPool::load(int fd, int64_t offset, int64_t length, int priority)
+int SoundPool::load(int fd, int64_t offset, int64_t length, int priority __unused)
{
ALOGV("load: fd=%d, offset=%lld, length=%lld, priority=%d",
fd, offset, length, priority);
@@ -496,7 +497,14 @@ status_t Sample::doLoad()
ALOGV("Start decode");
if (mUrl) {
- status = MediaPlayer::decode(mUrl, &sampleRate, &numChannels, &format, mHeap, &mSize);
+ status = MediaPlayer::decode(
+ NULL /* httpService */,
+ mUrl,
+ &sampleRate,
+ &numChannels,
+ &format,
+ mHeap,
+ &mSize);
} else {
status = MediaPlayer::decode(mFd, mOffset, mLength, &sampleRate, &numChannels, &format,
mHeap, &mSize);
@@ -579,7 +587,7 @@ void SoundChannel::play(const sp<Sample>& sample, int nextChannelID, float leftV
uint32_t sampleRate = uint32_t(float(sample->sampleRate()) * rate + 0.5);
uint32_t totalFrames = (kDefaultBufferCount * afFrameCount * sampleRate) / afSampleRate;
uint32_t bufferFrames = (totalFrames + (kDefaultBufferCount - 1)) / kDefaultBufferCount;
- uint32_t frameCount = 0;
+ size_t frameCount = 0;
if (loop) {
frameCount = sample->size()/numChannels/
@@ -600,16 +608,15 @@ void SoundChannel::play(const sp<Sample>& sample, int nextChannelID, float leftV
// wrong audio audio buffer size (mAudioBufferSize)
unsigned long toggle = mToggle ^ 1;
void *userData = (void *)((unsigned long)this | toggle);
- uint32_t channels = (numChannels == 2) ?
- AUDIO_CHANNEL_OUT_STEREO : AUDIO_CHANNEL_OUT_MONO;
+ audio_channel_mask_t channelMask = audio_channel_out_mask_from_count(numChannels);
// do not create a new audio track if current track is compatible with sample parameters
#ifdef USE_SHARED_MEM_BUFFER
newTrack = new AudioTrack(streamType, sampleRate, sample->format(),
- channels, sample->getIMemory(), AUDIO_OUTPUT_FLAG_FAST, callback, userData);
+ channelMask, sample->getIMemory(), AUDIO_OUTPUT_FLAG_FAST, callback, userData);
#else
newTrack = new AudioTrack(streamType, sampleRate, sample->format(),
- channels, frameCount, AUDIO_OUTPUT_FLAG_FAST, callback, userData,
+ channelMask, frameCount, AUDIO_OUTPUT_FLAG_FAST, callback, userData,
bufferFrames);
#endif
oldTrack = mAudioTrack;
@@ -730,7 +737,8 @@ void SoundChannel::process(int event, void *info, unsigned long toggle)
count = b->size;
}
memcpy(q, p, count);
-// ALOGV("fill: q=%p, p=%p, mPos=%u, b->size=%u, count=%d", q, p, mPos, b->size, count);
+// ALOGV("fill: q=%p, p=%p, mPos=%u, b->size=%u, count=%d", q, p, mPos, b->size,
+// count);
} else if (mPos < mAudioBufferSize) {
count = mAudioBufferSize - mPos;
if (count > b->size) {
diff --git a/media/libmedia/ToneGenerator.cpp b/media/libmedia/ToneGenerator.cpp
index adef3be..61b6d36 100644
--- a/media/libmedia/ToneGenerator.cpp
+++ b/media/libmedia/ToneGenerator.cpp
@@ -1057,7 +1057,7 @@ bool ToneGenerator::initAudioTrack() {
0, // notificationFrames
0, // sharedBuffer
mThreadCanCallJava,
- 0, // sessionId
+ AUDIO_SESSION_ALLOCATE,
AudioTrack::TRANSFER_CALLBACK);
if (mpAudioTrack->initCheck() != NO_ERROR) {
diff --git a/media/libmedia/autodetect.cpp b/media/libmedia/autodetect.cpp
deleted file mode 100644
index be5c3b2..0000000
--- a/media/libmedia/autodetect.cpp
+++ /dev/null
@@ -1,885 +0,0 @@
-/*
- * Copyright (C) 2008 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 "autodetect.h"
-
-struct CharRange {
- uint16_t first;
- uint16_t last;
-};
-
-#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*x))
-
-// generated from http://unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WINDOWS/CP932.TXT
-static const CharRange kShiftJISRanges[] = {
- { 0x8140, 0x817E },
- { 0x8180, 0x81AC },
- { 0x81B8, 0x81BF },
- { 0x81C8, 0x81CE },
- { 0x81DA, 0x81E8 },
- { 0x81F0, 0x81F7 },
- { 0x81FC, 0x81FC },
- { 0x824F, 0x8258 },
- { 0x8260, 0x8279 },
- { 0x8281, 0x829A },
- { 0x829F, 0x82F1 },
- { 0x8340, 0x837E },
- { 0x8380, 0x8396 },
- { 0x839F, 0x83B6 },
- { 0x83BF, 0x83D6 },
- { 0x8440, 0x8460 },
- { 0x8470, 0x847E },
- { 0x8480, 0x8491 },
- { 0x849F, 0x84BE },
- { 0x8740, 0x875D },
- { 0x875F, 0x8775 },
- { 0x877E, 0x877E },
- { 0x8780, 0x879C },
- { 0x889F, 0x88FC },
- { 0x8940, 0x897E },
- { 0x8980, 0x89FC },
- { 0x8A40, 0x8A7E },
- { 0x8A80, 0x8AFC },
- { 0x8B40, 0x8B7E },
- { 0x8B80, 0x8BFC },
- { 0x8C40, 0x8C7E },
- { 0x8C80, 0x8CFC },
- { 0x8D40, 0x8D7E },
- { 0x8D80, 0x8DFC },
- { 0x8E40, 0x8E7E },
- { 0x8E80, 0x8EFC },
- { 0x8F40, 0x8F7E },
- { 0x8F80, 0x8FFC },
- { 0x9040, 0x907E },
- { 0x9080, 0x90FC },
- { 0x9140, 0x917E },
- { 0x9180, 0x91FC },
- { 0x9240, 0x927E },
- { 0x9280, 0x92FC },
- { 0x9340, 0x937E },
- { 0x9380, 0x93FC },
- { 0x9440, 0x947E },
- { 0x9480, 0x94FC },
- { 0x9540, 0x957E },
- { 0x9580, 0x95FC },
- { 0x9640, 0x967E },
- { 0x9680, 0x96FC },
- { 0x9740, 0x977E },
- { 0x9780, 0x97FC },
- { 0x9840, 0x9872 },
- { 0x989F, 0x98FC },
- { 0x9940, 0x997E },
- { 0x9980, 0x99FC },
- { 0x9A40, 0x9A7E },
- { 0x9A80, 0x9AFC },
- { 0x9B40, 0x9B7E },
- { 0x9B80, 0x9BFC },
- { 0x9C40, 0x9C7E },
- { 0x9C80, 0x9CFC },
- { 0x9D40, 0x9D7E },
- { 0x9D80, 0x9DFC },
- { 0x9E40, 0x9E7E },
- { 0x9E80, 0x9EFC },
- { 0x9F40, 0x9F7E },
- { 0x9F80, 0x9FFC },
- { 0xE040, 0xE07E },
- { 0xE080, 0xE0FC },
- { 0xE140, 0xE17E },
- { 0xE180, 0xE1FC },
- { 0xE240, 0xE27E },
- { 0xE280, 0xE2FC },
- { 0xE340, 0xE37E },
- { 0xE380, 0xE3FC },
- { 0xE440, 0xE47E },
- { 0xE480, 0xE4FC },
- { 0xE540, 0xE57E },
- { 0xE580, 0xE5FC },
- { 0xE640, 0xE67E },
- { 0xE680, 0xE6FC },
- { 0xE740, 0xE77E },
- { 0xE780, 0xE7FC },
- { 0xE840, 0xE87E },
- { 0xE880, 0xE8FC },
- { 0xE940, 0xE97E },
- { 0xE980, 0xE9FC },
- { 0xEA40, 0xEA7E },
- { 0xEA80, 0xEAA4 },
- { 0xED40, 0xED7E },
- { 0xED80, 0xEDFC },
- { 0xEE40, 0xEE7E },
- { 0xEE80, 0xEEEC },
- { 0xEEEF, 0xEEFC },
- { 0xFA40, 0xFA7E },
- { 0xFA80, 0xFAFC },
- { 0xFB40, 0xFB7E },
- { 0xFB80, 0xFBFC },
- { 0xFC40, 0xFC4B },
-};
-
-// generated from http://unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WINDOWS/CP936.TXT
-static const CharRange kGBKRanges[] = {
- { 0x8140, 0x817E },
- { 0x8180, 0x81FE },
- { 0x8240, 0x827E },
- { 0x8280, 0x82FE },
- { 0x8340, 0x837E },
- { 0x8380, 0x83FE },
- { 0x8440, 0x847E },
- { 0x8480, 0x84FE },
- { 0x8540, 0x857E },
- { 0x8580, 0x85FE },
- { 0x8640, 0x867E },
- { 0x8680, 0x86FE },
- { 0x8740, 0x877E },
- { 0x8780, 0x87FE },
- { 0x8840, 0x887E },
- { 0x8880, 0x88FE },
- { 0x8940, 0x897E },
- { 0x8980, 0x89FE },
- { 0x8A40, 0x8A7E },
- { 0x8A80, 0x8AFE },
- { 0x8B40, 0x8B7E },
- { 0x8B80, 0x8BFE },
- { 0x8C40, 0x8C7E },
- { 0x8C80, 0x8CFE },
- { 0x8D40, 0x8D7E },
- { 0x8D80, 0x8DFE },
- { 0x8E40, 0x8E7E },
- { 0x8E80, 0x8EFE },
- { 0x8F40, 0x8F7E },
- { 0x8F80, 0x8FFE },
- { 0x9040, 0x907E },
- { 0x9080, 0x90FE },
- { 0x9140, 0x917E },
- { 0x9180, 0x91FE },
- { 0x9240, 0x927E },
- { 0x9280, 0x92FE },
- { 0x9340, 0x937E },
- { 0x9380, 0x93FE },
- { 0x9440, 0x947E },
- { 0x9480, 0x94FE },
- { 0x9540, 0x957E },
- { 0x9580, 0x95FE },
- { 0x9640, 0x967E },
- { 0x9680, 0x96FE },
- { 0x9740, 0x977E },
- { 0x9780, 0x97FE },
- { 0x9840, 0x987E },
- { 0x9880, 0x98FE },
- { 0x9940, 0x997E },
- { 0x9980, 0x99FE },
- { 0x9A40, 0x9A7E },
- { 0x9A80, 0x9AFE },
- { 0x9B40, 0x9B7E },
- { 0x9B80, 0x9BFE },
- { 0x9C40, 0x9C7E },
- { 0x9C80, 0x9CFE },
- { 0x9D40, 0x9D7E },
- { 0x9D80, 0x9DFE },
- { 0x9E40, 0x9E7E },
- { 0x9E80, 0x9EFE },
- { 0x9F40, 0x9F7E },
- { 0x9F80, 0x9FFE },
- { 0xA040, 0xA07E },
- { 0xA080, 0xA0FE },
- { 0xA1A1, 0xA1FE },
- { 0xA2A1, 0xA2AA },
- { 0xA2B1, 0xA2E2 },
- { 0xA2E5, 0xA2EE },
- { 0xA2F1, 0xA2FC },
- { 0xA3A1, 0xA3FE },
- { 0xA4A1, 0xA4F3 },
- { 0xA5A1, 0xA5F6 },
- { 0xA6A1, 0xA6B8 },
- { 0xA6C1, 0xA6D8 },
- { 0xA6E0, 0xA6EB },
- { 0xA6EE, 0xA6F2 },
- { 0xA6F4, 0xA6F5 },
- { 0xA7A1, 0xA7C1 },
- { 0xA7D1, 0xA7F1 },
- { 0xA840, 0xA87E },
- { 0xA880, 0xA895 },
- { 0xA8A1, 0xA8BB },
- { 0xA8BD, 0xA8BE },
- { 0xA8C0, 0xA8C0 },
- { 0xA8C5, 0xA8E9 },
- { 0xA940, 0xA957 },
- { 0xA959, 0xA95A },
- { 0xA95C, 0xA95C },
- { 0xA960, 0xA97E },
- { 0xA980, 0xA988 },
- { 0xA996, 0xA996 },
- { 0xA9A4, 0xA9EF },
- { 0xAA40, 0xAA7E },
- { 0xAA80, 0xAAA0 },
- { 0xAB40, 0xAB7E },
- { 0xAB80, 0xABA0 },
- { 0xAC40, 0xAC7E },
- { 0xAC80, 0xACA0 },
- { 0xAD40, 0xAD7E },
- { 0xAD80, 0xADA0 },
- { 0xAE40, 0xAE7E },
- { 0xAE80, 0xAEA0 },
- { 0xAF40, 0xAF7E },
- { 0xAF80, 0xAFA0 },
- { 0xB040, 0xB07E },
- { 0xB080, 0xB0FE },
- { 0xB140, 0xB17E },
- { 0xB180, 0xB1FE },
- { 0xB240, 0xB27E },
- { 0xB280, 0xB2FE },
- { 0xB340, 0xB37E },
- { 0xB380, 0xB3FE },
- { 0xB440, 0xB47E },
- { 0xB480, 0xB4FE },
- { 0xB540, 0xB57E },
- { 0xB580, 0xB5FE },
- { 0xB640, 0xB67E },
- { 0xB680, 0xB6FE },
- { 0xB740, 0xB77E },
- { 0xB780, 0xB7FE },
- { 0xB840, 0xB87E },
- { 0xB880, 0xB8FE },
- { 0xB940, 0xB97E },
- { 0xB980, 0xB9FE },
- { 0xBA40, 0xBA7E },
- { 0xBA80, 0xBAFE },
- { 0xBB40, 0xBB7E },
- { 0xBB80, 0xBBFE },
- { 0xBC40, 0xBC7E },
- { 0xBC80, 0xBCFE },
- { 0xBD40, 0xBD7E },
- { 0xBD80, 0xBDFE },
- { 0xBE40, 0xBE7E },
- { 0xBE80, 0xBEFE },
- { 0xBF40, 0xBF7E },
- { 0xBF80, 0xBFFE },
- { 0xC040, 0xC07E },
- { 0xC080, 0xC0FE },
- { 0xC140, 0xC17E },
- { 0xC180, 0xC1FE },
- { 0xC240, 0xC27E },
- { 0xC280, 0xC2FE },
- { 0xC340, 0xC37E },
- { 0xC380, 0xC3FE },
- { 0xC440, 0xC47E },
- { 0xC480, 0xC4FE },
- { 0xC540, 0xC57E },
- { 0xC580, 0xC5FE },
- { 0xC640, 0xC67E },
- { 0xC680, 0xC6FE },
- { 0xC740, 0xC77E },
- { 0xC780, 0xC7FE },
- { 0xC840, 0xC87E },
- { 0xC880, 0xC8FE },
- { 0xC940, 0xC97E },
- { 0xC980, 0xC9FE },
- { 0xCA40, 0xCA7E },
- { 0xCA80, 0xCAFE },
- { 0xCB40, 0xCB7E },
- { 0xCB80, 0xCBFE },
- { 0xCC40, 0xCC7E },
- { 0xCC80, 0xCCFE },
- { 0xCD40, 0xCD7E },
- { 0xCD80, 0xCDFE },
- { 0xCE40, 0xCE7E },
- { 0xCE80, 0xCEFE },
- { 0xCF40, 0xCF7E },
- { 0xCF80, 0xCFFE },
- { 0xD040, 0xD07E },
- { 0xD080, 0xD0FE },
- { 0xD140, 0xD17E },
- { 0xD180, 0xD1FE },
- { 0xD240, 0xD27E },
- { 0xD280, 0xD2FE },
- { 0xD340, 0xD37E },
- { 0xD380, 0xD3FE },
- { 0xD440, 0xD47E },
- { 0xD480, 0xD4FE },
- { 0xD540, 0xD57E },
- { 0xD580, 0xD5FE },
- { 0xD640, 0xD67E },
- { 0xD680, 0xD6FE },
- { 0xD740, 0xD77E },
- { 0xD780, 0xD7F9 },
- { 0xD840, 0xD87E },
- { 0xD880, 0xD8FE },
- { 0xD940, 0xD97E },
- { 0xD980, 0xD9FE },
- { 0xDA40, 0xDA7E },
- { 0xDA80, 0xDAFE },
- { 0xDB40, 0xDB7E },
- { 0xDB80, 0xDBFE },
- { 0xDC40, 0xDC7E },
- { 0xDC80, 0xDCFE },
- { 0xDD40, 0xDD7E },
- { 0xDD80, 0xDDFE },
- { 0xDE40, 0xDE7E },
- { 0xDE80, 0xDEFE },
- { 0xDF40, 0xDF7E },
- { 0xDF80, 0xDFFE },
- { 0xE040, 0xE07E },
- { 0xE080, 0xE0FE },
- { 0xE140, 0xE17E },
- { 0xE180, 0xE1FE },
- { 0xE240, 0xE27E },
- { 0xE280, 0xE2FE },
- { 0xE340, 0xE37E },
- { 0xE380, 0xE3FE },
- { 0xE440, 0xE47E },
- { 0xE480, 0xE4FE },
- { 0xE540, 0xE57E },
- { 0xE580, 0xE5FE },
- { 0xE640, 0xE67E },
- { 0xE680, 0xE6FE },
- { 0xE740, 0xE77E },
- { 0xE780, 0xE7FE },
- { 0xE840, 0xE87E },
- { 0xE880, 0xE8FE },
- { 0xE940, 0xE97E },
- { 0xE980, 0xE9FE },
- { 0xEA40, 0xEA7E },
- { 0xEA80, 0xEAFE },
- { 0xEB40, 0xEB7E },
- { 0xEB80, 0xEBFE },
- { 0xEC40, 0xEC7E },
- { 0xEC80, 0xECFE },
- { 0xED40, 0xED7E },
- { 0xED80, 0xEDFE },
- { 0xEE40, 0xEE7E },
- { 0xEE80, 0xEEFE },
- { 0xEF40, 0xEF7E },
- { 0xEF80, 0xEFFE },
- { 0xF040, 0xF07E },
- { 0xF080, 0xF0FE },
- { 0xF140, 0xF17E },
- { 0xF180, 0xF1FE },
- { 0xF240, 0xF27E },
- { 0xF280, 0xF2FE },
- { 0xF340, 0xF37E },
- { 0xF380, 0xF3FE },
- { 0xF440, 0xF47E },
- { 0xF480, 0xF4FE },
- { 0xF540, 0xF57E },
- { 0xF580, 0xF5FE },
- { 0xF640, 0xF67E },
- { 0xF680, 0xF6FE },
- { 0xF740, 0xF77E },
- { 0xF780, 0xF7FE },
- { 0xF840, 0xF87E },
- { 0xF880, 0xF8A0 },
- { 0xF940, 0xF97E },
- { 0xF980, 0xF9A0 },
- { 0xFA40, 0xFA7E },
- { 0xFA80, 0xFAA0 },
- { 0xFB40, 0xFB7E },
- { 0xFB80, 0xFBA0 },
- { 0xFC40, 0xFC7E },
- { 0xFC80, 0xFCA0 },
- { 0xFD40, 0xFD7E },
- { 0xFD80, 0xFDA0 },
- { 0xFE40, 0xFE4F },
-};
-
-// generated from http://unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WINDOWS/CP949.TXT
-static const CharRange kEUCKRRanges[] = {
- { 0x8141, 0x815A },
- { 0x8161, 0x817A },
- { 0x8181, 0x81FE },
- { 0x8241, 0x825A },
- { 0x8261, 0x827A },
- { 0x8281, 0x82FE },
- { 0x8341, 0x835A },
- { 0x8361, 0x837A },
- { 0x8381, 0x83FE },
- { 0x8441, 0x845A },
- { 0x8461, 0x847A },
- { 0x8481, 0x84FE },
- { 0x8541, 0x855A },
- { 0x8561, 0x857A },
- { 0x8581, 0x85FE },
- { 0x8641, 0x865A },
- { 0x8661, 0x867A },
- { 0x8681, 0x86FE },
- { 0x8741, 0x875A },
- { 0x8761, 0x877A },
- { 0x8781, 0x87FE },
- { 0x8841, 0x885A },
- { 0x8861, 0x887A },
- { 0x8881, 0x88FE },
- { 0x8941, 0x895A },
- { 0x8961, 0x897A },
- { 0x8981, 0x89FE },
- { 0x8A41, 0x8A5A },
- { 0x8A61, 0x8A7A },
- { 0x8A81, 0x8AFE },
- { 0x8B41, 0x8B5A },
- { 0x8B61, 0x8B7A },
- { 0x8B81, 0x8BFE },
- { 0x8C41, 0x8C5A },
- { 0x8C61, 0x8C7A },
- { 0x8C81, 0x8CFE },
- { 0x8D41, 0x8D5A },
- { 0x8D61, 0x8D7A },
- { 0x8D81, 0x8DFE },
- { 0x8E41, 0x8E5A },
- { 0x8E61, 0x8E7A },
- { 0x8E81, 0x8EFE },
- { 0x8F41, 0x8F5A },
- { 0x8F61, 0x8F7A },
- { 0x8F81, 0x8FFE },
- { 0x9041, 0x905A },
- { 0x9061, 0x907A },
- { 0x9081, 0x90FE },
- { 0x9141, 0x915A },
- { 0x9161, 0x917A },
- { 0x9181, 0x91FE },
- { 0x9241, 0x925A },
- { 0x9261, 0x927A },
- { 0x9281, 0x92FE },
- { 0x9341, 0x935A },
- { 0x9361, 0x937A },
- { 0x9381, 0x93FE },
- { 0x9441, 0x945A },
- { 0x9461, 0x947A },
- { 0x9481, 0x94FE },
- { 0x9541, 0x955A },
- { 0x9561, 0x957A },
- { 0x9581, 0x95FE },
- { 0x9641, 0x965A },
- { 0x9661, 0x967A },
- { 0x9681, 0x96FE },
- { 0x9741, 0x975A },
- { 0x9761, 0x977A },
- { 0x9781, 0x97FE },
- { 0x9841, 0x985A },
- { 0x9861, 0x987A },
- { 0x9881, 0x98FE },
- { 0x9941, 0x995A },
- { 0x9961, 0x997A },
- { 0x9981, 0x99FE },
- { 0x9A41, 0x9A5A },
- { 0x9A61, 0x9A7A },
- { 0x9A81, 0x9AFE },
- { 0x9B41, 0x9B5A },
- { 0x9B61, 0x9B7A },
- { 0x9B81, 0x9BFE },
- { 0x9C41, 0x9C5A },
- { 0x9C61, 0x9C7A },
- { 0x9C81, 0x9CFE },
- { 0x9D41, 0x9D5A },
- { 0x9D61, 0x9D7A },
- { 0x9D81, 0x9DFE },
- { 0x9E41, 0x9E5A },
- { 0x9E61, 0x9E7A },
- { 0x9E81, 0x9EFE },
- { 0x9F41, 0x9F5A },
- { 0x9F61, 0x9F7A },
- { 0x9F81, 0x9FFE },
- { 0xA041, 0xA05A },
- { 0xA061, 0xA07A },
- { 0xA081, 0xA0FE },
- { 0xA141, 0xA15A },
- { 0xA161, 0xA17A },
- { 0xA181, 0xA1FE },
- { 0xA241, 0xA25A },
- { 0xA261, 0xA27A },
- { 0xA281, 0xA2E7 },
- { 0xA341, 0xA35A },
- { 0xA361, 0xA37A },
- { 0xA381, 0xA3FE },
- { 0xA441, 0xA45A },
- { 0xA461, 0xA47A },
- { 0xA481, 0xA4FE },
- { 0xA541, 0xA55A },
- { 0xA561, 0xA57A },
- { 0xA581, 0xA5AA },
- { 0xA5B0, 0xA5B9 },
- { 0xA5C1, 0xA5D8 },
- { 0xA5E1, 0xA5F8 },
- { 0xA641, 0xA65A },
- { 0xA661, 0xA67A },
- { 0xA681, 0xA6E4 },
- { 0xA741, 0xA75A },
- { 0xA761, 0xA77A },
- { 0xA781, 0xA7EF },
- { 0xA841, 0xA85A },
- { 0xA861, 0xA87A },
- { 0xA881, 0xA8A4 },
- { 0xA8A6, 0xA8A6 },
- { 0xA8A8, 0xA8AF },
- { 0xA8B1, 0xA8FE },
- { 0xA941, 0xA95A },
- { 0xA961, 0xA97A },
- { 0xA981, 0xA9FE },
- { 0xAA41, 0xAA5A },
- { 0xAA61, 0xAA7A },
- { 0xAA81, 0xAAF3 },
- { 0xAB41, 0xAB5A },
- { 0xAB61, 0xAB7A },
- { 0xAB81, 0xABF6 },
- { 0xAC41, 0xAC5A },
- { 0xAC61, 0xAC7A },
- { 0xAC81, 0xACC1 },
- { 0xACD1, 0xACF1 },
- { 0xAD41, 0xAD5A },
- { 0xAD61, 0xAD7A },
- { 0xAD81, 0xADA0 },
- { 0xAE41, 0xAE5A },
- { 0xAE61, 0xAE7A },
- { 0xAE81, 0xAEA0 },
- { 0xAF41, 0xAF5A },
- { 0xAF61, 0xAF7A },
- { 0xAF81, 0xAFA0 },
- { 0xB041, 0xB05A },
- { 0xB061, 0xB07A },
- { 0xB081, 0xB0FE },
- { 0xB141, 0xB15A },
- { 0xB161, 0xB17A },
- { 0xB181, 0xB1FE },
- { 0xB241, 0xB25A },
- { 0xB261, 0xB27A },
- { 0xB281, 0xB2FE },
- { 0xB341, 0xB35A },
- { 0xB361, 0xB37A },
- { 0xB381, 0xB3FE },
- { 0xB441, 0xB45A },
- { 0xB461, 0xB47A },
- { 0xB481, 0xB4FE },
- { 0xB541, 0xB55A },
- { 0xB561, 0xB57A },
- { 0xB581, 0xB5FE },
- { 0xB641, 0xB65A },
- { 0xB661, 0xB67A },
- { 0xB681, 0xB6FE },
- { 0xB741, 0xB75A },
- { 0xB761, 0xB77A },
- { 0xB781, 0xB7FE },
- { 0xB841, 0xB85A },
- { 0xB861, 0xB87A },
- { 0xB881, 0xB8FE },
- { 0xB941, 0xB95A },
- { 0xB961, 0xB97A },
- { 0xB981, 0xB9FE },
- { 0xBA41, 0xBA5A },
- { 0xBA61, 0xBA7A },
- { 0xBA81, 0xBAFE },
- { 0xBB41, 0xBB5A },
- { 0xBB61, 0xBB7A },
- { 0xBB81, 0xBBFE },
- { 0xBC41, 0xBC5A },
- { 0xBC61, 0xBC7A },
- { 0xBC81, 0xBCFE },
- { 0xBD41, 0xBD5A },
- { 0xBD61, 0xBD7A },
- { 0xBD81, 0xBDFE },
- { 0xBE41, 0xBE5A },
- { 0xBE61, 0xBE7A },
- { 0xBE81, 0xBEFE },
- { 0xBF41, 0xBF5A },
- { 0xBF61, 0xBF7A },
- { 0xBF81, 0xBFFE },
- { 0xC041, 0xC05A },
- { 0xC061, 0xC07A },
- { 0xC081, 0xC0FE },
- { 0xC141, 0xC15A },
- { 0xC161, 0xC17A },
- { 0xC181, 0xC1FE },
- { 0xC241, 0xC25A },
- { 0xC261, 0xC27A },
- { 0xC281, 0xC2FE },
- { 0xC341, 0xC35A },
- { 0xC361, 0xC37A },
- { 0xC381, 0xC3FE },
- { 0xC441, 0xC45A },
- { 0xC461, 0xC47A },
- { 0xC481, 0xC4FE },
- { 0xC541, 0xC55A },
- { 0xC561, 0xC57A },
- { 0xC581, 0xC5FE },
- { 0xC641, 0xC652 },
- { 0xC6A1, 0xC6FE },
- { 0xC7A1, 0xC7FE },
- { 0xC8A1, 0xC8FE },
- { 0xCAA1, 0xCAFE },
- { 0xCBA1, 0xCBFE },
- { 0xCCA1, 0xCCFE },
- { 0xCDA1, 0xCDFE },
- { 0xCEA1, 0xCEFE },
- { 0xCFA1, 0xCFFE },
- { 0xD0A1, 0xD0FE },
- { 0xD1A1, 0xD1FE },
- { 0xD2A1, 0xD2FE },
- { 0xD3A1, 0xD3FE },
- { 0xD4A1, 0xD4FE },
- { 0xD5A1, 0xD5FE },
- { 0xD6A1, 0xD6FE },
- { 0xD7A1, 0xD7FE },
- { 0xD8A1, 0xD8FE },
- { 0xD9A1, 0xD9FE },
- { 0xDAA1, 0xDAFE },
- { 0xDBA1, 0xDBFE },
- { 0xDCA1, 0xDCFE },
- { 0xDDA1, 0xDDFE },
- { 0xDEA1, 0xDEFE },
- { 0xDFA1, 0xDFFE },
- { 0xE0A1, 0xE0FE },
- { 0xE1A1, 0xE1FE },
- { 0xE2A1, 0xE2FE },
- { 0xE3A1, 0xE3FE },
- { 0xE4A1, 0xE4FE },
- { 0xE5A1, 0xE5FE },
- { 0xE6A1, 0xE6FE },
- { 0xE7A1, 0xE7FE },
- { 0xE8A1, 0xE8FE },
- { 0xE9A1, 0xE9FE },
- { 0xEAA1, 0xEAFE },
- { 0xEBA1, 0xEBFE },
- { 0xECA1, 0xECFE },
- { 0xEDA1, 0xEDFE },
- { 0xEEA1, 0xEEFE },
- { 0xEFA1, 0xEFFE },
- { 0xF0A1, 0xF0FE },
- { 0xF1A1, 0xF1FE },
- { 0xF2A1, 0xF2FE },
- { 0xF3A1, 0xF3FE },
- { 0xF4A1, 0xF4FE },
- { 0xF5A1, 0xF5FE },
- { 0xF6A1, 0xF6FE },
- { 0xF7A1, 0xF7FE },
- { 0xF8A1, 0xF8FE },
- { 0xF9A1, 0xF9FE },
- { 0xFAA1, 0xFAFE },
- { 0xFBA1, 0xFBFE },
- { 0xFCA1, 0xFCFE },
- { 0xFDA1, 0xFDFE },
-};
-
-// generated from http://unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WINDOWS/CP950.TXT
-static const CharRange kBig5Ranges[] = {
- { 0xA140, 0xA17E },
- { 0xA1A1, 0xA1FE },
- { 0xA240, 0xA27E },
- { 0xA2A1, 0xA2FE },
- { 0xA340, 0xA37E },
- { 0xA3A1, 0xA3BF },
- { 0xA3E1, 0xA3E1 },
- { 0xA440, 0xA47E },
- { 0xA4A1, 0xA4FE },
- { 0xA540, 0xA57E },
- { 0xA5A1, 0xA5FE },
- { 0xA640, 0xA67E },
- { 0xA6A1, 0xA6FE },
- { 0xA740, 0xA77E },
- { 0xA7A1, 0xA7FE },
- { 0xA840, 0xA87E },
- { 0xA8A1, 0xA8FE },
- { 0xA940, 0xA97E },
- { 0xA9A1, 0xA9FE },
- { 0xAA40, 0xAA7E },
- { 0xAAA1, 0xAAFE },
- { 0xAB40, 0xAB7E },
- { 0xABA1, 0xABFE },
- { 0xAC40, 0xAC7E },
- { 0xACA1, 0xACFE },
- { 0xAD40, 0xAD7E },
- { 0xADA1, 0xADFE },
- { 0xAE40, 0xAE7E },
- { 0xAEA1, 0xAEFE },
- { 0xAF40, 0xAF7E },
- { 0xAFA1, 0xAFFE },
- { 0xB040, 0xB07E },
- { 0xB0A1, 0xB0FE },
- { 0xB140, 0xB17E },
- { 0xB1A1, 0xB1FE },
- { 0xB240, 0xB27E },
- { 0xB2A1, 0xB2FE },
- { 0xB340, 0xB37E },
- { 0xB3A1, 0xB3FE },
- { 0xB440, 0xB47E },
- { 0xB4A1, 0xB4FE },
- { 0xB540, 0xB57E },
- { 0xB5A1, 0xB5FE },
- { 0xB640, 0xB67E },
- { 0xB6A1, 0xB6FE },
- { 0xB740, 0xB77E },
- { 0xB7A1, 0xB7FE },
- { 0xB840, 0xB87E },
- { 0xB8A1, 0xB8FE },
- { 0xB940, 0xB97E },
- { 0xB9A1, 0xB9FE },
- { 0xBA40, 0xBA7E },
- { 0xBAA1, 0xBAFE },
- { 0xBB40, 0xBB7E },
- { 0xBBA1, 0xBBFE },
- { 0xBC40, 0xBC7E },
- { 0xBCA1, 0xBCFE },
- { 0xBD40, 0xBD7E },
- { 0xBDA1, 0xBDFE },
- { 0xBE40, 0xBE7E },
- { 0xBEA1, 0xBEFE },
- { 0xBF40, 0xBF7E },
- { 0xBFA1, 0xBFFE },
- { 0xC040, 0xC07E },
- { 0xC0A1, 0xC0FE },
- { 0xC140, 0xC17E },
- { 0xC1A1, 0xC1FE },
- { 0xC240, 0xC27E },
- { 0xC2A1, 0xC2FE },
- { 0xC340, 0xC37E },
- { 0xC3A1, 0xC3FE },
- { 0xC440, 0xC47E },
- { 0xC4A1, 0xC4FE },
- { 0xC540, 0xC57E },
- { 0xC5A1, 0xC5FE },
- { 0xC640, 0xC67E },
- { 0xC940, 0xC97E },
- { 0xC9A1, 0xC9FE },
- { 0xCA40, 0xCA7E },
- { 0xCAA1, 0xCAFE },
- { 0xCB40, 0xCB7E },
- { 0xCBA1, 0xCBFE },
- { 0xCC40, 0xCC7E },
- { 0xCCA1, 0xCCFE },
- { 0xCD40, 0xCD7E },
- { 0xCDA1, 0xCDFE },
- { 0xCE40, 0xCE7E },
- { 0xCEA1, 0xCEFE },
- { 0xCF40, 0xCF7E },
- { 0xCFA1, 0xCFFE },
- { 0xD040, 0xD07E },
- { 0xD0A1, 0xD0FE },
- { 0xD140, 0xD17E },
- { 0xD1A1, 0xD1FE },
- { 0xD240, 0xD27E },
- { 0xD2A1, 0xD2FE },
- { 0xD340, 0xD37E },
- { 0xD3A1, 0xD3FE },
- { 0xD440, 0xD47E },
- { 0xD4A1, 0xD4FE },
- { 0xD540, 0xD57E },
- { 0xD5A1, 0xD5FE },
- { 0xD640, 0xD67E },
- { 0xD6A1, 0xD6FE },
- { 0xD740, 0xD77E },
- { 0xD7A1, 0xD7FE },
- { 0xD840, 0xD87E },
- { 0xD8A1, 0xD8FE },
- { 0xD940, 0xD97E },
- { 0xD9A1, 0xD9FE },
- { 0xDA40, 0xDA7E },
- { 0xDAA1, 0xDAFE },
- { 0xDB40, 0xDB7E },
- { 0xDBA1, 0xDBFE },
- { 0xDC40, 0xDC7E },
- { 0xDCA1, 0xDCFE },
- { 0xDD40, 0xDD7E },
- { 0xDDA1, 0xDDFE },
- { 0xDE40, 0xDE7E },
- { 0xDEA1, 0xDEFE },
- { 0xDF40, 0xDF7E },
- { 0xDFA1, 0xDFFE },
- { 0xE040, 0xE07E },
- { 0xE0A1, 0xE0FE },
- { 0xE140, 0xE17E },
- { 0xE1A1, 0xE1FE },
- { 0xE240, 0xE27E },
- { 0xE2A1, 0xE2FE },
- { 0xE340, 0xE37E },
- { 0xE3A1, 0xE3FE },
- { 0xE440, 0xE47E },
- { 0xE4A1, 0xE4FE },
- { 0xE540, 0xE57E },
- { 0xE5A1, 0xE5FE },
- { 0xE640, 0xE67E },
- { 0xE6A1, 0xE6FE },
- { 0xE740, 0xE77E },
- { 0xE7A1, 0xE7FE },
- { 0xE840, 0xE87E },
- { 0xE8A1, 0xE8FE },
- { 0xE940, 0xE97E },
- { 0xE9A1, 0xE9FE },
- { 0xEA40, 0xEA7E },
- { 0xEAA1, 0xEAFE },
- { 0xEB40, 0xEB7E },
- { 0xEBA1, 0xEBFE },
- { 0xEC40, 0xEC7E },
- { 0xECA1, 0xECFE },
- { 0xED40, 0xED7E },
- { 0xEDA1, 0xEDFE },
- { 0xEE40, 0xEE7E },
- { 0xEEA1, 0xEEFE },
- { 0xEF40, 0xEF7E },
- { 0xEFA1, 0xEFFE },
- { 0xF040, 0xF07E },
- { 0xF0A1, 0xF0FE },
- { 0xF140, 0xF17E },
- { 0xF1A1, 0xF1FE },
- { 0xF240, 0xF27E },
- { 0xF2A1, 0xF2FE },
- { 0xF340, 0xF37E },
- { 0xF3A1, 0xF3FE },
- { 0xF440, 0xF47E },
- { 0xF4A1, 0xF4FE },
- { 0xF540, 0xF57E },
- { 0xF5A1, 0xF5FE },
- { 0xF640, 0xF67E },
- { 0xF6A1, 0xF6FE },
- { 0xF740, 0xF77E },
- { 0xF7A1, 0xF7FE },
- { 0xF840, 0xF87E },
- { 0xF8A1, 0xF8FE },
- { 0xF940, 0xF97E },
- { 0xF9A1, 0xF9FE },
-};
-
-static bool charMatchesEncoding(int ch, const CharRange* encodingRanges, int rangeCount) {
- // Use binary search to see if the character is contained in the encoding
- int low = 0;
- int high = rangeCount;
-
- while (low < high) {
- int i = (low + high) / 2;
- const CharRange* range = &encodingRanges[i];
- if (ch >= range->first && ch <= range->last)
- return true;
- if (ch > range->last)
- low = i + 1;
- else
- high = i;
- }
-
- return false;
-}
-
-extern uint32_t findPossibleEncodings(int ch)
-{
- // ASCII matches everything
- if (ch < 256) return kEncodingAll;
-
- int result = kEncodingNone;
-
- if (charMatchesEncoding(ch, kShiftJISRanges, ARRAY_SIZE(kShiftJISRanges)))
- result |= kEncodingShiftJIS;
- if (charMatchesEncoding(ch, kGBKRanges, ARRAY_SIZE(kGBKRanges)))
- result |= kEncodingGBK;
- if (charMatchesEncoding(ch, kBig5Ranges, ARRAY_SIZE(kBig5Ranges)))
- result |= kEncodingBig5;
- if (charMatchesEncoding(ch, kEUCKRRanges, ARRAY_SIZE(kEUCKRRanges)))
- result |= kEncodingEUCKR;
-
- return result;
-}
diff --git a/media/libmedia/autodetect.h b/media/libmedia/autodetect.h
deleted file mode 100644
index 9675db3..0000000
--- a/media/libmedia/autodetect.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2008 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.
- */
-
-#ifndef AUTODETECT_H
-#define AUTODETECT_H
-
-#include <inttypes.h>
-
-// flags used for native encoding detection
-enum {
- kEncodingNone = 0,
- kEncodingShiftJIS = (1 << 0),
- kEncodingGBK = (1 << 1),
- kEncodingBig5 = (1 << 2),
- kEncodingEUCKR = (1 << 3),
-
- kEncodingAll = (kEncodingShiftJIS | kEncodingGBK | kEncodingBig5 | kEncodingEUCKR),
-};
-
-
-// returns a bitfield containing the possible native encodings for the given character
-extern uint32_t findPossibleEncodings(int ch);
-
-#endif // AUTODETECT_H
diff --git a/media/libmedia/mediametadataretriever.cpp b/media/libmedia/mediametadataretriever.cpp
index 110b94c..1d6bb6f 100644
--- a/media/libmedia/mediametadataretriever.cpp
+++ b/media/libmedia/mediametadataretriever.cpp
@@ -21,6 +21,7 @@
#include <binder/IServiceManager.h>
#include <binder/IPCThreadState.h>
#include <media/mediametadataretriever.h>
+#include <media/IMediaHTTPService.h>
#include <media/IMediaPlayerService.h>
#include <utils/Log.h>
#include <dlfcn.h>
@@ -93,7 +94,9 @@ void MediaMetadataRetriever::disconnect()
}
status_t MediaMetadataRetriever::setDataSource(
- const char *srcUrl, const KeyedVector<String8, String8> *headers)
+ const sp<IMediaHTTPService> &httpService,
+ const char *srcUrl,
+ const KeyedVector<String8, String8> *headers)
{
ALOGV("setDataSource");
Mutex::Autolock _l(mLock);
@@ -106,7 +109,7 @@ status_t MediaMetadataRetriever::setDataSource(
return UNKNOWN_ERROR;
}
ALOGV("data source (%s)", srcUrl);
- return mRetriever->setDataSource(srcUrl, headers);
+ return mRetriever->setDataSource(httpService, srcUrl, headers);
}
status_t MediaMetadataRetriever::setDataSource(int fd, int64_t offset, int64_t length)
@@ -157,7 +160,7 @@ sp<IMemory> MediaMetadataRetriever::extractAlbumArt()
return mRetriever->extractAlbumArt();
}
-void MediaMetadataRetriever::DeathNotifier::binderDied(const wp<IBinder>& who) {
+void MediaMetadataRetriever::DeathNotifier::binderDied(const wp<IBinder>& who __unused) {
Mutex::Autolock lock(MediaMetadataRetriever::sServiceLock);
MediaMetadataRetriever::sService.clear();
ALOGW("MediaMetadataRetriever server died!");
diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp
index 7a6f31d..0be01a9 100644
--- a/media/libmedia/mediaplayer.cpp
+++ b/media/libmedia/mediaplayer.cpp
@@ -58,7 +58,7 @@ MediaPlayer::MediaPlayer()
mVideoWidth = mVideoHeight = 0;
mLockThreadId = 0;
mAudioSessionId = AudioSystem::newAudioSessionId();
- AudioSystem::acquireAudioSessionId(mAudioSessionId);
+ AudioSystem::acquireAudioSessionId(mAudioSessionId, -1);
mSendLevel = 0;
mRetransmitEndpointValid = false;
}
@@ -66,7 +66,7 @@ MediaPlayer::MediaPlayer()
MediaPlayer::~MediaPlayer()
{
ALOGV("destructor");
- AudioSystem::releaseAudioSessionId(mAudioSessionId);
+ AudioSystem::releaseAudioSessionId(mAudioSessionId, -1);
disconnect();
IPCThreadState::self()->flushCommands();
}
@@ -136,6 +136,7 @@ status_t MediaPlayer::attachNewPlayer(const sp<IMediaPlayer>& player)
}
status_t MediaPlayer::setDataSource(
+ const sp<IMediaHTTPService> &httpService,
const char *url, const KeyedVector<String8, String8> *headers)
{
ALOGV("setDataSource(%s)", url);
@@ -145,7 +146,7 @@ status_t MediaPlayer::setDataSource(
if (service != 0) {
sp<IMediaPlayer> player(service->create(this, mAudioSessionId));
if ((NO_ERROR != doSetRetransmitEndpoint(player)) ||
- (NO_ERROR != player->setDataSource(url, headers))) {
+ (NO_ERROR != player->setDataSource(httpService, url, headers))) {
player.clear();
}
err = attachNewPlayer(player);
@@ -530,6 +531,14 @@ status_t MediaPlayer::setAudioStreamType(audio_stream_type_t type)
return OK;
}
+status_t MediaPlayer::getAudioStreamType(audio_stream_type_t *type)
+{
+ ALOGV("getAudioStreamType");
+ Mutex::Autolock _l(mLock);
+ *type = mStreamType;
+ return OK;
+}
+
status_t MediaPlayer::setLooping(int loop)
{
ALOGV("MediaPlayer::setLooping");
@@ -575,8 +584,8 @@ status_t MediaPlayer::setAudioSessionId(int sessionId)
return BAD_VALUE;
}
if (sessionId != mAudioSessionId) {
- AudioSystem::acquireAudioSessionId(sessionId);
- AudioSystem::releaseAudioSessionId(mAudioSessionId);
+ AudioSystem::acquireAudioSessionId(sessionId, -1);
+ AudioSystem::releaseAudioSessionId(mAudioSessionId, -1);
mAudioSessionId = sessionId;
}
return NO_ERROR;
@@ -776,15 +785,20 @@ void MediaPlayer::notify(int msg, int ext1, int ext2, const Parcel *obj)
}
}
-/*static*/ status_t MediaPlayer::decode(const char* url, uint32_t *pSampleRate,
- int* pNumChannels, audio_format_t* pFormat,
- const sp<IMemoryHeap>& heap, size_t *pSize)
+/*static*/ status_t MediaPlayer::decode(
+ const sp<IMediaHTTPService> &httpService,
+ const char* url,
+ uint32_t *pSampleRate,
+ int* pNumChannels,
+ audio_format_t* pFormat,
+ const sp<IMemoryHeap>& heap,
+ size_t *pSize)
{
ALOGV("decode(%s)", url);
status_t status;
const sp<IMediaPlayerService>& service = getMediaPlayerService();
if (service != 0) {
- status = service->decode(url, pSampleRate, pNumChannels, pFormat, heap, pSize);
+ status = service->decode(httpService, url, pSampleRate, pNumChannels, pFormat, heap, pSize);
} else {
ALOGE("Unable to locate media service");
status = DEAD_OBJECT;
@@ -832,15 +846,4 @@ status_t MediaPlayer::setNextMediaPlayer(const sp<MediaPlayer>& next) {
return mPlayer->setNextPlayer(next == NULL ? NULL : next->mPlayer);
}
-status_t MediaPlayer::updateProxyConfig(
- const char *host, int32_t port, const char *exclusionList) {
- const sp<IMediaPlayerService>& service = getMediaPlayerService();
-
- if (service != NULL) {
- return service->updateProxyConfig(host, port, exclusionList);
- }
-
- return INVALID_OPERATION;
-}
-
}; // namespace android