1c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim/*
2c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim * Copyright 2014 The Android Open Source Project
3c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim *
4c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim * Licensed under the Apache License, Version 2.0 (the "License");
5c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim * you may not use this file except in compliance with the License.
6c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim * You may obtain a copy of the License at
7c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim *
8c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim *      http://www.apache.org/licenses/LICENSE-2.0
9c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim *
10c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim * Unless required by applicable law or agreed to in writing, software
11c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim * distributed under the License is distributed on an "AS IS" BASIS,
12c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim * See the License for the specific language governing permissions and
14c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim * limitations under the License.
15c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim */
16c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim
17c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim#define LOG_TAG "TvInputHal"
18c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim
19c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim//#define LOG_NDEBUG 0
20c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim
21a617074c531dfa317e5051fa70ec6b6c21d14386Wonsik Kim#include "android_os_MessageQueue.h"
22c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim#include "android_runtime/AndroidRuntime.h"
23c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim#include "android_runtime/android_view_Surface.h"
24c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim#include "JNIHelp.h"
25c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim#include "jni.h"
26c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim
27c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim#include <gui/Surface.h>
28c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim#include <utils/Errors.h>
29c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim#include <utils/KeyedVector.h>
30c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim#include <utils/Log.h>
31a617074c531dfa317e5051fa70ec6b6c21d14386Wonsik Kim#include <utils/Looper.h>
32c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim#include <utils/NativeHandle.h>
33c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim#include <hardware/tv_input.h>
34c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim
35c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kimnamespace android {
36c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim
37c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kimstatic struct {
38c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim    jmethodID deviceAvailable;
39c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim    jmethodID deviceUnavailable;
40c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim    jmethodID streamConfigsChanged;
41c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo    jmethodID firstFrameCaptured;
42c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim} gTvInputHalClassInfo;
43c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim
44c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kimstatic struct {
45c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim    jclass clazz;
46c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim} gTvStreamConfigClassInfo;
47c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim
48c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kimstatic struct {
49c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim    jclass clazz;
50c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim
51c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim    jmethodID constructor;
52c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim    jmethodID streamId;
53c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim    jmethodID type;
54c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim    jmethodID maxWidth;
55c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim    jmethodID maxHeight;
56c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim    jmethodID generation;
57c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim    jmethodID build;
58c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim} gTvStreamConfigBuilderClassInfo;
59c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim
60d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kimstatic struct {
61d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim    jclass clazz;
62d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim
63d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim    jmethodID constructor;
64d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim    jmethodID deviceId;
65d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim    jmethodID type;
66a358b53e1d0bb7a7fc08b0a4d2a2e256f3045859Wonsik Kim    jmethodID hdmiPortId;
67d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim    jmethodID audioType;
68d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim    jmethodID audioAddress;
69d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim    jmethodID build;
70d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim} gTvInputHardwareInfoBuilderClassInfo;
71d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim
72c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim////////////////////////////////////////////////////////////////////////////////
73c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim
740b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kimclass BufferProducerThread : public Thread {
750b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kimpublic:
760b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim    BufferProducerThread(tv_input_device_t* device, int deviceId, const tv_stream_t* stream);
770b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim
780b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim    virtual status_t readyToRun();
790b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim
800b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim    void setSurface(const sp<Surface>& surface);
810b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim    void onCaptured(uint32_t seq, bool succeeded);
820b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim    void shutdown();
830b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim
840b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kimprivate:
850b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim    Mutex mLock;
860b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim    Condition mCondition;
870b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim    sp<Surface> mSurface;
880b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim    tv_input_device_t* mDevice;
890b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim    int mDeviceId;
900b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim    tv_stream_t mStream;
910b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim    sp<ANativeWindowBuffer_t> mBuffer;
920b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim    enum {
930b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim        CAPTURING,
940b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim        CAPTURED,
950b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim        RELEASED,
960b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim    } mBufferState;
970b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim    uint32_t mSeq;
980b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim    bool mShutdown;
990b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim
1000b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim    virtual bool threadLoop();
1010b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim
1020b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim    void setSurfaceLocked(const sp<Surface>& surface);
1030b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim};
1040b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim
1050b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik KimBufferProducerThread::BufferProducerThread(
1060b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim        tv_input_device_t* device, int deviceId, const tv_stream_t* stream)
1070b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim    : Thread(false),
1080b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim      mDevice(device),
1090b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim      mDeviceId(deviceId),
1100b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim      mBuffer(NULL),
1110b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim      mBufferState(RELEASED),
1120b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim      mSeq(0u),
1130b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim      mShutdown(false) {
1140b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim    memcpy(&mStream, stream, sizeof(mStream));
1150b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim}
1160b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim
1170b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kimstatus_t BufferProducerThread::readyToRun() {
1180b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim    sp<ANativeWindow> anw(mSurface);
1190b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim    status_t err = native_window_set_usage(anw.get(), mStream.buffer_producer.usage);
1200b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim    if (err != NO_ERROR) {
1210b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim        return err;
1220b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim    }
1230b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim    err = native_window_set_buffers_dimensions(
1240b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim            anw.get(), mStream.buffer_producer.width, mStream.buffer_producer.height);
1250b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim    if (err != NO_ERROR) {
1260b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim        return err;
1270b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim    }
1280b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim    err = native_window_set_buffers_format(anw.get(), mStream.buffer_producer.format);
1290b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim    if (err != NO_ERROR) {
1300b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim        return err;
1310b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim    }
1320b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim    return NO_ERROR;
1330b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim}
1340b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim
1350b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kimvoid BufferProducerThread::setSurface(const sp<Surface>& surface) {
1360b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim    Mutex::Autolock autoLock(&mLock);
1370b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim    setSurfaceLocked(surface);
1380b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim}
1390b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim
1400b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kimvoid BufferProducerThread::setSurfaceLocked(const sp<Surface>& surface) {
1410b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim    if (surface == mSurface) {
1420b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim        return;
1430b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim    }
1440b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim
1450b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim    if (mBufferState == CAPTURING) {
1460b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim        mDevice->cancel_capture(mDevice, mDeviceId, mStream.stream_id, mSeq);
1470b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim    }
1480b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim    while (mBufferState == CAPTURING) {
1490b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim        status_t err = mCondition.waitRelative(mLock, s2ns(1));
1500b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim        if (err != NO_ERROR) {
1510b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim            ALOGE("error %d while wating for buffer state to change.", err);
1520b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim            break;
1530b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim        }
1540b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim    }
1550b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim    mBuffer.clear();
1560b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim    mBufferState = RELEASED;
1570b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim
1580b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim    mSurface = surface;
1590b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim    mCondition.broadcast();
1600b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim}
1610b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim
1620b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kimvoid BufferProducerThread::onCaptured(uint32_t seq, bool succeeded) {
1630b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim    Mutex::Autolock autoLock(&mLock);
1640b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim    if (seq != mSeq) {
1650b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim        ALOGW("Incorrect sequence value: expected %u actual %u", mSeq, seq);
1660b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim    }
1670b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim    if (mBufferState != CAPTURING) {
1680b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim        ALOGW("mBufferState != CAPTURING : instead %d", mBufferState);
1690b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim    }
1700b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim    if (succeeded) {
1710b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim        mBufferState = CAPTURED;
1720b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim    } else {
1730b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim        mBuffer.clear();
1740b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim        mBufferState = RELEASED;
1750b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim    }
1760b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim    mCondition.broadcast();
1770b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim}
1780b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim
1790b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kimvoid BufferProducerThread::shutdown() {
1800b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim    Mutex::Autolock autoLock(&mLock);
1810b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim    mShutdown = true;
1820b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim    setSurfaceLocked(NULL);
1830b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim    requestExitAndWait();
1840b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim}
1850b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim
1860b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kimbool BufferProducerThread::threadLoop() {
1870b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim    Mutex::Autolock autoLock(&mLock);
1880b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim
1890b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim    status_t err = NO_ERROR;
1900b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim    if (mSurface == NULL) {
1910b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim        err = mCondition.waitRelative(mLock, s2ns(1));
1920b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim        // It's OK to time out here.
1930b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim        if (err != NO_ERROR && err != TIMED_OUT) {
1940b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim            ALOGE("error %d while wating for non-null surface to be set", err);
1950b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim            return false;
1960b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim        }
1970b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim        return true;
1980b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim    }
1990b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim    sp<ANativeWindow> anw(mSurface);
2000b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim    while (mBufferState == CAPTURING) {
2010b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim        err = mCondition.waitRelative(mLock, s2ns(1));
2020b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim        if (err != NO_ERROR) {
2030b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim            ALOGE("error %d while wating for buffer state to change.", err);
2040b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim            return false;
2050b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim        }
2060b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim    }
2070b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim    if (mBufferState == CAPTURED && anw != NULL) {
2080b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim        err = anw->queueBuffer(anw.get(), mBuffer.get(), -1);
2090b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim        if (err != NO_ERROR) {
2100b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim            ALOGE("error %d while queueing buffer to surface", err);
2110b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim            return false;
2120b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim        }
2130b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim        mBuffer.clear();
2140b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim        mBufferState = RELEASED;
2150b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim    }
2160b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim    if (mBuffer == NULL && !mShutdown && anw != NULL) {
2170b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim        ANativeWindowBuffer_t* buffer = NULL;
2180b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim        err = native_window_dequeue_buffer_and_wait(anw.get(), &buffer);
2190b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim        if (err != NO_ERROR) {
2200b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim            ALOGE("error %d while dequeueing buffer to surface", err);
2210b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim            return false;
2220b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim        }
2230b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim        mBuffer = buffer;
2240b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim        mBufferState = CAPTURING;
2250b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim        mDevice->request_capture(mDevice, mDeviceId, mStream.stream_id,
2260b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim                                 buffer->handle, ++mSeq);
2270b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim    }
2280b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim
2290b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim    return true;
2300b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim}
2310b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim
2320b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim////////////////////////////////////////////////////////////////////////////////
2330b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim
234c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kimclass JTvInputHal {
235c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kimpublic:
236c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim    ~JTvInputHal();
237c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim
238a617074c531dfa317e5051fa70ec6b6c21d14386Wonsik Kim    static JTvInputHal* createInstance(JNIEnv* env, jobject thiz, const sp<Looper>& looper);
239c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim
2408f24a8b60f9afc1aedb89e7ee80ce65515439600Wonsik Kim    int addOrUpdateStream(int deviceId, int streamId, const sp<Surface>& surface);
241839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim    int removeStream(int deviceId, int streamId);
2424a3a601082b88ee057aa71421e45cb00041ecfffDongwon Kang    const tv_stream_config_t* getStreamConfigs(int deviceId, int* numConfigs);
243c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim
244a617074c531dfa317e5051fa70ec6b6c21d14386Wonsik Kim    void onDeviceAvailable(const tv_input_device_info_t& info);
245a617074c531dfa317e5051fa70ec6b6c21d14386Wonsik Kim    void onDeviceUnavailable(int deviceId);
246a617074c531dfa317e5051fa70ec6b6c21d14386Wonsik Kim    void onStreamConfigurationsChanged(int deviceId);
247a617074c531dfa317e5051fa70ec6b6c21d14386Wonsik Kim    void onCaptured(int deviceId, int streamId, uint32_t seq, bool succeeded);
248a617074c531dfa317e5051fa70ec6b6c21d14386Wonsik Kim
249c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kimprivate:
2500b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim    // Connection between a surface and a stream.
251c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim    class Connection {
252c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim    public:
253839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim        Connection() {}
254c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim
255c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim        sp<Surface> mSurface;
2560b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim        tv_stream_type_t mStreamType;
2570b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim
2580b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim        // Only valid when mStreamType == TV_STREAM_TYPE_INDEPENDENT_VIDEO_SOURCE
259c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim        sp<NativeHandle> mSourceHandle;
2600b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim        // Only valid when mStreamType == TV_STREAM_TYPE_BUFFER_PRODUCER
2610b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim        sp<BufferProducerThread> mThread;
262c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim    };
263c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim
264a617074c531dfa317e5051fa70ec6b6c21d14386Wonsik Kim    class NotifyHandler : public MessageHandler {
265a617074c531dfa317e5051fa70ec6b6c21d14386Wonsik Kim    public:
266a617074c531dfa317e5051fa70ec6b6c21d14386Wonsik Kim        NotifyHandler(JTvInputHal* hal, const tv_input_event_t* event);
26762f38d14c531e5983dafb2e0b93bae9f7769953cSungsoo Lim        ~NotifyHandler();
268a617074c531dfa317e5051fa70ec6b6c21d14386Wonsik Kim
269a617074c531dfa317e5051fa70ec6b6c21d14386Wonsik Kim        virtual void handleMessage(const Message& message);
270a617074c531dfa317e5051fa70ec6b6c21d14386Wonsik Kim
271a617074c531dfa317e5051fa70ec6b6c21d14386Wonsik Kim    private:
272a617074c531dfa317e5051fa70ec6b6c21d14386Wonsik Kim        tv_input_event_t mEvent;
273a617074c531dfa317e5051fa70ec6b6c21d14386Wonsik Kim        JTvInputHal* mHal;
274a617074c531dfa317e5051fa70ec6b6c21d14386Wonsik Kim    };
275a617074c531dfa317e5051fa70ec6b6c21d14386Wonsik Kim
276a617074c531dfa317e5051fa70ec6b6c21d14386Wonsik Kim    JTvInputHal(JNIEnv* env, jobject thiz, tv_input_device_t* dev, const sp<Looper>& looper);
277c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim
278c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim    static void notify(
2790b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim            tv_input_device_t* dev, tv_input_event_t* event, void* data);
280c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim
28162f38d14c531e5983dafb2e0b93bae9f7769953cSungsoo Lim    static void cloneTvInputEvent(
28262f38d14c531e5983dafb2e0b93bae9f7769953cSungsoo Lim            tv_input_event_t* dstEvent, const tv_input_event_t* srcEvent);
28362f38d14c531e5983dafb2e0b93bae9f7769953cSungsoo Lim
2840b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim    Mutex mLock;
285c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim    jweak mThiz;
286c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim    tv_input_device_t* mDevice;
287c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim    tv_input_callback_ops_t mCallback;
288a617074c531dfa317e5051fa70ec6b6c21d14386Wonsik Kim    sp<Looper> mLooper;
289c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim
290839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim    KeyedVector<int, KeyedVector<int, Connection> > mConnections;
291c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim};
292c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim
293a617074c531dfa317e5051fa70ec6b6c21d14386Wonsik KimJTvInputHal::JTvInputHal(JNIEnv* env, jobject thiz, tv_input_device_t* device,
2944a3a601082b88ee057aa71421e45cb00041ecfffDongwon Kang        const sp<Looper>& looper) {
295c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim    mThiz = env->NewWeakGlobalRef(thiz);
296c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim    mDevice = device;
297c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim    mCallback.notify = &JTvInputHal::notify;
298a617074c531dfa317e5051fa70ec6b6c21d14386Wonsik Kim    mLooper = looper;
299c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim
300c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim    mDevice->initialize(mDevice, &mCallback, this);
301c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim}
302c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim
303c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik KimJTvInputHal::~JTvInputHal() {
304c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim    mDevice->common.close((hw_device_t*)mDevice);
305c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim
306c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim    JNIEnv* env = AndroidRuntime::getJNIEnv();
307c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim    env->DeleteWeakGlobalRef(mThiz);
308c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim    mThiz = NULL;
309c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim}
310c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim
311a617074c531dfa317e5051fa70ec6b6c21d14386Wonsik KimJTvInputHal* JTvInputHal::createInstance(JNIEnv* env, jobject thiz, const sp<Looper>& looper) {
312c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim    tv_input_module_t* module = NULL;
313c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim    status_t err = hw_get_module(TV_INPUT_HARDWARE_MODULE_ID,
314c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            (hw_module_t const**)&module);
315c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim    if (err) {
316c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim        ALOGE("Couldn't load %s module (%s)",
317c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                TV_INPUT_HARDWARE_MODULE_ID, strerror(-err));
318c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim        return 0;
319c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim    }
320c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim
321c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim    tv_input_device_t* device = NULL;
322c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim    err = module->common.methods->open(
323c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            (hw_module_t*)module,
324c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            TV_INPUT_DEFAULT_DEVICE,
325c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            (hw_device_t**)&device);
326c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim    if (err) {
327c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim        ALOGE("Couldn't open %s device (%s)",
328c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                TV_INPUT_DEFAULT_DEVICE, strerror(-err));
329c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim        return 0;
330c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim    }
331c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim
332a617074c531dfa317e5051fa70ec6b6c21d14386Wonsik Kim    return new JTvInputHal(env, thiz, device, looper);
333c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim}
334c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim
3358f24a8b60f9afc1aedb89e7ee80ce65515439600Wonsik Kimint JTvInputHal::addOrUpdateStream(int deviceId, int streamId, const sp<Surface>& surface) {
336839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim    KeyedVector<int, Connection>& connections = mConnections.editValueFor(deviceId);
337839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim    if (connections.indexOfKey(streamId) < 0) {
338839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim        connections.add(streamId, Connection());
339839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim    }
340839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim    Connection& connection = connections.editValueFor(streamId);
341839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim    if (connection.mSurface == surface) {
342c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim        // Nothing to do
343c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim        return NO_ERROR;
344c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim    }
3450b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim    // Clear the surface in the connection.
3460b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim    if (connection.mSurface != NULL) {
3470b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim        if (connection.mStreamType == TV_STREAM_TYPE_INDEPENDENT_VIDEO_SOURCE) {
3480b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim            if (Surface::isValid(connection.mSurface)) {
3490b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim                connection.mSurface->setSidebandStream(NULL);
3500b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim            }
3510b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim        }
352c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim        connection.mSurface.clear();
353c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim    }
3540b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim    if (connection.mSourceHandle == NULL && connection.mThread == NULL) {
355c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim        // Need to configure stream
356c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim        int numConfigs = 0;
3574a3a601082b88ee057aa71421e45cb00041ecfffDongwon Kang        const tv_stream_config_t* configs = NULL;
3584a3a601082b88ee057aa71421e45cb00041ecfffDongwon Kang        if (mDevice->get_stream_configurations(
3594a3a601082b88ee057aa71421e45cb00041ecfffDongwon Kang                mDevice, deviceId, &numConfigs, &configs) != 0) {
360c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            ALOGE("Couldn't get stream configs");
361c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            return UNKNOWN_ERROR;
362c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim        }
363c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim        int configIndex = -1;
364c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim        for (int i = 0; i < numConfigs; ++i) {
3654a3a601082b88ee057aa71421e45cb00041ecfffDongwon Kang            if (configs[i].stream_id == streamId) {
366c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                configIndex = i;
367c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                break;
368c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            }
369c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim        }
370c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim        if (configIndex == -1) {
371c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            ALOGE("Cannot find a config with given stream ID: %d", streamId);
372c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            return BAD_VALUE;
373c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim        }
3744a3a601082b88ee057aa71421e45cb00041ecfffDongwon Kang        connection.mStreamType = configs[configIndex].type;
37521aa3467cd14260418cc47334b656adf841a567cWonsik Kim
376c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim        tv_stream_t stream;
3774a3a601082b88ee057aa71421e45cb00041ecfffDongwon Kang        stream.stream_id = configs[configIndex].stream_id;
3780b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim        if (connection.mStreamType == TV_STREAM_TYPE_BUFFER_PRODUCER) {
3794a3a601082b88ee057aa71421e45cb00041ecfffDongwon Kang            stream.buffer_producer.width = configs[configIndex].max_video_width;
3804a3a601082b88ee057aa71421e45cb00041ecfffDongwon Kang            stream.buffer_producer.height = configs[configIndex].max_video_height;
3810b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim        }
382c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim        if (mDevice->open_stream(mDevice, deviceId, &stream) != 0) {
383c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            ALOGE("Couldn't add stream");
384c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            return UNKNOWN_ERROR;
385c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim        }
3860b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim        if (connection.mStreamType == TV_STREAM_TYPE_INDEPENDENT_VIDEO_SOURCE) {
3870b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim            connection.mSourceHandle = NativeHandle::create(
3880b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim                    stream.sideband_stream_source_handle, false);
3890b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim        } else if (connection.mStreamType == TV_STREAM_TYPE_BUFFER_PRODUCER) {
3900b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim            if (connection.mThread != NULL) {
3910b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim                connection.mThread->shutdown();
3920b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim            }
3930b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim            connection.mThread = new BufferProducerThread(mDevice, deviceId, &stream);
39466f4831aa105f981ba1d5c21e3dcf8f1e0d76de8Brian Carlstrom            connection.mThread->run("BufferProducerThread");
3950b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim        }
3960b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim    }
3970b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim    connection.mSurface = surface;
3980b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim    if (connection.mStreamType == TV_STREAM_TYPE_INDEPENDENT_VIDEO_SOURCE) {
399c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim        connection.mSurface->setSidebandStream(connection.mSourceHandle);
4000b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim    } else if (connection.mStreamType == TV_STREAM_TYPE_BUFFER_PRODUCER) {
4010b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim        connection.mThread->setSurface(surface);
402c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim    }
403c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim    return NO_ERROR;
404c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim}
405c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim
406839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kimint JTvInputHal::removeStream(int deviceId, int streamId) {
407839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim    KeyedVector<int, Connection>& connections = mConnections.editValueFor(deviceId);
408839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim    if (connections.indexOfKey(streamId) < 0) {
409839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim        return BAD_VALUE;
410839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim    }
411839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim    Connection& connection = connections.editValueFor(streamId);
412839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim    if (connection.mSurface == NULL) {
413839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim        // Nothing to do
414839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim        return NO_ERROR;
415839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim    }
416839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim    if (Surface::isValid(connection.mSurface)) {
417839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim        connection.mSurface->setSidebandStream(NULL);
418839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim    }
4196b1e695c56d19e8931c3bfecda77a9bbf30a6f02Wonsik Kim    connection.mSurface.clear();
420b82de3600f15edbff693d1362bf33140c2aabd33Wonsik Kim    if (connection.mThread != NULL) {
421b82de3600f15edbff693d1362bf33140c2aabd33Wonsik Kim        connection.mThread->shutdown();
422b82de3600f15edbff693d1362bf33140c2aabd33Wonsik Kim        connection.mThread.clear();
423b82de3600f15edbff693d1362bf33140c2aabd33Wonsik Kim    }
424b82de3600f15edbff693d1362bf33140c2aabd33Wonsik Kim    if (mDevice->close_stream(mDevice, deviceId, streamId) != 0) {
425b82de3600f15edbff693d1362bf33140c2aabd33Wonsik Kim        ALOGE("Couldn't remove stream");
426b82de3600f15edbff693d1362bf33140c2aabd33Wonsik Kim        return BAD_VALUE;
427b82de3600f15edbff693d1362bf33140c2aabd33Wonsik Kim    }
428839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim    if (connection.mSourceHandle != NULL) {
429839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim        connection.mSourceHandle.clear();
430839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim    }
431839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim    return NO_ERROR;
432839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim}
433839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim
4344a3a601082b88ee057aa71421e45cb00041ecfffDongwon Kangconst tv_stream_config_t* JTvInputHal::getStreamConfigs(int deviceId, int* numConfigs) {
4354a3a601082b88ee057aa71421e45cb00041ecfffDongwon Kang    const tv_stream_config_t* configs = NULL;
4364a3a601082b88ee057aa71421e45cb00041ecfffDongwon Kang    if (mDevice->get_stream_configurations(
4374a3a601082b88ee057aa71421e45cb00041ecfffDongwon Kang            mDevice, deviceId, numConfigs, &configs) != 0) {
4384a3a601082b88ee057aa71421e45cb00041ecfffDongwon Kang        ALOGE("Couldn't get stream configs");
4394a3a601082b88ee057aa71421e45cb00041ecfffDongwon Kang        return NULL;
440c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim    }
441c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim    return configs;
442c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim}
443c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim
444c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim// static
445c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kimvoid JTvInputHal::notify(
446c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim        tv_input_device_t* dev, tv_input_event_t* event, void* data) {
447c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim    JTvInputHal* thiz = (JTvInputHal*)data;
448a617074c531dfa317e5051fa70ec6b6c21d14386Wonsik Kim    thiz->mLooper->sendMessage(new NotifyHandler(thiz, event), event->type);
449c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim}
450c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim
45162f38d14c531e5983dafb2e0b93bae9f7769953cSungsoo Lim// static
45262f38d14c531e5983dafb2e0b93bae9f7769953cSungsoo Limvoid JTvInputHal::cloneTvInputEvent(
45362f38d14c531e5983dafb2e0b93bae9f7769953cSungsoo Lim        tv_input_event_t* dstEvent, const tv_input_event_t* srcEvent) {
45462f38d14c531e5983dafb2e0b93bae9f7769953cSungsoo Lim    memcpy(dstEvent, srcEvent, sizeof(tv_input_event_t));
45562f38d14c531e5983dafb2e0b93bae9f7769953cSungsoo Lim    if ((srcEvent->type == TV_INPUT_EVENT_DEVICE_AVAILABLE ||
45662f38d14c531e5983dafb2e0b93bae9f7769953cSungsoo Lim            srcEvent->type == TV_INPUT_EVENT_DEVICE_UNAVAILABLE ||
45762f38d14c531e5983dafb2e0b93bae9f7769953cSungsoo Lim            srcEvent->type == TV_INPUT_EVENT_STREAM_CONFIGURATIONS_CHANGED) &&
45862f38d14c531e5983dafb2e0b93bae9f7769953cSungsoo Lim            srcEvent->device_info.audio_address != NULL){
45962f38d14c531e5983dafb2e0b93bae9f7769953cSungsoo Lim        char* audio_address = new char[strlen(srcEvent->device_info.audio_address) + 1];
46062f38d14c531e5983dafb2e0b93bae9f7769953cSungsoo Lim        strcpy(audio_address, srcEvent->device_info.audio_address);
46162f38d14c531e5983dafb2e0b93bae9f7769953cSungsoo Lim        dstEvent->device_info.audio_address = audio_address;
46262f38d14c531e5983dafb2e0b93bae9f7769953cSungsoo Lim    }
46362f38d14c531e5983dafb2e0b93bae9f7769953cSungsoo Lim}
46462f38d14c531e5983dafb2e0b93bae9f7769953cSungsoo Lim
465c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kimvoid JTvInputHal::onDeviceAvailable(const tv_input_device_info_t& info) {
4660b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim    {
4670b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim        Mutex::Autolock autoLock(&mLock);
4680b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim        mConnections.add(info.device_id, KeyedVector<int, Connection>());
4690b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim    }
470c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim    JNIEnv* env = AndroidRuntime::getJNIEnv();
471d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim
472d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim    jobject builder = env->NewObject(
473d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim            gTvInputHardwareInfoBuilderClassInfo.clazz,
474d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim            gTvInputHardwareInfoBuilderClassInfo.constructor);
475d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim    env->CallObjectMethod(
476d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim            builder, gTvInputHardwareInfoBuilderClassInfo.deviceId, info.device_id);
477d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim    env->CallObjectMethod(
478d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim            builder, gTvInputHardwareInfoBuilderClassInfo.type, info.type);
479a358b53e1d0bb7a7fc08b0a4d2a2e256f3045859Wonsik Kim    if (info.type == TV_INPUT_TYPE_HDMI) {
480a358b53e1d0bb7a7fc08b0a4d2a2e256f3045859Wonsik Kim        env->CallObjectMethod(
481a358b53e1d0bb7a7fc08b0a4d2a2e256f3045859Wonsik Kim                builder, gTvInputHardwareInfoBuilderClassInfo.hdmiPortId, info.hdmi.port_id);
482a358b53e1d0bb7a7fc08b0a4d2a2e256f3045859Wonsik Kim    }
483d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim    env->CallObjectMethod(
484d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim            builder, gTvInputHardwareInfoBuilderClassInfo.audioType, info.audio_type);
485d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim    if (info.audio_type != AUDIO_DEVICE_NONE) {
486d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim        jstring audioAddress = env->NewStringUTF(info.audio_address);
487d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim        env->CallObjectMethod(
488d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim                builder, gTvInputHardwareInfoBuilderClassInfo.audioAddress, audioAddress);
489d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim        env->DeleteLocalRef(audioAddress);
490d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim    }
491d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim
492d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim    jobject infoObject = env->CallObjectMethod(builder, gTvInputHardwareInfoBuilderClassInfo.build);
493d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim
494c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim    env->CallVoidMethod(
495c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            mThiz,
496c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            gTvInputHalClassInfo.deviceAvailable,
497d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim            infoObject);
498d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim
499d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim    env->DeleteLocalRef(builder);
500d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim    env->DeleteLocalRef(infoObject);
501c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim}
502c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim
503c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kimvoid JTvInputHal::onDeviceUnavailable(int deviceId) {
5040b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim    {
5050b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim        Mutex::Autolock autoLock(&mLock);
5060b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim        KeyedVector<int, Connection>& connections = mConnections.editValueFor(deviceId);
5070b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim        for (size_t i = 0; i < connections.size(); ++i) {
5080b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim            removeStream(deviceId, connections.keyAt(i));
5090b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim        }
5100b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim        connections.clear();
5110b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim        mConnections.removeItem(deviceId);
512839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim    }
5130b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim    JNIEnv* env = AndroidRuntime::getJNIEnv();
514c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim    env->CallVoidMethod(
515c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            mThiz,
516c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            gTvInputHalClassInfo.deviceUnavailable,
517c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            deviceId);
518c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim}
519c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim
520c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kimvoid JTvInputHal::onStreamConfigurationsChanged(int deviceId) {
5210b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim    {
5220b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim        Mutex::Autolock autoLock(&mLock);
5230b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim        KeyedVector<int, Connection>& connections = mConnections.editValueFor(deviceId);
5240b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim        for (size_t i = 0; i < connections.size(); ++i) {
5250b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim            removeStream(deviceId, connections.keyAt(i));
5260b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim        }
5270b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim        connections.clear();
528839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim    }
5290b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim    JNIEnv* env = AndroidRuntime::getJNIEnv();
530c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim    env->CallVoidMethod(
531c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            mThiz,
532c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            gTvInputHalClassInfo.streamConfigsChanged,
533c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            deviceId);
534c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim}
535c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim
5360b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kimvoid JTvInputHal::onCaptured(int deviceId, int streamId, uint32_t seq, bool succeeded) {
5370b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim    sp<BufferProducerThread> thread;
5380b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim    {
5390b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim        Mutex::Autolock autoLock(&mLock);
5400b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim        KeyedVector<int, Connection>& connections = mConnections.editValueFor(deviceId);
5410b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim        Connection& connection = connections.editValueFor(streamId);
5420b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim        if (connection.mThread == NULL) {
5430b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim            ALOGE("capture thread not existing.");
5440b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim            return;
5450b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim        }
5460b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim        thread = connection.mThread;
5470b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim    }
5480b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim    thread->onCaptured(seq, succeeded);
549c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo    if (seq == 0) {
550c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo        JNIEnv* env = AndroidRuntime::getJNIEnv();
551c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo        env->CallVoidMethod(
552c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo                mThiz,
553c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo                gTvInputHalClassInfo.firstFrameCaptured,
554c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo                deviceId,
555c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo                streamId);
556c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo    }
5570b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim}
5580b2691b6873f9d328884c5a9e5ab1fe308f3ee36Wonsik Kim
559a617074c531dfa317e5051fa70ec6b6c21d14386Wonsik KimJTvInputHal::NotifyHandler::NotifyHandler(JTvInputHal* hal, const tv_input_event_t* event) {
560a617074c531dfa317e5051fa70ec6b6c21d14386Wonsik Kim    mHal = hal;
56162f38d14c531e5983dafb2e0b93bae9f7769953cSungsoo Lim    cloneTvInputEvent(&mEvent, event);
56262f38d14c531e5983dafb2e0b93bae9f7769953cSungsoo Lim}
56362f38d14c531e5983dafb2e0b93bae9f7769953cSungsoo Lim
56462f38d14c531e5983dafb2e0b93bae9f7769953cSungsoo LimJTvInputHal::NotifyHandler::~NotifyHandler() {
56562f38d14c531e5983dafb2e0b93bae9f7769953cSungsoo Lim    if ((mEvent.type == TV_INPUT_EVENT_DEVICE_AVAILABLE ||
56662f38d14c531e5983dafb2e0b93bae9f7769953cSungsoo Lim            mEvent.type == TV_INPUT_EVENT_DEVICE_UNAVAILABLE ||
56762f38d14c531e5983dafb2e0b93bae9f7769953cSungsoo Lim            mEvent.type == TV_INPUT_EVENT_STREAM_CONFIGURATIONS_CHANGED) &&
56862f38d14c531e5983dafb2e0b93bae9f7769953cSungsoo Lim            mEvent.device_info.audio_address != NULL) {
56962f38d14c531e5983dafb2e0b93bae9f7769953cSungsoo Lim        delete mEvent.device_info.audio_address;
57062f38d14c531e5983dafb2e0b93bae9f7769953cSungsoo Lim    }
571a617074c531dfa317e5051fa70ec6b6c21d14386Wonsik Kim}
572a617074c531dfa317e5051fa70ec6b6c21d14386Wonsik Kim
573a617074c531dfa317e5051fa70ec6b6c21d14386Wonsik Kimvoid JTvInputHal::NotifyHandler::handleMessage(const Message& message) {
574a617074c531dfa317e5051fa70ec6b6c21d14386Wonsik Kim    switch (mEvent.type) {
575a617074c531dfa317e5051fa70ec6b6c21d14386Wonsik Kim        case TV_INPUT_EVENT_DEVICE_AVAILABLE: {
576a617074c531dfa317e5051fa70ec6b6c21d14386Wonsik Kim            mHal->onDeviceAvailable(mEvent.device_info);
577a617074c531dfa317e5051fa70ec6b6c21d14386Wonsik Kim        } break;
578a617074c531dfa317e5051fa70ec6b6c21d14386Wonsik Kim        case TV_INPUT_EVENT_DEVICE_UNAVAILABLE: {
579a617074c531dfa317e5051fa70ec6b6c21d14386Wonsik Kim            mHal->onDeviceUnavailable(mEvent.device_info.device_id);
580a617074c531dfa317e5051fa70ec6b6c21d14386Wonsik Kim        } break;
581a617074c531dfa317e5051fa70ec6b6c21d14386Wonsik Kim        case TV_INPUT_EVENT_STREAM_CONFIGURATIONS_CHANGED: {
582a617074c531dfa317e5051fa70ec6b6c21d14386Wonsik Kim            mHal->onStreamConfigurationsChanged(mEvent.device_info.device_id);
583a617074c531dfa317e5051fa70ec6b6c21d14386Wonsik Kim        } break;
584a617074c531dfa317e5051fa70ec6b6c21d14386Wonsik Kim        case TV_INPUT_EVENT_CAPTURE_SUCCEEDED: {
585a617074c531dfa317e5051fa70ec6b6c21d14386Wonsik Kim            mHal->onCaptured(mEvent.capture_result.device_id,
586a617074c531dfa317e5051fa70ec6b6c21d14386Wonsik Kim                             mEvent.capture_result.stream_id,
587a617074c531dfa317e5051fa70ec6b6c21d14386Wonsik Kim                             mEvent.capture_result.seq,
588a617074c531dfa317e5051fa70ec6b6c21d14386Wonsik Kim                             true /* succeeded */);
589a617074c531dfa317e5051fa70ec6b6c21d14386Wonsik Kim        } break;
590a617074c531dfa317e5051fa70ec6b6c21d14386Wonsik Kim        case TV_INPUT_EVENT_CAPTURE_FAILED: {
591a617074c531dfa317e5051fa70ec6b6c21d14386Wonsik Kim            mHal->onCaptured(mEvent.capture_result.device_id,
592a617074c531dfa317e5051fa70ec6b6c21d14386Wonsik Kim                             mEvent.capture_result.stream_id,
593a617074c531dfa317e5051fa70ec6b6c21d14386Wonsik Kim                             mEvent.capture_result.seq,
594a617074c531dfa317e5051fa70ec6b6c21d14386Wonsik Kim                             false /* succeeded */);
595a617074c531dfa317e5051fa70ec6b6c21d14386Wonsik Kim        } break;
596a617074c531dfa317e5051fa70ec6b6c21d14386Wonsik Kim        default:
597a617074c531dfa317e5051fa70ec6b6c21d14386Wonsik Kim            ALOGE("Unrecognizable event");
598a617074c531dfa317e5051fa70ec6b6c21d14386Wonsik Kim    }
599a617074c531dfa317e5051fa70ec6b6c21d14386Wonsik Kim}
600a617074c531dfa317e5051fa70ec6b6c21d14386Wonsik Kim
601c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim////////////////////////////////////////////////////////////////////////////////
602c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim
603a617074c531dfa317e5051fa70ec6b6c21d14386Wonsik Kimstatic jlong nativeOpen(JNIEnv* env, jobject thiz, jobject messageQueueObj) {
604a617074c531dfa317e5051fa70ec6b6c21d14386Wonsik Kim    sp<MessageQueue> messageQueue =
605a617074c531dfa317e5051fa70ec6b6c21d14386Wonsik Kim            android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
606a617074c531dfa317e5051fa70ec6b6c21d14386Wonsik Kim    return (jlong)JTvInputHal::createInstance(env, thiz, messageQueue->getLooper());
607c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim}
608c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim
6098f24a8b60f9afc1aedb89e7ee80ce65515439600Wonsik Kimstatic int nativeAddOrUpdateStream(JNIEnv* env, jclass clazz,
610c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim        jlong ptr, jint deviceId, jint streamId, jobject jsurface) {
611c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim    JTvInputHal* tvInputHal = (JTvInputHal*)ptr;
612839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim    if (!jsurface) {
613839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim        return BAD_VALUE;
614839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim    }
615839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim    sp<Surface> surface(android_view_Surface_getSurface(env, jsurface));
6166b1e695c56d19e8931c3bfecda77a9bbf30a6f02Wonsik Kim    if (!Surface::isValid(surface)) {
6176b1e695c56d19e8931c3bfecda77a9bbf30a6f02Wonsik Kim        return BAD_VALUE;
6186b1e695c56d19e8931c3bfecda77a9bbf30a6f02Wonsik Kim    }
6198f24a8b60f9afc1aedb89e7ee80ce65515439600Wonsik Kim    return tvInputHal->addOrUpdateStream(deviceId, streamId, surface);
620839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim}
621839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim
622839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kimstatic int nativeRemoveStream(JNIEnv* env, jclass clazz,
623839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim        jlong ptr, jint deviceId, jint streamId) {
624839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim    JTvInputHal* tvInputHal = (JTvInputHal*)ptr;
625839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim    return tvInputHal->removeStream(deviceId, streamId);
626c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim}
627c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim
628c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kimstatic jobjectArray nativeGetStreamConfigs(JNIEnv* env, jclass clazz,
629c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim        jlong ptr, jint deviceId, jint generation) {
630c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim    JTvInputHal* tvInputHal = (JTvInputHal*)ptr;
631c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim    int numConfigs = 0;
6324a3a601082b88ee057aa71421e45cb00041ecfffDongwon Kang    const tv_stream_config_t* configs = tvInputHal->getStreamConfigs(deviceId, &numConfigs);
633c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim
634c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim    jobjectArray result = env->NewObjectArray(numConfigs, gTvStreamConfigClassInfo.clazz, NULL);
635c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim    for (int i = 0; i < numConfigs; ++i) {
636c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim        jobject builder = env->NewObject(
637c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                gTvStreamConfigBuilderClassInfo.clazz,
638c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                gTvStreamConfigBuilderClassInfo.constructor);
639c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim        env->CallObjectMethod(
6404a3a601082b88ee057aa71421e45cb00041ecfffDongwon Kang                builder, gTvStreamConfigBuilderClassInfo.streamId, configs[i].stream_id);
641c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim        env->CallObjectMethod(
6424a3a601082b88ee057aa71421e45cb00041ecfffDongwon Kang                builder, gTvStreamConfigBuilderClassInfo.type, configs[i].type);
643c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim        env->CallObjectMethod(
6444a3a601082b88ee057aa71421e45cb00041ecfffDongwon Kang                builder, gTvStreamConfigBuilderClassInfo.maxWidth, configs[i].max_video_width);
645c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim        env->CallObjectMethod(
6464a3a601082b88ee057aa71421e45cb00041ecfffDongwon Kang                builder, gTvStreamConfigBuilderClassInfo.maxHeight, configs[i].max_video_height);
647c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim        env->CallObjectMethod(
648c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                builder, gTvStreamConfigBuilderClassInfo.generation, generation);
649c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim
650c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim        jobject config = env->CallObjectMethod(builder, gTvStreamConfigBuilderClassInfo.build);
651c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim
652c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim        env->SetObjectArrayElement(result, i, config);
653c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim
654c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim        env->DeleteLocalRef(config);
655c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim        env->DeleteLocalRef(builder);
656c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim    }
657c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim    return result;
658c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim}
659c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim
660c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kimstatic void nativeClose(JNIEnv* env, jclass clazz, jlong ptr) {
661c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim    JTvInputHal* tvInputHal = (JTvInputHal*)ptr;
662c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim    delete tvInputHal;
663c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim}
664c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim
66576f6a86de25e1bf74717e047e55fd44b089673f3Daniel Micaystatic const JNINativeMethod gTvInputHalMethods[] = {
666c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim    /* name, signature, funcPtr */
667a617074c531dfa317e5051fa70ec6b6c21d14386Wonsik Kim    { "nativeOpen", "(Landroid/os/MessageQueue;)J",
668c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            (void*) nativeOpen },
6698f24a8b60f9afc1aedb89e7ee80ce65515439600Wonsik Kim    { "nativeAddOrUpdateStream", "(JIILandroid/view/Surface;)I",
6708f24a8b60f9afc1aedb89e7ee80ce65515439600Wonsik Kim            (void*) nativeAddOrUpdateStream },
671839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim    { "nativeRemoveStream", "(JII)I",
672839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim            (void*) nativeRemoveStream },
673d5cc4a281e7ce29d1e8687ff3394b57a3a549260Jae Seo    { "nativeGetStreamConfigs", "(JII)[Landroid/media/tv/TvStreamConfig;",
674c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            (void*) nativeGetStreamConfigs },
675c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim    { "nativeClose", "(J)V",
676c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            (void*) nativeClose },
677c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim};
678c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim
679c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim#define FIND_CLASS(var, className) \
680c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim        var = env->FindClass(className); \
681c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim        LOG_FATAL_IF(! var, "Unable to find class " className)
682c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim
683c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim#define GET_METHOD_ID(var, clazz, methodName, fieldDescriptor) \
684c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim        var = env->GetMethodID(clazz, methodName, fieldDescriptor); \
685c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim        LOG_FATAL_IF(! var, "Unable to find method" methodName)
686c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim
687c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kimint register_android_server_tv_TvInputHal(JNIEnv* env) {
688c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim    int res = jniRegisterNativeMethods(env, "com/android/server/tv/TvInputHal",
689c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            gTvInputHalMethods, NELEM(gTvInputHalMethods));
690c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim    LOG_FATAL_IF(res < 0, "Unable to register native methods.");
6914048a4bcb1ea709ddb83a4fde3ff5c53e642f7d0Bernhard Rosenkränzer    (void)res; // Don't complain about unused variable in the LOG_NDEBUG case
692c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim
693c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim    jclass clazz;
694c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim    FIND_CLASS(clazz, "com/android/server/tv/TvInputHal");
695c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim
696c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim    GET_METHOD_ID(
697d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim            gTvInputHalClassInfo.deviceAvailable, clazz,
698d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim            "deviceAvailableFromNative", "(Landroid/media/tv/TvInputHardwareInfo;)V");
699c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim    GET_METHOD_ID(
700c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            gTvInputHalClassInfo.deviceUnavailable, clazz, "deviceUnavailableFromNative", "(I)V");
701c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim    GET_METHOD_ID(
702c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            gTvInputHalClassInfo.streamConfigsChanged, clazz,
703c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            "streamConfigsChangedFromNative", "(I)V");
704c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo    GET_METHOD_ID(
705c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            gTvInputHalClassInfo.firstFrameCaptured, clazz,
706c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            "firstFrameCapturedFromNative", "(II)V");
707c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim
708d5cc4a281e7ce29d1e8687ff3394b57a3a549260Jae Seo    FIND_CLASS(gTvStreamConfigClassInfo.clazz, "android/media/tv/TvStreamConfig");
709c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim    gTvStreamConfigClassInfo.clazz = jclass(env->NewGlobalRef(gTvStreamConfigClassInfo.clazz));
710c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim
711d5cc4a281e7ce29d1e8687ff3394b57a3a549260Jae Seo    FIND_CLASS(gTvStreamConfigBuilderClassInfo.clazz, "android/media/tv/TvStreamConfig$Builder");
712c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim    gTvStreamConfigBuilderClassInfo.clazz =
713c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            jclass(env->NewGlobalRef(gTvStreamConfigBuilderClassInfo.clazz));
714c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim
715c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim    GET_METHOD_ID(
716c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            gTvStreamConfigBuilderClassInfo.constructor,
717c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            gTvStreamConfigBuilderClassInfo.clazz,
718c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            "<init>", "()V");
719c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim    GET_METHOD_ID(
720c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            gTvStreamConfigBuilderClassInfo.streamId,
721c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            gTvStreamConfigBuilderClassInfo.clazz,
722d5cc4a281e7ce29d1e8687ff3394b57a3a549260Jae Seo            "streamId", "(I)Landroid/media/tv/TvStreamConfig$Builder;");
723c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim    GET_METHOD_ID(
724c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            gTvStreamConfigBuilderClassInfo.type,
725c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            gTvStreamConfigBuilderClassInfo.clazz,
726d5cc4a281e7ce29d1e8687ff3394b57a3a549260Jae Seo            "type", "(I)Landroid/media/tv/TvStreamConfig$Builder;");
727c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim    GET_METHOD_ID(
728c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            gTvStreamConfigBuilderClassInfo.maxWidth,
729c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            gTvStreamConfigBuilderClassInfo.clazz,
730d5cc4a281e7ce29d1e8687ff3394b57a3a549260Jae Seo            "maxWidth", "(I)Landroid/media/tv/TvStreamConfig$Builder;");
731c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim    GET_METHOD_ID(
732c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            gTvStreamConfigBuilderClassInfo.maxHeight,
733c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            gTvStreamConfigBuilderClassInfo.clazz,
734d5cc4a281e7ce29d1e8687ff3394b57a3a549260Jae Seo            "maxHeight", "(I)Landroid/media/tv/TvStreamConfig$Builder;");
735c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim    GET_METHOD_ID(
736c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            gTvStreamConfigBuilderClassInfo.generation,
737c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            gTvStreamConfigBuilderClassInfo.clazz,
738d5cc4a281e7ce29d1e8687ff3394b57a3a549260Jae Seo            "generation", "(I)Landroid/media/tv/TvStreamConfig$Builder;");
739c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim    GET_METHOD_ID(
740c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            gTvStreamConfigBuilderClassInfo.build,
741c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            gTvStreamConfigBuilderClassInfo.clazz,
742d5cc4a281e7ce29d1e8687ff3394b57a3a549260Jae Seo            "build", "()Landroid/media/tv/TvStreamConfig;");
743c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim
744d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim    FIND_CLASS(gTvInputHardwareInfoBuilderClassInfo.clazz,
745d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim            "android/media/tv/TvInputHardwareInfo$Builder");
746d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim    gTvInputHardwareInfoBuilderClassInfo.clazz =
747d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim            jclass(env->NewGlobalRef(gTvInputHardwareInfoBuilderClassInfo.clazz));
748d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim
749d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim    GET_METHOD_ID(
750d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim            gTvInputHardwareInfoBuilderClassInfo.constructor,
751d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim            gTvInputHardwareInfoBuilderClassInfo.clazz,
752d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim            "<init>", "()V");
753d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim    GET_METHOD_ID(
754d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim            gTvInputHardwareInfoBuilderClassInfo.deviceId,
755d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim            gTvInputHardwareInfoBuilderClassInfo.clazz,
756d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim            "deviceId", "(I)Landroid/media/tv/TvInputHardwareInfo$Builder;");
757d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim    GET_METHOD_ID(
758d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim            gTvInputHardwareInfoBuilderClassInfo.type,
759d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim            gTvInputHardwareInfoBuilderClassInfo.clazz,
760d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim            "type", "(I)Landroid/media/tv/TvInputHardwareInfo$Builder;");
761d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim    GET_METHOD_ID(
762a358b53e1d0bb7a7fc08b0a4d2a2e256f3045859Wonsik Kim            gTvInputHardwareInfoBuilderClassInfo.hdmiPortId,
763a358b53e1d0bb7a7fc08b0a4d2a2e256f3045859Wonsik Kim            gTvInputHardwareInfoBuilderClassInfo.clazz,
764a358b53e1d0bb7a7fc08b0a4d2a2e256f3045859Wonsik Kim            "hdmiPortId", "(I)Landroid/media/tv/TvInputHardwareInfo$Builder;");
765a358b53e1d0bb7a7fc08b0a4d2a2e256f3045859Wonsik Kim    GET_METHOD_ID(
766d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim            gTvInputHardwareInfoBuilderClassInfo.audioType,
767d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim            gTvInputHardwareInfoBuilderClassInfo.clazz,
768d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim            "audioType", "(I)Landroid/media/tv/TvInputHardwareInfo$Builder;");
769d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim    GET_METHOD_ID(
770d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim            gTvInputHardwareInfoBuilderClassInfo.audioAddress,
771d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim            gTvInputHardwareInfoBuilderClassInfo.clazz,
772d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim            "audioAddress", "(Ljava/lang/String;)Landroid/media/tv/TvInputHardwareInfo$Builder;");
773d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim    GET_METHOD_ID(
774d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim            gTvInputHardwareInfoBuilderClassInfo.build,
775d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim            gTvInputHardwareInfoBuilderClassInfo.clazz,
776d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim            "build", "()Landroid/media/tv/TvInputHardwareInfo;");
777d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim
778c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim    return 0;
779c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim}
780c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim
781c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim} /* namespace android */
782