/* Network-Integrated Multimedia Middleware (NMM)
 * http://www.motama.com/nmm.html
 *  
 * Copyright (C) 2006-2007
 * Motama GmbH, Saarbruecken, Germany
 * http://www.motama.com
 *  
 * This file is part of NMM. 
 * 
 * NMM 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; only version 2 of the License.      
 * 
 * NMM 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 NMM; if not, write to the Free Software Foundation,    
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 */


#ifndef _NMM_MASTER_SLAVE_SOURCE_SYNCHRONIZER_HPP_
#define _NMM_MASTER_SLAVE_SOURCE_SYNCHRONIZER_HPP_ _NMM_MASTER_SLAVE_SOURCE_SYNCHRONIZER_HPP_

#include "nmm/nmm_prefix.hpp"

#include "Synchronizer.hpp"
#include "nmm/multimedia/sync/interfaces/IMasterSlaveSourceSynchronizerImpl.hpp"
#include "nmm/utils/time/Interval.hpp"

#include "visibility.hpp" 

namespace NMM {
  //! This class represents a synchronizer for SourceNodes.
  /*!
   * The MasterSlaveSourceSynchronizer communicates with both the master source
   * controller and the slave source controller(s).
   */
  class DLLEXPORT MasterSlaveSourceSynchronizer : public SourceSynchronizer,
					virtual public IMasterSlaveSourceSynchronizerImpl{
  private:
    ISourceController* master_source_controller;         //!< Controller of the master source node.
    list<ISourceController*> slave_source_controllers;   //!< The controller(s) of the slave source node(s).

    Interval master_skew;       //!< The skew between audio and video.
    Time     pause_start;       //!< The time of the last pause call.
    Interval start_delay;       ///< The time to wait before the controllers should restart
                                ///< the nodes; useful after pausing or stopping to
                                ///< avoid latencies


  protected:

    //! The states of the MasterSlaveSourceSynchronizer.
    enum State {
      WORKING,   //!< The default state.
      PAUSE
    };

    //! The state of this MasterSlaveSourceSynchronizer.
    State state;

    //! Mutex to gurantee a consistent state.
    ThreadMutex state_mutex;

  public:
    //! The main constructor.
    /*!
     * After constructing a new MasterSlaveSourceSynchronizer, it has to be 
     * connected to the audio and video source nodes with the methods
     * setAudioSource and setVideoSource.
     */
    MasterSlaveSourceSynchronizer(const char* name = "SourceSynchronizer");

    //! The main destructor.
    virtual ~MasterSlaveSourceSynchronizer();

  protected:
    /**
     * Implementation of IMasterSlaveSourceSynchronizer interface.
     */
    /**
     * Sets the time interval to wait before starting after start() is called.
     * This allows the MasterSlaveSourceSynchronizer to tell its controllers the
     * delay time.
     * With the help of a start delay, the nodes
     * are told to start at the current time + delay to avoid scheduling
     * problems (as one node would always be started some time after the other).
     * This is done by setting calling the setStartTime-Method of the controllers
     * with (current_time + delay).
     */
    virtual Result setStartDelay(const Interval& interval);

    /**
     * Sets the master (audio) source node.
     * This allows the MasterSlaveSourceSynchronizer to connect to its master controller.
     */
    virtual Result setMasterController(const ISourceController* value);

    /**
     * Adds a slave source node. (e.g. video)
     * This allows the MasterSlaveSourceSynchronizer to connect to its slave controller(s).
     */
    virtual Result addSlaveController(const ISourceController* value);

    /**
     * Removes a slave source node. (e.g. video)
     */
    virtual Result removeSlaveController(const ISourceController* value);

    /**
     * Resets the MasterSlaveSourceSynchronizer.
     * Only internal variables are resetted, you don't need to set the
     * audio and video source after a reset - call.
     * The reset-method is normally not called directly, but by the
     * ISourceControllers.
     * It switches the state between WORKING and RESET.
     */
    virtual Result resetAll();

    /**
     * Implementation of ISourceSynchronizer interface.
     */
    /**
     * Sets a skew between audio and video output.
     * The video output is presented later as the audio output.
     */
    virtual Result setMasterSkew(const Interval& skew);

    /**
     * Implementation of ISynchronizer interface.
     */
    virtual Result pause();

    virtual Result wakeup();

    /**
     * Resets the Synchronizer.
     * This method is used by the sink controllers and should not be called 
     * directly.
     * Only internal variables are reset, you don't need to set the
     * audio and video sink after a reset call.
     * Switches the state from WORKING to RESET.
     * @param sink sink ID
     */
    virtual Result reset(const nmm_int32& );
  };
}

#include "nmm/nmm_suffix.hpp"

#endif // _NMM_MASTER_SLAVE_SOURCE_SYNCHRONIZER_HPP_
