android4.2 RemoteDisplay远程显示修改为保存文件

论坛 期权论坛 脚本     
已经匿名di用户   2022-7-2 21:58   1625   0

RemoteDisplay其是具体Display的业务实现,其包含JAVA层与JNI,library三个层。

在android 4.2当中主要是WifiDisplayAdapter使用了RemoteDisplay。

也就是RemoteDisplay其是基础,WifiDisplayAdapter只是使用了其的功能!!!

pizza\frameworks\base\media\java\android\media\RemoteDisplay.java

private native int nativeListen(String iface);
private native int nativeStartRecord(String iface);
private native int nativePauseRecord(int ptr);
private native int nativeResumeRecord(int ptr);
private native int nativeStopRecord(int ptr);
private native void nativeDispose(int ptr);

public static RemoteDisplay recordScreen(String outfile, Listener listener, Handler handler) {
if (outfile == null) {
throw new IllegalArgumentException("iface must not be null");
}
if (listener == null) {
throw new IllegalArgumentException("listener must not be null");
}
if (handler == null) {
throw new IllegalArgumentException("handler must not be null");
}

RemoteDisplay display = new RemoteDisplay(listener, handler);
display.startRecording(outfile);
return display;
}

private void startListening(String iface) {
mPtr = nativeListen(iface);
if (mPtr == 0) {
throw new IllegalStateException("Could not start listening for "
+ "remote display connection on \"" + iface + "\"");
}
mGuard.open("dispose");
mGuard.open("stopRecording");
}
public void startRecording(String outfile) {
Log.e(TAG, "### startRecording ###");
mPtr = nativeStartRecord(outfile);
if (mPtr == 0) {
throw new IllegalStateException("Could not start listening for "
+ "remote display connection on \"" + outfile + "\"");
}
}

public void pauseRecording() {
Log.e(TAG, "### pauseRecording ###");
if(mPtr != 0)
{
nativePauseRecord(mPtr);
}
}
public void resumeRecording() {
Log.e(TAG, "### resumeRecording ###");
if(mPtr != 0)
{
nativeResumeRecord(mPtr);
}
}

public void stopRecording() {
Log.e(TAG, "### stopRecording ###");
stopRecording(false);
}

private void stopRecording(boolean finalized) {
if(mPtr != 0)
{
if (mGuardRecScr != null) {
if (finalized) {
mGuardRecScr.warnIfOpen();
} else {
mGuardRecScr.close();
}
}
nativeStopRecord(mPtr);
mPtr = 0;
}
}

// Called from native.
private void notifyRecordScreen(final byte[] buffer, final int len) {
Log.e(TAG, "### notifyRecordScreen ###");
mHandler.post(new Runnable() {
@Override
public void run() {
mListener.onRecordScreen(buffer, len);
}
});
}

/**
* Listener invoked when the remote display connection changes state.
*/
public interface Listener {
void onDisplayConnected(Surface surface, int width, int height, int flags);
void onDisplayDisconnected();
void onDisplayError(int error);
void onRecordScreen(byte[] buffer, int len);
}

pizza\frameworks\base\core\jni\android_media_RemoteDisplay.cpp

