root/libcore/asobj/Microphone_as.cpp

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. microphone_class_init
  2. registerMicrophoneNative
  3. attachMicrophoneStaticInterface
  4. attachMicrophoneProperties
  5. attachMicrophoneInterface
  6. setGain
  7. gain
  8. index
  9. muted
  10. name
  11. setRate
  12. rate
  13. silenceLevel
  14. activityLevel
  15. setUseEchoSuppression
  16. useEchoSuppression
  17. silenceTimeout
  18. setSilenceTimeout
  19. setSilenceLevel
  20. microphone_ctor
  21. microphone_get
  22. microphone_setgain
  23. microphone_setrate
  24. microphone_activityLevel
  25. microphone_gain
  26. microphone_index
  27. microphone_muted
  28. microphone_name
  29. microphone_names
  30. microphone_rate
  31. microphone_silenceLevel
  32. microphone_silenceTimeout
  33. microphone_useEchoSuppression
  34. microphone_setsilencelevel
  35. microphone_setuseechosuppression

// Microphone_as.cpp:  ActionScript "Microphone" class, for Gnash.
//
//   Copyright (C) 2009, 2010, 2011 Free Software Foundation, Inc.
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
//


#include "Microphone_as.h"

#include <algorithm>
#include <boost/scoped_ptr.hpp>
#include <memory>

#include "as_object.h" // for inheritance
#include "log.h"
#include "fn_call.h"
#include "Global_as.h"
#include "smart_ptr.h" // for boost intrusive_ptr
#include "NativeFunction.h"
#include "Object.h"
#include "GnashNumeric.h"
#include "AudioInput.h"
#include "MediaHandler.h"
#include "Relay.h"
#include "RunResources.h"
#include "namedStrings.h"


namespace gnash {

namespace {

    as_value microphone_ctor(const fn_call& fn);
    as_value microphone_get(const fn_call& fn);
    as_value microphone_setgain(const fn_call& fn);
    as_value microphone_setrate(const fn_call& fn);
    as_value microphone_setsilencelevel(const fn_call& fn);
    as_value microphone_setuseechosuppression(const fn_call& fn);
    as_value microphone_activityLevel(const fn_call& fn);
    as_value microphone_gain(const fn_call& fn);
    as_value microphone_index(const fn_call& fn);
    as_value microphone_muted(const fn_call& fn);
    as_value microphone_name(const fn_call& fn);
    as_value microphone_names(const fn_call& fn);
    as_value microphone_rate(const fn_call& fn);
    as_value microphone_silenceLevel(const fn_call& fn);
    as_value microphone_silenceTimeout(const fn_call& fn);
    as_value microphone_useEchoSuppression(const fn_call& fn);

    void attachMicrophoneStaticInterface(as_object& o);
    void attachMicrophoneInterface(as_object& o);
}

// extern (used by Global.cpp)
void
microphone_class_init(as_object& where, const ObjectURI& uri)
{
    registerBuiltinClass(where, microphone_ctor, attachMicrophoneInterface,
                         attachMicrophoneStaticInterface, uri);
}

void
registerMicrophoneNative(as_object& global)
{
    VM& vm = getVM(global);
    vm.registerNative(microphone_names, 2104, 201);
    vm.registerNative(microphone_setsilencelevel, 2104, 0);
    vm.registerNative(microphone_setrate, 2104, 1);
    vm.registerNative(microphone_setgain, 2104, 2);
    vm.registerNative(microphone_setuseechosuppression, 2104, 3);
}

namespace {

// get() and names are static properties in AS2.
void
attachMicrophoneStaticInterface(as_object& o)
{
    Global_as& gl = getGlobal(o);

    const int flags = 0;

        o.init_member("get", gl.createFunction(microphone_get), flags);
 
    VM& vm = getVM(o);   
    NativeFunction* getset = vm.getNative(2102, 201);
    o.init_property("names", *getset, *getset);
}

// These are added to the AS2 prototype when get() is called.
void
attachMicrophoneProperties(as_object& o)
{
    Global_as& gl = getGlobal(o);


    as_function* getset = gl.createFunction(microphone_activityLevel);
    o.init_readonly_property("activityLevel", microphone_activityLevel);
    getset = gl.createFunction(microphone_gain);
    o.init_readonly_property("gain", microphone_gain);
    getset = gl.createFunction(microphone_index);
    o.init_readonly_property("index", microphone_index);
    getset = gl.createFunction(microphone_muted);
    o.init_readonly_property("muted", microphone_muted);
    getset = gl.createFunction(microphone_name);
    o.init_readonly_property("name", *getset);
    getset = gl.createFunction(microphone_rate);
    o.init_readonly_property("rate", *getset);
    getset = gl.createFunction(microphone_silenceLevel);
    o.init_readonly_property("silenceLevel", *getset);
    getset = gl.createFunction(microphone_silenceTimeout);
    o.init_readonly_property("silenceTimeout", *getset);
    getset = gl.createFunction(microphone_useEchoSuppression);
    o.init_readonly_property("useEchoSuppression", *getset);
}

void
attachMicrophoneInterface(as_object& o)
{

    VM& vm = getVM(o);

    const int flags = as_object::DefaultFlags | PropFlags::onlySWF6Up;

        o.init_member("setSilenceLevel", vm.getNative(2104, 0), flags);
        o.init_member("setRate", vm.getNative(2104, 1), flags);
        o.init_member("setGain", vm.getNative(2104, 2), flags);
        o.init_member("setUseEchoSuppression", vm.getNative(2104, 3), flags);
    
}

class Microphone_as : public Relay
{

public:

