1 /*
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
17 //#define LOG_NDEBUG 0
18 #define LOG_TAG "UDPPusher"
19 #include <utils/Log.h>
20
21 #include <media/stagefright/rtsp/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
30 namespace android {
31
UDPPusher(const char * filename,unsigned port)32 UDPPusher::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
~UDPPusher()54 UDPPusher::~UDPPusher() {
55 close(mSocket);
56 mSocket = -1;
57
58 fclose(mFile);
59 mFile = NULL;
60 }
61
start()62 void 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, this))->post();
69 }
70
onPush()71 bool UDPPusher::onPush() {
72 uint32_t length;
73 if (fread(&length, 1, sizeof(length), mFile) < sizeof(length)) {
74 ALOGI("No more data to push.");
75 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) {
84 ALOGE("File truncated?.");
85 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)) {
96 ALOGI("No more data to push.");
97 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, this))->post(whenUs - nowUs);
107
108 return true;
109 }
110
onMessageReceived(const sp<AMessage> & msg)111 void UDPPusher::onMessageReceived(const sp<AMessage> &msg) {
112 switch (msg->what()) {
113 case kWhatPush:
114 {
115 if (!onPush() && !(ntohs(mRemoteAddr.sin_port) & 1)) {
116 ALOGI("emulating BYE packet");
117
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
151