namespace android {

static struct {
jmethodID notifyDisplayConnected;
jmethodID notifyDisplayDisconnected;
jmethodID notifyDisplayError;
jmethodID notifyRecordScreen;
} gRemoteDisplayClassInfo;

// ----------------------------------------------------------------------------

class NativeRemoteDisplayClient : public BnRemoteDisplayClient {
public:
NativeRemoteDisplayClient(JNIEnv* env, jobject remoteDisplayObj) :
mRemoteDisplayObjGlobal(env->NewGlobalRef(remoteDisplayObj)) {
}

protected:
~NativeRemoteDisplayClient() {
JNIEnv* env = AndroidRuntime::getJNIEnv();
env->DeleteGlobalRef(mRemoteDisplayObjGlobal);
}

public:
virtual void onDisplayConnected(const sp<ISurfaceTexture>& surfaceTexture,
uint32_t width, uint32_t height, uint32_t flags) {
JNIEnv* env = AndroidRuntime::getJNIEnv();

jobject surfaceObj = android_view_Surface_createFromISurfaceTexture(env, surfaceTexture);
if (surfaceObj == NULL) {
ALOGE("Could not create Surface from surface texture %p provided by media server.",
surfaceTexture.get());
return;
}

env->CallVoidMethod(mRemoteDisplayObjGlobal,
gRemoteDisplayClassInfo.notifyDisplayConnected,
surfaceObj, width, height, flags);
env->DeleteLocalRef(surfaceObj);
checkAndClearExceptionFromCallback(env, "notifyDisplayConnected");
}

virtual void onDisplayDisconnected() {
JNIEnv* env = AndroidRuntime::getJNIEnv();

env->CallVoidMethod(mRemoteDisplayObjGlobal,
gRemoteDisplayClassInfo.notifyDisplayDisconnected);
checkAndClearExceptionFromCallback(env, "notifyDisplayDisconnected");
}

virtual void onDisplayError(int32_t error) {
JNIEnv* env = AndroidRuntime::getJNIEnv();

env->CallVoidMethod(mRemoteDisplayObjGlobal,
gRemoteDisplayClassInfo.notifyDisplayError, error);
checkAndClearExceptionFromCallback(env, "notifyDisplayError");
}

virtual void onRecordScreen(char *buffer, int len) {
}

private:
jobject mRemoteDisplayObjGlobal;

static void checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName) {
if (env->ExceptionCheck()) {
ALOGE("An exception was thrown by callback '%s'.", methodName);
LOGE_EX(env);
env->ExceptionClear();
}
}
};

class NativeRemoteDisplay {
public:
NativeRemoteDisplay(const sp<IRemoteDisplay>& display,
const sp<NativeRemoteDisplayClient>& client) :
mDisplay(display), mClient(client) {
}

~NativeRemoteDisplay() {
mDisplay->dispose();
}

private:
sp<IRemoteDisplay> mDisplay;
sp<NativeRemoteDisplayClient> mClient;
};

// ----------------------------------------------------------------------------

struct RemoteDisplayClient : public BnRemoteDisplayClient {
RemoteDisplayClient(JNIEnv* env, jobject remoteDisplayObj);

virtual void onDisplayConnected(
const sp<ISurfaceTexture> &surfaceTexture,
uint32_t width,
uint32_t height,
uint32_t flags);

virtual void onDisplayDisconnected();
virtual void onDisplayError(int32_t error);
virtual void onRecordScreen(char *buffer, int len);

void waitUntilDone();

protected:
virtual ~RemoteDisplayClient();

private:
JNIEnv* mEnv;

Mutex mLock;
Condition mCondition;

bool mDone;

// 有了这个几个Display才能够真正的镜像显示数据

sp<SurfaceComposerClient> mComposerClient;

sp<ISurfaceTexture> mSurfaceTexture;

sp<IBinder> mDisplayBinder;

jobject mRemoteDisplayObjGlobal;
static void checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName) {
if (env->ExceptionCheck()) {
ALOGE("An exception was thrown by callback '%s'.", methodName);
LOGE_EX(env);
env->ExceptionClear();
}
}

DISALLOW_EVIL_CONSTRUCTORS(RemoteDisplayClient);
};

static status_t enableAudioSubmix(bool enable) {
status_t err = AudioSystem::setDeviceConnectionState(
AUDIO_DEVICE_IN_REMOTE_SUBMIX,
enable
? AUDIO_POLICY_DEVICE_STATE_AVAILABLE
: AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
NULL /* device_address */);

if (err != OK) {
return err;
}

err = AudioSystem::setDeviceConnectionState(
AUDIO_DEVICE_OUT_REMOTE_SUBMIX,
enable
? AUDIO_POLICY_DEVICE_STATE_AVAILABLE
: AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
NULL /* device_address */);

return err;
}

RemoteDisplayClient::RemoteDisplayClient(JNIEnv* env, jobject remoteDisplayObj) :
mEnv(env),
mRemoteDisplayObjGlobal(env->NewGlobalRef(remoteDisplayObj)),
mDone(false) {
mComposerClient = new SurfaceComposerClient;
mComposerClient->initCheck();
//CHECK_EQ(mComposerClient->initCheck(), (status_t)OK);
}

