summaryrefslogtreecommitdiffstats
path: root/media/libstagefright/wifi-display/wfd.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'media/libstagefright/wifi-display/wfd.cpp')
-rw-r--r--media/libstagefright/wifi-display/wfd.cpp184
1 files changed, 181 insertions, 3 deletions
diff --git a/media/libstagefright/wifi-display/wfd.cpp b/media/libstagefright/wifi-display/wfd.cpp
index 011edab..03a1123 100644
--- a/media/libstagefright/wifi-display/wfd.cpp
+++ b/media/libstagefright/wifi-display/wfd.cpp
@@ -23,22 +23,163 @@
#include <binder/ProcessState.h>
#include <binder/IServiceManager.h>
+#include <gui/SurfaceComposerClient.h>
+#include <media/AudioSystem.h>
#include <media/IMediaPlayerService.h>
+#include <media/IRemoteDisplay.h>
+#include <media/IRemoteDisplayClient.h>
#include <media/stagefright/DataSource.h>
#include <media/stagefright/foundation/ADebug.h>
namespace android {
-} // namespace android
-
static void usage(const char *me) {
fprintf(stderr,
"usage:\n"
" %s -c host[:port]\tconnect to wifi source\n"
- " -u uri \tconnect to an rtsp uri\n",
+ " -u uri \tconnect to an rtsp uri\n"
+ " -l ip[:port] \tlisten on the specified port "
+ "(create a sink)\n",
me);
}
+struct RemoteDisplayClient : public BnRemoteDisplayClient {
+ RemoteDisplayClient();
+
+ 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);
+
+ void waitUntilDone();
+
+protected:
+ virtual ~RemoteDisplayClient();
+
+private:
+ Mutex mLock;
+ Condition mCondition;
+
+ bool mDone;
+
+ sp<SurfaceComposerClient> mComposerClient;
+ sp<ISurfaceTexture> mSurfaceTexture;
+ sp<IBinder> mDisplayBinder;
+
+ DISALLOW_EVIL_CONSTRUCTORS(RemoteDisplayClient);
+};
+
+RemoteDisplayClient::RemoteDisplayClient()
+ : mDone(false) {
+ mComposerClient = new SurfaceComposerClient;
+ CHECK_EQ(mComposerClient->initCheck(), (status_t)OK);
+}
+
+RemoteDisplayClient::~RemoteDisplayClient() {
+}
+
+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);
+
+ mSurfaceTexture = surfaceTexture;
+ mDisplayBinder = mComposerClient->createDisplay(
+ String8("foo"), false /* secure */);
+
+ SurfaceComposerClient::openGlobalTransaction();
+ mComposerClient->setDisplaySurface(mDisplayBinder, mSurfaceTexture);
+
+ Rect layerStackRect(1280, 720); // XXX fix this.
+ Rect displayRect(1280, 720);
+
+ mComposerClient->setDisplayProjection(
+ mDisplayBinder, 0 /* 0 degree rotation */,
+ layerStackRect,
+ displayRect);
+
+ SurfaceComposerClient::closeGlobalTransaction();
+}
+
+void RemoteDisplayClient::onDisplayDisconnected() {
+ ALOGI("onDisplayDisconnected");
+
+ Mutex::Autolock autoLock(mLock);
+ mDone = true;
+ mCondition.broadcast();
+}
+
+void RemoteDisplayClient::onDisplayError(int32_t error) {
+ ALOGI("onDisplayError error=%d", error);
+
+ Mutex::Autolock autoLock(mLock);
+ mDone = true;
+ mCondition.broadcast();
+}
+
+void RemoteDisplayClient::waitUntilDone() {
+ Mutex::Autolock autoLock(mLock);
+ while (!mDone) {
+ mCondition.wait(mLock);
+ }
+}
+
+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;
+}
+
+static void createSource(const AString &addr, int32_t port) {
+ 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 */);
+
+ String8 iface;
+ iface.append(addr.c_str());
+ iface.append(StringPrintf(":%d", port).c_str());
+
+ sp<RemoteDisplayClient> client = new RemoteDisplayClient;
+ sp<IRemoteDisplay> display = service->listenForRemoteDisplay(client, iface);
+
+ client->waitUntilDone();
+
+ display->dispose();
+ display.clear();
+
+ enableAudioSubmix(false /* enable */);
+}
+
+} // namespace android
+
int main(int argc, char **argv) {
using namespace android;
@@ -50,6 +191,9 @@ int main(int argc, char **argv) {
int32_t connectToPort = -1;
AString uri;
+ AString listenOnAddr;
+ int32_t listenOnPort = -1;
+
int res;
while ((res = getopt(argc, argv, "hc:l:u:")) >= 0) {
switch (res) {
@@ -81,6 +225,28 @@ int main(int argc, char **argv) {
break;
}
+ case 'l':
+ {
+ const char *colonPos = strrchr(optarg, ':');
+
+ if (colonPos == NULL) {
+ listenOnAddr = optarg;
+ listenOnPort = WifiDisplaySource::kWifiDisplayDefaultPort;
+ } else {
+ listenOnAddr.setTo(optarg, colonPos - optarg);
+
+ char *end;
+ listenOnPort = strtol(colonPos + 1, &end, 10);
+
+ if (*end != '\0' || end == colonPos + 1
+ || listenOnPort < 1 || listenOnPort > 65535) {
+ fprintf(stderr, "Illegal port specified.\n");
+ exit(1);
+ }
+ }
+ break;
+ }
+
case '?':
case 'h':
default:
@@ -89,6 +255,18 @@ int main(int argc, char **argv) {
}
}
+ if (connectToPort >= 0 && listenOnPort >= 0) {
+ fprintf(stderr,
+ "You can connect to a source or create one, "
+ "but not both at the same time.\n");
+ exit(1);
+ }
+
+ if (listenOnPort >= 0) {
+ createSource(listenOnAddr, listenOnPort);
+ exit(0);
+ }
+
if (connectToPort < 0 && uri.empty()) {
fprintf(stderr,
"You need to select either source host or uri.\n");