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 "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 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 54 UDPPusher::~UDPPusher() { 55 close(mSocket); 56 mSocket = -1; 57 58 fclose(mFile); 59 mFile = NULL; 60 } 61 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, id()))->post(); 69 } 70 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, id()))->post(whenUs - nowUs); 107 108 return true; 109 } 110 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