RemoteDisplayClient::~RemoteDisplayClient() {
JNIEnv* env = AndroidRuntime::getJNIEnv();
env->DeleteGlobalRef(mRemoteDisplayObjGlobal);
}

void RemoteDisplayClient::onDisplayConnected(
const sp<ISurfaceTexture> &surfaceTexture,
uint32_t width,
uint32_t height,
uint32_t flags) {
ALOGI("#### onDisplayConnected width=%u, height=%u, flags = 0x%08x",
width, height, flags);
if(999 == flags)
{
onRecordScreen((char *)width, (int)height);
return;
}
mSurfaceTexture = surfaceTexture;

// 内部通过SurfaceComposerClient,最终调用SurfaceFlinger来创建一个DisplayDeviceState,添加到

// DisplayDeviceState info(DisplayDevice::DISPLAY_VIRTUAL); –> 所有createDisplay均是DISPLAY_VIRTUAL类型

//mCurrentState.displays.add(token,info); 在SurfaceFlinger当中添加了一个显示设备,SurfaceFlinger就会将这些数据

// 写到这些显示设备上面
mDisplayBinder = mComposerClient->createDisplay(
String8("foo"), false /* secure */);

SurfaceComposerClient::openGlobalTransaction();

// 修改内部DisplayState 定义在LayerState.h当中

// DisplayState &s(getDisplayStateLocked(token));

//s.surface = bufferProducer;

//s.what |= DisplayState::eSurfaceChanged;


mComposerClient->setDisplaySurface(mDisplayBinder, mSurfaceTexture);

//Rect layerStackRect(1280, 720); // XXX fix this.
Rect layerStackRect(width, height); // XXX fix this.
//Rect displayRect(1280, 720);
Rect displayRect(width, height);

mComposerClient->setDisplayProjection(
mDisplayBinder, 0 /* 0 degree rotation */,
layerStackRect,
displayRect);

SurfaceComposerClient::closeGlobalTransaction();
}

void RemoteDisplayClient::onDisplayDisconnected() {

enableAudioSubmix(false /* enable */);
//Mutex::Autolock autoLock(mLock);
//mDone = true;
ALOGD("onDisplayDisconnected");
//mCondition.broadcast();
}

void RemoteDisplayClient::onDisplayError(int32_t error) {
ALOGI("onDisplayError error=%d", error);

Mutex::Autolock autoLock(mLock);
mDone = true;
mCondition.broadcast();
}

void RemoteDisplayClient::onRecordScreen(char *buffer, int len) {
//JNIEnv* env = AndroidRuntime::getJNIEnv();
JNIEnv* env = mEnv;
jbyteArray data = env->NewByteArray(len);
env->SetByteArrayRegion(data, 0, len,
reinterpret_cast<const jbyte*>(buffer));

ALOGE("### onRecordScreen in android_media_RemoteDisplay.cpp ###");
env->CallVoidMethod(mRemoteDisplayObjGlobal,
gRemoteDisplayClassInfo.notifyRecordScreen, data, len);
checkAndClearExceptionFromCallback(env, "notifyRecordScreen");
}

void RemoteDisplayClient::waitUntilDone() {
Mutex::Autolock autoLock(mLock);
while (!mDone) {
mCondition.wait(mLock);
}
}

class NativeRemoteDisplayEx {
public:
NativeRemoteDisplayEx(const sp<IRemoteDisplay>& display,
const sp<RemoteDisplayClient>& client) :
mDisplay(display), mClient(client) {
}

~NativeRemoteDisplayEx()
{
ALOGI("### ~NativeRemoteDisplayEx 01 ###");
if(mDisplay != NULL)
{
ALOGI("### ~NativeRemoteDisplayEx 02 ###");
mDisplay->dispose();
}
}

void pauseRecord()
{
ALOGI("### pauseRecord 01 ###");
if(mDisplay != NULL)
{
ALOGI("### pauseRecord 02 ###");
mDisplay->pause();
}
}

void resumeRecord()
{
ALOGI("### resumeRecord 01 ###");
if(mDisplay != NULL)
{
ALOGI("### resumeRecord 02 ###");
mDisplay->resume();
}
}

void stopRecord()
{
ALOGI("### stopRecord 01 ###");
if(mDisplay != NULL)
{
ALOGI("### stopRecord 02 ###");
mDisplay->dispose();
}
}

private:
sp<IRemoteDisplay> mDisplay;
sp<RemoteDisplayClient> mClient;
};

