Пример #1
0
void
NetConnection_as::connect(const std::string& uri)
{
    // Close any current connections. (why?) Because that's what happens.
    close();

    // TODO: check for other kind of invalidities here...
    if ( uri.empty() )
    {
        _isConnected = false;
        notifyStatus(CONNECT_FAILED);
        return;
    }

    URL url(uri, getRunResources(owner()).baseURL());

    if ((url.protocol() != "rtmp")
        && (url.protocol() != "rtmpt")
        && (url.protocol() != "rtmpts")
        && (url.protocol() != "https")
        && (url.protocol() != "http")) {

        IF_VERBOSE_ASCODING_ERRORS(
		 log_aserror("NetConnection.connect(%s): invalid connection "
			     "protocol", url);
				   );
Пример #2
0
Video::Video(as_object* object,
             const SWF::DefineVideoStreamTag* def, DisplayObject* parent)
    :
    DisplayObject(getRoot(*object), object, parent),
    m_def(def),
    _ns(nullptr),
    _embeddedStream(m_def),
    _lastDecodedVideoFrameNum(-1),
    _lastDecodedVideoFrame(),
    _smoothing(false)
{
    assert(object);
    assert(def);

    media::MediaHandler* mh = getRunResources(*object).mediaHandler();
    if (!mh) {
        LOG_ONCE(log_error(_("No Media handler registered, "
                             "won't be able to decode embedded video")) );
        return;
    }

    media::VideoInfo* info = m_def->getVideoInfo();
    if (!info) return;

    try {
        _decoder = mh->createVideoDecoder(*info);
    }
    catch (const MediaException& e) {
        log_error(_("Could not create Video Decoder: %s"), e.what());
    }
}
Пример #3
0
Sound_as::Sound_as(as_object* owner) 
    :
    ActiveRelay(owner),
    _attachedCharacter(0),
    soundId(-1),
    externalSound(false),
    isStreaming(false),
    _soundHandler(getRunResources(*owner).soundHandler()),
    _mediaHandler(getRunResources(*owner).mediaHandler()),
    _startTime(0),
    _leftOverData(),
    _leftOverPtr(0),
    _leftOverSize(0),
    _inputStream(0),
    remainingLoops(0),
    _soundCompleted(false),
    _soundLoaded(false)
{
}
Пример #4
0
/// FIXME: this should not use _uri, but rather take a URL argument.
/// Validation should probably be done on connect() only and return a 
/// bool indicating validity. That can be used to return a failure
/// for invalid or blocked URLs.
std::string
NetConnection_as::validateURL() const
{

    URL uri(_uri, getRunResources(owner()).baseURL());

    std::string uriStr(uri.str());
    assert(uriStr.find("://") != std::string::npos);

    // Check if we're allowed to open url
    if (!URLAccessManager::allow(uri)) {
        log_security(_("Gnash is not allowed to open this url: %s"), uriStr);
        return "";
    }

    log_debug(_("Connection to movie: %s"), uriStr);

    return uriStr;
}
Пример #5
0
bool
HTTPRemotingHandler::advance()
{

#ifdef GNASH_DEBUG_REMOTING
    log_debug("advancing HTTPRemotingHandler");
#endif
    if (_connection) {

#ifdef GNASH_DEBUG_REMOTING
        log_debug("have connection");
#endif

        // Fill last chunk before reading in the next
        size_t toRead = reply.capacity() - reply.size();
        if (! toRead) toRead = NCCALLREPLYCHUNK;

#ifdef GNASH_DEBUG_REMOTING
        log_debug("Attempt to read %d bytes", toRead);
#endif

        // See if we need to allocate more bytes for the next
        // read chunk
        if (reply.capacity() < reply.size() + toRead) {
            // if _connection->size() >= 0, reserve for it, so
            // if HTTP Content-Length response header is correct
            // we'll be allocating only once for all.
            const size_t newCapacity = reply.size() + toRead;

#ifdef GNASH_DEBUG_REMOTING
            log_debug("NetConnection.call: reply buffer capacity (%d) "
                      "is too small to accept next %d bytes of chunk "
                      "(current size is %d). Reserving %d bytes.",
                reply.capacity(), toRead, reply.size(), newCapacity);
#endif

            reply.reserve(newCapacity);

#ifdef GNASH_DEBUG_REMOTING
            log_debug(" after reserve, new capacity is %d", reply.capacity());
#endif
        }

        const int read =
            _connection->readNonBlocking(reply.data() + reply.size(), toRead);

        if (read > 0) {
#ifdef GNASH_DEBUG_REMOTING
            log_debug("read '%1%' bytes: %2%", read, 
                    hexify(reply.data() + reply.size(), read, false));
#endif
            reply.resize(reply.size() + read);
        }

        // There is no way to tell if we have a whole amf reply without
        // parsing everything
        //
        // The reply format has a header field which specifies the
        // number of bytes in the reply, but potlatch sends 0xffffffff
        // and works fine in the proprietary player
        //
        // For now we just wait until we have the full reply.
        //
        // FIXME make this parse on other conditions, including: 1) when
        // the buffer is full, 2) when we have a "length in bytes" value
        // thas is satisfied

        if (_connection->bad()) {
            log_debug("connection is in error condition, calling "
                    "NetConnection.onStatus");
            reply.resize(0);
            reply_start = 0;
            // reset connection before calling the callback
            _connection.reset();

            // This is just a guess, but is better than sending
            // 'undefined'
            _nc.notifyStatus(NetConnection_as::CALL_FAILED);
        }
        else if (_connection->eof()) {

            if (reply.size() > 8) {


#ifdef GNASH_DEBUG_REMOTING
                log_debug("hit eof");
#endif
                boost::uint16_t li;
                const boost::uint8_t *b = reply.data() + reply_start;
                const boost::uint8_t *end = reply.data() + reply.size();
                
                amf::Reader rd(b, end, getGlobal(_nc.owner()));

                // parse header
                b += 2; // skip version indicator and client id

                // NOTE: this looks much like parsing of an OBJECT_AMF0
                boost::int16_t si = readNetworkShort(b);
                b += 2; // number of headers
                uint8_t headers_ok = 1;
                if (si != 0) {

#ifdef GNASH_DEBUG_REMOTING
                    log_debug("NetConnection::call(): amf headers "
                            "section parsing");
#endif
                    as_value tmp;
                    for (size_t i = si; i > 0; --i) {
                        if(b + 2 > end) {
                            headers_ok = 0;
                            break;
                        }
                        si = readNetworkShort(b); b += 2; // name length
                        if(b + si > end) {
                            headers_ok = 0;
                            break;
                        }
                        std::string headerName((char*)b, si); // end-b);
#ifdef GNASH_DEBUG_REMOTING
                        log_debug("Header name %s", headerName);
#endif
                        b += si;
                        if ( b + 5 > end ) {
                            headers_ok = 0;
                            break;
                        }
                        b += 5; // skip past bool and length long
                        if(!rd(tmp)) {
                            headers_ok = 0;
                            break;
                        }
#ifdef GNASH_DEBUG_REMOTING
                        log_debug("Header value %s", tmp);
#endif

                        { // method call for each header
                          // FIXME: it seems to me that the call should happen
                            VM& vm = getVM(_nc.owner());
                            string_table& st = vm.getStringTable();
                            string_table::key key = st.find(headerName);
#ifdef GNASH_DEBUG_REMOTING
                            log_debug("Calling NetConnection.%s(%s)",
                                    headerName, tmp);
#endif
                            callMethod(&_nc.owner(), key, tmp);
                        }
                    }
                }

                if(headers_ok == 1) {

                    si = readNetworkShort(b); b += 2; // number of replies

                    // TODO consider counting number of replies we
                    // actually parse and doing something if it
                    // doesn't match this value (does it matter?
                    if(si > 0) {
                        // parse replies until we get a parse error or we reach the end of the buffer
                        while(b < end) {
                            if(b + 2 > end) break;
                            si = readNetworkShort(b); b += 2; // reply length
                            if(si < 4) { // shorted valid response is '/1/a'
                                log_error("NetConnection::call(): reply message name too short");
                                break;
                            }
                            if(b + si > end) break;

                            // Reply message is: '/id/methodName'

                            int ns = 1; // next slash position
                            while (ns<si-1 && *(b+ns) != '/') ++ns;
                            if ( ns >= si-1 ) {
                                std::string msg(
                                        reinterpret_cast<const char*>(b), si);
                                log_error("NetConnection::call(): invalid "
                                        "reply message name (%s)", msg);
                                break;
                            }

                            std::string id(reinterpret_cast<const char*>(b),
                                    ns);

                            std::string methodName(
                                    reinterpret_cast<const char*>(b+ns+1),
                                    si-ns-1);

                            b += si;

                            // parse past unused string in header
                            if(b + 2 > end) break;
                            si = readNetworkShort(b); b += 2; // reply length
                            if(b + si > end) break;
                            b += si;

                            // this field is supposed to hold the
                            // total number of bytes in the rest of
                            // this particular reply value, but
                            // openstreetmap.org (which works great
                            // in the adobe player) sends
                            // 0xffffffff. So we just ignore it
                            if(b + 4 > end) break;
                            li = readNetworkLong(b); b += 4; // reply length

#ifdef GNASH_DEBUG_REMOTING
                            log_debug("about to parse amf value");
#endif
                            // this updates b to point to the next unparsed byte
                            as_value replyval;
                            if (!rd(replyval)) {
                                log_error("parse amf failed");
                                // this will happen if we get
                                // bogus data, or if the data runs
                                // off the end of the buffer
                                // provided, or if we get data we
                                // don't know how to parse
                                break;
                            }
#ifdef GNASH_DEBUG_REMOTING
                            log_debug("parsed amf");
#endif

                            // update variable to show how much we've parsed
                            reply_start = b - reply.data();

                            // if actionscript specified a callback object,
                            // call it
                            as_object* callback = pop_callback(id);
                            if (callback) {

                                string_table::key methodKey;
                                if ( methodName == "onResult" ) {
                                    methodKey = NSV::PROP_ON_RESULT;
                                }
                                else if (methodName == "onStatus") {
                                    methodKey = NSV::PROP_ON_STATUS;
                                }
                                else {
                                    // NOTE: the pp is known to actually
                                    // invoke the custom method, but with 7
                                    // undefined arguments (?)
                                    log_error("Unsupported HTTP Remoting "
                                            "response callback: '%s' "
                                            "(size %d)", methodName,
                                            methodName.size());
                                    continue;
                                }

#ifdef GNASH_DEBUG_REMOTING
                                log_debug("calling onResult callback");
#endif
                                // FIXME check if above line can fail and we
                                // have to react
                                callMethod(callback, methodKey, replyval);
#ifdef GNASH_DEBUG_REMOTING
                                log_debug("callback called");
#endif
                            } else {
                                log_error("Unknown HTTP Remoting response identifier '%s'", id);
                            }
                        }
                    }
                }
            }
            else
            {
                log_error("Response from remoting service < 8 bytes");
            }

#ifdef GNASH_DEBUG_REMOTING
            log_debug("deleting connection");
#endif
            _connection.reset();
            reply.resize(0);
            reply_start = 0;
        }
    }

    if(!_connection && queued_count > 0) {
//#ifdef GNASH_DEBUG_REMOTING
        log_debug("creating connection");
//#endif
        // set the "number of bodies" header

        (reinterpret_cast<boost::uint16_t*>(_postdata.data() + 4))[0] = htons(queued_count);
        std::string postdata_str(reinterpret_cast<char*>(_postdata.data()), _postdata.size());
#ifdef GNASH_DEBUG_REMOTING
        log_debug("NetConnection.call(): encoded args from %1% calls: %2%", queued_count, hexify(postdata.data(), postdata.size(), false));
#endif
        queued_count = 0;

        // TODO: it might be useful for a Remoting Handler to have a 
        // StreamProvider member
        const StreamProvider& sp =
            getRunResources(_nc.owner()).streamProvider();

        _connection.reset(sp.getStream(_url, postdata_str, _headers).release());

        _postdata.resize(6);
#ifdef GNASH_DEBUG_REMOTING
        log_debug("connection created");
#endif
    }

    if (_connection == 0) {
        // nothing more to do
        return false;
    }

    return true;
}
Пример #6
0
void
Sound_as::loadSound(const std::string& file, bool streaming)
{
    if (!_mediaHandler || !_soundHandler) {
        log_debug("No media or sound handlers, won't load any sound");
        return;
    }

    /// If we are already streaming stop doing so as we'll replace
    /// the media parser
    if (_inputStream) {
        _soundHandler->unplugInputStream(_inputStream);
        _inputStream = 0;
    }
    
    /// Mark sound as not being loaded
    // TODO: should we check for _soundLoaded == true?
    _soundLoaded = false;

    /// Delete any media parser being used (make sure we have detached!)
    _mediaParser.reset();

    /// Start at offset 0, in case a previous ::start() call
    /// changed that.
    _startTime = 0;

    const RunResources& rr = getRunResources(owner());
    URL url(file, rr.streamProvider().baseURL());

    const RcInitFile& rcfile = RcInitFile::getDefaultInstance();

    const StreamProvider& streamProvider = rr.streamProvider();
    std::auto_ptr<IOChannel> inputStream(streamProvider.getStream(url,
                rcfile.saveStreamingMedia()));

    if (!inputStream.get()) {
        log_error(_("Gnash could not open this URL: %s"), url );
        // dispatch onLoad (false)
        callMethod(&owner(), NSV::PROP_ON_LOAD, false);
        return;
    }

    externalSound = true;
    isStreaming = streaming;

    _mediaParser.reset(_mediaHandler->createMediaParser(inputStream).release());
    if (!_mediaParser) {
        log_error(_("Unable to create parser for Sound at %s"), url);
        // not necessarely correct, the stream might have been found...
        // dispatch onLoad (false)
        callMethod(&owner(), NSV::PROP_ON_LOAD, false);
        return;
    }

    // TODO: use global _soundbuftime
    if (isStreaming) {
        _mediaParser->setBufferTime(60000); // one minute buffer... should be fine
    } else {
        // If this is an event sound, we must not limit buffering (parsing),
        // because onLoad will not be called until we have finished doing so.
        _mediaParser->setBufferTime(std::numeric_limits<boost::uint64_t>::max());
    }

    startProbeTimer();

    owner().set_member(NSV::PROP_DURATION, getDuration());
    owner().set_member(NSV::PROP_POSITION, getPosition());
}