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