Home | History | Annotate | Download | only in rtsp
      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