blob: 6a4c87b5b69d43e0843a62c52af0fe50434b01d0 [file] [log] [blame]
Andreas Huber57648e42010-08-04 10:14:30 -07001/*
2 * Copyright (C) 2010 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
Andreas Huber6e3fa442010-09-21 13:13:15 -070017//#define LOG_NDEBUG 0
18#define LOG_TAG "UDPPusher"
19#include <utils/Log.h>
20
Andreas Huber57648e42010-08-04 10:14:30 -070021#include "UDPPusher.h"
22
23#include <media/stagefright/foundation/ABuffer.h>
24#include <media/stagefright/foundation/ADebug.h>
25#include <media/stagefright/foundation/AMessage.h>
26#include <utils/ByteOrder.h>
27
28#include <sys/socket.h>
29
30namespace android {
31
32UDPPusher::UDPPusher(const char *filename, unsigned port)
33 : mFile(fopen(filename, "rb")),
34 mFirstTimeMs(0),
35 mFirstTimeUs(0) {
36 CHECK(mFile != NULL);
37
38 mSocket = socket(AF_INET, SOCK_DGRAM, 0);
39
40 struct sockaddr_in addr;
41 memset(addr.sin_zero, 0, sizeof(addr.sin_zero));
42 addr.sin_family = AF_INET;
43 addr.sin_addr.s_addr = INADDR_ANY;
44 addr.sin_port = 0;
45
46 CHECK_EQ(0, bind(mSocket, (const struct sockaddr *)&addr, sizeof(addr)));
47
48 memset(mRemoteAddr.sin_zero, 0, sizeof(mRemoteAddr.sin_zero));
49 mRemoteAddr.sin_family = AF_INET;
50 mRemoteAddr.sin_addr.s_addr = INADDR_ANY;
51 mRemoteAddr.sin_port = htons(port);
52}
53
54UDPPusher::~UDPPusher() {
55 close(mSocket);
56 mSocket = -1;
57
58 fclose(mFile);
59 mFile = NULL;
60}
61
62void UDPPusher::start() {
63 uint32_t timeMs;
64 CHECK_EQ(fread(&timeMs, 1, sizeof(timeMs), mFile), sizeof(timeMs));
65 mFirstTimeMs = fromlel(timeMs);
66 mFirstTimeUs = ALooper::GetNowUs();
67
68 (new AMessage(kWhatPush, id()))->post();
69}
70
71bool UDPPusher::onPush() {
72 uint32_t length;
73 if (fread(&length, 1, sizeof(length), mFile) < sizeof(length)) {
Steve Block6215d3f2012-01-04 20:05:49 +000074 ALOGI("No more data to push.");
Andreas Huber57648e42010-08-04 10:14:30 -070075 return false;
76 }
77
78 length = fromlel(length);
79
80 CHECK_GT(length, 0u);
81
82 sp<ABuffer> buffer = new ABuffer(length);
83 if (fread(buffer->data(), 1, length, mFile) < length) {
Andreas Huber6e3fa442010-09-21 13:13:15 -070084 LOGE("File truncated?.");
Andreas Huber57648e42010-08-04 10:14:30 -070085 return false;
86 }
87
88 ssize_t n = sendto(
89 mSocket, buffer->data(), buffer->size(), 0,
90 (const struct sockaddr *)&mRemoteAddr, sizeof(mRemoteAddr));
91
92 CHECK_EQ(n, (ssize_t)buffer->size());
93
94 uint32_t timeMs;
95 if (fread(&timeMs, 1, sizeof(timeMs), mFile) < sizeof(timeMs)) {
Steve Block6215d3f2012-01-04 20:05:49 +000096 ALOGI("No more data to push.");
Andreas Huber57648e42010-08-04 10:14:30 -070097 return false;
98 }
99
100 timeMs = fromlel(timeMs);
101 CHECK_GE(timeMs, mFirstTimeMs);
102
103 timeMs -= mFirstTimeMs;
104 int64_t whenUs = mFirstTimeUs + timeMs * 1000ll;
105 int64_t nowUs = ALooper::GetNowUs();
106 (new AMessage(kWhatPush, id()))->post(whenUs - nowUs);
107
108 return true;
109}
110
111void UDPPusher::onMessageReceived(const sp<AMessage> &msg) {
112 switch (msg->what()) {
113 case kWhatPush:
114 {
115 if (!onPush() && !(ntohs(mRemoteAddr.sin_port) & 1)) {
Steve Block6215d3f2012-01-04 20:05:49 +0000116 ALOGI("emulating BYE packet");
Andreas Huber57648e42010-08-04 10:14:30 -0700117
118 sp<ABuffer> buffer = new ABuffer(8);
119 uint8_t *data = buffer->data();
120 *data++ = (2 << 6) | 1;
121 *data++ = 203;
122 *data++ = 0;
123 *data++ = 1;
124 *data++ = 0x8f;
125 *data++ = 0x49;
126 *data++ = 0xc0;
127 *data++ = 0xd0;
128 buffer->setRange(0, 8);
129
130 struct sockaddr_in tmp = mRemoteAddr;
131 tmp.sin_port = htons(ntohs(mRemoteAddr.sin_port) | 1);
132
133 ssize_t n = sendto(
134 mSocket, buffer->data(), buffer->size(), 0,
135 (const struct sockaddr *)&tmp,
136 sizeof(tmp));
137
138 CHECK_EQ(n, (ssize_t)buffer->size());
139 }
140 break;
141 }
142
143 default:
144 TRESPASS();
145 break;
146 }
147}
148
149} // namespace android
150