static jint nativeStartRecord(JNIEnv* env, jobject remoteDisplayObj, jstring ifaceStr) {
ScopedUtfChars iface(env, ifaceStr);
ALOGI("### nativeStartRecord ###");
sp<IServiceManager> sm = defaultServiceManager();
sp<IBinder> binder = sm->getService(String16("media.player"));
sp<IMediaPlayerService> service =
interface_cast<IMediaPlayerService>(binder);

CHECK(service.get() != NULL);

enableAudioSubmix(true /* enable */);

sp<RemoteDisplayClient> client = new RemoteDisplayClient(env, remoteDisplayObj);
sp<IRemoteDisplay> display = service->listenForRemoteDisplay(client, String8(iface.c_str()));

#if 0 //{
if(wrapper != NULL)
{
//delete wrapper;
//wrapper = NULL;
}
#endif //}
NativeRemoteDisplayEx* wrapper = new NativeRemoteDisplayEx(display, client);

return reinterpret_cast<jint>(wrapper);
}

static jint nativePauseRecord(JNIEnv* env, jobject remoteDisplayObj, jint ptr) {
ALOGI("### nativePauseRecord ###");
NativeRemoteDisplayEx* wrapper = reinterpret_cast<NativeRemoteDisplayEx*>(ptr);
wrapper->pauseRecord();
return 0;
}

static jint nativeResumeRecord(JNIEnv* env, jobject remoteDisplayObj, jint ptr) {
ALOGI("### nativeResumeRecord ###");
NativeRemoteDisplayEx* wrapper = reinterpret_cast<NativeRemoteDisplayEx*>(ptr);
wrapper->resumeRecord();
return 0;
}

static jint nativeStopRecord(JNIEnv* env, jobject remoteDisplayObj, jint ptr) {
ALOGI("### nativeStopRecord ###");
NativeRemoteDisplayEx* wrapper = reinterpret_cast<NativeRemoteDisplayEx*>(ptr);
delete wrapper;
//wrapper->stopRecord();
return 0;
}

static jint nativeListen(JNIEnv* env, jobject remoteDisplayObj, jstring ifaceStr) {
ScopedUtfChars iface(env, ifaceStr);

sp<IServiceManager> sm = defaultServiceManager();
sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(
sm->getService(String16("media.player")));
if (service == NULL) {
ALOGE("Could not obtain IMediaPlayerService from service manager");
return 0;
}

sp<NativeRemoteDisplayClient> client(new NativeRemoteDisplayClient(env, remoteDisplayObj));
sp<IRemoteDisplay> display = service->listenForRemoteDisplay(
client, String8(iface.c_str()));
if (display == NULL) {
ALOGE("Media player service rejected request to listen for remote display '%s'.",
iface.c_str());
return 0;
}

NativeRemoteDisplay* wrapper = new NativeRemoteDisplay(display, client);
return reinterpret_cast<jint>(wrapper);
}

static void nativeDispose(JNIEnv* env, jobject remoteDisplayObj, jint ptr) {
NativeRemoteDisplay* wrapper = reinterpret_cast<NativeRemoteDisplay*>(ptr);
delete wrapper;
}

// ----------------------------------------------------------------------------

static JNINativeMethod gMethods[] = {
{"nativeListen", "(Ljava/lang/String;)I",
(void*)nativeListen },
{"nativeStartRecord", "(Ljava/lang/String;)I",
(void*)nativeStartRecord },
{"nativePauseRecord", "(I)I",
(void*)nativePauseRecord },
{"nativeResumeRecord", "(I)I",
(void*)nativeResumeRecord },
{"nativeStopRecord", "(I)I",
(void*)nativeStopRecord },
{"nativeDispose", "(I)V",
(void*)nativeDispose },
};