    Microphone_as(std::auto_ptr<media::AudioInput> input)
        :
        _input(input.release())
    {
        assert(_input.get());
    }

    /// Takes a value from 0..100
    void setGain(int gain) {
        _input->setGain(gain);
    }

    /// Returns a value from 0..100
    int gain() const {
        return _input->gain();
    }

    /// The index of this AudioInput.
    //
    /// Should this be stored in the AudioInput, this class, or somewhere else?
    size_t index() const {
        return _input->index();
    }

    /// Whether Microphone access is allowedd
    //
    /// This is set in the rcfile; should we query that, or the AudioInput
    /// itself?
    bool muted() const {
        return _input->muted();
    }

    /// The name of the Microphone
    const std::string& name() const {
        return _input->name();
    }

    /// Takes any int, is then set to the nearest available by the AudioInput
    //
    /// Supported rates are: 5, 8, 11, 16, 22, 44
    void setRate(int rate) {
        _input->setRate(rate);
    }

    /// Returns the actual value of the AudioInput rate
    //
    /// Values are in kHz.
    int rate() const {
        return _input->rate();
    }

    /// Range 0..100
    int silenceLevel() const {
        return _input->silenceLevel();
    }

    /// Range?
    int activityLevel() const {
        return _input->activityLevel();
    }

    void setUseEchoSuppression(bool b) {
        _input->setUseEchoSuppression(b);
    }

    bool useEchoSuppression() const {
        return _input->useEchoSuppression();
    }

    int silenceTimeout() const {
        return _input->silenceTimeout();
    }

    void setSilenceTimeout(int i) const {
        _input->setSilenceTimeout(i);
    }

