RtpMultiCaster.cpp 7.45 KB
Newer Older
xiongziliang committed
1
/*
xiongziliang committed
2
 * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
xiongziliang committed
3
 *
4
 * This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
xiongziliang committed
5
 *
xiongziliang committed
6 7 8
 * Use of this source code is governed by MIT license that can be found in the
 * LICENSE file in the root of the source tree. All contributing project authors
 * may be found in the AUTHORS file in the root of the source tree.
xzl committed
9 10 11
 */

#include <list>
12
#include <type_traits>
xiongziliang committed
13
#include "RtpMultiCaster.h"
xiongzilaing committed
14 15
#include "Util/util.h"
#include "Network/sockutil.h"
16
#include "RtspSession.h"
mtdxc committed
17
#include "Common/config.h"
18

19
using namespace std;
xiongziliang committed
20
using namespace toolkit;
xzl committed
21

xiongziliang committed
22
namespace mediakit{
xzl committed
23

24
MultiCastAddressMaker &MultiCastAddressMaker::Instance() {
25 26
    static MultiCastAddressMaker instance;
    return instance;
27 28
}

29 30 31 32 33 34 35 36 37 38 39
bool MultiCastAddressMaker::isMultiCastAddress(uint32_t addr) {
    static uint32_t addrMin = mINI::Instance()[MultiCast::kAddrMin].as<uint32_t>();
    static uint32_t addrMax = mINI::Instance()[MultiCast::kAddrMax].as<uint32_t>();
    return addr >= addrMin && addr <= addrMax;
}

string MultiCastAddressMaker::toString(uint32_t addr) {
    addr = htonl(addr);
    return SockUtil::inet_ntoa((struct in_addr &) (addr));
}

40 41
static uint32_t addressToInt(const string &ip){
    struct in_addr addr;
42 43 44
    bzero(&addr, sizeof(addr));
    addr.s_addr = inet_addr(ip.data());
    return (uint32_t) ntohl((uint32_t &) addr.s_addr);
45
}
xzl committed
46

47
std::shared_ptr<uint32_t> MultiCastAddressMaker::obtain(uint32_t max_try) {
48
    lock_guard<recursive_mutex> lck(_mtx);
49 50 51 52 53 54
    GET_CONFIG_FUNC(uint32_t, addrMin, MultiCast::kAddrMin, [](const string &str) {
        return addressToInt(str);
    });
    GET_CONFIG_FUNC(uint32_t, addrMax, MultiCast::kAddrMax, [](const string &str) {
        return addressToInt(str);
    });
55

56 57
    if (_addr > addrMax || _addr == 0) {
        _addr = addrMin;
58
    }
59 60
    auto iGotAddr = _addr++;
    if (_used_addr.find(iGotAddr) != _used_addr.end()) {
61
        //已经分配过了
62 63
        if (max_try) {
            return obtain(--max_try);
64 65 66 67 68
        }
        //分配完了,应该不可能到这里
        ErrorL;
        return nullptr;
    }
69 70
    _used_addr.emplace(iGotAddr);
    std::shared_ptr<uint32_t> ret(new uint32_t(iGotAddr), [](uint32_t *ptr) {
71 72 73 74
        MultiCastAddressMaker::Instance().release(*ptr);
        delete ptr;
    });
    return ret;
xzl committed
75
}
76 77

void MultiCastAddressMaker::release(uint32_t addr){
78
    lock_guard<recursive_mutex> lck(_mtx);
79
    _used_addr.erase(addr);
xzl committed
80 81
}

82
////////////////////////////////////////////////////////////////////////////////////
xzl committed
83

84 85
recursive_mutex g_mtx;
unordered_map<string, weak_ptr<RtpMultiCaster> > g_multi_caster_map;
xzl committed
86

xiongziliang committed
87
void RtpMultiCaster::setDetachCB(void* listener, const onDetach& cb) {
88
    lock_guard<recursive_mutex> lck(_mtx);
89 90 91 92
    if (cb) {
        _detach_map.emplace(listener, cb);
    } else {
        _detach_map.erase(listener);
93
    }
xzl committed
94
}
95

xiongziliang committed
96
RtpMultiCaster::~RtpMultiCaster() {
97 98
    _rtp_reader->setReadCB(nullptr);
    _rtp_reader->setDetachCB(nullptr);
99
    DebugL;
xzl committed
100
}
101

102
RtpMultiCaster::RtpMultiCaster(SocketHelper &helper, const string &local_ip, const string &vhost, const string &app, const string &stream, uint32_t multicast_ip, uint16_t video_port, uint16_t audio_port) {
103 104 105 106 107
    auto src = dynamic_pointer_cast<RtspMediaSource>(MediaSource::find(RTSP_SCHEMA, vhost, app, stream));
    if (!src) {
        auto err = StrPrinter << "未找到媒体源:" << vhost << " " << app << " " << stream << endl;
        throw std::runtime_error(err);
    }
108
    _multicast_ip = (multicast_ip) ? make_shared<uint32_t>(multicast_ip) : MultiCastAddressMaker::Instance().obtain();
109 110
    if (!_multicast_ip) {
        throw std::runtime_error("获取组播地址失败");
111
    }
112

113 114 115
    for (auto i = 0; i < 2; ++i) {
        //创建udp socket, 数组下标为TrackType
        _udp_sock[i] = helper.createSocket();
116
        if (!_udp_sock[i]->bindUdpSock((i == TrackVideo) ? video_port : audio_port, local_ip.data())) {
117 118 119 120 121
            auto err = StrPrinter << "绑定UDP端口失败:" << local_ip << endl;
            throw std::runtime_error(err);
        }
        auto fd = _udp_sock[i]->rawFD();
        GET_CONFIG(uint32_t, udpTTL, MultiCast::kUdpTTL);
122
        SockUtil::setMultiTTL(fd, udpTTL);
123
        SockUtil::setMultiLOOP(fd, false);
124 125 126 127 128 129 130 131 132
        SockUtil::setMultiIF(fd, local_ip.data());

        struct sockaddr_in peer;
        peer.sin_family = AF_INET;
        //组播目标端口为本地发送端口
        peer.sin_port = htons(_udp_sock[i]->get_local_port());
        //组播目标地址
        peer.sin_addr.s_addr = htonl(*_multicast_ip);
        bzero(&(peer.sin_zero), sizeof peer.sin_zero);
ziyue committed
133
        _udp_sock[i]->bindPeerAddr((struct sockaddr *) &peer);
134
    }
135

136
    src->pause(false);
137 138
    _rtp_reader = src->getRing()->attach(helper.getPoller());
    _rtp_reader->setReadCB([this](const RtspMediaSource::RingDataType &pkt) {
139 140
        size_t i = 0;
        auto size = pkt->size();
141
        pkt->for_each([&](const RtpPacket::Ptr &rtp) {
142 143
            auto &sock = _udp_sock[rtp->type];
            sock->send(std::make_shared<BufferRtp>(rtp, 4), nullptr, 0, ++i == size);
144
        });
145
    });
146

147 148
    _rtp_reader->setDetachCB([this]() {
        unordered_map<void *, onDetach> _detach_map_copy;
149 150
        {
            lock_guard<recursive_mutex> lck(_mtx);
151
            _detach_map_copy = std::move(_detach_map);
152
        }
153
        for (auto &pr : _detach_map_copy) {
154 155 156
            pr.second();
        }
    });
157 158 159 160 161

    DebugL << MultiCastAddressMaker::toString(*_multicast_ip) << " "
           << _udp_sock[0]->get_local_port() << " "
           << _udp_sock[1]->get_local_port() << " "
           << vhost << " " << app << " " << stream;
xzl committed
162
}
163 164 165

uint16_t RtpMultiCaster::getMultiCasterPort(TrackType trackType) {
    return _udp_sock[trackType]->get_local_port();
xzl committed
166
}
167 168 169 170 171

string RtpMultiCaster::getMultiCasterIP() {
    struct in_addr addr;
    addr.s_addr = htonl(*_multicast_ip);
    return SockUtil::inet_ntoa(addr);
xzl committed
172
}
173

174 175
RtpMultiCaster::Ptr RtpMultiCaster::get(SocketHelper &helper, const string &local_ip, const string &vhost, const string &app, const string &stream, uint32_t multicast_ip, uint16_t video_port, uint16_t audio_port) {
    static auto on_create = [](SocketHelper &helper, const string &local_ip, const string &vhost, const string &app, const string &stream, uint32_t multicast_ip, uint16_t video_port, uint16_t audio_port){
176 177
        try {
            auto poller = helper.getPoller();
178
            auto ret = RtpMultiCaster::Ptr(new RtpMultiCaster(helper, local_ip, vhost, app, stream, multicast_ip, video_port, audio_port), [poller](RtpMultiCaster *ptr) {
179 180 181
                poller->async([ptr]() {
                    delete ptr;
                });
182
            });
183 184 185 186 187 188 189 190 191
            lock_guard<recursive_mutex> lck(g_mtx);
            string strKey = StrPrinter << local_ip << " " << vhost << " " << app << " " << stream << endl;
            g_multi_caster_map.emplace(strKey, ret);
            return ret;
        } catch (std::exception &ex) {
            WarnL << ex.what();
            return RtpMultiCaster::Ptr();
        }
    };
xzl committed
192

193
    string strKey = StrPrinter << local_ip << " " << vhost << " " << app << " " << stream << endl;
194
    lock_guard<recursive_mutex> lck(g_mtx);
195 196
    auto it = g_multi_caster_map.find(strKey);
    if (it == g_multi_caster_map.end()) {
197
        return on_create(helper, local_ip, vhost, app, stream, multicast_ip, video_port, audio_port);
198 199 200
    }
    auto ret = it->second.lock();
    if (!ret) {
201
        g_multi_caster_map.erase(it);
202
        return on_create(helper, local_ip, vhost, app, stream, multicast_ip, video_port, audio_port);
203 204
    }
    return ret;
xzl committed
205 206 207
}


xiongziliang committed
208
}//namespace mediakit