int register_android_media_RemoteDisplay(JNIEnv* env)
{
int err = AndroidRuntime::registerNativeMethods(env, "android/media/RemoteDisplay",
gMethods, NELEM(gMethods));

jclass clazz = env->FindClass("android/media/RemoteDisplay");
gRemoteDisplayClassInfo.notifyDisplayConnected =
env->GetMethodID(clazz, "notifyDisplayConnected",
"(Landroid/view/Surface;III)V");
gRemoteDisplayClassInfo.notifyDisplayDisconnected =
env->GetMethodID(clazz, "notifyDisplayDisconnected", "()V");
gRemoteDisplayClassInfo.notifyDisplayError =
env->GetMethodID(clazz, "notifyDisplayError", "(I)V");
gRemoteDisplayClassInfo.notifyRecordScreen =
env->GetMethodID(clazz, "notifyRecordScreen", "([BI)V");
return err;
}

pizza\frameworks\base\core\java\android\hardware\display\IDisplayManager.aidl

DisplayManager负责管理所有的Display对象,给JAVA用户负责使用的接口

// No permissions required.
void startScreenRecord(String outfile);

// No permissions required.
void pauseScreenRecord();

// No permissions required.
void resumeScreenRecord();

// No permissions required.
void stopScreenRecord();

// No permissions required.
boolean canRecordScreen();

// No permissions required.
boolean canUseWfd();

pizza\frameworks\base\services\java\com\android\server\display\DisplayManagerService.java

public void startScreenRecord(String outfile) {
final long token = Binder.clearCallingIdentity();
try {
synchronized (mSyncRoot) {
if (mWifiDisplayAdapter != null) {
mWifiDisplayAdapter.requestStartRecordScreenLocked(outfile);
}
}
} finally {
Binder.restoreCallingIdentity(token);
}
}

@Override // Binder call
public void pauseScreenRecord() {
final long token = Binder.clearCallingIdentity();
try {
synchronized (mSyncRoot) {
if (mWifiDisplayAdapter != null) {
mWifiDisplayAdapter.requestPauseRecordScreenLocked();
}
}
} finally {
Binder.restoreCallingIdentity(token);
}
}
@Override // Binder call
public void resumeScreenRecord() {
final long token = Binder.clearCallingIdentity();
try {
synchronized (mSyncRoot) {
if (mWifiDisplayAdapter != null) {
mWifiDisplayAdapter.requestResumeRecordScreenLocked();
}
}
} finally {
Binder.restoreCallingIdentity(token);
}
}

@Override // Binder call
public void stopScreenRecord() {
final long token = Binder.clearCallingIdentity();
try {
synchronized (mSyncRoot) {
if (mWifiDisplayAdapter != null) {
mWifiDisplayAdapter.requestStopRecordScreenLocked();
}
}
} finally {
Binder.restoreCallingIdentity(token);
}
}

@Override // Binder call
public boolean canRecordScreen() {
if (mWifiDisplayAdapter != null) {
return mWifiDisplayAdapter.requestCanRecordScreenLocked();
}
return false;
}

@Override // Binder call
public boolean canUseWfd() {
if (mWifiDisplayAdapter != null) {
return mWifiDisplayAdapter.requestCanUseWfdLocked();
}
return false;
}

@Override // Binder call

RemoteDisplay 其被有三个部分WifiDisplayAdapter,WifiDisplayController.java, WifiDisplayDevice集成起来使用。

pizza\frameworks\base\services\java\com\android\server\display\WifiDisplayAdapter.java

public void requestStartRecordScreenLocked(final String outfile) {
if (DEBUG) {
Slog.d(TAG, "requestStartRecordScreenLocked");
}

getHandler().post(new Runnable() {
@Override
public void run() {
if (mDisplayController != null) {
mDisplayController.requestStartRecordScreen(outfile);
}
}
});
}

public void requestPauseRecordScreenLocked() {
if (DEBUG) {
Slog.d(TAG, "requestPauseRecordScreenLocked");
}

getHandler().post(new Runnable() {
@Override
public void run() {
if (mDisplayController != null) {
mDisplayController.requestPauseRecordScreen();
}
}
});
}

