com_android_server_tv_TvInputHal.cpp revision 21aa3467cd14260418cc47334b656adf841a567c
1/*
2 * Copyright 2014 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_TAG "TvInputHal"
18
19//#define LOG_NDEBUG 0
20
21#include "android_runtime/AndroidRuntime.h"
22#include "android_runtime/android_view_Surface.h"
23#include "JNIHelp.h"
24#include "jni.h"
25
26#include <gui/Surface.h>
27#include <utils/Errors.h>
28#include <utils/KeyedVector.h>
29#include <utils/Log.h>
30#include <utils/NativeHandle.h>
31#include <hardware/tv_input.h>
32
33namespace android {
34
35static struct {
36    jmethodID deviceAvailable;
37    jmethodID deviceUnavailable;
38    jmethodID streamConfigsChanged;
39    jmethodID firstFrameCaptured;
40} gTvInputHalClassInfo;
41
42static struct {
43    jclass clazz;
44} gTvStreamConfigClassInfo;
45
46static struct {
47    jclass clazz;
48
49    jmethodID constructor;
50    jmethodID streamId;
51    jmethodID type;
52    jmethodID maxWidth;
53    jmethodID maxHeight;
54    jmethodID generation;
55    jmethodID build;
56} gTvStreamConfigBuilderClassInfo;
57
58static struct {
59    jclass clazz;
60
61    jmethodID constructor;
62    jmethodID deviceId;
63    jmethodID type;
64    jmethodID hdmiPortId;
65    jmethodID audioType;
66    jmethodID audioAddress;
67    jmethodID build;
68} gTvInputHardwareInfoBuilderClassInfo;
69
70////////////////////////////////////////////////////////////////////////////////
71
72class BufferProducerThread : public Thread {
73public:
74    BufferProducerThread(tv_input_device_t* device, int deviceId, const tv_stream_t* stream);
75
76    virtual status_t readyToRun();
77
78    void setSurface(const sp<Surface>& surface);
79    void onCaptured(uint32_t seq, bool succeeded);
80    void shutdown();
81
82private:
83    Mutex mLock;
84    Condition mCondition;
85    sp<Surface> mSurface;
86    tv_input_device_t* mDevice;
87    int mDeviceId;
88    tv_stream_t mStream;
89    sp<ANativeWindowBuffer_t> mBuffer;
90    enum {
91        CAPTURING,
92        CAPTURED,
93        RELEASED,
94    } mBufferState;
95    uint32_t mSeq;
96    bool mShutdown;
97
98    virtual bool threadLoop();
99
100    void setSurfaceLocked(const sp<Surface>& surface);
101};
102
103BufferProducerThread::BufferProducerThread(
104        tv_input_device_t* device, int deviceId, const tv_stream_t* stream)
105    : Thread(false),
106      mDevice(device),
107      mDeviceId(deviceId),
108      mBuffer(NULL),
109      mBufferState(RELEASED),
110      mSeq(0u),
111      mShutdown(false) {
112    memcpy(&mStream, stream, sizeof(mStream));
113}
114
115status_t BufferProducerThread::readyToRun() {
116    sp<ANativeWindow> anw(mSurface);
117    status_t err = native_window_set_usage(anw.get(), mStream.buffer_producer.usage);
118    if (err != NO_ERROR) {
119        return err;
120    }
121    err = native_window_set_buffers_dimensions(
122            anw.get(), mStream.buffer_producer.width, mStream.buffer_producer.height);
123    if (err != NO_ERROR) {
124        return err;
125    }
126    err = native_window_set_buffers_format(anw.get(), mStream.buffer_producer.format);
127    if (err != NO_ERROR) {
128        return err;
129    }
130    return NO_ERROR;
131}
132
133void BufferProducerThread::setSurface(const sp<Surface>& surface) {
134    Mutex::Autolock autoLock(&mLock);
135    setSurfaceLocked(surface);
136}
137
138void BufferProducerThread::setSurfaceLocked(const sp<Surface>& surface) {
139    if (surface == mSurface) {
140        return;
141    }
142
143    if (mBufferState == CAPTURING) {
144        mDevice->cancel_capture(mDevice, mDeviceId, mStream.stream_id, mSeq);
145    }
146    while (mBufferState == CAPTURING) {
147        status_t err = mCondition.waitRelative(mLock, s2ns(1));
148        if (err != NO_ERROR) {
149            ALOGE("error %d while wating for buffer state to change.", err);
150            break;
151        }
152    }
153    mBuffer.clear();
154    mBufferState = RELEASED;
155
156    mSurface = surface;
157    mCondition.broadcast();
158}
159
160void BufferProducerThread::onCaptured(uint32_t seq, bool succeeded) {
161    Mutex::Autolock autoLock(&mLock);
162    if (seq != mSeq) {
163        ALOGW("Incorrect sequence value: expected %u actual %u", mSeq, seq);
164    }
165    if (mBufferState != CAPTURING) {
166        ALOGW("mBufferState != CAPTURING : instead %d", mBufferState);
167    }
168    if (succeeded) {
169        mBufferState = CAPTURED;
170    } else {
171        mBuffer.clear();
172        mBufferState = RELEASED;
173    }
174    mCondition.broadcast();
175}
176
177void BufferProducerThread::shutdown() {
178    Mutex::Autolock autoLock(&mLock);
179    mShutdown = true;
180    setSurfaceLocked(NULL);
181    requestExitAndWait();
182}
183
184bool BufferProducerThread::threadLoop() {
185    Mutex::Autolock autoLock(&mLock);
186
187    status_t err = NO_ERROR;
188    if (mSurface == NULL) {
189        err = mCondition.waitRelative(mLock, s2ns(1));
190        // It's OK to time out here.
191        if (err != NO_ERROR && err != TIMED_OUT) {
192            ALOGE("error %d while wating for non-null surface to be set", err);
193            return false;
194        }
195        return true;
196    }
197    sp<ANativeWindow> anw(mSurface);
198    while (mBufferState == CAPTURING) {
199        err = mCondition.waitRelative(mLock, s2ns(1));
200        if (err != NO_ERROR) {
201            ALOGE("error %d while wating for buffer state to change.", err);
202            return false;
203        }
204    }
205    if (mBufferState == CAPTURED && anw != NULL) {
206        err = anw->queueBuffer(anw.get(), mBuffer.get(), -1);
207        if (err != NO_ERROR) {
208            ALOGE("error %d while queueing buffer to surface", err);
209            return false;
210        }
211        mBuffer.clear();
212        mBufferState = RELEASED;
213    }
214    if (mBuffer == NULL && !mShutdown && anw != NULL) {
215        ANativeWindowBuffer_t* buffer = NULL;
216        err = native_window_dequeue_buffer_and_wait(anw.get(), &buffer);
217        if (err != NO_ERROR) {
218            ALOGE("error %d while dequeueing buffer to surface", err);
219            return false;
220        }
221        mBuffer = buffer;
222        mBufferState = CAPTURING;
223        mDevice->request_capture(mDevice, mDeviceId, mStream.stream_id,
224                                 buffer->handle, ++mSeq);
225    }
226
227    return true;
228}
229
230////////////////////////////////////////////////////////////////////////////////
231
232class JTvInputHal {
233public:
234    ~JTvInputHal();
235
236    static JTvInputHal* createInstance(JNIEnv* env, jobject thiz);
237
238    int addStream(int deviceId, int streamId, const sp<Surface>& surface);
239    int removeStream(int deviceId, int streamId);
240    const tv_stream_config_t* getStreamConfigs(int deviceId, int* numConfigs);
241
242private:
243    // Connection between a surface and a stream.
244    class Connection {
245    public:
246        Connection() {}
247
248        sp<Surface> mSurface;
249        tv_stream_type_t mStreamType;
250
251        // Only valid when mStreamType == TV_STREAM_TYPE_INDEPENDENT_VIDEO_SOURCE
252        sp<NativeHandle> mSourceHandle;
253        // Only valid when mStreamType == TV_STREAM_TYPE_BUFFER_PRODUCER
254        sp<BufferProducerThread> mThread;
255    };
256
257    JTvInputHal(JNIEnv* env, jobject thiz, tv_input_device_t* dev);
258
259    static void notify(
260            tv_input_device_t* dev, tv_input_event_t* event, void* data);
261
262    void onDeviceAvailable(const tv_input_device_info_t& info);
263    void onDeviceUnavailable(int deviceId);
264    void onStreamConfigurationsChanged(int deviceId);
265    void onCaptured(int deviceId, int streamId, uint32_t seq, bool succeeded);
266
267    Mutex mLock;
268    jweak mThiz;
269    tv_input_device_t* mDevice;
270    tv_input_callback_ops_t mCallback;
271
272    KeyedVector<int, KeyedVector<int, Connection> > mConnections;
273};
274
275JTvInputHal::JTvInputHal(JNIEnv* env, jobject thiz, tv_input_device_t* device) {
276    mThiz = env->NewWeakGlobalRef(thiz);
277    mDevice = device;
278    mCallback.notify = &JTvInputHal::notify;
279
280    mDevice->initialize(mDevice, &mCallback, this);
281}
282
283JTvInputHal::~JTvInputHal() {
284    mDevice->common.close((hw_device_t*)mDevice);
285
286    JNIEnv* env = AndroidRuntime::getJNIEnv();
287    env->DeleteWeakGlobalRef(mThiz);
288    mThiz = NULL;
289}
290
291JTvInputHal* JTvInputHal::createInstance(JNIEnv* env, jobject thiz) {
292    tv_input_module_t* module = NULL;
293    status_t err = hw_get_module(TV_INPUT_HARDWARE_MODULE_ID,
294            (hw_module_t const**)&module);
295    if (err) {
296        ALOGE("Couldn't load %s module (%s)",
297                TV_INPUT_HARDWARE_MODULE_ID, strerror(-err));
298        return 0;
299    }
300
301    tv_input_device_t* device = NULL;
302    err = module->common.methods->open(
303            (hw_module_t*)module,
304            TV_INPUT_DEFAULT_DEVICE,
305            (hw_device_t**)&device);
306    if (err) {
307        ALOGE("Couldn't open %s device (%s)",
308                TV_INPUT_DEFAULT_DEVICE, strerror(-err));
309        return 0;
310    }
311
312    return new JTvInputHal(env, thiz, device);
313}
314
315int JTvInputHal::addStream(int deviceId, int streamId, const sp<Surface>& surface) {
316    KeyedVector<int, Connection>& connections = mConnections.editValueFor(deviceId);
317    if (connections.indexOfKey(streamId) < 0) {
318        connections.add(streamId, Connection());
319    }
320    Connection& connection = connections.editValueFor(streamId);
321    if (connection.mSurface == surface) {
322        // Nothing to do
323        return NO_ERROR;
324    }
325    // Clear the surface in the connection.
326    if (connection.mSurface != NULL) {
327        if (connection.mStreamType == TV_STREAM_TYPE_INDEPENDENT_VIDEO_SOURCE) {
328            if (Surface::isValid(connection.mSurface)) {
329                connection.mSurface->setSidebandStream(NULL);
330            }
331        }
332        connection.mSurface.clear();
333    }
334    if (connection.mSourceHandle == NULL && connection.mThread == NULL) {
335        // Need to configure stream
336        int numConfigs = 0;
337        const tv_stream_config_t* configs = NULL;
338        if (mDevice->get_stream_configurations(
339                mDevice, deviceId, &numConfigs, &configs) != 0) {
340            ALOGE("Couldn't get stream configs");
341            return UNKNOWN_ERROR;
342        }
343        int configIndex = -1;
344        for (int i = 0; i < numConfigs; ++i) {
345            if (configs[i].stream_id == streamId) {
346                configIndex = i;
347                break;
348            }
349        }
350        if (configIndex == -1) {
351            ALOGE("Cannot find a config with given stream ID: %d", streamId);
352            return BAD_VALUE;
353        }
354        connection.mStreamType = configs[configIndex].type;
355
356        tv_stream_t stream;
357        stream.stream_id = configs[configIndex].stream_id;
358        if (connection.mStreamType == TV_STREAM_TYPE_BUFFER_PRODUCER) {
359            stream.buffer_producer.width = configs[configIndex].max_video_width;
360            stream.buffer_producer.height = configs[configIndex].max_video_height;
361        }
362        if (mDevice->open_stream(mDevice, deviceId, &stream) != 0) {
363            ALOGE("Couldn't add stream");
364            return UNKNOWN_ERROR;
365        }
366        if (connection.mStreamType == TV_STREAM_TYPE_INDEPENDENT_VIDEO_SOURCE) {
367            connection.mSourceHandle = NativeHandle::create(
368                    stream.sideband_stream_source_handle, false);
369        } else if (connection.mStreamType == TV_STREAM_TYPE_BUFFER_PRODUCER) {
370            if (connection.mThread != NULL) {
371                connection.mThread->shutdown();
372            }
373            connection.mThread = new BufferProducerThread(mDevice, deviceId, &stream);
374            connection.mThread->run();
375        }
376    }
377    connection.mSurface = surface;
378    if (connection.mStreamType == TV_STREAM_TYPE_INDEPENDENT_VIDEO_SOURCE) {
379        connection.mSurface->setSidebandStream(connection.mSourceHandle);
380    } else if (connection.mStreamType == TV_STREAM_TYPE_BUFFER_PRODUCER) {
381        connection.mThread->setSurface(surface);
382    }
383    return NO_ERROR;
384}
385
386int JTvInputHal::removeStream(int deviceId, int streamId) {
387    KeyedVector<int, Connection>& connections = mConnections.editValueFor(deviceId);
388    if (connections.indexOfKey(streamId) < 0) {
389        return BAD_VALUE;
390    }
391    Connection& connection = connections.editValueFor(streamId);
392    if (connection.mSurface == NULL) {
393        // Nothing to do
394        return NO_ERROR;
395    }
396    if (Surface::isValid(connection.mSurface)) {
397        connection.mSurface.clear();
398    }
399    if (connection.mSurface != NULL) {
400        connection.mSurface->setSidebandStream(NULL);
401        connection.mSurface.clear();
402    }
403    if (connection.mSourceHandle != NULL) {
404        // Need to reset streams
405        if (mDevice->close_stream(mDevice, deviceId, streamId) != 0) {
406            ALOGE("Couldn't remove stream");
407            return BAD_VALUE;
408        }
409
410        // Clear everything
411        if (connection.mThread != NULL) {
412            connection.mThread->shutdown();
413            connection.mThread.clear();
414        }
415        connection.mSourceHandle.clear();
416    }
417    return NO_ERROR;
418}
419
420const tv_stream_config_t* JTvInputHal::getStreamConfigs(int deviceId, int* numConfigs) {
421    const tv_stream_config_t* configs = NULL;
422    if (mDevice->get_stream_configurations(
423            mDevice, deviceId, numConfigs, &configs) != 0) {
424        ALOGE("Couldn't get stream configs");
425        return NULL;
426    }
427    return configs;
428}
429
430// static
431void JTvInputHal::notify(
432        tv_input_device_t* dev, tv_input_event_t* event, void* data) {
433    JTvInputHal* thiz = (JTvInputHal*)data;
434    switch (event->type) {
435        case TV_INPUT_EVENT_DEVICE_AVAILABLE: {
436            thiz->onDeviceAvailable(event->device_info);
437        } break;
438        case TV_INPUT_EVENT_DEVICE_UNAVAILABLE: {
439            thiz->onDeviceUnavailable(event->device_info.device_id);
440        } break;
441        case TV_INPUT_EVENT_STREAM_CONFIGURATIONS_CHANGED: {
442            thiz->onStreamConfigurationsChanged(event->device_info.device_id);
443        } break;
444        case TV_INPUT_EVENT_CAPTURE_SUCCEEDED: {
445            thiz->onCaptured(event->capture_result.device_id,
446                             event->capture_result.stream_id,
447                             event->capture_result.seq,
448                             true /* succeeded */);
449        } break;
450        case TV_INPUT_EVENT_CAPTURE_FAILED: {
451            thiz->onCaptured(event->capture_result.device_id,
452                             event->capture_result.stream_id,
453                             event->capture_result.seq,
454                             false /* succeeded */);
455        } break;
456        default:
457            ALOGE("Unrecognizable event");
458    }
459}
460
461void JTvInputHal::onDeviceAvailable(const tv_input_device_info_t& info) {
462    {
463        Mutex::Autolock autoLock(&mLock);
464        mConnections.add(info.device_id, KeyedVector<int, Connection>());
465    }
466    JNIEnv* env = AndroidRuntime::getJNIEnv();
467
468    jobject builder = env->NewObject(
469            gTvInputHardwareInfoBuilderClassInfo.clazz,
470            gTvInputHardwareInfoBuilderClassInfo.constructor);
471    env->CallObjectMethod(
472            builder, gTvInputHardwareInfoBuilderClassInfo.deviceId, info.device_id);
473    env->CallObjectMethod(
474            builder, gTvInputHardwareInfoBuilderClassInfo.type, info.type);
475    if (info.type == TV_INPUT_TYPE_HDMI) {
476        env->CallObjectMethod(
477                builder, gTvInputHardwareInfoBuilderClassInfo.hdmiPortId, info.hdmi.port_id);
478    }
479    env->CallObjectMethod(
480            builder, gTvInputHardwareInfoBuilderClassInfo.audioType, info.audio_type);
481    if (info.audio_type != AUDIO_DEVICE_NONE) {
482        jstring audioAddress = env->NewStringUTF(info.audio_address);
483        env->CallObjectMethod(
484                builder, gTvInputHardwareInfoBuilderClassInfo.audioAddress, audioAddress);
485        env->DeleteLocalRef(audioAddress);
486    }
487
488    jobject infoObject = env->CallObjectMethod(builder, gTvInputHardwareInfoBuilderClassInfo.build);
489
490    env->CallVoidMethod(
491            mThiz,
492            gTvInputHalClassInfo.deviceAvailable,
493            infoObject);
494
495    env->DeleteLocalRef(builder);
496    env->DeleteLocalRef(infoObject);
497}
498
499void JTvInputHal::onDeviceUnavailable(int deviceId) {
500    {
501        Mutex::Autolock autoLock(&mLock);
502        KeyedVector<int, Connection>& connections = mConnections.editValueFor(deviceId);
503        for (size_t i = 0; i < connections.size(); ++i) {
504            removeStream(deviceId, connections.keyAt(i));
505        }
506        connections.clear();
507        mConnections.removeItem(deviceId);
508    }
509    JNIEnv* env = AndroidRuntime::getJNIEnv();
510    env->CallVoidMethod(
511            mThiz,
512            gTvInputHalClassInfo.deviceUnavailable,
513            deviceId);
514}
515
516void JTvInputHal::onStreamConfigurationsChanged(int deviceId) {
517    {
518        Mutex::Autolock autoLock(&mLock);
519        KeyedVector<int, Connection>& connections = mConnections.editValueFor(deviceId);
520        for (size_t i = 0; i < connections.size(); ++i) {
521            removeStream(deviceId, connections.keyAt(i));
522        }
523        connections.clear();
524    }
525    JNIEnv* env = AndroidRuntime::getJNIEnv();
526    env->CallVoidMethod(
527            mThiz,
528            gTvInputHalClassInfo.streamConfigsChanged,
529            deviceId);
530}
531
532void JTvInputHal::onCaptured(int deviceId, int streamId, uint32_t seq, bool succeeded) {
533    sp<BufferProducerThread> thread;
534    {
535        Mutex::Autolock autoLock(&mLock);
536        KeyedVector<int, Connection>& connections = mConnections.editValueFor(deviceId);
537        Connection& connection = connections.editValueFor(streamId);
538        if (connection.mThread == NULL) {
539            ALOGE("capture thread not existing.");
540            return;
541        }
542        thread = connection.mThread;
543    }
544    thread->onCaptured(seq, succeeded);
545    if (seq == 0) {
546        JNIEnv* env = AndroidRuntime::getJNIEnv();
547        env->CallVoidMethod(
548                mThiz,
549                gTvInputHalClassInfo.firstFrameCaptured,
550                deviceId,
551                streamId);
552    }
553}
554
555////////////////////////////////////////////////////////////////////////////////
556
557static jlong nativeOpen(JNIEnv* env, jobject thiz) {
558    return (jlong)JTvInputHal::createInstance(env, thiz);
559}
560
561static int nativeAddStream(JNIEnv* env, jclass clazz,
562        jlong ptr, jint deviceId, jint streamId, jobject jsurface) {
563    JTvInputHal* tvInputHal = (JTvInputHal*)ptr;
564    if (!jsurface) {
565        return BAD_VALUE;
566    }
567    sp<Surface> surface(android_view_Surface_getSurface(env, jsurface));
568    return tvInputHal->addStream(deviceId, streamId, surface);
569}
570
571static int nativeRemoveStream(JNIEnv* env, jclass clazz,
572        jlong ptr, jint deviceId, jint streamId) {
573    JTvInputHal* tvInputHal = (JTvInputHal*)ptr;
574    return tvInputHal->removeStream(deviceId, streamId);
575}
576
577static jobjectArray nativeGetStreamConfigs(JNIEnv* env, jclass clazz,
578        jlong ptr, jint deviceId, jint generation) {
579    JTvInputHal* tvInputHal = (JTvInputHal*)ptr;
580    int numConfigs = 0;
581    const tv_stream_config_t* configs = tvInputHal->getStreamConfigs(deviceId, &numConfigs);
582
583    jobjectArray result = env->NewObjectArray(numConfigs, gTvStreamConfigClassInfo.clazz, NULL);
584    for (int i = 0; i < numConfigs; ++i) {
585        jobject builder = env->NewObject(
586                gTvStreamConfigBuilderClassInfo.clazz,
587                gTvStreamConfigBuilderClassInfo.constructor);
588        env->CallObjectMethod(
589                builder, gTvStreamConfigBuilderClassInfo.streamId, configs[i].stream_id);
590        env->CallObjectMethod(
591                builder, gTvStreamConfigBuilderClassInfo.type, configs[i].type);
592        env->CallObjectMethod(
593                builder, gTvStreamConfigBuilderClassInfo.maxWidth, configs[i].max_video_width);
594        env->CallObjectMethod(
595                builder, gTvStreamConfigBuilderClassInfo.maxHeight, configs[i].max_video_height);
596        env->CallObjectMethod(
597                builder, gTvStreamConfigBuilderClassInfo.generation, generation);
598
599        jobject config = env->CallObjectMethod(builder, gTvStreamConfigBuilderClassInfo.build);
600
601        env->SetObjectArrayElement(result, i, config);
602
603        env->DeleteLocalRef(config);
604        env->DeleteLocalRef(builder);
605    }
606    return result;
607}
608
609static void nativeClose(JNIEnv* env, jclass clazz, jlong ptr) {
610    JTvInputHal* tvInputHal = (JTvInputHal*)ptr;
611    delete tvInputHal;
612}
613
614static JNINativeMethod gTvInputHalMethods[] = {
615    /* name, signature, funcPtr */
616    { "nativeOpen", "()J",
617            (void*) nativeOpen },
618    { "nativeAddStream", "(JIILandroid/view/Surface;)I",
619            (void*) nativeAddStream },
620    { "nativeRemoveStream", "(JII)I",
621            (void*) nativeRemoveStream },
622    { "nativeGetStreamConfigs", "(JII)[Landroid/media/tv/TvStreamConfig;",
623            (void*) nativeGetStreamConfigs },
624    { "nativeClose", "(J)V",
625            (void*) nativeClose },
626};
627
628#define FIND_CLASS(var, className) \
629        var = env->FindClass(className); \
630        LOG_FATAL_IF(! var, "Unable to find class " className)
631
632#define GET_METHOD_ID(var, clazz, methodName, fieldDescriptor) \
633        var = env->GetMethodID(clazz, methodName, fieldDescriptor); \
634        LOG_FATAL_IF(! var, "Unable to find method" methodName)
635
636int register_android_server_tv_TvInputHal(JNIEnv* env) {
637    int res = jniRegisterNativeMethods(env, "com/android/server/tv/TvInputHal",
638            gTvInputHalMethods, NELEM(gTvInputHalMethods));
639    LOG_FATAL_IF(res < 0, "Unable to register native methods.");
640
641    jclass clazz;
642    FIND_CLASS(clazz, "com/android/server/tv/TvInputHal");
643
644    GET_METHOD_ID(
645            gTvInputHalClassInfo.deviceAvailable, clazz,
646            "deviceAvailableFromNative", "(Landroid/media/tv/TvInputHardwareInfo;)V");
647    GET_METHOD_ID(
648            gTvInputHalClassInfo.deviceUnavailable, clazz, "deviceUnavailableFromNative", "(I)V");
649    GET_METHOD_ID(
650            gTvInputHalClassInfo.streamConfigsChanged, clazz,
651            "streamConfigsChangedFromNative", "(I)V");
652    GET_METHOD_ID(
653            gTvInputHalClassInfo.firstFrameCaptured, clazz,
654            "firstFrameCapturedFromNative", "(II)V");
655
656    FIND_CLASS(gTvStreamConfigClassInfo.clazz, "android/media/tv/TvStreamConfig");
657    gTvStreamConfigClassInfo.clazz = jclass(env->NewGlobalRef(gTvStreamConfigClassInfo.clazz));
658
659    FIND_CLASS(gTvStreamConfigBuilderClassInfo.clazz, "android/media/tv/TvStreamConfig$Builder");
660    gTvStreamConfigBuilderClassInfo.clazz =
661            jclass(env->NewGlobalRef(gTvStreamConfigBuilderClassInfo.clazz));
662
663    GET_METHOD_ID(
664            gTvStreamConfigBuilderClassInfo.constructor,
665            gTvStreamConfigBuilderClassInfo.clazz,
666            "<init>", "()V");
667    GET_METHOD_ID(
668            gTvStreamConfigBuilderClassInfo.streamId,
669            gTvStreamConfigBuilderClassInfo.clazz,
670            "streamId", "(I)Landroid/media/tv/TvStreamConfig$Builder;");
671    GET_METHOD_ID(
672            gTvStreamConfigBuilderClassInfo.type,
673            gTvStreamConfigBuilderClassInfo.clazz,
674            "type", "(I)Landroid/media/tv/TvStreamConfig$Builder;");
675    GET_METHOD_ID(
676            gTvStreamConfigBuilderClassInfo.maxWidth,
677            gTvStreamConfigBuilderClassInfo.clazz,
678            "maxWidth", "(I)Landroid/media/tv/TvStreamConfig$Builder;");
679    GET_METHOD_ID(
680            gTvStreamConfigBuilderClassInfo.maxHeight,
681            gTvStreamConfigBuilderClassInfo.clazz,
682            "maxHeight", "(I)Landroid/media/tv/TvStreamConfig$Builder;");
683    GET_METHOD_ID(
684            gTvStreamConfigBuilderClassInfo.generation,
685            gTvStreamConfigBuilderClassInfo.clazz,
686            "generation", "(I)Landroid/media/tv/TvStreamConfig$Builder;");
687    GET_METHOD_ID(
688            gTvStreamConfigBuilderClassInfo.build,
689            gTvStreamConfigBuilderClassInfo.clazz,
690            "build", "()Landroid/media/tv/TvStreamConfig;");
691
692    FIND_CLASS(gTvInputHardwareInfoBuilderClassInfo.clazz,
693            "android/media/tv/TvInputHardwareInfo$Builder");
694    gTvInputHardwareInfoBuilderClassInfo.clazz =
695            jclass(env->NewGlobalRef(gTvInputHardwareInfoBuilderClassInfo.clazz));
696
697    GET_METHOD_ID(
698            gTvInputHardwareInfoBuilderClassInfo.constructor,
699            gTvInputHardwareInfoBuilderClassInfo.clazz,
700            "<init>", "()V");
701    GET_METHOD_ID(
702            gTvInputHardwareInfoBuilderClassInfo.deviceId,
703            gTvInputHardwareInfoBuilderClassInfo.clazz,
704            "deviceId", "(I)Landroid/media/tv/TvInputHardwareInfo$Builder;");
705    GET_METHOD_ID(
706            gTvInputHardwareInfoBuilderClassInfo.type,
707            gTvInputHardwareInfoBuilderClassInfo.clazz,
708            "type", "(I)Landroid/media/tv/TvInputHardwareInfo$Builder;");
709    GET_METHOD_ID(
710            gTvInputHardwareInfoBuilderClassInfo.hdmiPortId,
711            gTvInputHardwareInfoBuilderClassInfo.clazz,
712            "hdmiPortId", "(I)Landroid/media/tv/TvInputHardwareInfo$Builder;");
713    GET_METHOD_ID(
714            gTvInputHardwareInfoBuilderClassInfo.audioType,
715            gTvInputHardwareInfoBuilderClassInfo.clazz,
716            "audioType", "(I)Landroid/media/tv/TvInputHardwareInfo$Builder;");
717    GET_METHOD_ID(
718            gTvInputHardwareInfoBuilderClassInfo.audioAddress,
719            gTvInputHardwareInfoBuilderClassInfo.clazz,
720            "audioAddress", "(Ljava/lang/String;)Landroid/media/tv/TvInputHardwareInfo$Builder;");
721    GET_METHOD_ID(
722            gTvInputHardwareInfoBuilderClassInfo.build,
723            gTvInputHardwareInfoBuilderClassInfo.clazz,
724            "build", "()Landroid/media/tv/TvInputHardwareInfo;");
725
726    return 0;
727}
728
729} /* namespace android */
730