blob: f398aac0a3d7d9c6f6ea16b44e8aaa4bb6e6411b [file] [log] [blame]
/*
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <Buffer.h>
#include <DeviceAsWebcamServiceManager.h>
#include <FrameProvider.h>
#include <Utils.h>
#include <android-base/unique_fd.h>
#include <android/hardware_buffer.h>
#include <linux/usb/g_uvc.h>
#include <linux/usb/video.h>
#include <atomic>
#include <thread>
#include <vector>
namespace android {
namespace webcam {
typedef std::vector<struct epoll_event> Events;
using android::base::unique_fd;
class EpollW {
public:
Status init();
Status add(int fd, uint32_t events);
Status modify(int fd, uint32_t events);
Status remove(int fd);
Events waitForEvents();
private:
unique_fd mEpollFd;
};
struct ConfigFrame {
uint32_t index = 0;
uint32_t width = 0;
uint32_t height = 0;
std::vector<uint32_t> intervals;
};
struct ConfigFormat {
uint32_t formatIndex = 0;
uint32_t fcc;
std::vector<ConfigFrame> frames;
};
struct ConfigEndPoint {
uint32_t streamingInterval = 0;
uint32_t streamingMaxPacketSize = 0;
uint32_t streamingMaxBurst = 0;
};
struct ConfigStreaming {
ConfigEndPoint ep;
std::vector<ConfigFormat> formats;
uint32_t interfaceNumber = 0;
};
struct UVCProperties {
std::string videoNode;
std::string udc;
ConfigStreaming streaming;
uint32_t controlInterfaceNumber = 0;
};
// This struct has the information needed to uniquely identify a 'chosen' format : the format index
// which indexes into the format list advertised by the UVC V4L2 node, the frame index which indexes
// the frame size in the frame size list per format, and finally the frame interval for the
// particular format and size chosen.
struct FormatTriplet {
// Note: These are '1' indexed.
uint8_t formatIndex = 1;
uint8_t frameSizeIndex = 1;
uint32_t frameInterval = 0;
FormatTriplet(uint8_t formatIndex, uint8_t frameSizeIndex, uint32_t frameInterval)
: formatIndex(formatIndex), frameSizeIndex(frameSizeIndex), frameInterval(frameInterval) {}
};
// This class manages all things related to UVC event handling.
class UVCProvider : public std::enable_shared_from_this<UVCProvider> {
public:
static std::string getVideoNode();
UVCProvider() = default;
~UVCProvider();
Status init();
// Start listening for UVC events
Status startService();
void stopService();
int encodeImage(AHardwareBuffer* hardwareBuffer, long timestamp, jint rotation);
void watchStreamEvent();
private:
// Created after a UVC_SETUP event has been received and processed by UVCProvider
// This class manages stream related events UVC_STREAMON / STREAMOFF and queries by the host
// for probing and committing controls.
class UVCDevice : public BufferCreatorAndDestroyer {
public:
explicit UVCDevice(std::weak_ptr<UVCProvider> parent);
~UVCDevice() override = default;
void closeUVCFd();
[[nodiscard]] bool isInited() const;
int getUVCFd() { return mUVCFd.get(); }
void processSetupEvent(const struct usb_ctrlrequest* request,
struct uvc_request_data* response);
void processSetupControlEvent(const struct usb_ctrlrequest* request,
struct uvc_request_data* response);
void processSetupStreamingEvent(const struct usb_ctrlrequest* request,
struct uvc_request_data* response);
void processSetupClassEvent(const struct usb_ctrlrequest* request,
struct uvc_request_data* response);
void processDataEvent(const struct uvc_request_data*);
void processStreamOnEvent();
void processStreamOffEvent();
void processStreamEvent();
Status encodeImage(AHardwareBuffer* buffer, long timestamp, int rotation);
// BufferCreatorAndDestroyer overrides
Status allocateAndMapBuffers(
std::shared_ptr<Buffer>* consumerBuffer,
std::vector<std::shared_ptr<Buffer>>* producerBuffers) override;
void destroyBuffers(std::shared_ptr<Buffer>& consumerBuffer,
std::vector<std::shared_ptr<Buffer>>& producerBuffers) override;
private:
std::shared_ptr<UVCProperties> parseUvcProperties();
std::vector<ConfigFormat> getFormats();
void getFrameIntervals(ConfigFrame* frame, ConfigFormat* format);
void getFormatFrames(ConfigFormat* format);
Status openV4L2DeviceAndSubscribe(const std::string& videoNode);
void setStreamingControl(struct uvc_streaming_control* streamingControl,
const FormatTriplet* req);
void commitControls();
std::shared_ptr<Buffer> mapBuffer(uint32_t i);
static Status unmapBuffer(std::shared_ptr<Buffer>& buffer);
Status getFrameAndQueueBufferToGadgetDriver(bool firstBuffer = false);
struct uvc_streaming_control mProbe {};
struct uvc_streaming_control mCommit {};
uint8_t mCurrentControlState = UVC_VS_CONTROL_UNDEFINED;
std::weak_ptr<UVCProvider> mParent;
std::shared_ptr<UVCProperties> mUVCProperties;
std::shared_ptr<BufferManager> mBufferManager;
std::shared_ptr<FrameProvider> mFrameProvider;
unique_fd mUVCFd;
// Path to /dev/video*, this is the node we open up and poll the fd for uvc / v4l2 events.
std::string mVideoNode;
struct v4l2_format mV4l2Format {};
uint32_t mFps = 0;
bool mInited = false;
};
void stopAndWaitForUVCListenerThread();
void startUVCListenerThread();
void ListenToUVCFds();
void processUVCEvent();
std::shared_ptr<UVCDevice> mUVCDevice;
std::thread mUVCListenerThread;
volatile bool mListenToUVCFds = true;
EpollW mEpollW;
};
} // namespace webcam
} // namespace android