    void setSilenceLevel(int i) const {
        _input->setSilenceLevel(i);
    }

private:
    boost::scoped_ptr<media::AudioInput> _input;

};

// There is a constructor for Microphone that returns an object with
// the correct properties, but it is not usable.
as_value
microphone_ctor(const fn_call& /*fn*/)
{
    return as_value();
}

// AS2 static accessor.
as_value
microphone_get(const fn_call& fn)
{
    as_object* ptr = ensure<ValidThis>(fn);

    // Properties are attached to the prototype (not __proto__) when get() is
    // called. 
    as_object* proto = toObject(getMember(*ptr, NSV::PROP_PROTOTYPE), getVM(fn));
    attachMicrophoneProperties(*proto);
 
    // TODO: this should return the same object when the same device is
    // meant, not a new object each time. It will be necessary to query
    // the MediaHandler for this, and possibly to store the as_objects
    // somewhere.
    const RunResources& r = getRunResources(getGlobal(fn));
    media::MediaHandler* handler = r.mediaHandler();

    if (!handler) {
        log_error(_("No MediaHandler exists! Cannot create a Microphone "
                    "object"));
        return as_value();
    }
    std::auto_ptr<media::AudioInput> input(handler->getAudioInput(0));

    if (!input.get()) {
        // TODO: what should happen if the index is not available?
        return as_value();
    }

    // Normally the VM would furnish us with a newly instantiated object, if
    // a constructor were used. But we're in a factory, so we have to build
    // one for ourselves.
    as_object* mic_obj = createObject(getGlobal(fn));
    mic_obj->set_prototype(proto);
    attachMicrophoneInterface(*mic_obj);
    attachMicrophoneProperties(*mic_obj);

    mic_obj->setRelay(new Microphone_as(input));

    return as_value(mic_obj);
}


as_value 
microphone_setgain(const fn_call& fn)
{
    Microphone_as* ptr = ensure<ThisIsNative<Microphone_as> >(fn);
    
    // Really return if there are 2 args?
    if (fn.nargs != 1) {
        log_error("Microphone.gain(): wrong number of parameters passed");
        return as_value();
    } 

    const boost::int32_t gain = clamp<boost::int32_t>(toInt(fn.arg(0), getVM(fn)), 0, 100);
    ptr->setGain(gain);
    return as_value();
}


as_value
microphone_setrate(const fn_call& fn)
{
    Microphone_as* ptr = ensure<ThisIsNative<Microphone_as> >(fn);
    
    if (fn.nargs != 1) {
        log_error("Microphone.setRate: wrong number of parameters passed");
        return as_value();
    }
    ptr->setRate(toInt(fn.arg(0), getVM(fn)));
    return as_value();
}

as_value
microphone_activityLevel(const fn_call& fn)
{
    Microphone_as* ptr = ensure<ThisIsNative<Microphone_as> >(fn);
        
    if (!fn.nargs) {
        log_unimpl("Microphone::activityLevel only has default value (-1)");
        return as_value(ptr->activityLevel());
    }

    IF_VERBOSE_ASCODING_ERRORS(
        log_aserror(_("Attempt to set activity property of Microphone"));
    );

    return as_value();
}

as_value
microphone_gain(const fn_call& fn)
{
    Microphone_as* ptr = ensure<ThisIsNative<Microphone_as> >(fn);
        
    if (!fn.nargs) {
        return as_value(ptr->gain());
    }
    return as_value();
}

as_value
microphone_index(const fn_call& fn)
{
    Microphone_as* ptr = ensure<ThisIsNative<Microphone_as> >(fn);
    
    if (!fn.nargs) {
        return as_value(ptr->index());
    }

    return as_value();
}

as_value
microphone_muted(const fn_call& fn)
{
    Microphone_as* ptr = ensure<ThisIsNative<Microphone_as> >(fn);
    
    if (!fn.nargs) {
        log_unimpl("Microphone::muted is always false (always allows access)");
        return as_value(ptr->muted());
    }

    return as_value();
}

as_value
microphone_name(const fn_call& fn)
{
    Microphone_as* ptr = ensure<ThisIsNative<Microphone_as> >(fn);
        
    if (!fn.nargs) {
        return as_value(ptr->name());
    }

    return as_value();
}


as_value
microphone_names(const fn_call& fn)
{
    // TODO: populate from MediaHandler like Camera.names.
    std::vector<std::string> vect;
    
    size_t size = vect.size();
    
    Global_as& gl = getGlobal(fn);
    as_object* data = gl.createArray();
    
    for (size_t i = 0; i < size; ++i) {
        callMethod(data, NSV::PROP_PUSH, vect[i]);
    }
        
    return as_value();
} 


as_value
microphone_rate(const fn_call& fn)
{
    Microphone_as* ptr = ensure<ThisIsNative<Microphone_as> >(fn);
    
    return as_value(ptr->rate());
}

as_value
microphone_silenceLevel(const fn_call& fn)
{
    Microphone_as* ptr = ensure<ThisIsNative<Microphone_as> >(fn);

    return as_value(ptr->silenceLevel());
}

as_value
microphone_silenceTimeout(const fn_call& fn)
{
    Microphone_as* ptr = ensure<ThisIsNative<Microphone_as> >(fn);
        
    log_unimpl("Microphone::silenceTimeout can be set, but is unimplemented");
    return as_value(ptr->silenceTimeout());
}

as_value
microphone_useEchoSuppression(const fn_call& fn)
{
    Microphone_as* ptr = ensure<ThisIsNative<Microphone_as> >(fn);
 
    // Documented to be a bool (which would make sense), but is a number.
    const double d = ptr->useEchoSuppression();
    return as_value(d);
}


as_value
microphone_setsilencelevel(const fn_call& fn)
{

    Microphone_as* ptr = ensure<ThisIsNative<Microphone_as> >(fn);
    
    const size_t numargs = fn.nargs;
    if (numargs > 2) {
        log_error("%s: Too many arguments", __FUNCTION__);
        return as_value();
    }

    const double level = clamp<double>(toNumber(fn.arg(0), getVM(fn)), 0, 100);
    ptr->setSilenceLevel(level);
    
    if (numargs > 1) {
        // If it's less than 0, it's set to 0.
        const int timeout = std::max<boost::int32_t>(toInt(fn.arg(1), getVM(fn)), 0);
        ptr->setSilenceTimeout(timeout);
    }
    return as_value();
}

as_value 
microphone_setuseechosuppression(const fn_call& fn)
{
    Microphone_as* ptr = ensure<ThisIsNative<Microphone_as> >(fn);
    
    if (!fn.nargs) {
        return as_value();
    }
    ptr->setUseEchoSuppression(toBool(fn.arg(0), getVM(fn)));
    return as_value();
}

} // anonymous

} // end of gnash namespace

/* [<][>][^][v][top][bottom][index][help] */