int TCPSocket::send(const char* data, std::size_t len, const net::Address& /* peerAddress */, int /* flags */) { //assert(len <= net::MAX_TCP_PACKET_SIZE); // libuv handles this for us TraceS(this) << "Send: " << len << endl; assert(Thread::currentID() == tid()); #if 0 if (len < 300) TraceS(this) << "Send: " << len << ": " << std::string(data, len) << endl; else { std::string str(data, len); TraceS(this) << "Send: START: " << len << ": " << str.substr(0, 100) << endl; TraceS(this) << "Send: END: " << len << ": " << str.substr(str.length() - 100, str.length()) << endl; } #endif if (!Stream::write(data, len)) { WarnL << "Send error" << endl; return -1; } // R is -1 on error, otherwise return len // TODO: Return native error code? return len; }
bool AudioEncoder::encode(/*const */ std::uint8_t* samples, const int numSamples, const std::int64_t pts) { TraceS(this) << "Encoding audio packet: " << numSamples << endl; // Resample input data or add it to the buffer directly if (resampler) { if (!resampler->resample((std::uint8_t**)&samples, numSamples)) { // The resampler may buffer frames TraceS(this) << "Samples buffered by resampler" << endl; return false; } TraceS(this) << "Resampled audio packet: " << numSamples << " <=> " << resampler->outNumSamples << endl; // Add the converted input samples to the FIFO buffer. fifo.write((void**)resampler->outSamples, resampler->outNumSamples); } else { // Add the input samples to the FIFO buffer. fifo.write((void**)&samples, numSamples); } // Set a timestamp value on the frame to be encoded if given. if (pts != AV_NOPTS_VALUE) { frame->pts = pts; } return flushBuffer(this) > 0; }
void ClientConnection::onSocketConnect() { TraceS(this) << "On connect" << endl; // Set the connection to active _active = true; // Emit the connect signal so raw connections like // websockets can kick off the data flow Connect.emit(this); // Start the outgoing send stream if there are // any queued packets or adapters attached // startInputStream(); // startOutputStream(); // Flush queued packets if (!_outgoingBuffer.empty()) { for (const auto & packet : _outgoingBuffer) { Outgoing.write(packet.c_str(), packet.length()); } _outgoingBuffer.clear(); } // Send the outgoing HTTP header if it hasn't already been sent. // Note the first call to socket().send() will flush headers. // Note if there are stream adapters we wait for the stream to push // through any custom headers. See ChunkedAdapter::emitHeader if (Outgoing.numAdapters() == 0) { TraceS(this) << "On connect: Send header" << endl; sendHeader(); } }
void SSLSocket::onConnect(uv_connect_t* handle, int status) { TraceS(this) << "On connect" << endl; if (status) { setUVError("SSL connect error", status); return; } else readStart(); SSL* ssl = SSL_new(_context->sslContext()); // TODO: Automatic SSL session handling. // Maybe add a stored session to the network manager. if (_session) SSL_set_session(ssl, _session->sslSession()); SSL_set_connect_state(ssl); SSL_do_handshake(ssl); _sslAdapter.init(ssl); _sslAdapter.flush(); //emitConnect(); onSocketConnect(); TraceS(this) << "On connect: OK" << endl; }
bool DeviceManager::getAudioDevices(bool input, std::vector<Device>& devs) { devs.clear(); #if defined(ANDROID) // Under Android, we don't access the device file directly. // Arbitrary use 0 for the mic and 1 for the output. // These ids are used in MediaEngine::SetSoundDevices(in, out); // The strings are for human consumption. if (input) { devs.push_back(Device("audioin", "audiorecord", 0)); } else { devs.push_back(Device("audioout", "audiotrack", 1)); } return true; #elif defined(HAVE_RTAUDIO) // Since we are using RtAudio for audio capture it's best to // use RtAudio to enumerate devices to ensure indexes match. RtAudio audio; // Determine the number of devices available auto ndevices = audio.getDeviceCount(); TraceS(this) << "Get audio devices: " << ndevices << endl; // Scan through devices for various capabilities RtAudio::DeviceInfo info; for (unsigned i = 0; i <= ndevices; i++) { try { info = audio.getDeviceInfo(i); // may throw RtAudioError TraceS(this) << "Device:" << "\n\tName: " << info.name << "\n\tOutput Channels: " << info.outputChannels << "\n\tInput Channels: " << info.inputChannels << "\n\tDuplex Channels: " << info.duplexChannels << "\n\tDefault Output: " << info.isDefaultOutput << "\n\tDefault Input: " << info.isDefaultInput << "\n\tProbed: " << info.probed << endl; if (info.probed == true && ( (input && info.inputChannels > 0) || (!input && info.outputChannels > 0))) { TraceS(this) << "Adding device: " << info.name << endl; Device dev((input ? "audioin" : "audioout"), i, info.name, "", (input ? info.isDefaultInput : info.isDefaultOutput)); devs.push_back(dev); } } catch (RtAudioError& e) { ErrorS(this) << "Cannot probe audio device: " << e.getMessage() << endl; } } return filterDevices(devs, kFilteredAudioDevicesName); #endif }
SSLAdapter::~SSLAdapter() { TraceS(this) << "Destroy" << endl; if (_ssl) { SSL_free(_ssl); _ssl = nullptr; } TraceS(this) << "Destroy: OK" << endl; }
void TCPConnectionPair::onPeerDataReceived(net::Socket&, const MutableBuffer& buffer, const net::Address& peerAddress) { TraceS(this) << "Peer => Client: " << buffer.size() << endl; // assert(pkt.buffer.position() == 0); // if (pkt.buffer.available() < 300) // TraceS(this) << "Peer => Client: " << pkt.buffer << endl; // auto socket = reinterpret_cast<net::Socket*>(sender); // char* buf = bufferCast<char*>(buf); // Buffer& buf = pkt.buffer; const char* buf = bufferCast<const char*>(buffer); std::size_t len = buffer.size(); if (client) { allocation.updateUsage(len); if (allocation.deleted()) return; // assert(buf.position() == 0); client->send(buf, len); } // Flash policy requests // TODO: Handle elsewhere? Bloody flash... else if (len == 23 && (strcmp(buf, "<policy-file-request/>") == 0)) { TraceS(this) << "Handle flash policy" << endl; std::string policy( "<?xml version=\"1.0\"?><cross-domain-policy><allow-access-from " "domain=\"*\" to-ports=\"*\" /></cross-domain-policy>"); // assert(peer->get() == pkt.info->socket); peer->send(policy.c_str(), policy.length() + 1); peer->close(); } // Buffer early media // TODO: Make buffer size server option else { std::size_t maxSize = allocation.server().options().earlyMediaBufferSize; DebugS(this) << "Buffering early data: " << len << endl; //#ifdef _DEBUG // DebugS(this) << "Printing early data: " << std::string(buf, // len) << endl; //#endif if (len > maxSize) WarnL << "Dropping early media: Oversize packet: " << len << endl; if (earlyPeerData.size() > maxSize) WarnL << "Dropping early media: Buffer at capacity >= " << maxSize << endl; // earlyPeerData.append(static_cast<const char*>(pkt.data()), len); earlyPeerData.insert(earlyPeerData.end(), buf, buf + len); } }
void Thread::join() { TraceS(this) << "Joining" << std::endl; assert(this->tid() != Thread::currentID()); //assert(this->cancelled()); // probably should be cancelled, but depends on impl uv_thread_join(&_handle); assert(!this->running()); assert(!this->started()); TraceS(this) << "Joining: OK" << std::endl; }
void PacketStream::resume() { TraceS(this) << "Resume" << endl; if (!stateEquals(PacketStreamState::Paused)) { TraceS(this) << "Resume: Not paused" << endl; return; } setState(this, PacketStreamState::Active); }
Connection::~Connection() { TraceS(this) << "Destroy" << endl; replaceAdapter(nullptr); //assert(_closed); close(); // don't want pure virtual on onClose. // the shared pointer is being destroyed, // no need for close() anyway TraceS(this) << "Destroy: OK" << endl; }
void Client::removeConnection(ClientConnection* conn) { TraceS(this) << "Removing connection: " << conn << endl; for (auto it = _connections.begin(); it != _connections.end(); ++it) { if (conn == it->get()) { TraceS(this) << "Removed connection: " << conn << endl; _connections.erase(it); return; } } assert(0 && "unknown connection"); }
void Client::shutdown() { TraceS(this) << "Shutdown" << endl; //_timer.stop(); Shutdown.emit(this); //_connections.clear(); auto conns = _connections; for (auto conn : conns) { TraceS(this) << "Shutdown: " << conn << endl; conn->close(); // close and remove via callback } assert(_connections.empty()); }
void Roster::update(const json::Value& data, bool whiny) { if (data.isObject() && data.isMember("id") && data.isMember("user") && data.isMember("name") //&& //data.isMember("type") ) { TraceS(this) << "Updating: " << json::stringify(data, true) << endl; std::string id = data["id"].asString(); Peer* peer = get(id, false); if (!peer) { peer = new Peer(data); add(id, peer); } else static_cast<json::Value&>(*peer) = data; } else if (data.isArray()) { for (auto it = data.begin(); it != data.end(); it++) { update(*it, whiny); } } else { std::string error("Bad presence data: " + json::stringify(data)); ErrorS(this) << error << endl; if (whiny) throw std::runtime_error(error); } }
void Connection::onSocketError(const scy::Error& error) { TraceS(this) << "On socket error" << endl; // Handle the socket error locally setError(error); }
void Client::addConnection(ClientConnection::Ptr conn) { TraceS(this) << "Adding connection: " << conn << endl; conn->Close += sdelegate(this, &Client::onConnectionClose, -1); // lowest priority _connections.push_back(conn); }
UDPSocket::UDPSocket(uv::Loop* loop) : uv::Handle(loop), _buffer(65536) { TraceS(this) << "Create" << endl; init(); }
void ClientConnection::onHeaders() { TraceS(this) << "On headers" << endl; IncomingProgress.total = _response.getContentLength(); Headers.emit(this, _response); }
void TCPSocket::listen(int backlog) { TraceS(this) << "Listening" << endl; init(); int r = uv_listen(ptr<uv_stream_t>(), backlog, internal::onAcceptConnection); if (r) setAndThrowError("TCP listen failed", r); }
int ConnectionAdapter::send(const char* data, std::size_t len, int flags) { TraceS(this) << "Send: " << len << endl; try { // Send headers on initial send if (_connection.shouldSendHeader()) { int res = _connection.sendHeader(); // The initial packet may be empty to push the headers through if (len == 0) return res; } // Other packets should not be empty assert(len > 0); // Send body / chunk return SocketAdapter::send(data, len, flags); } catch (std::exception& exc) { ErrorS(this) << "Send error: " << exc.what() << endl; // Swallow the exception, the socket error will // cause the connection to close on next iteration. } return -1; }
void Connection::onSocketClose() { TraceS(this) << "On socket close" << endl; // Close the connection when the socket closes close(); }
void Connection::onClose() { TraceS(this) << "On close" << endl; // assert(0); Close.emit(this); }
void AsyncPacketQueue::onStreamStateChange(const PacketStreamState& state) { TraceS(this) << "Stream state: " << state << endl; switch (state.id()) { case PacketStreamState::Active: break; case PacketStreamState::Stopped: break; case PacketStreamState::Error: case PacketStreamState::Closed: // Flush queued items, some protocols can't afford dropped packets flush(); assert(empty()); cancel(); _thread.join(); break; //case PacketStreamState::Resetting: //case PacketStreamState::None: //case PacketStreamState::Stopping: } }
Client::Client() { TraceS(this) << "Create" << endl; //_timer.Timeout += sdelegate(this, &Client::onConnectionTimer); //_timer.start(5000); }
void PacketStream::close() { if (stateEquals(PacketStreamState::None) || stateEquals(PacketStreamState::Closed)) { // TraceS(this) << "Already closed" << endl; // assert(0); return; } // Stop the stream gracefully (if running) if (!stateEquals(PacketStreamState::Stopped) && !stateEquals(PacketStreamState::Stopping)) stop(); TraceS(this) << "Closing" << endl; // Queue the Closed state setState(this, PacketStreamState::Closed); { // Lock the processor mutex to synchronize multi source streams std::lock_guard<std::mutex> guard(_procMutex); // Teardown the adapter delegate chain teardown(); // Synchronize any pending states // This should be safe since the adapters won't be receiving // any more incoming packets after teardown. // This call is essential when using the event loop otherwise // failing to close some handles could result in deadlock. // See SyncQueue::cancel() synchronizeStates(); // Clear and delete managed adapters // Note: Can't call this because if closeOnCleanup is true // we may be inside a queue loop which will be destroyed by // the call to reset() // reset(); } // Send the Closed signal Close.emit(*this); TraceS(this) << "Close: OK" << endl; }
PacketStream::PacketStream(const std::string& name) : opaque(nullptr) , _name(name) , _autoStart(false) , _closeOnError(true) { TraceS(this) << "Create" << endl; }
SSLAdapter::SSLAdapter(net::SSLSocket* socket) : _socket(socket) , _ssl(nullptr) , _readBIO(nullptr) , _writeBIO(nullptr) { TraceS(this) << "Create" << endl; }
void SSLSocket::onRead(const char* data, std::size_t len) { TraceS(this) << "On SSL read: " << len << endl; // SSL encrypted data is sent to the SSL conetext _sslAdapter.addIncomingData(data, len); _sslAdapter.flush(); }
void ConnectionAdapter::onParserChunk(const char* buf, std::size_t len) { TraceS(this) << "On parser chunk: " << len << endl; // Dispatch the payload net::SocketAdapter::onSocketRecv(mutableBuffer(const_cast<char*>(buf), len), _connection.socket()->peerAddress()); }
void Connection::onSocketRecv(const MutableBuffer& buffer, const net::Address& peerAddress) { TraceS(this) << "On socket recv" << endl; //_timeout.stop(); // Handle payload data onPayload(buffer); //mutableBuffer(bufferCast<const char*>(buf) }
SSLSocket::SSLSocket(SSLContext::Ptr context, SSLSession::Ptr session, uv::Loop* loop) : TCPSocket(loop), _context(context), _session(session), _sslAdapter(this) { TraceS(this) << "Create" << endl; }