Add IP Streamer interface

This interface is used to push TS data from a socket to test IPTV
frontend.

Bug: 288170590
Test: atest VtsHalTvTunerTargetTest
Change-Id: I95f0f74cb6bb9b73c9584d335b52937ab56830e1
diff --git a/tv/tuner/aidl/vts/functional/utils/IpStreamer.cpp b/tv/tuner/aidl/vts/functional/utils/IpStreamer.cpp
new file mode 100644
index 0000000..02b2633
--- /dev/null
+++ b/tv/tuner/aidl/vts/functional/utils/IpStreamer.cpp
@@ -0,0 +1,57 @@
+#include "IpStreamer.h"
+
+IpStreamer::IpStreamer() {}
+
+IpStreamer::~IpStreamer() {}
+
+void IpStreamer::startIpStream() {
+    ALOGI("Starting IP Stream thread");
+    mFp = fopen(mFilePath.c_str(), "rb");
+    if (mFp == nullptr) {
+        ALOGE("Failed to open file at path: %s", mFilePath.c_str());
+        return;
+    }
+    mIpStreamerThread = std::thread(&IpStreamer::ipStreamThreadLoop, this, mFp);
+}
+
+void IpStreamer::stopIpStream() {
+    ALOGI("Stopping IP Stream thread");
+    close(mSockfd);
+    if (mFp != nullptr) fclose(mFp);
+    if (mIpStreamerThread.joinable()) {
+        mIpStreamerThread.join();
+    }
+}
+
+void IpStreamer::ipStreamThreadLoop(FILE* fp) {
+    mSockfd = socket(AF_INET, SOCK_DGRAM, 0);
+    if (mSockfd < 0) {
+        ALOGE("IpStreamer::ipStreamThreadLoop: Socket creation failed (%s)", strerror(errno));
+        exit(1);
+    }
+
+    if (mFp == NULL) {
+        ALOGE("IpStreamer::ipStreamThreadLoop: Cannot open file %s: (%s)", mFilePath.c_str(),
+              strerror(errno));
+        exit(1);
+    }
+
+    struct sockaddr_in destaddr;
+    memset(&destaddr, 0, sizeof(destaddr));
+    destaddr.sin_family = mIsIpV4 ? AF_INET : AF_INET6;
+    destaddr.sin_port = htons(mPort);
+    destaddr.sin_addr.s_addr = inet_addr(mIpAddress.c_str());
+
+    char buf[mBufferSize];
+    int n;
+    while (1) {
+        if (fp == nullptr) break;
+        n = fread(buf, 1, mBufferSize, fp);
+        ALOGI("IpStreamer::ipStreamThreadLoop: Bytes read from fread(): %d\n", n);
+        if (n <= 0) {
+            break;
+        }
+        sendto(mSockfd, buf, n, 0, (struct sockaddr*)&destaddr, sizeof(destaddr));
+        sleep(mSleepTime);
+    }
+}
diff --git a/tv/tuner/aidl/vts/functional/utils/IpStreamer.h b/tv/tuner/aidl/vts/functional/utils/IpStreamer.h
new file mode 100644
index 0000000..d073003
--- /dev/null
+++ b/tv/tuner/aidl/vts/functional/utils/IpStreamer.h
@@ -0,0 +1,48 @@
+#pragma once
+
+#include <arpa/inet.h>
+#include <errno.h>
+#include <log/log.h>
+#include <netinet/in.h>
+#include <stdio.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <string>
+#include <thread>
+
+/**
+ * IP Streamer class to send TS data to a specified socket for testing IPTV frontend functions
+ * e.g. tuning and playback.
+ */
+
+class IpStreamer {
+  public:
+    // Constructor for IP Streamer object
+    IpStreamer();
+
+    // Destructor for IP Streamer object
+    ~IpStreamer();
+
+    // Starts a thread to read data from a socket
+    void startIpStream();
+
+    // Stops the reading thread started by startIpStream
+    void stopIpStream();
+
+    // Thread function that consumes data from a socket
+    void ipStreamThreadLoop(FILE* fp);
+
+    std::string getFilePath() { return mFilePath; };
+
+  private:
+    int mSockfd = -1;
+    FILE* mFp;
+    bool mIsIpV4 = true;                                         // By default, set to IPV4
+    int mPort = 12345;                                           // default port
+    int mBufferSize = 188;                                       // bytes
+    int mSleepTime = 1;                                          // second
+    std::string mIpAddress = "127.0.0.1";                        // default IP address
+    std::string mFilePath = "/data/local/tmp/segment000000.ts";  // default path for TS file
+    std::thread mIpStreamerThread;
+};
\ No newline at end of file