summaryrefslogtreecommitdiffstats
path: root/media/libstagefright/rtsp/UDPPusher.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'media/libstagefright/rtsp/UDPPusher.cpp')
-rw-r--r--media/libstagefright/rtsp/UDPPusher.cpp150
1 files changed, 150 insertions, 0 deletions
diff --git a/media/libstagefright/rtsp/UDPPusher.cpp b/media/libstagefright/rtsp/UDPPusher.cpp
new file mode 100644
index 0000000..47ea6f1
--- /dev/null
+++ b/media/libstagefright/rtsp/UDPPusher.cpp
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2010 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "UDPPusher"
+#include <utils/Log.h>
+
+#include "UDPPusher.h"
+
+#include <media/stagefright/foundation/ABuffer.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/AMessage.h>
+#include <utils/ByteOrder.h>
+
+#include <sys/socket.h>
+
+namespace android {
+
+UDPPusher::UDPPusher(const char *filename, unsigned port)
+ : mFile(fopen(filename, "rb")),
+ mFirstTimeMs(0),
+ mFirstTimeUs(0) {
+ CHECK(mFile != NULL);
+
+ mSocket = socket(AF_INET, SOCK_DGRAM, 0);
+
+ struct sockaddr_in addr;
+ memset(addr.sin_zero, 0, sizeof(addr.sin_zero));
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = INADDR_ANY;
+ addr.sin_port = 0;
+
+ CHECK_EQ(0, bind(mSocket, (const struct sockaddr *)&addr, sizeof(addr)));
+
+ memset(mRemoteAddr.sin_zero, 0, sizeof(mRemoteAddr.sin_zero));
+ mRemoteAddr.sin_family = AF_INET;
+ mRemoteAddr.sin_addr.s_addr = INADDR_ANY;
+ mRemoteAddr.sin_port = htons(port);
+}
+
+UDPPusher::~UDPPusher() {
+ close(mSocket);
+ mSocket = -1;
+
+ fclose(mFile);
+ mFile = NULL;
+}
+
+void UDPPusher::start() {
+ uint32_t timeMs;
+ CHECK_EQ(fread(&timeMs, 1, sizeof(timeMs), mFile), sizeof(timeMs));
+ mFirstTimeMs = fromlel(timeMs);
+ mFirstTimeUs = ALooper::GetNowUs();
+
+ (new AMessage(kWhatPush, id()))->post();
+}
+
+bool UDPPusher::onPush() {
+ uint32_t length;
+ if (fread(&length, 1, sizeof(length), mFile) < sizeof(length)) {
+ ALOGI("No more data to push.");
+ return false;
+ }
+
+ length = fromlel(length);
+
+ CHECK_GT(length, 0u);
+
+ sp<ABuffer> buffer = new ABuffer(length);
+ if (fread(buffer->data(), 1, length, mFile) < length) {
+ ALOGE("File truncated?.");
+ return false;
+ }
+
+ ssize_t n = sendto(
+ mSocket, buffer->data(), buffer->size(), 0,
+ (const struct sockaddr *)&mRemoteAddr, sizeof(mRemoteAddr));
+
+ CHECK_EQ(n, (ssize_t)buffer->size());
+
+ uint32_t timeMs;
+ if (fread(&timeMs, 1, sizeof(timeMs), mFile) < sizeof(timeMs)) {
+ ALOGI("No more data to push.");
+ return false;
+ }
+
+ timeMs = fromlel(timeMs);
+ CHECK_GE(timeMs, mFirstTimeMs);
+
+ timeMs -= mFirstTimeMs;
+ int64_t whenUs = mFirstTimeUs + timeMs * 1000ll;
+ int64_t nowUs = ALooper::GetNowUs();
+ (new AMessage(kWhatPush, id()))->post(whenUs - nowUs);
+
+ return true;
+}
+
+void UDPPusher::onMessageReceived(const sp<AMessage> &msg) {
+ switch (msg->what()) {
+ case kWhatPush:
+ {
+ if (!onPush() && !(ntohs(mRemoteAddr.sin_port) & 1)) {
+ ALOGI("emulating BYE packet");
+
+ sp<ABuffer> buffer = new ABuffer(8);
+ uint8_t *data = buffer->data();
+ *data++ = (2 << 6) | 1;
+ *data++ = 203;
+ *data++ = 0;
+ *data++ = 1;
+ *data++ = 0x8f;
+ *data++ = 0x49;
+ *data++ = 0xc0;
+ *data++ = 0xd0;
+ buffer->setRange(0, 8);
+
+ struct sockaddr_in tmp = mRemoteAddr;
+ tmp.sin_port = htons(ntohs(mRemoteAddr.sin_port) | 1);
+
+ ssize_t n = sendto(
+ mSocket, buffer->data(), buffer->size(), 0,
+ (const struct sockaddr *)&tmp,
+ sizeof(tmp));
+
+ CHECK_EQ(n, (ssize_t)buffer->size());
+ }
+ break;
+ }
+
+ default:
+ TRESPASS();
+ break;
+ }
+}
+
+} // namespace android
+