Home | History | Annotate | Download | only in wifi-display
      1 /*
      2  * Copyright 2012, The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *     http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 //#define LOG_NDEBUG 0
     18 #define LOG_TAG "wfd"
     19 #include <utils/Log.h>
     20 
     21 #include "source/WifiDisplaySource.h"
     22 
     23 #include <binder/ProcessState.h>
     24 #include <binder/IServiceManager.h>
     25 #include <gui/ISurfaceComposer.h>
     26 #include <gui/SurfaceComposerClient.h>
     27 #include <media/AudioSystem.h>
     28 #include <media/IMediaPlayerService.h>
     29 #include <media/IRemoteDisplay.h>
     30 #include <media/IRemoteDisplayClient.h>
     31 #include <media/stagefright/DataSource.h>
     32 #include <media/stagefright/foundation/ADebug.h>
     33 #include <media/stagefright/foundation/AMessage.h>
     34 #include <ui/DisplayInfo.h>
     35 
     36 namespace android {
     37 
     38 static void usage(const char *me) {
     39     fprintf(stderr,
     40             "usage:\n"
     41             "           %s -l iface[:port]\tcreate a wifi display source\n"
     42             "               -f(ilename)  \tstream media\n",
     43             me);
     44 }
     45 
     46 struct RemoteDisplayClient : public BnRemoteDisplayClient {
     47     RemoteDisplayClient();
     48 
     49     virtual void onDisplayConnected(
     50             const sp<IGraphicBufferProducer> &bufferProducer,
     51             uint32_t width,
     52             uint32_t height,
     53             uint32_t flags);
     54 
     55     virtual void onDisplayDisconnected();
     56     virtual void onDisplayError(int32_t error);
     57 
     58     void waitUntilDone();
     59 
     60 protected:
     61     virtual ~RemoteDisplayClient();
     62 
     63 private:
     64     Mutex mLock;
     65     Condition mCondition;
     66 
     67     bool mDone;
     68 
     69     sp<SurfaceComposerClient> mComposerClient;
     70     sp<IGraphicBufferProducer> mSurfaceTexture;
     71     sp<IBinder> mDisplayBinder;
     72 
     73     DISALLOW_EVIL_CONSTRUCTORS(RemoteDisplayClient);
     74 };
     75 
     76 RemoteDisplayClient::RemoteDisplayClient()
     77     : mDone(false) {
     78     mComposerClient = new SurfaceComposerClient;
     79     CHECK_EQ(mComposerClient->initCheck(), (status_t)OK);
     80 }
     81 
     82 RemoteDisplayClient::~RemoteDisplayClient() {
     83 }
     84 
     85 void RemoteDisplayClient::onDisplayConnected(
     86         const sp<IGraphicBufferProducer> &bufferProducer,
     87         uint32_t width,
     88         uint32_t height,
     89         uint32_t flags) {
     90     ALOGI("onDisplayConnected width=%u, height=%u, flags = 0x%08x",
     91           width, height, flags);
     92 
     93     if (bufferProducer != NULL) {
     94         mSurfaceTexture = bufferProducer;
     95         mDisplayBinder = mComposerClient->createDisplay(
     96                 String8("foo"), false /* secure */);
     97 
     98         SurfaceComposerClient::openGlobalTransaction();
     99         mComposerClient->setDisplaySurface(mDisplayBinder, mSurfaceTexture);
    100 
    101         Rect layerStackRect(1280, 720);  // XXX fix this.
    102         Rect displayRect(1280, 720);
    103 
    104         mComposerClient->setDisplayProjection(
    105                 mDisplayBinder, 0 /* 0 degree rotation */,
    106                 layerStackRect,
    107                 displayRect);
    108 
    109         SurfaceComposerClient::closeGlobalTransaction();
    110     }
    111 }
    112 
    113 void RemoteDisplayClient::onDisplayDisconnected() {
    114     ALOGI("onDisplayDisconnected");
    115 
    116     Mutex::Autolock autoLock(mLock);
    117     mDone = true;
    118     mCondition.broadcast();
    119 }
    120 
    121 void RemoteDisplayClient::onDisplayError(int32_t error) {
    122     ALOGI("onDisplayError error=%d", error);
    123 
    124     Mutex::Autolock autoLock(mLock);
    125     mDone = true;
    126     mCondition.broadcast();
    127 }
    128 
    129 void RemoteDisplayClient::waitUntilDone() {
    130     Mutex::Autolock autoLock(mLock);
    131     while (!mDone) {
    132         mCondition.wait(mLock);
    133     }
    134 }
    135 
    136 static status_t enableAudioSubmix(bool enable) {
    137     status_t err = AudioSystem::setDeviceConnectionState(
    138             AUDIO_DEVICE_IN_REMOTE_SUBMIX,
    139             enable
    140                 ? AUDIO_POLICY_DEVICE_STATE_AVAILABLE
    141                 : AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
    142             NULL /* device_address */);
    143 
    144     if (err != OK) {
    145         return err;
    146     }
    147 
    148     err = AudioSystem::setDeviceConnectionState(
    149             AUDIO_DEVICE_OUT_REMOTE_SUBMIX,
    150             enable
    151                 ? AUDIO_POLICY_DEVICE_STATE_AVAILABLE
    152                 : AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
    153             NULL /* device_address */);
    154 
    155     return err;
    156 }
    157 
    158 static void createSource(const AString &addr, int32_t port) {
    159     sp<IServiceManager> sm = defaultServiceManager();
    160     sp<IBinder> binder = sm->getService(String16("media.player"));
    161     sp<IMediaPlayerService> service =
    162         interface_cast<IMediaPlayerService>(binder);
    163 
    164     CHECK(service.get() != NULL);
    165 
    166     enableAudioSubmix(true /* enable */);
    167 
    168     String8 iface;
    169     iface.append(addr.c_str());
    170     iface.append(StringPrintf(":%d", port).c_str());
    171 
    172     sp<RemoteDisplayClient> client = new RemoteDisplayClient;
    173     sp<IRemoteDisplay> display = service->listenForRemoteDisplay(client, iface);
    174 
    175     client->waitUntilDone();
    176 
    177     display->dispose();
    178     display.clear();
    179 
    180     enableAudioSubmix(false /* enable */);
    181 }
    182 
    183 static void createFileSource(
    184         const AString &addr, int32_t port, const char *path) {
    185     sp<ANetworkSession> session = new ANetworkSession;
    186     session->start();
    187 
    188     sp<ALooper> looper = new ALooper;
    189     looper->start();
    190 
    191     sp<RemoteDisplayClient> client = new RemoteDisplayClient;
    192     sp<WifiDisplaySource> source = new WifiDisplaySource(session, client, path);
    193     looper->registerHandler(source);
    194 
    195     AString iface = StringPrintf("%s:%d", addr.c_str(), port);
    196     CHECK_EQ((status_t)OK, source->start(iface.c_str()));
    197 
    198     client->waitUntilDone();
    199 
    200     source->stop();
    201 }
    202 
    203 }  // namespace android
    204 
    205 int main(int argc, char **argv) {
    206     using namespace android;
    207 
    208     ProcessState::self()->startThreadPool();
    209 
    210     DataSource::RegisterDefaultSniffers();
    211 
    212     AString listenOnAddr;
    213     int32_t listenOnPort = -1;
    214 
    215     AString path;
    216 
    217     int res;
    218     while ((res = getopt(argc, argv, "hl:f:")) >= 0) {
    219         switch (res) {
    220             case 'f':
    221             {
    222                 path = optarg;
    223                 break;
    224             }
    225 
    226             case 'l':
    227             {
    228                 const char *colonPos = strrchr(optarg, ':');
    229 
    230                 if (colonPos == NULL) {
    231                     listenOnAddr = optarg;
    232                     listenOnPort = WifiDisplaySource::kWifiDisplayDefaultPort;
    233                 } else {
    234                     listenOnAddr.setTo(optarg, colonPos - optarg);
    235 
    236                     char *end;
    237                     listenOnPort = strtol(colonPos + 1, &end, 10);
    238 
    239                     if (*end != '\0' || end == colonPos + 1
    240                             || listenOnPort < 1 || listenOnPort > 65535) {
    241                         fprintf(stderr, "Illegal port specified.\n");
    242                         exit(1);
    243                     }
    244                 }
    245                 break;
    246             }
    247 
    248             case '?':
    249             case 'h':
    250             default:
    251                 usage(argv[0]);
    252                 exit(1);
    253         }
    254     }
    255 
    256     if (listenOnPort >= 0) {
    257         if (path.empty()) {
    258             createSource(listenOnAddr, listenOnPort);
    259         } else {
    260             createFileSource(listenOnAddr, listenOnPort, path.c_str());
    261         }
    262 
    263         exit(0);
    264     }
    265 
    266     usage(argv[0]);
    267 
    268     return 0;
    269 }
    270