xref: /aosp_15_r20/frameworks/av/media/libstagefright/rtsp/UDPPusher.cpp (revision ec779b8e0859a360c3d303172224686826e6e0e1)
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