public void requestResumeRecordScreenLocked() {
if (DEBUG) {
Slog.d(TAG, "requestResumeRecordScreenLocked");
}

getHandler().post(new Runnable() {
@Override
public void run() {
if (mDisplayController != null) {
mDisplayController.requestResumeRecordScreen();
}
}
});
}

public void requestStopRecordScreenLocked() {
if (DEBUG) {
Slog.d(TAG, "requestStopRecordScreenLocked");
}

getHandler().post(new Runnable() {
@Override
public void run() {
if (mDisplayController != null) {
mDisplayController.requestStopRecordScreen();
}
}
});
}

public boolean requestCanRecordScreenLocked() {
if (mDisplayController != null) {
return mDisplayController.requestCanRecordScreen();
}
return false;
}

public boolean requestCanUseWfdLocked() {
if (mDisplayController != null) {
return mDisplayController.requestCanUseWfd();
}
return false;
}

pizza\frameworks\base\services\java\com\android\server\display\WifiDisplayController.java

private static final int RECSCR_STATUS_UNKNOWN = -1;
private static final int RECSCR_STATUS_RECORDING = 1;
private static final int RECSCR_STATUS_PAUSED = 2;
private static final int RECSCR_STATUS_STOPPED = 3;

private RemoteDisplay mRecordScreen;

public void requestStartRecordScreen(String outfile) {
if(RECSCR_STATUS_UNKNOWN == mRecordStatus || RECSCR_STATUS_STOPPED == mRecordStatus)
{
if(mRemoteDisplay != null)
{
Slog.e(TAG, "### requestStartRecordScreen mRemoteDisplay != null ###");
return;
}
Slog.d(TAG, "### requestStartRecordScreen outfile: " + outfile + " ###");
mRecordScreen = RemoteDisplay.recordScreen(outfile, new RemoteDisplay.Listener() {
@Override
public void onDisplayConnected(Surface surface,
int width, int height, int flags) {
Slog.d(TAG, "### onDisplayConnected ###");
}

@Override
public void onDisplayDisconnected() {
Slog.d(TAG, "### onDisplayDisconnected ###");
}

@Override
public void onDisplayError(int error) {
Slog.d(TAG, "### onDisplayError ###");
}

@Override
public void onRecordScreen(byte[] buffer, int len) {
Slog.d(TAG, "### onRecordScreen ###");
}
}, mHandler);
mHandler.postDelayed(mRtspTimeout, RTSP_TIMEOUT_SECONDS * 1000 * 1000);
mRecordStatus = RECSCR_STATUS_RECORDING;
}
}

public void requestPauseRecordScreen() {
if(RECSCR_STATUS_RECORDING == mRecordStatus && mRecordScreen != null)
{
Slog.d(TAG, "### requestPauseRecordScreen ###");
mRecordScreen.pauseRecording();
mRecordStatus = RECSCR_STATUS_PAUSED;
}
}

public void requestResumeRecordScreen() {
if(RECSCR_STATUS_PAUSED == mRecordStatus && mRecordScreen != null)
{
Slog.d(TAG, "### requestResumeRecordScreen ###");
mRecordScreen.resumeRecording();
mRecordStatus = RECSCR_STATUS_RECORDING;
}
}

public void requestStopRecordScreen() {
if(RECSCR_STATUS_RECORDING == mRecordStatus && mRecordScreen != null)
{
Slog.d(TAG, "### requestStopRecordScreen ###");
mRecordScreen.stopRecording();
mRecordStatus = RECSCR_STATUS_STOPPED;
mRecordScreen = null;
}
}

public boolean requestCanRecordScreen() {
Slog.d(TAG, "### requestCanRecordScreen ###");
if(mRemoteDisplay == null)
{
Slog.d(TAG, "### requestCanRecordScreen true ###");
return true;
}
return false;
}

public boolean requestCanUseWfd() {
Slog.d(TAG, "### requestCanUseWfd ###");
if(mRecordScreen == null)
{
Slog.d(TAG, "### requestCanUseWfd true ###");
return true;
}
return false;
}

转载于:https://www.cnblogs.com/pengxinglove/p/5550933.html

分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:81
帖子:4969
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP