/* 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_MacOSXPlaybackNode_HPP_
#define _NMM_MacOSXPlaybackNode_HPP_

#include "nmm/nmm_prefix.hpp"


#include <CoreServices/CoreServices.h>
#include <CoreAudio/CoreAudio.h>
#include <AudioUnit/AudioUnit.h>
#include <AudioToolbox/AudioToolbox.h>

#include "nmm/multimedia/TDevicePlugin.hpp"
#include "nmm/multimedia/sync/GenericBSyncSinkNode.hpp"
#include "nmm/utils/time/Clock.hpp"

#include "nmm/plugins/audio/interfaces/IAudioDeviceImpl.hpp"
#include "nmm/multimedia/interfaces/ITrackImpl.hpp"
#include "nmm/multimedia/interfaces/IMuteImpl.hpp"

#include "nmm/utils/thread/Thread.hpp"

namespace NMM {

  //! This class plays an audio stream to a given output device.
  /*!*/
  class MacOSXPlaybackNode :
    public GenericBSyncSinkNode,
    protected IAudioDeviceImpl,
    protected ITrackImpl,
    protected IMuteImpl
  {
  	public:
  	//! The main constructor.
    	/*!
    	 *  Can take a BufferManager to use instead of creating its own Allocator.
    	 *  \param dev the device to open.
    	 *  \param manager the buffer manager to use.
    	 */
    MacOSXPlaybackNode(const char* name = "MacOSXPlaybackNode",
		 const StreamQueue::Mode queue_mode = StreamQueue::MODE_SUSPEND,
		 const int size = StreamQueue::DEFAULT_SIZE);
    virtual ~MacOSXPlaybackNode();
    
  	int readBuffer(float *, int len);
  
  protected:
  	virtual Result doInit();
    	virtual Result doInitOutput();
    	virtual Result doActivate();
    	virtual Result doStart();
    	virtual Result doStop();
    	virtual Result doDeactivate();
    
    void addFormat(const AudioStreamBasicDescription& format);

    virtual Buffer* presentBuffer(Buffer* );
 
    virtual Interval getOutputDelay();
 
  protected:
   	
    virtual void increaseVolume(){};

    virtual void decreaseVolume(){};

    virtual void setVolume(const nmm_int32& volume);

    virtual nmm_int32 getVolume(){ return 0;};

    /**
     * Mutes an audio source or sink
     */
    virtual void mute();

    /**
     * Un-mutes an audio source or sink
     */
    virtual void unmute();


    void setLineInVolume( int vol ){};
    int getLineInVolume(){ return 0;};
    
    //! Sets the output device.
    void setDevice(const string& ) throw (const DeviceNotFoundException&){};
    
    //! Sets the mixer devce
    void setMixerDevice(const string&) throw (const DeviceNotFoundException&){};

    //! Sets the mixer volume element
    void setMixerVolumeElement(const std::string&) {}
    
    //! Sets the output device.
    string getDevice() const{return string();};
    
    //! Gets the output device.
    string getMixerDevice() const{return string();};
   //! startTrack from ITrack interface
    virtual Result startTrack(const string&) {return SUCCESS;}

    virtual Result started(const NMM::Interval&){return SUCCESS;}
    
    //! Endtrack from ITrack interface
    virtual Result endTrack(){return SUCCESS;};

    //! finished from ITrack interface
    virtual Result finished(){return SUCCESS;};
    
    //! new seek method
    Result eventSeek(Interval&, Time&, long&){return SUCCESS;};
    
    //! speed up or delay playback
    Result eventSpeedUp(int& speedup){return SUCCESS;};
    
  private:
  	Result 	getNextBuffer();
    void 	toBigEndian(Buffer* buffer);
    
  private: 
    	AudioDeviceID 	__device;        	// ID of the used device
    	UInt32 			__buffer_size;   	// internal buffer size of used audio device
    
    	ThreadMutex 		__thread_mutex;  	// Mutex to synchronize access to internal buffer
    	ThreadMutex 		__condition_mutex; 	// Mutex used for ThreadCondition
    	ThreadCondition 	__condition;			// Notifies the node to write new data to audio buffer
    	Buffer* 			__current_buffer;	// Current buffer 
     	unsigned int		__read_pos;  		// Current read position of the used buffer
   	    list<Buffer*> 	__buffer_list;		// Internal list of buffers

    	bool 			__is_running;        	// is true if audio data should be processed
    	bool				__to_big_endian;		// is true if incoming data must be converted to big endian    
        ThreadMutex    __internal_buffer_mutex;  // This mutex must be aquired if you access the buffer array
        AudioStreamBasicDescription* format_list; 
        UInt32         format_size;
        int __current_sample_rate;
        int __current_channels;
  };
}

#include "nmm/nmm_suffix.hpp"

#endif // _NMM_PLAYBACKNODE_HPP_


